【问题标题】:How to Raise Property Changed in Derived Classes?如何在派生类中提高属性更改?
【发布时间】:2019-07-14 07:27:57
【问题描述】:

我如何在课堂上为SomeProperty 提高PropertyChanged B

此示例无法编译,因为PropertyChanged 无法通过这种方式访问​​...

public class A : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
}

public class B : A
{
    private object _someProperty;

    public object SomeProperty
    {
        get => _someProperty;
        set
        {
            _someProperty = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SomeProperty)))
        }
    }
}

【问题讨论】:

  • 这是每个 MVVM 框架或演示中解决的常见问题。

标签: c# wpf events inotifypropertychanged propertychanged


【解决方案1】:

解决方案 1:

你可以使用这个RaisePropertyChangedExtension

public static class RaisePropertyChangedExtension
{
    public static void RaisePropertyChanged(this INotifyPropertyChanged @this, [CallerMemberName] string propertyName = null)
    {
        var declaringType = @this.GetType().GetEvent(nameof(INotifyPropertyChanged.PropertyChanged)).DeclaringType;
        var propertyChangedFieldInfo = declaringType.GetField(nameof(INotifyPropertyChanged.PropertyChanged), BindingFlags.Instance | BindingFlags.NonPublic);
        var propertyChangedEventHandler = propertyChangedFieldInfo.GetValue(@this) as PropertyChangedEventHandler;
        propertyChangedEventHandler?.Invoke(@this, new PropertyChangedEventArgs(propertyName));
    }
}

像这样:

public class B : A
{
    private object _someProperty;

    public object SomeProperty
    {
        get => _someProperty;
        set
        {
            _someProperty = value;
            this.RaisePropertyChanged();
        }
    }
}

在我看来,这是迄今为止我所知道的最好的解决方案。

缺点是你可以像这样从另一个班级提出PropertyChanged

public class C
{
    public C(B b)
    {
        b.RaisePropertyChanged(nameof(b.SomeProperty));
    }
}

以这种方式从其他班级提高PropertyChanged 不是一个好习惯,所以我不担心这个缺点。

此解决方案的灵感来自 Thomas Levesque 的答案:Simple small INotifyPropertyChanged implementation

解决方案 2:

你可以在基类A中创建一个受保护的RaisePropertyChanged

public class A : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

并调用派生类中的方法B

public class B : A
{
    private object _someProperty;

    public object SomeProperty
    {
        get => _someProperty;
        set
        {
            _someProperty = value;
            RaisePropertyChanged();
        }
    }
}

缺点是你必须为你创建的每个新基类实现RaisePropertyChanged方法,相反你避免了解决方案1的缺点。

【讨论】:

  • 我更喜欢解决方案 2。尤其是当基类 (A) 已经给定时。
  • 我同意解决方案 2。特别是它实际上完全消除了传递属性名称的需要。如果能够直接调用事件,这将是必要的。
  • 我使用的基本视图模型与该基类几乎完全相同。除了我公开 RaisePropertyChanged。能够从一个虚拟机调用另一个虚拟机有时很有用。
  • 也许我没有抓住重点,但如果您在同一分钟内有一个问题和一个相当详细的答案,这应该去codereview.stackexchange.com
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-18
  • 2018-03-21
  • 1970-01-01
  • 2015-04-24
  • 1970-01-01
  • 2013-08-31
  • 1970-01-01
相关资源
最近更新 更多