【问题标题】:C# - How to handle model's property change to invoke notify in ViewModelC# - 如何处理模型的属性更改以在 ViewModel 中调用通知
【发布时间】:2018-08-20 11:38:16
【问题描述】:

按照 MVVM 架构,我们有一个带有 2 个 DataGrids 的视图,其数据是相关的,而视图模型有 ObservableCollection<Model>。

模型具有布尔属性,基于该属性是启用/禁用网格之一。一切正常,当我更改选定的Model 时,网格变得无法使用。但是,当我更改属性时,不会调用客户属性IsSelectedModelChecked 的Notify(当我选中/取消选中第一个网格中的复选框时,我需要在属性IsSelectedModelChecked 上调用Notify)。

问:如何在模型的属性更改时调用属性更改?

我检查了几个问题,但没有一个回答我的问题。我想提供一些想法,但我不知道。谢谢


XAML:

<DataGrid
      ItemsSource="{Binding Models}"
      SelectedItem="{Binding SelectedModel}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name"
                 Binding="{Binding Name}"/>
        <DataGridCheckBoxColumn Header="Check"
                 Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}">
    </DataGrid.Columns>
</DataGrid>

<DataGrid
      IsEnabled="{Binding IsSelectedModelChecked}"/>

型号:

public class Model : Microsoft.VisualStudio.PlatformUI.ObservableObject
{
    private string mName = @"<Name>";
    public string Name
    {
        get { return mName; }
        set { SetProperty(ref mName, value); }
    }

    private bool mIsChecked = false;
    public bool IsChecked
    {
        get { return mIsChecked; }
        set { SetProperty(ref mIsChecked, value); }
    }
}

视图模型:

public class ViewModel : Microsoft.VisualStudio.PlatformUI.ObservableObject
{
    private Model mSelectedModel;
    public Model SelectedModel
    {
        get { return mSelectedModel; }
        set
        {
            SetProperty(ref mSelectedModel, value);
            NotifyPropertyChanged(nameof(IsSelectedModelChecked));
        }
    }

    private ObservableCollection<Model> mModels = new ObservableCollection<Model>();
    public ObservableCollection<Model> Models
    {
        get { return mModels; }
        set { SetProperty(ref mModels, value); }
    }

    public bool IsSelectedModelChecked => SelectedModel?.IsChecked ?? false;
}

【问题讨论】:

  • Microsoft.VisualStudio.PlatformUI.ObservableObject?把那些垃圾扔进该死的垃圾篮里。它要求您调用 SetProperty 并发送 正在设置的属性的名称。没有这个,它不会通知任何人有关属性更改的信息(请参阅模型代码中的 Name 和 IsChecked)。难怪它没有按预期工作。只需找到 INPC 的实现,它使用 CallerMemberNameAttribute 来获取正在更新的属性的名称。
  • @Will 那东西能正常工作吗.. 你根本不明白这个问题。属性更改(在模型中)的通知不会传播到相关属性(在视图模型中),因为该关系在任何地方都没有“澄清”。否则,视图等的绑定将按预期工作.. ;)

标签: c# .net xaml mvvm binding


【解决方案1】:

您必须监听您的SelectedModel 的PropertyChanged 事件。

即

public Model SelectedModel
{
    get { return mSelectedModel; }
    set
    {
        if (mSelectedModel != null)
            mSelectedModel.PropertyChanged -= OnSelectedModelPropertyChanged;
        SetProperty(ref mSelectedModel, value);
        if (mSelectedModel != null)
            mSelectedModel.PropertyChanged += OnSelectedModelPropertyChanged;
        NotifyPropertyChanged(nameof(IsSelectedModelChecked));
    }
}

private void OnSelectedModelPropertyChanged( object sender, PropertyChangedEventArgs args )
{
    if (args.PropertyName == nameof(Model.IsChecked))
        NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}

此外,如果您的模型实例的寿命比视图模型长,您需要注意泄漏视图模型实例。

【讨论】:

  • 感谢您的回答!你让我走上了正确的轨道,我附上了我自己的答案,因为它还包括对可能的内存泄漏的处理。
【解决方案2】:

这是对Haukinger 答案的扩展。他提到了内存泄漏的问题,当 ViewModel 实例将被销毁但模型将存在并且处理程序仍将附加到事件时,可能会发生这种情况。

在这种情况下,WPF 实现了称为Weak Event Pattern 的东西,它允许处理这种情况。对于属性更改,现有的PropertyChangedEventManager 实现了这种弱事件模式。代码应该写成:

public Model SelectedModel
{
    get { return mSelectedModel; }
    set
    {
        if (mSelectedModel != null)
            PropertyChangedEventManager.RemoveHandler(mSelectedModel, OnSelectedModelPropertyChanged, "");

        SetProperty(ref mSelectedModel, value);

        if (mSelectedModel != null)
            PropertyChangedEventManager.AddHandler(mSelectedModel, OnSelectedModelPropertyChanged, "");

        NotifyPropertyChanged(nameof(IsSelectedModelChecked));
    }
}

private void OnSelectedModelPropertyChanged( object sender, PropertyChangedEventArgs args)
{
    if (args.PropertyName == nameof(Model.IsChecked))
        NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}

【讨论】:

    猜你喜欢
    • 2023-04-02
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 1970-01-01
    相关资源
    最近更新 更多