代码之家  ›  专栏  ›  技术社区  ›  Edward Tanguay

在MVVM中,ViewModel或Model是否应实现InotifyPropertiesChanged?

  •  148
  • Edward Tanguay  · 技术社区  · 16 年前

    我研究过的大多数MVVM示例都有 模型 实现InotifyPropertiesChanged,但在中 Josh Smith's CommandSink example ViewModel实现了InotifyPropertyChanged .

    我仍在认知地整理MVVM概念,因此我不知道是否:

    • 您必须在ViewModel中放置inotifyPropertiesChanged才能使commandSink正常工作。
    • 这只是一种反常现象,并不重要。
    • 您应该始终让模型实现inotifypropertieschanged,这只是一个错误,如果从一个代码示例开发到一个应用程序,就可以纠正这个错误。

    其他人对您所从事的MVVM项目有哪些经验?

    15 回复  |  直到 7 年前
        1
  •  95
  •   akjoshi HCP    9 年前

    我会说恰恰相反,我总是 INotifyPropertyChanged 在我的视图模型上-你真的不想用一个相当WPF特定的特性来污染你的模型,比如 InotifyProperty已更改 那东西应该放在视图模型中。

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

        2
  •  128
  •   Igor Popov    7 年前

    我强烈反对这个模型不应该实现 INotifyPropertyChanged . 此接口不特定于用户界面!它只是告知一个变化。实际上,WPF大量地使用它来标识更改,但这并不意味着它是一个UI接口。 我将其与以下评论进行比较: 轮胎是汽车附件 “。当然可以,但是自行车、公共汽车等也可以用。 总之,不要把那个接口当作一个用户界面。

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

    然而,实现目标的方法是不同的,但是我总是主张简单,避免冗余。

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

    当你看到有人声称 你不能这样或那样做 “这是一个他们不知道自己在说什么的迹象。

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

    我希望我能有更多的时间来解释MVVM的多种风格,以及一些常见问题的解决方案——大部分是由其他开发人员提供的,但我想我还得再做一次。

        3
  •  27
  •   Henk Holterman    8 年前

    在M-V-VM中,ViewModel Always(Model Not Always)实现InotifyPropertiesChanged

    从中查看m-v-v m项目模板/工具包 http://blogs.msdn.com/llobo/archive/2009/05/01/download-m-v-vm-project-template-toolkit.aspx . 它使用 DelegateCommand 对于您的M-V-VM项目来说,它应该是一个很好的开始模板。

        4
  •  9
  •   quetzalcoatl    12 年前

    我认为MVVM的名称很差,将ViewModel称为ViewModel会导致许多人错过设计良好的体系结构的一个重要功能,它是一个数据控制器,无论谁试图触摸数据,都可以控制数据。

    如果您认为视图模型更像一个数据控制器,并且实现了一个架构,其中数据控制器是唯一接触数据的项,那么您将永远不会直接接触数据,而是始终使用数据控制器。DataController对UI有用,但不一定只对UI有用。用于业务层、用户界面层等。

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

    你最终会得到一个这样的模型。甚至企业也应该只使用ViewModel接触数据。然后你的难题就消失了。

        5
  •  7
  •   Steve Mitcham    16 年前

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

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

    我们还有一些视图模型,它们在需要时从模型传播更改,但是视图模型本身正在监听底层模型更改。

        6
  •  3
  •   Andrey Khataev    15 年前

    但有时 link text )模型是服务,它向应用程序提供一些联机数据,然后您需要部署新数据到达或使用事件更改数据的通知…

        7
  •  3
  •   John D    12 年前

    我认为如果你想坚持mv-vm的话,答案是很清楚的。

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

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

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

        8
  •  2
  •   Steve Dunn supercat    16 年前

    我会在你的视图模型中说。它不是模型的一部分,因为模型与用户界面无关。模型应该是“除了商业不可知论之外的一切”

        9
  •  1
  •   dzendras    12 年前

    我认为这一切都取决于用例。

    当您有一个具有大量属性的简单模型时,您可以让它实现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告诉您什么?它的一些属性可能会改变。你不知道他们中的哪一个。事实上,设计是只有断开连接的更改,因为其余的更改是只读的。

    相反,IConnectionManager的意图是明确的:“我可以告诉您,我的未连接属性的值可能会更改”。

        10
  •  1
  •   akjoshi HCP    9 年前

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

    模型通常使用 IDataErrorInfo 要处理验证错误,只需保留在ViewModel中,就可以在MVVM道路上运行。

        11
  •  1
  •   Community CDub    8 年前

    我同意保罗的回答,执行 INotifyPropertyChanged 在模型中是完全可以接受的,甚至是微软建议的。-

    通常,该模型实现了使 绑定到视图。这通常意味着它支持属性和 集合更改通知通过 InotifyProperty已更改 INotifyCollectionChanged 接口。为表示 对象集合通常从 ObservableCollection<T> 类,它提供 不完整收集已更改 接口。

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

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

    有时,您需要使用不需要的模型对象 实施 InotifyProperty已更改 , 不完整收集已更改 , IDataErrorInfo INotifyDataErrorInfo 接口。在那些情况下, 视图模型可能需要包装模型对象并公开 视图的必需属性。这些属性的值将 由模型对象直接提供。视图模型将 为它公开的属性实现所需的接口,因此 视图可以轻松地将数据绑定到它们。

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

    我在一些项目中工作过,我们还没有实施 InotifyProperty已更改 在我们的模型中,由于这一点,我们面临着许多问题;在VM中需要不必要的属性重复,同时,我们必须先更新底层对象(使用更新的值),然后再将它们传递给BL/DL。

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


    最初是在另一个类似的问题上回答的,在此处添加,因为它包含此线程中缺少的imp.详细信息-

    https://stackoverflow.com/a/6923833/45382

        12
  •  0
  •   Dummy01    14 年前

    假设视图中对象的引用更改。如何通知所有要更新的属性以显示正确的值?打电话 OnPropertyChanged 在你看来,在我看来,所有物体的属性都是垃圾。

    因此,我要做的是让对象本身在属性中的值更改时通知任何人,在我的视图中,我使用的绑定如下 Object.Property1 , Object.Property2 然后继续。这样,如果我只想更改当前在我的视图中维护的对象,我就这样做了 OnPropertyChanged("Object") .

    为了避免在加载对象期间出现数百个通知,我有一个私有的布尔指示器,在加载期间将其设置为true,并从对象的 OnProperty已更改 什么也不做。

        13
  •  0
  •   dandan78 Tom Cool    14 年前

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

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

    优势

    通知程序处于业务模式中

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

    缺点

    模型具有属性(数量、费率、佣金、总费用)。使用数量、费率、佣金变化计算总费用。

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

    2. 如果在业务层中分配了比率、数量,则再次调用通知程序。

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

        14
  •  0
  •   akjoshi HCP    9 年前

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

    see here

        15
  •  0
  •   akjoshi HCP    9 年前

    我想ViewModel实现了 INotifyPropertyChange 模型可以在不同的“级别”上使用通知。

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

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