170

我处理过的大多数 MVVM 示例都有Model实现 INotifyPropertyChanged,但在Josh Smith 的 CommandSink 示例 中 ViewModel 实现了INotifyPropertyChanged

我仍在认知上将 MVVM 概念放在一起,所以我不知道是否:

  • 您必须将其放入INotifyPropertyChangedViewModel 才能开始CommandSink工作
  • 这只是规范的偏差,并不重要
  • 您应该始终实现模型INotifyPropertyChanged,这只是一个错误,如果将其从代码示例开发为应用程序,则可以更正

其他人在您从事的 MVVM 项目上有何经验?

4

17 回答 17

154

我强烈不同意模型不应该实现INotifyPropertyChanged. 此界面不是特定于 UI 的!它只是通知更改。实际上,WPF 大量使用它来识别更改,但这并不意味着它是一个 UI 界面。我会将其与以下评论进行比较:“轮胎是汽车配件”。当然可以,但自行车、公共汽车等也使用它。总之,不要把那个界面当作 UI 的东西。

话虽如此,但这并不一定意味着我相信模型应该提供通知。事实上,根据经验,模型不应该实现这个接口,除非有必要。在大多数情况下,没有将服务器数据推送到客户端应用程序,模型可能是陈旧的。但是如果听金融市场数据,那我不明白为什么模型不能实现接口。例如,如果我有非 UI 逻辑,例如当它收到给定值的买价或卖价时它会发出警报(例如通过电子邮件)或下订单的服务怎么办?这可能是一个可能的清洁解决方案。

然而,有不同的实现方式,但我总是主张简单并避免冗余。

什么是更好的?在视图模型上定义集合或属性更改的事件并将其传播到模型或让视图本质上更新模型(通过视图模型)?

最重要的是,每当你看到有人声称“你不能这样做或那样做”时,这表明他们不知道他们在说什么。

这真的取决于你的情况,事实上 MVVM 是一个有很多问题的框架,我还没有看到一个通用的 MVVM 实现。

我希望我有更多的时间来解释 MVVM 的多种风格和一些常见问题的解决方案——主要由其他开发人员提供,但我想我将不得不再做一次。

于 2010-05-10T16:49:13.593 回答
112

我想说的恰恰相反,我总是把我的 ViewModel 放在INotifyPropertyChanged我的 ViewModel 上——你真的不想用相当 WPF 特定的功能来污染你的模型,比如INotifyPropertyChanged那些东西应该放在 ViewModel 中。

我相信其他人会不同意,但这就是我的工作方式。

于 2009-04-21T12:09:11.657 回答
30

在 MV-VM 中,ViewModel 总是(Model not always)实现INotifyPropertyChanged

从http://blogs.msdn.com/llobo/archive/2009/05/01/download-mv-vm-project-template-toolkit.aspx查看 MV-VM 项目模板/工具包。它使用DelegateCommandfor 命令,它应该是您 MV-VM 项目的一个很好的起始模板。

于 2009-05-04T12:35:05.513 回答
13

我认为 MVVM 的命名非常糟糕,并且将 ViewModel 称为 ViewModel 会导致许多人错过精心设计的架构的一个重要特性,即无论谁试图触摸它都可以控制数据的 DataController。

如果您将 View-Model 更多地视为 DataController 并实现一个架构,其中您的 DataController 是唯一接触数据的项目,那么您永远不会直接接触数据,而是始终使用 DataController。DataController 对 UI 很有用,但不一定只对 UI 有用。它用于业务层,UI层等......

DataModel -------- DataController ------ View
                  /
Business --------/

你最终得到了这样的模型。即使是业务也应该只使用 ViewModel 来接触数据。然后你的难题就消失了。

于 2011-01-01T16:46:24.810 回答
9

这取决于您如何实现模型。我的公司使用类似于 Lhotka 的 CSLA 对象的业务对象,并在INotifyPropertyChanged整个业务模型中广泛使用。

