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

问题描述:

我的简化程序结构如下:

My simplified program structure looks like this:

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");
        }
    }
}

当在 ItemViewModel 中更改 SomeProperty 时,我希望在管理器内部触发 Recalculate().

When SomeProperty gets changed in ItemViewModel, I want Recalculate() to get triggered inside Manager.

我愿意吗

A)在 ManagerViewModel 内部有一个PropertyChangedListener,以侦听 MyItem 内部的属性更改,然后将其模型告知 Recalculate()

A) Have a PropertyChangedListener inside ManagerViewModel which listens for Property changes inside it's MyItem, and then tells it's Model to Recalculate()

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

B) Allow ItemViewModel to have access to Manager, so it can manually tell Manager to run Recalculate()

..

(B)似乎有点反模式……每个ViewModel难道不应该只关心自己的模型吗?(A)有它自己的问题-我需要大量使用这种重新计算"结构,而且似乎到处都是这些PropertyChangedListeners有点混乱.我意识到有几种不同的解决方法,但是我只是想知道在这种情况下最佳实践"是什么.

(B) seems kind of anti-pattern-ish... shouldn't each ViewModel only really be concerned with it's own Model? (A) has it's own issues -- I need to use this sort of 'Recalculation' structure a lot, and it seems having these PropertyChangedListeners all over the place is kind of messy. I realise there's a few different ways of going about this, but I'm just wondering what the 'best practice' is in this case.

As confirmed by Ed Plunkett, 'option A' is the best approach, as it separates the concerns of the ViewModels and Models.

ItemViewModel 仅与它自己的模型有关,它只是通知正在监听的人其属性已更改.

ItemViewModel is only concerned with it's own Model, and it just notifies whoever's listening that it's properties have been changed.

ManagerViewModel 侦听 ItemViewModel 内部的更改,然后在其自己的模型内执行 Recalculate().

ManagerViewModel listens for changes inside ItemViewModel, and then executes Recalculate() inside it's own model.

//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");
        }
    }
}