2016-01-27 30 views
8

私は、羊の剪断イベント(ニュージーランドでは巨大なスポーツではない)をvbnetからwpf C#にスコア付けするWindowsフォームプロジェクトを書き直しています。私は克服していないようです。ViewModelを複数のウィンドウにバインドする

私は2つのウィンドウを持っています。 1つは(現在のイベント名のような)物事を入力するソースウィンドウで、もう1つのウィンドウは他のデータとともに、スクリーンに投影するためにこの情報をフラッシュで表示します(したがって、2番目のモニターに表示されます)ネットワーク経由でXML経由で送信します。 ViewModelとModelを別々のプロジェクトとしてMVVMとしてセットアップしました。

私のメインウィンドウでは、コントロールを正しくバインドすることができます。同じテキストにバインドされている場合、1つのテキストボックスに入力するとすぐに別のテキストボックスに表示されます。 しかし、2番目のウィンドウでは、同じことをコントロールにバインドしていますが、更新はされていません。

私は一週間これを円で回ってきました。ネット上のすべての例は、うまくいっている1つのウィンドウでそれを行う方法を示していますが、2つのウィンドウの例がありません。ここで

これは私の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"); 
      }  
    } 
} 

です...私が持っているもの

ですそれから私は、メインウィンドウを持って、二を開くための回線以外の背後には、実際のコードではありません我々はに取得するウィンドウ...その後

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

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> 

上記のコードはすべて正常に動作します。最初のテキストボックスにテキストを入力すると、2番目のテキストボックスに表示されます。私が通知部分にconsole.writelineを置くと、私はそれが当たって更新されているのを見ることができます。

今、私は2番目のウィンドウ、セットアップまったく同じようアゲイン...

<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> 

、この中の背後には、実際のコードを追加します。

私はこのコントロールを双方向にして入力すると、同じ通知セクションに当たるのを見ることができますが、他のウィンドウは更新されません。

ここで私は何が欠けているのか分かりませんので、正しい方向に私を指差してくれれば助かります。

答えて

9

これは、の両方のウィンドウがViewModelとまったく同じインスタンスを共有する必要があるからです。

あなたのすべてのプロパティは

public string CurrentEventName { get { // snip 

ようインスタンスのプロパティ、であるため、すべての値は、各インスタンスに異なっています。 2つのインスタンスを各ウィンドウに1つずつ作成しています。

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

つのインスタンスだし、ここでは他の

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

は、XAMLがは、オブジェクトグラフにをデシリアライズされているだけでマークアップされ、覚えておいてくださいます。 2つの異なるマークアップファイルがあります。これらのマークアップファイルには、記述されたすべてのインスタンスが含まれています。

この問題は何も問題はなく、インスタンスプロパティを持つビューモデルを持つことは間違いありません。実際、静的なバインディングや静的なバインディングを使用するのが好ましい方法です。

答えは幸運にも簡単です。 両方のウィンドウ同じインスタンスをビューモデルに渡す必要があります。

まず、両方のウィンドウからすべて<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; 
} 

これで完了です。

+0

ありがとうございました、ありがとうございました。 これは完璧な意味を持っています。私は彼らが2つの別々のインスタンスであると感じましたが、VBのバックグラウンドから来て、私はこのようにリンクする方法がわかりませんでした。 –

+0

ハハハハ! +1だけのために "yaddayaddawhocares.derp" –

+0

@ TobyMillsあなたがインスタンスについてわからない場合、あなたは常にそれらを追跡するためにオブジェクトIDを使用することができます。 https://blogs.msdn.microsoft.com/zainnab/2010/03/04/make-object-id/剪断で幸運を祈る!ああ、あなたが書き直しを初演したときに私を叫ぶと、それは***超素晴らしい***になるでしょう。 – Will

1

私は、各ウィンドウがViewModelの独自のインスタンスを作成していると考えています。

+0

xamlのDataContextがInitializeComponent内に設定されているかどうかは不明なので、この時点でthis.DataContextがnullになることがあります。 – Will

+1

初期化後にdatacontextを設定できます。 – TrueEddie

+0

確かに分かりませんでしたので、確認するのに1分かかりました... DataContextはInitializeComponentの後に塗りつぶされていますが、オリジナルは元のようになりました。 – Will

0

viewmodelは、1つのインスタンスを取得する静的メソッドを定義しますが、インスタンシエートするためには使用しません。現在、デフォルトのコンストラクタでビューモデルが作成されています。これは、2つのウィンドウに別々のコピーがあることを意味します。

InitializeComponentまたはOnNavigatedToEventの下にあるコードの中にviewmodelを作成します。ここで

はさらに説明するためにいくつかのコードです:

はあなたのコンストラクタそのように両方のウィンドウで

property SheepViewModel ViewModel { get; set; } 

ようにViewModelにプロパティを定義します。

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

<vm:SheepViewModel/> 
を削除します

をxamlから削除する必要はありません。

+0

これは正しくありません。彼はすでにビューモデル(Window.DataContext)用に設計された両方のウィンドウ上にプロパティを持っています。 – Will

+0

私の答えをもう一度読んでください私はその呼び出しをデフォルトのコンストラクタと呼んでいますので、OPとして動作しません。インスタンスを取得する静的メソッドを記述しました。 –

+0

私のコメントをもう一度読んでください。彼は「両方のウィンドウでViewModelプロパティを定義してください」と言いましたが、これは非常に間違っています。ビューモデルは、いくつかのランダムプロパティではなく、 'DataContext'に入ります。 – Will

0

私はあなたが私はこのコンセプトにまだ新しいよこの

DataContext="{StaticResource MainViewModel}" 

のようにそれを呼び出して、私は、各ウィンドウに

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

アプリケーション・リソースとしてのViewModelになるだろうこれが最適かどうかはわかりません。それはしかし、動作します!