【问题标题】:MVVM: Notify view when model status changedMVVM:模型状态更改时通知视图
【发布时间】:2012-11-14 21:38:50
【问题描述】:

这是关于 MVVM 模式最佳实践的具体问题。我正在使用 MvvmLight 库。 它是这样的: 我的模型,比如“Flight”,实现了一些可以通过方法启动、暂停和停止航班的业务逻辑。无论是播放停止还是暂停飞行,每种方法都会执行其逻辑以实现功能。更改的一个重要变量是状态枚举,它指示飞行状态 - 播放、停止或暂停。如前所述,状态变量(和属性)在模型中定义。 另一方面,飞行类由一个 ViewModel 类包装,该类包含一个包含飞行模型中状态变量的 Status 属性,以及连接到飞行模型播放停止暂停方法的 RelayCommands。

问题从这里开始: 当我通过视图执行其中一个命令时,它执行模型中的方法,使状态变量本身直接改变,但它只在模型中改变.. ViewModel 中的状态属性不知道是否包装变量已更改,因为它是直接更改的...这意味着如果某些视图元素绑定到状态属性,它不会在命令执行时更改..

我知道解决这个问题的几种方法,但我要求一个不会破坏 MVVM 模式的公平解决方案(例如在 Model 的飞行类中使用 INotifyPropertyChanged )

【问题讨论】:

    标签: wpf mvvm mvvm-light


    【解决方案1】:

    这类问题没有灵丹妙药的解决方案。您的 ViewModel 和 Model 需要以允许信息传播到 View 的方式设计;如果这是不可能的,那么设计就有缺陷,需要改变。

    以下是您应该研究的几件事:

    • 如果模型的状态修改方法被记录为同步执行,则在 ViewModel 上创建将操作转发给模型的方法,然后立即查询其状态。使用这些方法来实现RelayCommands。
    • 如果模型的方法不是同步的,那么模型的客户端应该有一些机制可以在方法完成时通知他们。这可以通过延续回调、事件,甚至可能使用INotifyPropertyChanged 来完成。

    【讨论】:

      【解决方案2】:

      如上所述,您的 ViewModel 应按以下方式包装 Model:

      class Model
      {
         public int State{get;private set;}
         public void Fly()
         {
            State=1;
         }
      
         public void Stop()
         {
            State = 2;
         }
      }
      
      class ViewModel : ViewModelBase
      {
         int State{ get{ Model.State;}}
         ...
         OnFlyCommand()
         {
            Model.Fly();
            NotifyPropertyChanged("State");
         }
      }
      

      【讨论】:

      • 基本上就是我刚才写的:)
      【解决方案3】:

      您可以在 ViewModel 对 Model 执行方法之后调用 OnNotifyPropertyChanged。这不是很优雅,但是如果不重构 Model 类,您将无法变得更简单。

      【讨论】:

        【解决方案4】:

        你知道命令执行后哪些属性发生了变化吗?我的意思是,您能否明确提出特定属性集的更改通知,或者修改后的属性集正在更改?

        在前一种情况下,您调用命令并显式引发这些属性的事件:

        command.Execute();
        NotifyPropertyChanged("PropA");
        ...
        NotifyPropertyChanged("PropN");
        

        在第二种情况下,您可以使用反射为Model 类的每个属性引发更改通知事件,也可以使用更智能的解决方案,例如PostSharp.Domain.Toolkit。

        【讨论】:

          【解决方案5】:

          最佳实践是从命令执行调用 viewmodel,而不是从 viewmodel 调用模型更改,然后将视图模型状态标记为已更改

          【讨论】:

          • 如果模型无法更改会发生什么,例如如果抛出异常?
          • 比ViewModel也失败,你觉得这是个问题吗?
          • 我不确定“ViewModel 失败”是什么意思。我按下 Play,VM 状态变为“正在播放”,Model.Play() 被调用并抛出。虚拟机现在是什么状态?
          • 啊,你的意思是它应该改变模型,而不是改变视图模型状态?好的,我编辑了帖子,谢谢
          猜你喜欢
          • 2018-06-30
          • 2012-03-12
          • 1970-01-01
          • 1970-01-01
          • 2011-08-25
          • 2011-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多