我们的验证引擎很大程度上依赖于通过这种机制获得属性更改的通知,并且它运行良好。显然,如果您使用的是业务对象以外的其他实现,其中更改通知对操作来说不是那么重要,您可能有其他方法来检测业务模型中的更改。

我们也有视图模型在需要的地方传播模型的变化,但视图模型本身正在监听底层模型的变化。

于 2009-04-21T12:55:52.077 回答
8

我同意 Paulo 的回答,INotifyPropertyChanged在模型中实施是完全可以接受的,甚至微软也建议 -

通常,模型实现了可以轻松绑定到视图的工具。这通常意味着它通过INotifyPropertyChangedINotifyCollectionChanged接口支持属性和集合更改通知。表示对象集合的模型类通常派生自 ObservableCollection<T>提供 INotifyCollectionChanged接口实现的类。

虽然由您决定是否需要这种类型的实现,但请记住 -

如果您的模型类没有实现所需的接口怎么办?

有时您需要使用不实现INotifyPropertyChangedINotifyCollectionChangedIDataErrorInfoINotifyDataErrorInfo接口的模型对象。在这些情况下,视图模型可能需要包装模型对象并将所需的属性公开给视图。这些属性的值将由模型对象直接提供。视图模型将为它公开的属性实现所需的接口,以便视图可以轻松地将数据绑定到它们。

取自 - http://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx

我曾在一些尚未INotifyPropertyChanged在模型中实施的项目中工作过,因此我们面临很多问题;VM 中需要不必要的属性重复,同时我们必须在将底层对象(使用更新的值)传递给 BL/DL 之前更新它们。

如果您需要处理模型对象的集合(例如在可编辑的网格或列表中)或复杂模型,您将面临特别的问题;模型对象不会自动更新,您必须管理 VM 中的所有内容。

于 2015-12-15T09:06:50.947 回答
4

我认为这完全取决于用例。

当你有一个带有大量属性的简单模型时,你可以让它实现 INPC。简单来说,我的意思是这个模型看起来很像POCO

如果您的模型更复杂并且存在于交互式模型域中 - 模型引用模型,订阅其他模型的事件 - 将模型事件实现为 INPC 是一场噩梦。

将自己置于某个必须与其他模型合作的模型实体的位置。您有各种要订阅的事件。它们都作为 INPC 实施。想象一下您拥有的那些事件处理程序。大量的 if 子句和/或 switch 子句。

INPC的另一个问题。您应该将您的应用程序设计为依赖于抽象,而不是实现。这通常使用接口来完成。

让我们看一下同一抽象的两种不同实现:

public class ConnectionStateChangedEventArgs : EventArgs
{
    public bool IsConnected {get;set;}
}

interface IConnectionManagerINPC : INotifyPropertyChanged
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    bool IsConnected {get;}
}

interface IConnectionManager
{
    string Name {get;}
    int ConnectionsLimit {get;}
    /*

    A few more properties

    */
    event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
    bool IsConnected {get;}
}

现在看看他们两个。IConnectionManagerINPC 告诉你什么?它的某些属性可能会改变。你不知道他们中的哪一个。事实上,设计是只有 IsConnected 发生变化,因为其余的都是只读的。

相反,IConnectionManager 的意图很明确:“我可以告诉你,我的 IsConnected 属性的值可能会改变”。

于 2013-02-19T08:09:03.157 回答
3

我会在你的 ViewModel 中说。它不是模型的一部分,因为模型与 UI 无关。该模型应该是“除了业务不可知论之外的一切”

于 2009-04-21T12:48:55.680 回答
3

但有时(如在此演示链接文本中)模型是服务,它为应用程序在线提供一些数据,然后您需要使用事件实现新数据到达或数据已更改的通知......

于 2009-11-10T14:07:02.633 回答
3

如果你想坚持 MV-VM,我认为答案很清楚。

见: http: //msdn.microsoft.com/en-us/library/gg405484 (v=PandP.40).aspx

