MVVM Padrão, ViewModel DataContext pergunta
-
05-07-2019 - |
Pergunta
Eu preciso descobrir como se comunicar entre ViewModels. Eu sou novo para MVVM então por favor seja gentil.
Aqui está uma idiotizadas exemplo
definições de classe (supor que eu tenha ligado o evento Child.PropertyChanged na 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");
}
}
}
Aqui está o que você vê no recurso dicionário
<DataTemplate DataType="{x:Type vm:ParentViewModel}">
<vw:ParentView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
eo código-behind do ChildView:
public partial class ChildView : UserControl
{
public QueueView()
{
InitializeComponent();
DataContext = new ChildViewModel();
}
}
O problema óbvio é que quando o ChildView é instanciado (via seleção do DataTemplate) ele cria uma nova classe ChildViewModel e não o ParentViewModel não tem acesso a ele.
Então, como posso instanciar o DataContext do Vista para ser o ViewModel original que causou o DataTemplate para ser selecionado?
Uma correção óbvia é mmerge as propriedades na ChildViewModel no ParentViewModel, mas eu preferia separá-lo porque para reutilização.
Eu tenho certeza que a resposta é trivial, eu só gostaria de saber o que é. :)
Agradecemos antecipadamente.
Solução
Você deve simplesmente remover a linha:
DataContext = new ChildViewModel();
O DataContext
da exibição será definido automaticamente pelo WPF. DataTemplates
sempre tem o seu conjunto de contexto de dados para os dados para o modelo (neste caso, o ViewModel):
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
O resultado final é que você pode construir seu modelo de exibição objetos separadamente (ambas as classes pai e filho) e depois exibi-los mais tarde, basta conectá-los em controles de conteúdo.
Outras dicas
A maneira mais fácil de se comunicar entre ViewModels usando a abordagem MVVM é usar o Mediator (EventAggregator em Prism). Um bom exemplo desta abordagem pode ser visto nos seguintes links:
Além disso, verifique o MVVM quadro projeto amostra.
Vamos dizer que você tem uma QueueView que usa um 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>