MVVM 最佳实践:视图模型之间的通信

MVVM Best Practices: communication between view models

我的简化程序结构如下所示:

public class Manager
{
    public Item MyItem { get; set; }

    public void Recalculate(){ ... } 
}

public class Item
{
    public string SomeProperty { get; set; }
}

public class ManagerViewModel
{
    public Manager Model { get; set; }

    public ItemViewModel MyItem { get; set; }
}


public class ItemViewModel
{
    public Item Model { get; set; }

    public string SomeProperty
    {
        get => Model.SomeProperty;
        set 
        { 
            Model.SomeProperty = value;
            RaisePropertyChanged("SomeProperty");
        }
    }
}

SomePropertyItemViewModel 中发生变化时,我希望 Recalculate() 在 Manager 中被触发。

我:

A) 在 ManagerViewModel 内有一个 属性ChangedListener,它监听 属性 在它的 MyItem 内的变化,然后告诉它的模型到 Recalculate()

B) 允许 ItemViewModel 访问 Manager,因此它可以手动告诉 Manager 运行 Recalculate()

..

(B) 似乎有点反模式......每个 ViewModel 不应该只真正关心它自己的模型吗? (A) 有它自己的问题——我需要经常使用这种 'Recalculation' 结构,而且到处都是这些 属性ChangedListeners 似乎有点乱。我知道有几种不同的方法可以解决这个问题,但我只是想知道在这种情况下 'best practice' 是什么。

通过向模型添加 INotifyPropertyChanged 使您的模型可观察也没有错。然后你可以听你绑定的模型。在许多项目中,我更喜欢有一个静态数据集层,它发布商店中的模型列表,并且这些模型都是可观察的。这意味着它们可以绑定到并且由于存储是相同的源,任何 ViewModels 等都可以绑定到它们并在系统范围内更新。看起来你在正确的轨道上,所以不要再猜测自己。让事情变得可观察,直接针对模型,这不是坏事或被认为是不好的做法。我个人比较喜欢。

一样,'option A' 是最好的方法,因为它将 ViewModel 和模型的关注点分开。

ItemViewModel 只关心它自己的模型,它只是通知正在监听的人它的属性已更改。

ManagerViewModel 监听 ItemViewModel 内部的变化,然后在它自己的模型内部执行 Recalculate()

//Models

public class Manager
{
    public Item MyItem { get; set; }

    public void Recalculate(){ ... } 
}

public class Item
{
    public string SomeProperty { get; set; }
}

//ViewModels

public class ManagerViewModel
{
    public Manager Model { get; set; }

    public ItemViewModel MyItem { get; set; }

    public ManagerViewModel()
    {
        //Listen for property changes inside MyItem
        MyItem.PropertyChanged += ItemPropertyChanged;
    }

    //Whenever a Property gets updated inside MyItem, run Recalculate() inside the Manager Model 
    private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Model.Recalculate();
    }
}


public class ItemViewModel
{
    public Item Model { get; set; }

    public string SomeProperty
    {
        get => Model.SomeProperty;
        set 
        { 
            Model.SomeProperty = value;
            RaisePropertyChanged("SomeProperty");
        }
    }
}