Change Notification in MVVM Hierarchies

被刻印的时光 ゝ 提交于 2019-12-02 18:21:57

I recently blogged about this exact problem. I include a [DependsUpon("Size")] attribute with the Rectangle. I REALLY like this approach, because it keeps the dependency knowledge with the code that creates the dependency, not the other way around.

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

I use Josh Smith's PropertyObserver, which you can get from his MVVM Foundation library at http://mvvmfoundation.codeplex.com/.

Usage:

_viewmodel_observer = new PropertyObserver<OtherViewModel>(_OtherViewModel)
   .RegisterHandler(m => m.Size, m => RaisePropertyChanged(Rectangle);

Brian's attribute approach is nice too. One thing I like about PropertyObserver is that I can execute arbitrary code; allowing me to check conditions which may make me avoid the raise or perform other actions all together.

You can simply override OnPropertyChanged in the derived ViewModel like so:

protected override void OnPropertyChanged(string propertyName) {
    base.OnPropertyChanged(propertyName);
    if (propertyName == "Size") {
        base.OnPropertyChanged("Rectangle");
    }
}

Another possibility... A while back I put together a pretty nice ViewModel base class that supports attributes on properties like:

[DependsOn("Size")]
public Rect Rectangle {
    get { new Rect(0,0,Size.Width, Size.Height); }
}

Then the ViewModel base class collects these DependsOnAttribute's at runtime and in its OnPropertyChanged method it basically just looks to see what other properties need to be invalidated when a property change occurs.

A clean MVVM way would be to use a Messenger subscribe/notify mechanism (like in Josh Smith's MvvmFoundation)

Create a singleton Messenger object somewhere - the main App class is always a good place for this

public partial class App : Application
{
    private static Messenger _messenger;
    public static Messenger Messenger
    {
        get
        {
            if (_messenger == null)
            {
                _messenger = new Messenger();
            }
            return _messenger;
        }
    }
}

In the Size setter from the base class, notify changes:

public Size Size
{
    get { return _size; }
    set
    {
        _size = value;
        OnPropertyChanged("Size");

        App.Messenger.NotifyColleagues("SIZE_CHANGED");
    }
}

Now you can let your inherited ViewModel's listen for these changes, and raise PropertyChanged events as appropriate...

public MyViewModel : MyViewModelBase
{
    public MyViewModel()
    {
        App.Messenger.Register("SIZE_CHANGED", () => OnPropertyChanged("Rectangle"));
    }
}

Of course - you can add as many subscriptions to this message as you need - one for each property that needs changes to be notified back to the View...

Hope this helps :)

maybe because im a VB guy, but in your Rectangle code it looks like you are accessing the private _size declaration instead of the Public Size property which would not fire the OnPropertyChanged event to alert the view.

Also I may be off base, but shouldnt Rectangle be an actual Object while Size is a property of that object? Maybe that is what you are doing..some C# methodologies are still really foreign to me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!