2009-05-05 16 views
8

Ho bisogno di capire come comunicare tra ViewModels. Sono nuovo di MVVM quindi per favore sii gentile.MVVM Pattern, ViewModel DataContext domanda

Ecco un esempio instupiditi

definizioni di classe (si presuppone che ho agganciato l'evento Child.PropertyChanged nel ParentViewModel):

public class ParentViewModel : ViewModelBase 
{ 
    public ChildViewModel Child { get; set; } 
} 

public class ChildViewModel : ViewModelBase 
{ 
    String _FirstName; 
    public String FirstName 
    { 
     get { return _FirstName; } 
     set 
     { 
      _FirstName = value; 
      OnPropertyChanged("FirstName"); 
     } 
    } 
} 

Ecco cosa si vede nel dizionario risorse

<DataTemplate DataType="{x:Type vm:ParentViewModel}"> 
    <vw:ParentView/> 
</DataTemplate> 

<DataTemplate DataType="{x:Type vm:ChildViewModel}"> 
    <vw:ChildView/> 
</DataTemplate> 

e il code-behind di ChildView:

public partial class ChildView : UserControl 
{ 
    public QueueView() 
    { 
     InitializeComponent(); 
     DataContext = new ChildViewModel(); 
    } 
} 

Il problema ovvio è che quando ChildView viene istanziato (tramite selezione dal DataTemplate) crea una nuova classe ChildViewModel e il ParentViewModel non ha accesso ad esso.

Quindi, come è possibile creare un'istanza del DataContext della vista come ViewModel originale che ha causato la selezione del DataTemplate?

Una correzione ovvia è di mmerge le proprietà in ChildViewModel nel ParentViewModel, ma preferisco separarlo perché per il riutilizzo.

Sono sicuro che la risposta è banale, vorrei solo sapere di cosa si tratta. :)

Grazie in anticipo.

+0

A proposito, suppongo che abbiate modificato i nomi delle classi per semplificare l'esempio ... Il nome della classe per "ChildView" nel codice sottostante è "QueueView". –

+0

Era un errore? –

+0

Sì, questo era un errore di battitura. sorry :) – Jose

risposta

8

Si dovrà semplicemente rimuovere la riga:

DataContext = new ChildViewModel(); 

La DataContext della vista verrà impostato automaticamente dal WPF. DataTemplates sempre hanno il loro contesto insieme di dati ai dati per il modello (in questo caso il ViewModel):

<DataTemplate DataType="{x:Type vm:ChildViewModel}"> 
    <vw:ChildView/> 
</DataTemplate> 

Il risultato finale è che si può costruire il modello di visualizzazione degli oggetti a parte (entrambe le classi principali e secondari) e poi visualizzali in seguito semplicemente inserendoli nei controlli del contenuto.

+0

Se l'intento è per un ParentView di contenere un ChildView, come questo da solo imposta il DataContext di ChildView per essere ParentViewModel.Child? –

+0

Bene, lo scenario sarebbe probabilmente simile a questo: In un metodo factory o builder, si creerebbe l'oggetto genitore e figlio. Questo oggetto sarebbe consegnato a una vista. –

+0

La vista mostrerebbe il genitore in un controllo di contenuto e il bambino in un altro, o visualizzerebbe sia padre che figlio in un controllo HeaderedContent. –

1

Supponiamo di disporre di un QueueView che utilizza un QueueViewModel.

public class QueueViewModel : INotifyPropertyChanged 
{ 
    public ParentType Parent { get; set; } 

    public QueueViewModel(ParentType parent) 
    { 
     this.Parent = parent; 
     foreach (ChildType child in Parent) 
     { 
      child.PropertyChanged += delegate(object sender, 
       PropertyChangedEventArgs e) 
      { 
       if (e.PropertyName != "IsSelected") 
        return; 

       //do something like this: 
       Parent.IsSelected = AllChildrenAreSelected(); 
      }; 
     } 
    } 

} 

public class ParentType : INotifyPropertyChanged 
{ 
    private bool _isSelected; 

    public IList<ChildType> Children { get; set; } 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
      _isSelected = value; 
      OnPropertyChanged("IsSelected"); 
     } 
    } 
} 

public class ChildType : INotifyPropertyChanged 
{ 
    private string _name; 
    private bool _isSelected; 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      OnPropertyChanged("Name"); 
     } 
    } 

    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
      _isSelected = value; 
      OnPropertyChanged("IsSelected"); 
     } 
    } 
} 

- QueueView parte

<StackPanel> 
<CheckBlock Text="{Binding Path=Parent.Name}" 
      IsChecked="{Binding Parent.IsSelected}"/> 
<ItemsControl ItemsSource="{Binding Path=Parent.Children}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate>          
      <CheckBox Content="{Binding Path=Name}" 
         IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/> 
     </DataTemplate> 
    <ItemsControl.ItemTemplate> 
</ItemsControl> 
</StackPanel> 
+0

Gli esempi di codice non sembrano realmente correlati alla domanda. Uno o entrambi abbiamo perso il punto? –

+0

Supponevo che il modello figlio fosse una proprietà del modello principale. (ad esempio, ordine + elenco dei dettagli dell'ordine). In tal caso è possibile utilizzare le notifiche di modifica proprietà per comunicare all'interno del modello di visualizzazione. Ma se sono modelli di vista separati, è possibile utilizzare il modello di mediatore per comunicare. –

Problemi correlati