2016-08-07 41 views
0

Ich versuche noch, MVVM und WPF hier zu lernen.Verschachteltes Ansichtsmodell in WPF

Ich versuche, ein komplexes Ansichtsmodell EditArticleViewModel zu erstellen. Es hat Code, der für ähnliche Steuerelemente wiederholt wird, und so habe ich den Wiederholungscode in eine andere Klasse verschoben. Dann habe ich mehrere Instanzen dieser anderen Klasse in EditArticleViewModel hinzugefügt.

Ich werde eine Instanz von EditArticleViewModel als meines Fensters DataContext setzen. Und ich werde an Dinge wie Categories.Items und Subcategories.SelectedItem binden.

public class CategoryView 
{ 
    public ObservableCollection<object> Items { /* */ } 
    public object SelectedItem { /* ... */ } 
} 

public class SubcategoryView 
{ 
    public ObservableCollection<object> Items { /* */ } 
    public object SelectedItem { /* ... */ } 
} 

public class EditArticleViewModel : INotifyPropertyChanged 
{ 
    public CategoryView Categories { get; private set; } 
    public SubcategoryView Subcategories { get; private set; } 

    public EditArticleViewModel() 
    { 
     Categories = new CategoryView(); 
     SubcategoryView Subcategories new SubcategoryView(); 
    } 

    // Additional properties and methods here 

} 

Wie Sie sehen können, meine EditArticleViewModel Klasse implementiert INotifyPropertyChanged so, dass ich die visuellen Elemente benachrichtigen können, wenn sich etwas geändert hat.

Meine Frage ist, wie ich visuelle Elemente über Änderungen innerhalb CategoryView und SubcategoryView benachrichtigen. Gibt es eine Möglichkeit, das Fenster direkt über Änderungen in diesen Klassen zu benachrichtigen? Oder muss ich ein Ereignis von jeder Klasse auslösen und EditArticleViewModel behandeln dieses Ereignis, um die entsprechende Benachrichtigung zu senden?

Alle Tipps geschätzt.

+1

Könnten Sie 'SubcategoryView' und' CategoryView' 'INotifyPropertyChanged' implementieren lassen und die Ansicht einfach die Änderungen verarbeiten lassen? – Michael

+0

@Michael: Aber dann müsste ich den 'DataContext' nicht auf diese Klassen-Instanzen setzen? –

+0

@ JonathanWood Wenn die Bindung eine bestimmte Eigenschaft für ein bestimmtes Objekt finden kann, glauben Sie nicht, dass sie auch das Objekt finden kann, für das sie die Eigenschaft gefunden hat? Beenden Sie das Ausleihen von Problemen und schreiben Sie einen einfachen Code, um mit diesem Zeug zu spielen. Sie werden bald genug echte Fragen haben. –

Antwort

2

Es sollte nur ein ViewModel pro View geben, mit einer Erweiterung, dass das primäre ViewModel andere "ViewModels" enthalten kann.

Also, wenn Sie DataContext Ihrem primären Ansichtsmodell alle Inhalte davon angegeben wird, wird ein Abonnement für NotifyPropertyChanged Ereignis haben, so INotifyPropertyChanged Schnittstelle in anderen abgeleiteten Ansichtsmodell Umsetzung wird benachrichtigt.

Ich würde vorschlagen, eine Basisklasse mit INotifyPropertyChangedinterface zu implementieren, die Sie in Ihren anderen ViewModels ableiten könnten.

Indem diese Änderung das Problem zu lösen, sollten Sie haben:

public class ObservableViewModelBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public void OnPropertyChanged([CallerMemberName]string propName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 
    } 
} 

public class CategoryView : ObservableViewModelBase 
{ 
    public ObservableCollection<object> Items { /* */ } 
    public object SelectedItem { /* ... */ } 
} 

public class SubcategoryView : ObservableViewModelBase 
{ 
    public ObservableCollection<object> Items { /* */ } 
    public object SelectedItem { /* ... */ } 
} 

public class EditArticleView : ObservableViewModelBase 
{ 
    public CategoryView Categories { get; set; } = new CategoryView(); 
    public SubcategoryView Subcategories { get; set; } = new SubcategoryView(); 
} 

ObservableCollection Bezug. Die Ansicht wird nur dann geändert, wenn Sie Elemente hinzufügen/entfernen, benachrichtigt jedoch nicht, wenn Inhalte geändert werden. Blick auf Artikel Inhaltsänderung zu aktualisieren, sollten Sie so etwas haben:

public class GridRowItemViewModel : ObservableViewModelBase // From previous example. 
{ 
     private string _sampleProp;   
     public string SampleProp 
     { 
      get 
      { 
       return _sampleProp; 
      } 
      set 
      { 
       _sampleProp = value; 
       OnPropertyChanged(); 
      } 
     } 
} 

Und damit Ihr Hauptansichtsmodell sollte wie folgt aussehen:

public class MainViewModel : ObservableViewModelBase // This is your DataContext. 
{ 
    public ObservableCollection<GridRowItemViewModel> GridCollection { get; set; } 
} 

EDIT: Sie können nicht binden an Feldern, WPF löst Felder nicht auf. Es kann nur mit Eigenschaften umgehen. Wenn Sie also einfache Felder für untergeordnete ViewModels erstellen, erhalten Sie keinen Ort. Ändern Sie diese in Eigenschaften und Sie können auf den Inhalt in der Ansicht nach dem Namen der Eigenschaft zugreifen.

+0

Ich verstehe das nicht ganz. Die Implementierung von 'INotifyPropertyChanged' in meinen untergeordneten Klassen ist also einfach genug. Aber ich versuche zu verstehen, wie diese Benachrichtigungen an die übergeordnete 'EditArticleView' Klasse weitergegeben werden. Ich sehe die Antwort in Ihrem Code nicht. –

+0

Wenn Sie über Änderungen in Ihren untergeordneten ViewModels informieren möchten, sollten Sie die INotifyPropertyChanged-Schnittstelle innerhalb dieser untergeordneten ViewModels implementieren. View wird die Implementierung sehen und das NotifyPropertyChanged-Ereignis abonnieren. – Karolis