让我们说在一些抽象的ViewModel基类中我有一个普通的属性如下:
public Size Size
{
get { return _size; }
set
{
_size = value;
OnPropertyChanged("Size");
}
}
然后我创建一个更具体的ViewModel,继承自前一个,包含以下属性:
public Rect Rectangle
{
get { return new Rect(0, 0, _size.Width, _size.Height); }
}
现在,在一些View类中,我绑定到前面提到的ViewModel的Rectangle
属性。一切正常,直到我改变大小。当Size
更改时,Rectangle
不知道该更改,并且更改不会传播到视图。由于Rectangle
位于子类中,因此我不能简单地向OnPropertyChanged("Rectangle")
setter添加Size
。
现在假设我有许多不同的属性,如Rectangle
,它们都依赖于基类属性,并且没有传播这些更改。我需要一些轻量级和优雅的链接更改通知的方法,最好是不需要大量代码并且不强迫我使用依赖项属性的方法。
显然这里有很多难看的解决方案 - 我正在寻找的是干净而聪明的东西。在我看来,这将是一个非常常见的场景,在我看来可能有一种 MVVM友好的方式。
答案 0 :(得分:9)
我最近在博客上写到了这个确切的问题。我在Rectangle中包含[DependsUpon("Size")]
属性。我真的很喜欢这种方法,因为它将依赖性知识与创建依赖性的代码保持在一起,而不是相反。
答案 1 :(得分:4)
我使用Josh Smith的PropertyObserver,你可以从http://mvvmfoundation.codeplex.com/的MVVM Foundation库中获取它。
用法:
_viewmodel_observer = new PropertyObserver<OtherViewModel>(_OtherViewModel)
.RegisterHandler(m => m.Size, m => RaisePropertyChanged(Rectangle);
Brian的属性方法也很好。我喜欢PropertyObserver的一件事是我可以执行任意代码;允许我检查可能使我避免加注或一起执行其他操作的条件。
答案 2 :(得分:3)
您可以简单地在派生的ViewModel中覆盖OnPropertyChanged,如下所示:
protected override void OnPropertyChanged(string propertyName) {
base.OnPropertyChanged(propertyName);
if (propertyName == "Size") {
base.OnPropertyChanged("Rectangle");
}
}
另一种可能性...... 前段时间我把一个非常漂亮的ViewModel基类组合在一起,它支持以下属性的属性:
[DependsOn("Size")]
public Rect Rectangle {
get { new Rect(0,0,Size.Width, Size.Height); }
}
然后,ViewModel基类在运行时和OnPropertyChanged方法中收集这些DependsOnAttribute,它基本上只是查看当发生属性更改时需要使其他属性失效的内容。
答案 3 :(得分:1)
干净的MVVM方式是使用Messenger
订阅/通知机制(就像Josh Smith的MvvmFoundation)
在某处创建一个单独的Messenger对象 - 主要的App类始终是这个
的好地方public partial class App : Application
{
private static Messenger _messenger;
public static Messenger Messenger
{
get
{
if (_messenger == null)
{
_messenger = new Messenger();
}
return _messenger;
}
}
}
在基类的Size setter中,通知更改:
public Size Size
{
get { return _size; }
set
{
_size = value;
OnPropertyChanged("Size");
App.Messenger.NotifyColleagues("SIZE_CHANGED");
}
}
现在,您可以让继承的ViewModel监听这些更改,并根据需要引发PropertyChanged事件......
public MyViewModel : MyViewModelBase
{
public MyViewModel()
{
App.Messenger.Register("SIZE_CHANGED", () => OnPropertyChanged("Rectangle"));
}
}
当然 - 您可以根据需要为此消息添加任意数量的订阅 - 每个需要更改的属性一个,以通知回View ...
希望这会有所帮助:)
答案 4 :(得分:0)
也许是因为我是一个VB人,但是在你的Rectangle代码中,它看起来像是在访问私有_size声明而不是Public Size属性,它不会触发OnPropertyChanged事件来提醒视图。
另外我可能不在基础上,但是Rectangle不是实际的Object而Size是该对象的属性吗?也许这就是你在做什么......有些C#方法对我来说仍然很陌生。