【问题标题】:How to create my own PropertyChangedEventArgs for INotifyPropertyChanged interface?如何为 INotifyPropertyChanged 接口创建自己的 PropertyChangedEventArgs?
【发布时间】:2012-08-16 15:39:14
【问题描述】:

我遇到了一个问题,我在DataModelViewModelPropertyChanged event 之间陷入了无限循环。

我的结构:

public class SomeDataModel : DataModelBase
{
    public SomeDataModel()
    {

    }

    public object SomeProperty
    {
        get
        {
            //
        }
        set;
        {
            //
            OnPropertyChanged("SomeProperty");
        }
    }

    public bool SomeMethod()
    {
        SomeProperty = SomeNewObject
    }
}

public class SomeViewModel : ViewModelBase
{
    public SomeViewModel()
    {

    }

    public SomeDataModel SomeDataModel
    {
        get;
        set;
    }

    public object SomeProperty
    {
        get
        {
            return SomeDataModel.SomeProperty;
        }
        set
        {
            SomeDataModel.SomeProperty = value;
            OnPropertyChanged("SomeProperty");
        }
    }
}

ViewModelDataModel 都实现了 INotifyPropertyChanged

然后我的ViewModelBase 中有一个listener 用于在我的DataModel 中更改的任何property

private void DataModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    PropertyInfo toPropertyInfo = this.GetType().GetProperty(e.PropertyName);
    PropertyInfo fromPropertyInfo = DataModel.GetType().GetProperty(e.PropertyName);

    if (toPropertyInfo != null && fromPropertyInfo != null)
    {
        if (toPropertyInfo.CanWrite && fromPropertyInfo.CanRead)
        {
            toPropertyInfo.SetValue(this, fromPropertyInfo.GetValue(DataModel, null), null);
        }
    }
}

所以现在当propertyDataModel 中设置时,ViewModelBase 中的侦听器会捕获它并更新ViewModel 中的相关property。但是ViewModel 中的集合将其设置回DataModel,导致OnPropertyChanged("SomeProperty"); 再次触发,以无限循环结束。

  1. 是否有快速解决方法来解决它? (注意:不能改变结构)
  2. 我是否能够创建自己的自定义类,继承自 PropertyChangedEventArgs 并且我的 INotifyPropertyChanged 操作仍然有效?

我在想:

public class CustomPropertyChangedEventArgs : PropertyChangedEventArgs
{
    public CustomPropertyChangedEventArgs(string propertyName, SomeEnum enumName)
        : base(propertyName)
    {
        //Set enum
    }
}

然后在OnPropertyChanged 中我想使用新的CustomPropertyChangedEventArgs 并传递我想使用的enum

public void OnPropertyChanged(string propertyName)
{
    CustomPropertyChangedEventArgs handler = this.PropertyChanged;

    if (handler != null)
    {
        handler(this, new CustomPropertyChangedEventArgs(propertyName, newEnum));
    }
}

【问题讨论】:

  • 我可能会被炸死,但我放了一个类级别列表,其中列出了每个对象中当前正在更改的所有属性名称(检查并在输入方法时添加并在退出方法时删除)。如果,当我输入 OnPropertyChanged 时,属性名称已经在列表中,我只是返回而不做任何事情。我宁愿不刷新也不愿冒无限循环的风险。
  • 是的,我会在代码审查中抨击你。 :)
  • Amiram Korach 有最好的方法,只要您可以确定没有人会调用 OnPropertyChanged,而是调用属性集代码。否则总会有无限循环的风险。我会对愤怒的用户和崩溃的程序进行差评 =)

标签: c# .net class events mvvm


【解决方案1】:

您可以检查该值是否相同并且不要更新它。这就是INotifyPropertyChanged 通常的实现方式。只有当OnPropertyChanged真的发生了变化时,你才会触发它。

public object SomeProperty
{
    get
    {
        return SomeDataModel.SomeProperty;
    }
    set
    {
        if (SomeDataModel.SomeProperty != value)
        {
            SomeDataModel.SomeProperty = value;
            OnPropertyChanged("SomeProperty");
        }
    }
}

【讨论】:

  • 这是完美的。不敢相信我错过了这条路。谢谢:)
【解决方案2】:
you can disable and enable the event to avoid loop
private void DataModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    OnPropertyChanged -= DataModel_PropertyChanged;
    PropertyInfo toPropertyInfo = this.GetType().GetProperty(e.PropertyName);
    PropertyInfo fromPropertyInfo = DataModel.GetType().GetProperty(e.PropertyName);

    if (toPropertyInfo != null && fromPropertyInfo != null)
    {
        if (toPropertyInfo.CanWrite && fromPropertyInfo.CanRead)
        {
            toPropertyInfo.SetValue(this, fromPropertyInfo.GetValue(DataModel, null), null);
        }
    }
    OnPropertyChanged += DataModel_PropertyChanged;
}

【讨论】:

  • 我也会避免这种情况。如果您的模型/视图模型设置正确,则应该没有理由这样做。
  • 它也不是线程安全的,除非你真的不知道该怎么做,这是你可以尝试的最后一件事。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 2012-02-20
相关资源
最近更新 更多