2016-05-08 10 views
2

これは私が実装したアーキテクチャです。MVVM実装の疑問

enter image description here

基本的に私はビュー2で「セル」を選択すると「場所」は、選択されたセルから移入されます。それから私は "システム"とコンボボックスを持っていて、私はシステム選択をして、別のセルのセットを設定したい。そのために、IOCを使用して異なるビューモデルにアクセスしています。

MVVMパターンに従って実装しているかどうかは間違いありません。 UpdateModelの部分はあまり良くありません。誰かがアーキテクチャを見直して、私がもっと良くできたことを教えてもらえるかどうかは分かります。また、ビューモデルでモデルインスタンスを持つのは正しいですか、mvvm-lightボイラープレートのようなデータサービスパターンを使用する必要がありますか?

質問:UpdateModel関数を呼び出さずにmvvm-lightのネイティブメカニズムを使用してViewModel2を更新すると、システム変更に対する応答を実装できますか?

コードのいくつかの主要部分の下にあります。

ViewModel2:

public List<string> LocationList 
    { 
     get 
     { 
      var cells = _wList.GetCells(currentSystemNumber); 
      var cell = cells[_selectedCellItem.Key]; 
      return cell.Locations; 
     } 
    } 

    private KeyValuePair<int, string> _selectedCellItem; 
    public KeyValuePair<int, string> SelectedCellItem 
    { 
     get 
     { 
      return _selectedCellItem; 
     } 

     set 
     { 
      Set(ref _selectedCellItem, value); 
      RaisePropertyChanged("LocationList"); 
     } 
    } 

    public ObservableCollection<KeyValuePair<int, string>> CellList 
    { 
     get 
     { 
      int count = _wList.GetCells(currentSystemNumber).Count; 
      ObservableCollection<KeyValuePair<int, string>> cells = new ObservableCollection<KeyValuePair<int, string>>(); 
      for(int i = 0; i < count; i++) 
       cells.Add(new KeyValuePair<int, string>(i, string.Format("Cell {0}/{1}", i, currentSystemNumber+1))); 
      return cells; 
     } 
    } 

    public void UpdateModel(int system) 
    { 
     currentSystemNumber = system; 

     RaisePropertyChanged("CellList"); 
     RaisePropertyChanged("LocationList"); 
    } 

VIEW2:

<Grid> 
    <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="104" Margin="121,32,0,0" VerticalAlignment="Top" Width="144" ItemsSource="{Binding LocationList}"/> 
    <ListBox x:Name="listBox1" HorizontalAlignment="Left" Height="104" Margin="10,32,0,0" VerticalAlignment="Top" Width="102" ItemsSource="{Binding CellList}" SelectedItem="{Binding SelectedCellItem}" DisplayMemberPath="Value"/> 
    <Label x:Name="label" Content="Cells" HorizontalAlignment="Left" Margin="10,1,0,0" VerticalAlignment="Top"/> 
    <Label x:Name="label1" Content="Locations" HorizontalAlignment="Left" Margin="121,1,0,0" VerticalAlignment="Top"/> 
</Grid> 

ViewModel1:

private ObservableCollection<KeyValuePair<int, string>> _systems = new ObservableCollection<KeyValuePair<int, string>>(); 
    public ObservableCollection<KeyValuePair<int, string>> Systems 
    { 
     get 
     { 
      return _systems; 
     } 
    } 

    private KeyValuePair<int, string> _selectedSystemItem; 
    public KeyValuePair<int, string> SelectedSystemItem 
    { 
     get 
     { 
      return _selectedSystemItem; 
     } 
     set 
     { 
      Set(ref _selectedSystemItem, value); 
      var locator = (ViewModelLocator)Application.Current.Resources["Locator"]; 
      var vm = locator.DASrvPageVM; 
      vm.UpdateModel(value.Key); 
     } 
    } 
+0

'KeyValuePair'を' Tuple'に変更することで問題が解決されました。残っているのは、自分のアーキテクチャが臭いがないことを確認することだけです。 – Pablo

答えて

0

いくつかのコードに対処するため、ここで部分的な答えは、あなたのアーキテクチャを持って臭いや疑問:

  1. ViewModelsは他のViewModelsについて知ってはいけないので、ViewModel1はViewModel2を呼び出さないでください。

  2. 可能な限りServiceLocatorを使用しないでください。 ViewModelLocatorは、フレームワークによってのみ使用され、直接呼び出されるべきではありません。問題1を修正すると、この問題も削除されます。

  3. モデルでは、ViewModelsと同様にINotifyPropertyChangedを実装できます。この方法で、SelectedSystem、SelectedCell、およびSelectedLocationのプロパティをモデルに配置し、それらのプロパティをPropertyChangedイベントで発生させることができます。

  4. ViewModelを使用して、モデルをいくつかのタイプのリポジトリから引き出すことができます。このようにして、ViewModelがプロパティを更新すると、モデルの状態が保持されます。 ViewModelは、ViewModelLocatorが内部的にどのように動作しているかに基づいて状態を保持する場合と保持しない場合があります。モデルやリポジトリを使用して、状態がViewModelの寿命を超えて持続するようにします。

  5. ObservableCollectionsをViewModelsとModelsのほぼすべてのコレクションタイプに使用すると、ビューはgetterで多くのロジックを実行することなくこれらのビューにバインドできます。ビューの値やコレクションを見たい場合は、Observableであることを確認してください。これにより、MVVMバインディングの完全な機能が使用できるようになり、ビューの更新を維持しようとする大量の定型コードが削除されます。

+0

観測に感謝します。それは私の疑いをほとんど確認しました。では、モデルからXAMLバインディングオブジェクトを直接指定する必要がありますか?私はモデルが直接ビューと対話してはならないと思っていた。 – Pablo

+0

モデルはビューとやり取りしませんが、INotifyPropertyChangedを実装することができます。彼らはリスナーにその変更を通知するだけです。ビューは、モデルをプロパティとして持つことができるViewModelにバインドされています。このようにして、バインディングは 'Text =" {Binding Model.Name} "のようになります。 ViewModelはモデルとのやりとりをすべて実行する必要があり、Viewは単にBinding構文を使用してこれらの変更をサブスクライブします。 – ManOVision

+0

もう1つ... ViewModel2でモデルをインスタンス化すると、UIコンポーネントの1つがViewModel1からアクセスする必要があります。 ViewModel2でModelインスタンスを取得するためにsingletoneパターン(たとえばIOC)を使用するかどうか、またはより良い方法がありますか? – Pablo