在 MVVM 模式中,视图封装了 UI 和任何 UI 逻辑,视图模型封装了表示逻辑和状态,模型封装了业务逻辑和数据。

“视图通过数据绑定、命令和更改通知事件与视图模型交互。视图模型查询、观察和协调对模型的更新,根据需要转换、验证和聚合数据以在视图中显示。”

于 2013-08-24T06:46:42.893 回答
2

如果模型在 ViewModel 中明确公开,则可以在模型中实现 INPC。但一般来说,封装模型的 ViewModel 是他自己的类,以降低模型复杂度(这对绑定应该没有用处)。在这种情况下,INPC 应该在 ViewModel 中实现。

于 2019-04-05T16:40:46.930 回答
1

INotifyPropertyChange在模型中使用接口。实际上,模型属性更改应该只由 UI 或外部客户端触发。

我注意到几个优点和缺点:

优点

通知者在商业模式中

  1. 根据域驱动,它是正确的。它应该决定何时加注,何时不加注。

缺点

该模型具有属性(数量、费率、佣金、总运费)。Totalfrieght 是使用数量、费率、佣金变化来计算的。

  1. 从 db 加载值时,总运费计算称为 3 次(数量、费率、佣金)。应该是一次。

  2. 如果在业务层分配了rate,qty,则再次调用notifier。

  3. 应该有一个选项来禁用它,可能在基类中。但是,开发人员可能会忘记这样做。

于 2011-09-20T17:49:51.263 回答
1

只需INotifyPropertyChange在您的视图模型中使用,而不是在模型中使用,

该模型通常使用IDataErrorInfo来处理验证错误,因此只需保留在您的 ViewModel 中,您就可以在您的 MVVM 道路上。

于 2011-11-30T11:48:27.990 回答
0

假设您的视图中对象的引用发生了变化。您将如何通知所有要更新的属性以显示正确的值?OnPropertyChanged在我看来,在您的视图中调用所有对象的属性是垃圾。

所以我要做的是让对象本身在属性中的值发生变化时通知任何人,并且在我看来,我使用诸如Object.Property1,之类Object.Property2的绑定。这样,如果我只想更改当前在我的视图中维护的对象,我就这样做OnPropertyChanged("Object")

为了避免在加载对象期间收到数百个通知,我有一个私有布尔指示器,我在加载期间将其设置为 true,它从对象的检查中检查OnPropertyChanged并且什么都不做。

于 2011-08-23T07:15:45.797 回答
0

恕我直言,我认为视图模型实现INotifyPropertyChange并且模型可以在不同的“级别”上使用通知。

例如,对于某些文档服务和文档对象,您有一个 documentChanged 事件,视图模型会监听该事件以清除和重建视图。在编辑视图模型中,您对文档的属性进行了属性更改以支持视图。如果该服务在保存时对文档做了很多工作(更新更改日期、最后一个用户等),您很容易得到 Ipropertychanged 事件的过载,并且只需一个 documentchanged 就足够了。

但是如果你INotifyPropertyChange在你的模型中使用我认为在你的视图模型中传递它而不是直接在你的视图中订阅它是一个好习惯。在这种情况下,当模型中的事件发生变化时,您只需更改视图模型并且视图保持不变。

于 2011-10-14T05:01:11.593 回答
0

通常 ViewModel 将实现INotifyPropertyChanged. 模型可以是任何东西(xml 文件、数据库甚至对象)。模型用于将数据提供给视图模型,该视图模型会传播到视图。

看这里

于 2011-07-16T02:33:48.313 回答
0

所有绑定到我的视图的属性都在我的 ViewModel(s) 中。因此他们应该实现 INotifyPropertyChanged 接口。因此视图获得所有更改。

[使用 MVVM Light 工具包,我让它们继承自 ViewModelBase。]

Model 持有业务逻辑,但与视图无关。因此不需要 INotifyPropertyChanged 接口。

于 2019-02-28T13:27:32.997 回答