C# MVVM 模式,ViewModel DataContext 问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/825784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MVVM Pattern, ViewModel DataContext question
提问by Jose
I need to figure out how to communicate between ViewModels. I'm new to MVVM so please be kind.
我需要弄清楚如何在 ViewModel 之间进行通信。我是 MVVM 的新手,所以请多多关照。
Here's a dumbed down example
这是一个愚蠢的例子
class definitions(assume that I have hooked the Child.PropertyChanged event in the ParentViewModel):
类定义(假设我在 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");
}
}
}
Here's what you see in the resource dictionary
这是您在资源字典中看到的内容
<DataTemplate DataType="{x:Type vm:ParentViewModel}">
<vw:ParentView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
and the code-behind of the ChildView:
和 ChildView 的代码隐藏:
public partial class ChildView : UserControl
{
public QueueView()
{
InitializeComponent();
DataContext = new ChildViewModel();
}
}
The obvious problem is that when the ChildView gets instantiated (via selection from the DataTemplate) it creates a new ChildViewModel class and the ParentViewModel doesn't have access to it.
显而易见的问题是,当 ChildView 被实例化(通过从 DataTemplate 中选择)时,它会创建一个新的 ChildViewModel 类,而 ParentViewModel 无法访问它。
So how can I instantiate the DataContext of the View to be the original ViewModel that caused the DataTemplate to be selected?
那么如何将 View 的 DataContext 实例化为导致 DataTemplate 被选中的原始 ViewModel?
An obvious fix is to mmerge the properties in the ChildViewModel into the ParentViewModel, but I would rather separate it because for reuse.
一个明显的解决方法是将 ChildViewModel 中的属性合并到 ParentViewModel 中,但我宁愿将其分开,因为为了重用。
I'm sure the answer is trivial, I just would like to know what it is. :)
我确定答案很简单,我只是想知道它是什么。:)
Thanks in advance.
提前致谢。
采纳答案by Josh G
You should simply remove the line:
您应该简单地删除该行:
DataContext = new ChildViewModel();
The DataContext
of the view will be set automatically by WPF. DataTemplates
always have their data context set to the data for the template (in this case the ViewModel):
的DataContext
视图将自动通过WPF设定。DataTemplates
始终将它们的数据上下文设置为模板的数据(在本例中为 ViewModel):
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<vw:ChildView/>
</DataTemplate>
The end result is that you can build your view model objects separately (both parent and child classes) and then display them later by simply plugging them into content controls.
最终结果是您可以单独构建您的视图模型对象(父类和子类),然后通过简单地将它们插入内容控件来显示它们。
回答by Soni Ali
Let's say you have a QueueView that uses a QueueViewModel.
假设您有一个使用 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 part
-- 队列视图部分
<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>
回答by Soni Ali
The easiest way to communicate between ViewModels using the MVVM approach is to use the Mediator pattern (EventAggregator in Prism). A good example of this approach can be seen in the following links:
使用 MVVM 方法在 ViewModel 之间进行通信的最简单方法是使用 Mediator 模式(Prism 中的 EventAggregator)。在以下链接中可以看到这种方法的一个很好的例子:
Also check out the MVVM sampleproject framework.
另请查看 MVVM示例项目框架。