web-dev-qa-db-ja.com

プロパティの値が変更されるたびにイベントを発生させますか?

プロパティがあり、名前はImageFullPath1です

public string ImageFullPath1 {get; set; }

値が変更されるたびにイベントを発生させます。 INotifyPropertyChangedの変更は承知していますが、イベントを使用して変更したいです。

61
Mohammad Dayyan

INotifyPropertyChangedインターフェースは、イベントで実装されます。このインターフェイスには、PropertyChangedという1つのメンバーしかありません。これは、コンシューマがサブスクライブできるイベントです。

リチャードが投稿したバージョンは安全ではありません。このインターフェイスを安全に実装する方法は次のとおりです。

_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デリゲートbeforeのコピーを作成して、呼び出しを試みます(これを行わないと、競合状態が発生します)。

  • INotifyPropertyChangedインターフェイスを正しく実装します。

変更されたspecificプロパティの通知を追加作成する場合は、次のコードを追加できます。

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

public event EventHandler ImageFullPathChanged;
_

次に、OnImageFullPathChanged(EventArgs.Empty)行の後にOnPropertyChanged("ImageFullPath")行を追加します。

.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();
            }
        }
    }
_
149
Aaronaught

私は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メソッドを仮想化して、サブクラスがそれをオーバーライドしてプロパティの変更をキャッチできるようにします。

34
Mikael Sundberg

プロパティが変更されたときにイベントを発生させることは、まさにINotifyPropertyChangedが行うことです。 INotifyPropertyChangedを実装するために必要なメンバーが1つあり、それがPropertyChangedイベントです。自分で実装したものはすべて、おそらくその実装と同じになるため、使用しないことの利点はありません。

7
Ryan Brunner
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が存在する理由です。

5
Richard Berg

(自動プロパティの代わりに)バッキングフィールドを使用するようにプロパティを変更する場合、次のことができます。

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);
    }
  }
}
4
Oded