【问题标题】:MVVM viewmodel property triggering updateMVVM 视图模型属性触发更新
【发布时间】:2010-09-22 08:44:29
【问题描述】:

我开始为我的一个 Silverlight 应用程序实现 MVVM。 (我没有使用任何工具包)。

我的页面包含一个带有两个组合框的部分。在其中一个组合中选择一个项目会触发搜索,该搜索会更新组合下方可见的网格。

每个组合的选定项都绑定到我的视图模型中的一个属性。这些属性的设置器引发 INotifyPropertyChanged 属性更改并自动更新绑定到网格的数据。

一切都很好,直到我需要添加一个重置按钮,其目的是重置搜索参数,即:每个组合框不应指示任何项目并且网格应该为空。

  • 如果视图模型中的重置函数更新了支持字段,则 UI 不会反映更改,因为不会调用 RaisePropertyChanged。
  • 如果视图模型中的重置功能更新了属性,UI 将反映更改,但网格将更新两次:将第一个属性重置为 null 以及第二个属性时

任何帮助表示赞赏

/// <summary>Selected user.</summary>
public User SelectedUser
{
    get { return _selectedUser; }
    set
    {
        _selectedUser = value;
        RaisePropertyChanged("SelectedUser");

        UpdateProducts();
    }
}

/// <summary>Selected product category.</summary>
public ProductCategory SelectedProductCategory
{
    get { return _selectedProductCategory; }
    set
    {
        _selectedProductCategory = value;
        RaisePropertyChanged("SelectedProductCategory");

        UpdateProducts();
    }
}

// Reset option 1
public void Reset()
{
    _selectedUser = null;
    _selectedProductCategory = null;
    _products = null;
}

// Reset option 2
public void Reset()
{
    SelectedUser = null;
    SelectedProductCategory = null;
    // No need to update Products which has already been updated twice...
}

【问题讨论】:

    标签: mvvm


    【解决方案1】:

    这在很多框架中都让我很兴奋,包括 WPF。您需要一些延迟对更改通知的响应的概念,以便用户永远不会看到中间状态。但是,您无法更改 WPF 响应通知的方式,因此您可以做的最好的事情是将通知延迟到“尘埃落定之后”。在您的情况下,您需要在发送任何通知之前更改两个支持字段。您的重置方法可以将这个想法编码如下:

    public void Reset()
    {
        _selectedUser = null;
        _selectedProductCategory = null;
        _products = null;
    
        RaisePropertyChanged("SelectedUser");
        RaisePropertyChanged("SelectedProductCategory");
    }
    

    在我看来,WPF 同步更新显示以响应更改通知的方式是完全错误的。他们的 DependencyProperty 系统使他们有机会仅将依赖项标记为脏并在以后执行重新计算。

    我使用标记为脏和异步重新计算的想法作为您在这个问题中提到的问题的一般解决方案,这些天我无法想象没有它的编程。可惜更多的框架不能以这种方式工作。

    【讨论】:

    • 感谢您的回答,我同意您的看法。这不仅在理论上是“错误的”,如果我碰巧更改了属性的名称,重构将无法更新关联的 RaisePropertyChanged,如果它们位于一个地方(属性设置器)也没关系,但对我来说似乎危险的是它们可以在其他地方买到
    • 不要让我开始使用字符串的属性更改通知......哦,太脆弱了,效率低下。你会认为微软定义核心 API 的人会更聪明一些。
    【解决方案2】:

    更新支持字段后,您可以为所有属性引发单个 PropertyChanged 事件:

    RaisePropertyChanged(String.Empty);
    

    【讨论】:

    • 谢谢。这肯定会刷新所有控件,即使是那些不关心更改的控件。我的整个 UI 不会“闪烁”吗?
    • 是的,它将刷新绑定到您的视图模型的所有内容。但我怀疑你能否看到它“眨眼”……
    【解决方案3】:

    如果您使用支持字段,则必须调用

    RaisePropertyChanged("SelectedUser");
    RaisePropertyChanged("SelectedProductCategory");
    

    在 Reset() 方法中。

    【讨论】:

    • 感谢您的回答,这就是我要避免的:为同一属性复制 RaisePropertyChanged。我想理论上我不应该,但正如你所说,我可能没有选择......
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2013-08-30
    • 1970-01-01
    • 2021-06-04
    相关资源
    最近更新 更多