ViewModel为特定属性订阅Model的PropertyChanged事件

时间:2014-07-09 16:12:38

标签: c# wpf

我想在模型中的Property更改时执行methodToBeCalledWhenPropertyIsSet()。

我怎么能这样做?

如果我理解正确,我可以在我的ViewModel中的某处添加MyModel.PropertyChanged += methodToBeCalledWhenPropertyIsSet来订阅PropertyChanged事件,但我只关心设置了属性

public class ViewModel : INotifyPropertyChanged
{
    ...

    public Model MyModel { get; set; }

    public void methodToBeCalledWhenPropertyIsSet() { }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Model : INotifyPropertyChanged
{
    object _propertyField;
    public object Property
    {
        get
        {
            return _propertyField;
        }
        set
        {
            _propertyField = value;
             OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

2 个答案:

答案 0 :(得分:13)

INotifyPropertyChanged接口解决了这个问题。将您的视图模型订阅到模型PropertyChangedEventHandler并过滤您的结果。

public class ViewModel : INotifyPropertyChanged
{
    ...

    public Model MyModel { get; set; }

    public void methodToBeCalledWhenPropertyIsSet() { }

    public event PropertyChangedEventHandler PropertyChanged;

    public ViewModel()
    {
        // MyModel would need to be set in this example.
        MyModel.PropertyChanged += Model_PropertyChanged;
    }

    private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(e.PropertyName == "Property")
        {
             methodToBeCalledWhenPropertyIsSet();
        }
    }
}

在MVVM模式中,View Model旨在处理像这样的混乱情况。这仍然保留了你对模型的抽象。

修改 正如HighCore指出的那样,这段代码不能复制粘贴。 MyModel需要事先实例化。我为此目的使用MEF(http://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx)。您可以直接获取模型类,也可以使用某种工厂/经理来获取参考。

答案 1 :(得分:3)

一种可能的常用解决方案是使用ViewModel中的等效属性包装Model Property

public class ViewModel
{
    public object Property
    {
        get
        {
            return Model.Property;
        }
        set
        {
             Model.Property = value;
             methodToBeCalledWhenPropertyIsSet(); // Here you call your method directly
        }
    }
}

并将您的UI绑定到此属性而不是模型。

修改:如果模型因UI交互而发生变化,则会发生该互动" thru" ViewModel。如果模型由于模型本身的内部业务逻辑而发生更改,那么您将没有其他选择,只能订阅它的PropertyChanged事件,但请确保您在以后适当取消订阅。我通常把这样的订阅/取消订阅代码放在VM中Model属性的setter中:

public MyModel Model
{
    get { return _model; }
    set
    {
        if (_model != null)
            _model.PropertyChanged -= OnModelPropertyChanged;

        _model = value;

        if (_model != null
            _model.PropertyChanged += OnModelPropertyChanged;

        NotifyPropertyChange(() => Model);
     } 
}