我需要弄清楚如何在ViewModel之间进行通信。我是MVVM的新手,所以请善待。
这是一个愚蠢的例子
类定义(假设我在ParentViewModel中挂钩了Child.PropertyChanged事件):
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无法访问它。
那么如何将View的DataContext实例化为导致选择DataTemplate的原始ViewModel?
一个明显的解决方法是将ChildViewModel中的属性混合到ParentViewModel中,但我宁愿将其分开,因为要重用。
我确信答案是微不足道的,我只是想知道它是什么。 :)
提前致谢。
答案 0 :(得分:8)
您只需删除该行:
DataContext = new ChildViewModel();
视图的DataContext
将由WPF自动设置。 DataTemplates
始终将其数据上下文设置为模板的数据(在本例中为ViewModel):
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
最终结果是您可以单独构建视图模型对象(父类和子类),然后通过简单地将它们插入内容控件中来显示它们。
答案 1 :(得分:5)
使用MVVM方法在ViewModel之间进行通信的最简单方法是使用Mediator模式(Prism中的EventAggregator)。在以下链接中可以看到这种方法的一个很好的例子:
另请查看MVVM sample项目框架。
答案 2 :(得分:1)
假设您有一个使用QueueViewModel的QueueView。
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>