繁体   English   中英

每当属性值更改时引发事件?

[英]Raise an event whenever a property's value changed?

有一个属性,名为ImageFullPath1

public string ImageFullPath1 {get; set; }

每当其值发生变化时,我都会触发一个事件。 我知道改变INotifyPropertyChanged ,但我想用事件来做。

INotifyPropertyChanged接口通过事件实现的。 该接口只有一个成员PropertyChanged ,这是消费者可以订阅的事件。

Richard 发布的版本不安全。 下面是如何安全地实现这个接口:

public class MyClass : INotifyPropertyChanged
{
    private string imageFullPath;

    protected void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, e);
    }

    protected void OnPropertyChanged(string propertyName)
    {
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    public string ImageFullPath
    {
        get { return imageFullPath; }
        set
        {
            if (value != imageFullPath)
            {
                imageFullPath = value;
                OnPropertyChanged("ImageFullPath");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

请注意,这会执行以下操作:

  • 抽象属性更改通知方法,以便您可以轻松地将其应用于其他属性;

  • 尝试调用它之前制作PropertyChanged委托的副本(不这样做将创建竞争条件)。

  • 正确实现INotifyPropertyChanged接口。

如果您想为正在更改的特定属性另外创建通知,您可以添加以下代码:

protected void OnImageFullPathChanged(EventArgs e)
{
    EventHandler handler = ImageFullPathChanged;
    if (handler != null)
        handler(this, e);
}

public event EventHandler ImageFullPathChanged;

然后在OnImageFullPathChanged(EventArgs.Empty) OnPropertyChanged("ImageFullPath")行之后添加OnImageFullPathChanged(EventArgs.Empty)行。

由于我们有 .Net 4.5,因此存在CallerMemberAttribute ,它允许删除源代码中属性名称的硬编码字符串:

    protected void OnPropertyChanged(
        [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    public string ImageFullPath
    {
        get { return imageFullPath; }
        set
        {
            if (value != imageFullPath)
            {
                imageFullPath = value;
                OnPropertyChanged();
            }
        }
    }

我使用与 Aaronaught 大致相同的模式,但是如果您有很多属性,最好使用一些通用方法魔术来使您的代码更加DRY

public class TheClass : INotifyPropertyChanged {
    private int _property1;
    private string _property2;
    private double _property3;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
        PropertyChangedEventHandler handler = PropertyChanged;
        if(handler != null) {
            handler(this, e);
        }
    }

    protected void SetPropertyField<T>(string propertyName, ref T field, T newValue) {
        if(!EqualityComparer<T>.Default.Equals(field, newValue)) {
            field = newValue;
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
    }

    public int Property1 {
        get { return _property1; }
        set { SetPropertyField("Property1", ref _property1, value); }
    }
    public string Property2 {
        get { return _property2; }
        set { SetPropertyField("Property2", ref _property2, value); }
    }
    public double Property3 {
        get { return _property3; }
        set { SetPropertyField("Property3", ref _property3, value); }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

通常,我还将 OnPropertyChanged 方法设为虚拟方法,以允许子类覆盖它以捕获属性更改。

当属性更改时引发事件正是 INotifyPropertyChanged 所做的。 实现 INotifyPropertyChanged 需要一个成员,那就是 PropertyChanged 事件。 您自己实现的任何内容都可能与该实现相同,因此不使用它没有任何好处。

public event EventHandler ImageFullPath1Changed;

public string ImageFullPath1
{
    get
    {
        // insert getter logic
    }
    set
    {
        // insert setter logic       

        // EDIT -- this example is not thread safe -- do not use in production code
        if (ImageFullPath1Changed != null && value != _backingField)
            ImageFullPath1Changed(this, new EventArgs(/*whatever*/);
    }
}                        

也就是说,我完全同意瑞安。 这种情况正是 INotifyPropertyChanged 存在的原因。

如果您更改您的属性以使用支持字段(而不是自动属性),您可以执行以下操作:

public event EventHandler ImageFullPath1Changed;
private string _imageFullPath1 = string.Empty;

public string ImageFullPath1 
{
  get
  {
    return imageFullPath1 ;
  }
  set
  {
    if (_imageFullPath1 != value)
    { 
      _imageFullPath1 = value;

      EventHandler handler = ImageFullPathChanged;
      if (handler != null)
        handler(this, e);
    }
  }
}

已经有很好的答案了,但有些人还是一头雾水

  • EventArgs 以及他们可以使用它的人
  • 还有一些是关于如何传递自定义参数的
class Program
    {
        static void Main(string[] args)
        {
            Location loc = new Location();

            loc.LocationChanged += (obj, chngLoc) =>
            {
                Console.WriteLine("Your LocId Is");
                Console.WriteLine(chngLoc.LocId);
                Console.WriteLine(chngLoc.LocCode);
                Console.WriteLine(chngLoc.LocName);
                Console.ReadLine();
            };

            Console.WriteLine("Default Location Is");
            Console.WriteLine(loc.LocId);

            Console.WriteLine("Change Location");
            loc.LocId = Console.ReadLine();
        }
    }

    public class Location
    {

        private string _locId = "Default Location";
        public string LocId
        {
            get
            {
                return _locId;
            }
            set
            {

                _locId = value;
                if (LocationChanged != null && value != LocId)
                {
                    B1Events b1 = new B1Events();
                    b1.LocCode = "Changed LocCode";
                    b1.LocId = value;
                    b1.LocName = "Changed LocName";
                    LocationChanged(this, b1);
                }
                
            }
        }
         public event EventHandler<B1Events> LocationChanged;
    }

    public class B1Events : EventArgs
    {
        public string LocId { get; set; }
        public string LocCode{ get; set; }
        public string LocName { get; set; }
    }



 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM