Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVVM最佳实践:视图模型之间的通信_C#_Wpf_Mvvm_Inotifypropertychanged - Fatal编程技术网

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

C# MVVM最佳实践:视图模型之间的通信,c#,wpf,mvvm,inotifypropertychanged,C#,Wpf,Mvvm,Inotifypropertychanged,我的简化程序结构如下所示: 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; se

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

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
时,我希望在管理器内部触发
重新计算()

我是否:

A) 在
ManagerViewModel
中有一个PropertyChangedListener,它监听它的
MyItem
中的属性更改,然后告诉它的模型重新计算()

B) 允许ItemViewModel访问Manager,以便它可以手动告诉Manager运行重新计算()

(B) 似乎有点反模式。。。每个ViewModel不应该只关心自己的模型吗?
(A) 有它自己的问题--我需要经常使用这种“重新计算”结构,而且似乎到处都有这些PropertyChangedListener有点混乱。我意识到有几种不同的方法可以做到这一点,但我只是想知道这种情况下的“最佳实践”是什么。

通过添加INotifyPropertyChanged使您的模型可见并没有错。然后你可以听你一定要听的模型。在许多项目中,我更喜欢有一个静态数据集层,它发布存储中的模型列表,并且这些模型都是可观察的。这意味着它们可以绑定到,并且由于存储是相同的源,因此任何ViewModels等都可以绑定到它们并在系统范围内更新。看来你走对了路,所以不要再怀疑自己了。让事情变得可观察,完全符合模型,这不是不好的做法,也被认为是不好的做法。我个人更喜欢它。

因为“选项A”是最好的方法,因为它将视图模型和模型的关注点分开

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

ManagerViewModel
侦听
ItemViewModel
中的更改,然后在其自己的模型中执行
重新计算()

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

A是首选。B是一个讨厌的东西——与松耦合相反。更简洁的版本可能是为ItemViewModel提供另一个事件,该事件仅在更改将触发重新计算的属性值时才会引发。但是,同样,只有父VM真正知道它聚合的是哪些属性,所以可能只需要处理PropertyChanged,而将ItemViewModel排除在外。但有时是这样,我明白了!我非常喜欢自定义事件方法。我认为RaisePropertyChanged everywhere的问题在于它现在做了两件事:它告诉UI进行更新,并触发Recalculate()。在大多数情况下,这两种情况都会发生似乎是好事。。但在某些情况下,您可能希望其中一种情况发生,而不是另一种情况。”它告诉用户界面进行更新,并触发重新计算()“--一点也不!它说“它可能与谁有关:这个值改变了。”这只是一件事。黑暗中的多个处理程序可能出于其独特的邪恶目的而监听,但这没关系。“我可能会被重新计算,所以这是我的重新计算事件”是第二件事;“我可能会改变,所以这是我的改变事件”只是一件非常纯粹、基本和普遍的事情。为什么ItemViewModel应该知道或关心聚合函数?好的,这很有意义。我开始想办法了——谢谢!我想知道如果“ItemViewModel”有一个命令,可以重置它的所有属性(以及它的模型属性),我会怎么做。事实上,我希望能够重置所有属性,然后运行Recalculate(),因为在每次属性更改后运行它会很低效。在这种情况下,一个事件合适吗?我实际上有类似的事情。我的问题是,在设置模型属性时,有些情况下我不希望UI更新(至少是直接更新)。例如,我有一个xml文件导入器,它填充模型的属性——我不想在每次属性更改后通知UI(在我的例子中是“Recomculate()”)——只在加载完成后通知一次。同样,在一些情况下(非UI情况),我希望设置属性组,然后更新UI。我个人从不向UI公开模型,尽管许多模式和示例不同意。出于这个原因,无论模型有多小,我总是在新的ViewModel中包装模型。因为你永远不知道,我总是避免将模型直接暴露在用户界面上。啊,也许我误解了你的答案。你是说模特们应该互相观察吗?在我上面的示例中,“管理者”是否会监听其“项”中的属性更改,以便运行Recalculate()?嗯,不一定,也许我没有理解lol这个问题。模型本身可以观察到并绑定为“是”,但在绑定到它们时,我会始终记住依赖方向。EF打破了这条规则,这很可悲,但让模型相互绑定可能不是最好的主意。我会让ViewModels为您处理该逻辑,然后视图可以响应ViewModels。因此,在我的回答中,我会让您绑定到ViewModels中的模型,然后在模型更改时执行计算,并更新ViewModels上的属性,然后视图将在其中侦听和响应。