Binding ViewModel to multiple windows

I am rewriting my windows project, which catches events for shearing sheep (don't ask, its a huge sport in New Zealand) from vbnet to cp wpf and hit a problem that I cannot imagine to overcome.

I have two windows. One of them is the initial window in which you enter things (for example, the name of the current event), and the other window will display this information in flash mode for projection onto the screen (this will be on the second monitor) along with some other data via XML via net. I installed it as MVVM with ViewModel and Model as separate projects.

In my main window, I can bind controls in order, and if I enter one text field, it immediately appears in another text field if it is associated with the same. However, in the second window, I linked the control to the same, and it does not update.

I’m going around in circles for a week, each example on the network shows how to do this in one window, which I got normally, but there are no two examples of windows.

Here is what I have ...

This is in my ViewModel project

namespace SheepViewModel { public class SheepViewModel : INotifyPropertyChanged { private string _CurrentEventName; static SheepViewModel _details; public string CurrentEventName { get { return _CurrentEventName; } set { _CurrentEventName = value; OnPropertyChanged("CurrentEventName"); } } public static SheepViewModel GetDetails() { if (_details == null) _details = new SheepViewModel(); return _details; } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string prop) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop)); Console.WriteLine("Test"); } } } 

Then I have the main window, there is no real code except a line to open the second window, which we get ...

  public MainWindow() { ScoreScreen SW = new ScoreScreen(); SW.Show(); InitializeComponent(); } 

Then xaml

 <Window x:Class="Sheep_Score_3._1.MainWindow" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:SheepViewModel;assembly=SheepViewModel" mc:Ignorable="d" Title="MainWindow" Height="433.689" Width="941.194"> <Window.DataContext> <vm:SheepViewModel/> </Window.DataContext> <Window.Resources> <Grid Margin="0,0,0,0"> <TextBox x:Name="CurrentEventName" Height="23" Margin="131.01,163.013,0,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Left" Width="327.151" Text="{Binding CurrentEventName, Mode=TwoWay}"/> <TextBox Text="{Binding CurrentEventName, Mode=TwoWay}" Margin="39.605,0,0,108.567" Height="49.111" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="399" /> </Grid> 

The code above works fine if I enter text in the first text box, it appears in the second text box. If I put console.writeline in the notification part, then I see how it hits and updates it.

Now I am adding a second window, setting up exactly the same ...

 <Window x:Class="Sheep_Score_3._1.ScoreScreen" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:SheepViewModel;assembly=SheepViewModel" mc:Ignorable="d" Title="ScoreScreen" Height="300" Width="300"> <Window.DataContext> <vm:SheepViewModel/> </Window.DataContext> <Grid> <TextBox x:Name="textBlock" HorizontalAlignment="Left" Margin="79.374,116.672,0,0" TextWrapping="Wrap" Text="{Binding CurrentEventName, Mode=TwoWay}" VerticalAlignment="Top"/> </Grid> 

Again, there is no real code in this.

The strange thing is, if I do this management in two ways and type it, I see that it falls into the same notification section, but does not update another window.

I'm not sure what I'm missing here, so any help in pointing me in the right direction would be greatly appreciated.

+8
c # wpf mvvm binding xaml
source share
4 answers

This is because both windows must share the same instance of ViewModel.

All your properties are instance properties, for example

 public string CurrentEventName { get { // snip 

and therefore, all values ​​are different for each instance. You create two instances, one for each window.

 <Window x:Class="Sheep_Score_3._1.MainWindow" xmlns:blah="http://inurxamlskippinurschemas.org"> <Window.DataContext> <vm:SheepViewModel/> </Window.DataContext> 

This one instance, and here another

 <Window x:Class="Sheep_Score_3._1.ScoreScreen" xmlns:blah="http://yaddayaddawhocares.derp"> <Window.DataContext> <vm:SheepViewModel/> </Window.DataContext> 

Remember that xaml is just markup that is deserialized in the object graph. You have two different markup files, they contain different instances of everything that is described in them.

There is nothing wrong with that, and there is nothing wrong with having a view model with instance properties. In fact, this is the preferred way to use statics and static bindings.

The answer is simple. You need to pass both windows the same instance of your view model.

First remove all the <Window.DataContext> tags from both of your windows. This is not for you. Now just change the constructor to

 public MainWindow() { var viewModel = new SheepViewModel(); ScoreScreen SW = new ScoreScreen(); SW.DataContext = viewModel; SW.Show(); InitializeComponent(); //NOTICE! After Init is called! DataContext = viewModel; } 

And you're done.

+9
source share

I suspect that each window creates its own instance of the ViewModel. You can try the following:

 public MainWindow() { InitializeComponent(); SheepViewModel svm = new SheepViewModel(); this.DataContext = svm; ScoreScreen SW = new ScoreScreen(); SW.DataContext = svm; SW.Show(); } 
+1
source share

Your viewmodel defines a static method to get a single instance, but you do not use it to create it. Your viewmodel is currently being created using the default constructor, which means the two windows will have separate copies.

Create your view model in the code below either InitializeComponent or OnNavigatedToEvent.

Here is the code for further explanation:

define a ViewModel property similar to this in both windows

 property SheepViewModel ViewModel { get; set; } 

Then your constructor:

 public MainWindow() { InitializeComponent(); ViewModel = SheepViewModel.GetDetails(); // include this line ScoreScreen SW = new ScoreScreen(); SW.Show(); } 

also delete

 <vm:SheepViewModel/> 

from haml as it is not required.

0
source share

I would make ViewModel as an application resource

 <Application.Resources> <VM:ViewModel x:Key="SharedViewModel" /> .... </Application.Resources> 

then in each window you call it like this:

 DataContext="{StaticResource MainViewModel}" 

I'm still new to this concept, and I'm not sure if this is optimal. It works though!

0
source share

All Articles