我有一个嵌套的视图模型结构,如下面的例子所示:
public class SubViewModel : INotifyPropertyChanged
{
public string Property
{
get
{
// calculate result and return it
}
}
}
public class ViewModel : INotifyPropertyChanged
{
public SubViewModel Sub { get; set; }
public void MyMethod()
{
// executes code that changes some parameters such that Sub.Property changes
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Sub.Property"));
}
}
在某些情况下,父视图模型中的更改会影响嵌套视图模型的属性。换句话说,子视图模型上的一个属性(在这个例子中是SubViewModel.Property
)发生了变化,但是子视图模型并不知道。
我想以一种方式调用PropertyChanged
,告诉WPF绑定引擎子视图模型Sub
上的属性Property
已经更改。我尝试了以下所有选项,但到目前为止都不起作用:
OnPropertyChanged("");
OnPropertyChanged("*");
OnPropertyChanged("Sub");
OnPropertyChanged("Sub.Property");
OnPropertyChanged("Sub.*");
有办法做到这一点吗?
请注意:我知道父视图模型可以调用子视图模型上的方法,这会引发子视图模型上的PropertyChanged
事件。我有我的理由不那样做。
- 当你改变SubViewModel时调用OnPropertyChanged。
- 你的SubviewModel应该创建在你的MainViewModel
- 在你的视图中你必须调用:"DataContext ={Binding Sub}"
- 在你的子视图中不能有"DataContext"这个词
-
在你的SubView中,你必须像这样绑定属性:"Example = {Binding MyProperty}"
public class SubViewModel : INotifyPropertyChanged { private string _MyProperty; public string MyProperty { get { return _MyProperty; } set { _MyProperty = value; NotifyPropertyChanged(); } } #region NotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] string info = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info)); } #endregion } public class ViewModel : INotifyPropertyChanged { private SubViewModel _Sub; public SubViewModel Sub { get { return _Sub; } set { _Sub = value; NotifyPropertyChanged(); } } public void MyMethod() { // executes code that changes some parameters such that Sub.Property changes NotifyPropertyChanged(); } #region NotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] string info = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info)); } #endregion }
在SubViewModel
中创建一个事件,并在发生变化时引发该事件。父视图模型将订阅该事件。
您正在创建ViewModel
和SubViewModel
之间的循环依赖关系。这导致两者之间的强耦合,这从来都不是好事。我提出了一个不同的解决方案。INotifyPropertyChanged
已经提供了基础设施来完成您想要的。
所以SubViewModel
依赖于ViewModel
。我假设它需要ViewModel
的一个属性的值来计算SubViewModel.Property
的值。因此,解决方案很自然地将SubViewModel
连接到ViewModel.PropertyChanged
:
public class SubViewModel : INotifyPropertyChanged
{
private ViewModel parent;
public event PropertyChangedEventHandler PropertyChanged;
public SubViewModel(ViewModel parent)
{
this.parent = parent;
// Hook up to parent's property changes.
this.parent.PropertyChanged += (sender, e) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SubProperty"));
}
public string SubProperty
{
get { return parent.Property; }
}
}
请注意,通过在SubViewModel
的构造函数中期望ViewModel
来显式地实现依赖关系。这样,下一个程序员立即看到SubViewModel
需要ViewModel
才能正常工作,而不能构造一个不能正常工作的SubViewModel
。
e.PropertyName
做任何事情之前检查它。无论如何,它的基本目的是通知所有订阅SubViewModel
属性更改的客户端,只要ViewModel.Property
已经更改。
为了避免循环依赖,最好不要有从ViewModel
到SubViewModel
的关系。去掉Sub
属性,像这样实现ViewModel
:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string property;
public string Property
{
get { return this.property; }
set
{
this.property = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Property"));
}
}
}
注意ViewModel
的实现看起来与任何其他INotifyPropertyChanged
实现完全相同。父进程不需要知道它的子进程如何处理它的值。只有ViewModel
的客户端实现了处理ViewModel
的属性更改的逻辑,而不是父级。