将ViewModel绑定到多个窗口

Tob*_*lls 8 c# wpf xaml binding mvvm

我正在重新编写我的Windows表单项目,该项目为羊剪切事件(不要问,这是新西兰的一项大型运动)从vbnet到wpf c#进行评分,并且遇到了一个我似乎无法克服的问题.

我有两个窗户.一个是您输入内容的源窗口(如当前事件名称),另一个窗口将以闪存方式显示此信息,以便投影到屏幕上(因此将在第二个监视器上)以及其他一些数据在via XML over the network.我将它设置为MVVM,将ViewModel和Model作为单独的项目.

在我的主窗口上,我可以很好地绑定控件,如果我输入一个文本框,它会立即出现在另一个文本框中,如果它绑定到同一个东西.但是,在第二个窗口中,我将控件绑定到同一个窗口,并且它没有更新.

我已经围绕这个问题进行了一个星期的讨论,网上的每个例子都显示了如何在一个窗口上进行操作,我已经工作正常,但是缺少两个窗口示例.

这是我的......

这是在我的ViewModel项目中

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");
            }     
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个主窗口,没有真正的代码,除了一行打开第二个窗口,我们将...

 public MainWindow()
    {
        ScoreScreen SW = new ScoreScreen();
        SW.Show();
        InitializeComponent();
    }
Run Code Online (Sandbox Code Playgroud)

然后是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>
Run Code Online (Sandbox Code Playgroud)

上面的代码都可以正常工作,如果我在第一个文本框中键入它出现在第二个文本框中的文本.如果我在通知部分放置一个console.writeline,那么我可以看到它击中并更新.

现在我添加第二个窗口,设置完全相同...

<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>
Run Code Online (Sandbox Code Playgroud)

同样,这里没有真正的代码.

奇怪的是,如果我以两种方式进行此控制并输入它,我可以看到它击中相同的通知部分,但它没有更新其他窗口.

我不确定我在这里缺少什么,所以任何指导我正确方向的帮助将非常感激.

小智 11

那是因为两个窗口必须共享ViewModel的完全相同的实例.

您的所有属性都是实例属性,例如

public string CurrentEventName { get { // snip
Run Code Online (Sandbox Code Playgroud)

因此,所有值都与每个实例不同.您正在创建两个实例,每个窗口一个.

<Window x:Class="Sheep_Score_3._1.MainWindow"
    xmlns:blah="http://inurxamlskippinurschemas.org">
    <Window.DataContext>
        <vm:SheepViewModel/>
    </Window.DataContext>
Run Code Online (Sandbox Code Playgroud)

那是一个例子,这是另一个例子

<Window x:Class="Sheep_Score_3._1.ScoreScreen"
        xmlns:blah="http://yaddayaddawhocares.derp">
    <Window.DataContext>
        <vm:SheepViewModel/>
    </Window.DataContext>
Run Code Online (Sandbox Code Playgroud)

请记住,xaml只是被反序列化为对象图的标记.您有两个不同的标记文件,它们包含其中描述的所有内容的不同实例.

这没有什么不对,使用具有实例属性的视图模型没有任何问题.事实上,这是使用静态和静态绑定的首选方式.

答案很幸运.您需要将两个窗口都放在视图模型的同一个实例中.

首先,删除<Window.DataContext>两个窗口中的所有废话.那不适合你.现在,只需将构造函数更改为

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

而且你已经完成了.