MVVM Pattern, ViewModel DataContext вопрос
-
05-07-2019 - |
Вопрос
Мне нужно выяснить, как общаться между ViewModels. Я новичок в MVVM, поэтому будьте добры.
Вот глупый пример
определения классов (предположим, что я перехватил событие Child.PropertyChanged в 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");
}
}
}
Вот что вы видите в словаре ресурсов
<DataTemplate DataType="{x:Type vm:ParentViewModel}">
<vw:ParentView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
и программный код ChildView:
public partial class ChildView : UserControl
{
public QueueView()
{
InitializeComponent();
DataContext = new ChildViewModel();
}
}
Очевидная проблема заключается в том, что, когда экземпляр ChildView создается (посредством выбора из DataTemplate), он создает новый класс ChildViewModel, а ParentViewModel не имеет к нему доступа.
Итак, как мне создать экземпляр DataContext для View, чтобы он был исходным ViewModel, который привел к выбору DataTemplate?
Очевидным решением проблемы является объединение свойств в ChildViewModel с ParentViewModel, но я бы предпочел разделить его, потому что для повторного использования.
Я уверен, что ответ тривиален, я просто хотел бы знать, что это такое. :) Р>
Заранее спасибо.
Решение
Вы должны просто удалить строку:
DataContext = new ChildViewModel();
DataContext
представления будет автоматически установлен WPF. Для DataTemplates
всегда устанавливается контекст данных, равный данным для шаблона (в данном случае ViewModel):
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
Конечным результатом является то, что вы можете построить объекты модели представления отдельно (родительский и дочерний классы), а затем отобразить их позже, просто подключив их к элементам управления содержимым.
Другие советы
Самый простой способ связи между ViewModels с использованием подхода MVVM - это использование шаблона Mediator (EventAggregator в Prism). Хороший пример такого подхода можно увидеть по следующим ссылкам:
<Ол>Также посмотрите MVVM образец основы проекта.
Допустим, у вас есть QueueView, который использует 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
<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>