如果 viewmodel1 属性 发生变化,通知 viewmodel2

notify viewmodel2 if viewmodel1 property changes

我在 wpf +mvvm 中有一个场景,即如果我在 viewmodel1 中的特定 属性 发生变化,那么我想通知具有可观察集合的 viewmodel2 属性 "A" 已经改变 1) 我想为特定 属性 而非所有人开火。

我试过下面的代码但没有用。请告诉我我是怎么做到的。

public class Model1 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    // Create custom event
    public event EventHandler NotifyChange;

    private string testProperty;
    public string TestProperty
    {
        get
        {
            return testProperty;
        }
        set
        {
            testProperty = value;
            // If changing properties, fire your OnPropertyChanged to update UI
            OnPropertyChanged("TestProperty");
        }
    }

    private void OnPropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
            // Fire your custom event if a property changed
            NotifyChange(this, null);
        }
    }
}


public class Model2 : INotifyCollectionChanged
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public Model2()
    {
        // Assuming there is an accessible instance of model1
        Model1 m1Instance = new Model1();
        // Hook up your NotifyChange event from model1
        m1Instance.NotifyChange += Model1Changed;
    }

    private void Model1Changed(object sender, EventArgs e)
    {
        // this will be triggered on change in model1
    }

    private void OnCollectionChanged(object singleObject)
    {
        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset, singleObject));
    }
}

那是因为您没有注册 PropertyChanged。您正在 NotifyChange 上注册您的事件处理程序,以便 Model1 中的 PropertyChangedNULL,因此不会触发 NotifyChange

因此,您需要按以下方式实现 OnPropertyChanged

private void OnPropertyChanged(string propName)
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propName));

    if (NotifyChange != null)
        NotifyChange(this, null);
}

最后,如果您希望针对特定 属性 触发您的 NotifyChange,请调整上面的代码以在触发事件之前检查 propName

如果这只是为了通知 Model2,我认为您不需要所有这些实现。你可以这样做

public string TestProperty
{
    get
    {
        return testProperty;
    }
    set
    {
        testProperty = value;
        // If changing properties, fire your OnPropertyChanged to update UI
        OnPropertyChanged("TestProperty");
        //Here you can call a method of Model2 sating that its changed
          Model2 m2Instance = new Model2();
          m2Instance.ValueChanged();

    }
}

在模型 2 中添加方法 ValueChanged。

使用 PubSub 事件

我的建议是调查 PubSub 个事件。

我的建议是使用 Prism。这里有更多信息:http://www.c-sharpcorner.com/UploadFile/5ffb84/prism-event-aggregator-in-wpf-with-mvvm/

在这种情况下,您将坚持正确的 MVVM 实践。

这是 MSDN 的有用指南:https://msdn.microsoft.com/en-us/library/ff649664.aspx

仔细阅读它的工作原理,以及如何 use/implement 它。


或者

这会起作用,但如果可能,我仍然会推迟使用 PubSub 事件。

你可以试试这个:

public class Model1 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _property;
    public string Property
    {
        get { return _property; }
        set
        {
            _property = value;
            OnPropertyChanged("Property");
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class Model2
{
    public Model2()
    {
        // You might be storing your Model1 as a property in the Model2?
        // I don't know, but I've put it in the constructor just for example.
        var model1 = new Model1();
        model1.PropertyChanged += OnModel1PropertyChanged;
    }

    private void OnModel1PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Property")
        {
            // Do stuff here when the right property has changed in model 1
        }
    }
}

我仅在 Model2 的构造函数中 new 建立了一个 Model1 作为示例 - 您可能正在分配它并将其存储为字段或 属性 Model2 ViewModel 中的其他地方。

如果您在 ViewModel 中有 ViewModel(父 VM > 子 VM),这可能特别有用。

我经常使用父 > 子 VM,我不认为它违反 MVVM 最佳实践,但我仍然 使用 EventAggregator,而不是 events.


附带说明一下,如果您使用的是 C#6:

  • 使用nameof(Property)代替"magic strings"(例如"Property")。这使得重构变得更加容易,并且编译器可以告诉您有关错误的信息——但本质上是做同样的工作。在 setter
  • OnPropertyChanged() 调用中使用它
  • 检查属性名称时也可以使用nameof关键字,原理同上。像这样:if (e.PropertyName == nameof(Model1.Property)) ...
  • 使用空传播:PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));。将 OnPropertyChanged 的方法体更改为一个漂亮的单行代码,同时仍然做同样的工作

我跑题了

我会 总是 考虑在可能的情况下坚持正确的 MVVM 实践。

我每天都使用 Prism 的 EventAggregator,我会发誓。

仔细阅读 PubSub Events(您可以使用任何类型的事件聚合器,但我建议最好使用 Prism 的)

希望这对您有所帮助! :)