更改MVVM层次结构中的通知

时间:2010-01-05 23:51:33

标签: wpf mvvm inotifypropertychanged

让我们说在一些抽象的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友好的方式。

5 个答案:

答案 0 :(得分:9)

我最近在博客上写到了这个确切的问题。我在Rectangle中包含[DependsUpon("Size")]属性。我真的很喜欢这种方法,因为它将依赖性知识与创建依赖性的代码保持在一起,而不是相反。

看看:http://houseofbilz.com/archive/2009/11/14/adventures-in-mvvm----dependant-properties-with-inotifypropertychanged.aspx

答案 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#方法对我来说仍然很陌生。