【问题标题】:Raising a propertychanged event without adding a private variable在不添加私有变量的情况下引发 propertychanged 事件
【发布时间】:2011-10-21 08:48:33
【问题描述】:

我有一个看起来像这样的属性。

public int NumberOfElephants { get; set; }

这个属性在一个 observablecollection 中,它必须通知另一个属性它已经改变了。

我将如何进行以下操作

public int NumberOfElephants { get; set { OnPropertyChanged("totalAnimals"); }

不需要这样的代码

private int _numberOfElephants;
public int NumberOfElephants { 
    get { 
        return _numberOfElephants; 
    } 

    set { 
        _numberOfElephants = value; 
        OnPropertyChanged("totalAnimals"); 
    } 
}

【问题讨论】:

标签: c#


【解决方案1】:

作为 Jon 的答案的替代方案,您可以通过 IL weaving 获得可以执行此操作的工具,例如 NotifyPropertyWeaver,也可以通过 VS Gallery 作为工具获得

对于您的示例,根据他们的doco on Attributes,您应该能够拥有以下内容:

[NotifyProperty(AlsoNotifyFor = new[] { "TotalAnimals" })]
public int NumberOfElephants { get; set; }

public int TotalAnimals { get; set; }

但是,根据他们网站的以下示例,根据TotalAnimals 的实施,可能不需要它:

您的代码

public class Person : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

}

编译的内容

public class Person : INotifyPropertyChanged {

    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

【讨论】:

  • 但是我将如何使用 notifypropertyweaver 告诉属性 totalAnimals 这也会改变
  • 我实际上并没有使用它,但是阅读文档似乎是可能的(根据约定或具有显式属性)。我会更新答案
【解决方案2】:

你没有。你不能。

自动实现的属性在属性很小的情况下起作用 - 除了“返回变量的值”或“设置变量的值”之外,get/set 不需要任何代码。当然,您可以通过重新格式化使其更短......我会这样写:

private int numberOfElephants;
public int NumberOfElephants {
    get { return numberOfElephants; }

    set {
        _numberOfElephants = value; 
        OnPropertyChanged("totalAnimals"); 
    } 
}

实际上,我会使用“单独一行上的左大括号”作为集合的开头和属性的开头,但我保留了您喜欢的样式。但是在一行中使用“单个表达式get/set 实现”可以使具有大量属性的类更加简洁。

【讨论】:

  • 有没有办法“扩展”getter 和 setter?
  • @JosephLeBrech:只有完整地写出来。两者之间没有任何关系。
  • 真可惜,即使像 [Property("totalAnimals")] 这样的魔法也会很好,我问这个问题是因为我还有 10 个属性可以做同样的事情。
  • @JosephLeBrech 根据我的回答,您可以通过 IL weaving 获得工具
  • 我现在正在看这个,但我需要通知 totalAnimals 它也需要更改。我必须专门这样做吗?
【解决方案3】:

@jeffora 扩展答案

使用NotifyPropertyWeaver 你可以这样写

public class Animals: INotifyPropertyChanged
{
    public int NumberOfElephants { get; set; }
    public int NumberOfMonkeys { get; set; }

    public int TotalAnimals
    {
        get
        {
            return NumberOfElephants + NumberOfMonkeys;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

这将被编译

public class Animals : INotifyPropertyChanged
{
    int numberOfElephants;
    int numberOfMonkeys;

    public int NumberOfElephants
    {
        get { return numberOfElephants; }
        set
        {
            numberOfElephants = value;
            OnPropertyChanged("TotalAnimals");
            OnPropertyChanged("NumberOfElephants");
        }
    }

    public int NumberOfMonkeys
    {
        get { return numberOfMonkeys; }
        set
        {
            numberOfMonkeys = value;
            OnPropertyChanged("TotalAnimals");
            OnPropertyChanged("NumberOfMonkeys");
        }
    }


    public int TotalAnimals
    {
        get { return NumberOfElephants + NumberOfMonkeys; }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

【讨论】:

    【解决方案4】:

    我会在 C#6 中使用它

    private int numberOfElephants;
    public int NumberOfElephants {
        get => numberOfElephants; 
    
        set {
            _numberOfElephants = value; 
            OnPropertyChanged(); 
        } 
    }
    
    
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    

    这需要

    using System.Runtime.CompilerServices;
    

    【讨论】:

      【解决方案5】:

      使用 PostSharp 之类的工具,您可以编织属性以创建样板代码代码。更多,你不必实现INotifyPropertyChanged,PostSharp 可以为你做。

      看到这个blog post

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-16
        • 1970-01-01
        • 2011-12-14
        • 2022-01-02
        • 2019-10-08
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多