2016-05-08 9 views
2

Dies ist die Architektur, die ich implementiert habe.Zweifel an der MVVM-Implementierung

enter image description here

Grundsätzlich möchte ich die Option „Zellen“ in View 2 und „Orte“ wird von der ausgewählten Zelle aufgefüllt werden. Dann habe ich Combo-Box mit "Systemen" und ich möchte nach der Systemauswahl, verschiedene Sätze von Zellen bevölkern. Dafür benutze ich IOC, um auf ein anderes Ansichtsmodell zuzugreifen.

Zweifel ist, ob ich nach MVVM Muster implementiert habe. Der Teil mit UpdateModel sieht mir nicht so gut aus. Ich würde mich freuen, wenn jemand die Architektur überprüfen und mir sagen könnte, was ich besser hätte machen können. Ist es auch richtig, Modellinstanzen im View-Modell zu haben, oder sollte ich Datendienstmuster verwenden, wie in mvvm-light boilerplate?

Frage: Kann ich die Reaktion auf Systemänderungen implementieren, ohne die UpdateModel-Funktion aufzurufen, sondern mithilfe der nativen Mechanismen von mvvm-light ViewModel2 zu aktualisieren?

Nachfolgend einige wichtige Teile des Codes.

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

Das Ändern von 'KeyValuePair' in' Tuple' löste das Problem. Einzige Sache ist, sicherzustellen, dass meine Architektur keine stinkigen Plätze hat. – Pablo

Antwort

0

Teil Antwort hier einige Code zur Adresse Gerüche und Zweifel, die Sie haben mit Ihrer Architektur:

  1. ViewModels sollte nichts über andere ViewModels wissen, daher sollte ViewModel1 nicht in ViewModel2 aufrufen.

  2. ServiceLocator sollte nicht verwendet werden, wenn überhaupt möglich. ViewModelLocator sollte nur vom Framework verwendet und nicht direkt aufgerufen werden. Wenn Sie Problem 1 beheben, wird dieses Problem ebenfalls behoben.

  3. Modelle können sowohl INotifyPropertyChanged als auch ViewModels implementieren. Auf diese Weise können Sie Eigenschaften für SelectedSystem, SelectedCell und SelectedLocation in ein Modell einfügen und diese das PropertyChanged-Ereignis auslösen.

  4. Verwenden Sie Ihr ViewModel, um Ihre Modelle aus einem Repository zu extrahieren. Auf diese Weise wird der Status des Modells beibehalten, wenn die ViewModels ihre Eigenschaften aktualisieren. ViewModels kann den Status basierend darauf, wie der ViewModelLocator intern arbeitet, beibehalten oder nicht. Verwenden Sie Modelle und/oder Repositories, um sicherzustellen, dass der Status über die Lebensdauer des ViewModel hinaus anhält.

  5. Verwenden Sie ObservableCollections für fast alle Auflistungstypen in ViewModels und Modellen, damit die Ansichten an diese binden können, ohne dass so viel Logik auf den Gettern ausgeführt werden muss. Faustregel: Wenn Sie einen Wert oder eine Sammlung in der Ansicht sehen möchten, stellen Sie sicher, dass sie Observable sind. Dies ermöglicht die volle Nutzung der MVVM-Bindungen und entfernt jede Menge Code, um die View zu aktualisieren.

+0

Danke für die Beobachtungen. Das hat meine Zweifel ziemlich bestätigt. Also sollte ich direkt in XAML Objekte aus dem Modell binden?Ich dachte, das Modell sollte nicht direkt mit der Sicht interagieren. – Pablo

+0

Modelle interagieren nicht mit der Ansicht, aber sie können und sollten INotifyPropertyChanged implementieren. Sie informieren die Zuhörer nur über die Änderung. Die Ansicht ist an das ViewModel gebunden, das das Modell als Eigenschaft haben kann. Auf diese Weise sieht die Bindung wie folgt aus: Text = "{Binding Model.Name}" '. Das ViewModel sollte weiterhin die gesamte Interaktion mit dem Modell durchführen, und die Ansicht abonniert diese Änderungen einfach über die Binding-Syntax. – ManOVision

+0

nur noch eine Sache ... Wenn ich mein Modell in ViewModel2 instanziiere, muss ich immer noch auf ViewModel1 zugreifen, da sich dort eine der UI-Komponenten befindet. Ist es sinnvoll, ein Singletone-Muster (zB IOC) zu verwenden, um eine Model-Instanz in ViewModel2 zu erhalten, oder gibt es einen besseren Weg? – Pablo