Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding ViewModel to multiple windows

I'm re-writing my windows forms project that does scoring for sheep shearing events (don't ask, its a huge sport in New Zealand) from vbnet to wpf c# and have struck a problem that I can't seem to overcome.

I have two windows. One is the source window where you type things in (like the current event name), and the other window will display this information in a flash way for projection onto a screen (so will be on a second monitor) along with some other data coming in via XML over the network. I have set it up as MVVM with a ViewModel and a Model as separate projects.

On my Main window, I can bind controls fine and if I type in one text box it immediately appears in another text box if it is bound to the same thing. However, on a second window, I have bound a control to the same thing and it is not updating.

I've been going around in circles on this for a week, every example on the net shows how to do it on One window which I have got working fine, but there is a lack of two window examples.

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 a main window, there is no real code behind other than a line to open a second window which we will get to...

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

Then the 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 above code all works fine, if I type text in the first textbox it appears in the second text box. If I put a console.writeline in the notify part then I can see it hitting it and updating.

Now I add a second window, setup exactly the same way...

<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, no real code behind in this.

The strange thing, is if I make this control two way and type in it, I can see it hitting the same notify section, but it is not updating the other window.

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

like image 555
Toby Mills Avatar asked Jan 27 '16 20:01

Toby Mills


People also ask

Can a view have multiple Viewmodels?

ViewModel is nothing but a single class that may have multiple models. It contains multiple models as a property.

Can a view have multiple Viewmodels in WPF?

Err no - it's just convention that you have one instance, but there actually aren't any rules that you can't have multiple VM's in the XAML - the key thing to understand is that every item has it's own DataContext (that's inherited), so if you need to use a different DataContext then you just bind to the appropriate VM ...

What is the use of INotifyPropertyChanged in C#?

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed. For example, consider a Person object with a property called FirstName .

What is DataContext in WPF?

The DataContext property is the default source of your bindings, unless you specifically declare another source, like we did in the previous chapter with the ElementName property. It's defined on the FrameworkElement class, which most UI controls, including the WPF Window, inherits from.


1 Answers

I would make the ViewModel as an application resource

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

then in the 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!

like image 91
Muhannad Avatar answered Oct 17 '22 00:10

Muhannad