【问题标题】:Who should call the VIewModel in WPF/MVVM the logical unit or the view?谁应该将 WPF/MVVM 中的 VIewModel 称为逻辑单元或视图?
【发布时间】:2013-09-18 02:30:57
【问题描述】:

我的问题是 “什么是最佳实践?” 类型,在一个非常具体的情况下:

我有一个包含复选框列表框的视图。

listbox.ItemsSource 绑定到 ViewModel(人员列表)中的集合。并且每个 checkbox.IsChecked 都绑定到 Person.IsSelected

复选框的选中/取消选中会激活 ViewModel 中的“刷新”方法,该方法可能会或可能不会重新设置所有 Person 的 Person.IsChecked。当然,这应该通知 UI Person.IsChecked(可能已经)已更改。

我的问题是:谁应该负责调用 ViewMode.Refresh? UI 是否应该通过事件或命令调用该方法?或者 ViewModel 是否应该订阅 Person 中的适当事件。

【问题讨论】:

    标签: c# wpf data-binding mvvm binding


    【解决方案1】:

    如果 UI 绑定到IsChecked,则无需通知它。或者,更确切地说,WPF 本身会通知它。这是 MVVM 的吸引力之一。视图模型可以根据自己的一套规则简单地更新其状态,视图会通过绑定自动接收这些更改。

    【讨论】:

    • 好的,但是VM需要实现INotifyPropertyChaged来让V注意到值改变了。
    【解决方案2】:

    取决于你所说的“呼叫”是什么意思

    这里有答案

    如果你的意思是创建:

    • 其他视图模型
    • 任何不是视图或模型的东西(因为它们都不应该知道你的虚拟机)

    如果您谈论的是执行方法:

    • 自执行(例如在 PropertyChanged、Command、...之后)
    • 其他视图模型
    • 任何不是视图或模型的东西(因为它们都不应该知道你的虚拟机)

    在你的情况下也很重要:

    您说您的列表仅限于 Collection
    在这里您可能会遇到一些麻烦,因为您的视图更改了Person.IsSelected,这应该为您的 IsSelected 引发 PropertyChanged。
    现在它会卡住,因为ObservableCollection 在您的项目属性发生更改时不会收到通知这是一个已知问题。要解决此问题,您需要将您的INotifyPropertyChanged 事件连接到来自ObservableCollectionCollectionChanged 事件。所以它可以冒泡到你的虚拟机,它可以执行他的Refresh()

    Here你可以看到一个例子,你可以怎么做。

    【讨论】:

      【解决方案3】:

      我想你得问问自己,“刷新”是什么反应?

      如果它是对实际单击复选框的响应,则调用它是视图的责任。

      如果它是为了响应被选中的人,则视图模型应该监视自己的集合以了解对 IsSelected 的更改。

      我同意MehaJain 的观点,后者更难设置,但替代方案打破了层之间单个工作单元的职责,这意味着逻辑将需要在任何其他导致IsSelected 被改变。这包括绑定到相同信息的其他视图、其他命令(例如,您有一个用于运行筛选器以选择某些人的按钮)和测试。

      【讨论】:

      • Refresh 是对被选中人员的响应,但这里没有我可以绑定的 SelectedItem 属性。除了使用来自 Person 的事件之外,我没有看到任何其他方法,这会导致一大堆其他问题。你有更好的办法吗?
      • @NirSmadar 我认为使用 Person 的 PropertyChanged 事件是最好的方法。我认为这并没有太大问题——您基本上只需要为 Person 的 ObservableCollection 处理 CollectionChanged,并在添加/删除它们时订阅/取消订阅它们。
      【解决方案4】:

      我希望通过事件或命令来刷新视图模型。

      因为订阅集合成员很棘手。 假设您想使用第二种方法:订阅 Person 类更改事件。 那么它可能有以下缺点:

      • 在视图模型的构造函数中,您必须订阅列表中的每个“Person”成员。
      • 在视图模型中,只要集合被修改,您就必须订阅/取消订阅该列表中添加/删除的成员。
      • 在处理视图模型时,您必须取消订阅已订阅的更改事件。

      所以,如果你去订阅 Person 类的 change 事件,这是一个开销。

      【讨论】:

      • 在我看来,引发 Checked 事件时调用 Refresh 将导致无限循环:Refresh 正在更改 IsSelected 道具,因此该事件将再次引发......你有没有四处走走?
      • @NirSmadar 您可以在 ViewModel 中存储一个布尔值,isRefreshing,在 Refresh 方法的开头设置为 true,在结尾设置为 false。如果isRefreshing在你设置之前就已经为真,你可以提前跳出方法来避免循环。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 1970-01-01
      • 2010-12-01
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      相关资源
      最近更新 更多