web-dev-qa-db-ja.com

変数の値が変更されたときにイベントをトリガーする方法は?

現在、Visual Studioを使用してC#でアプリケーションを作成しています。変数の値が1になったときに特定のコードが実行されるように、コードを作成したいと思います。私はifステートメントを使用できることを知っていますが、問題は非同期プロセスで値が変更されるため、技術的には値が変更される前にifステートメントを無視できることです。

変数値が変更されたときにイベントがトリガーされるようにイベントハンドラーを作成することは可能ですか?もしそうなら、どうすればこれを行うことができますか?

Ifステートメントがどのように機能するかを誤解していた可能性があります。どんな助けでも大歓迎です。

89
James Mundy

私はあなたがプロパティを作成したいようです。

public int MyProperty
{
    get { return _myProperty; }
    set
    {
        _myProperty = value;
        if (_myProperty == 1)
        {
            // DO SOMETHING HERE
        }
    }
}

private int _myProperty;

これにより、プロパティ値が変更されるたびにコードを実行できます。必要に応じて、ここでイベントを発生させることができます。

112
Jonathan Wood

プロパティセッターを使用して、フィールドの値が変更されるたびにイベントを発生させることができます。

独自のEventHandlerデリゲートを持つことも、有名なSystem.EventHandlerデリゲートを使用することもできます。

通常、これにはパターンがあります。

  1. イベントハンドラーデリゲート(EventArgs型の引数を持つ)でパブリックイベントを定義します。
  2. OnXXXXX(たとえば、OnMyPropertyValueChanged)と呼ばれる保護された仮想メソッドを定義します。このメソッドでは、イベントハンドラーデリゲートがnullであるかどうかを確認し、そうでない場合は呼び出すことができます(イベント委任に1つ以上のメソッドが関連付けられていることを意味します)。
  3. 何かが変更されたことをサブスクライバーに通知する場合は常に、このprotectedメソッドを呼び出します。

ここに例があります

private int _age;

//#1
public event System.EventHandler AgeChanged;

//#2
protected virtual void OnAgeChanged()
{ 
     if (AgeChanged != null) AgeChanged(this,EventArgs.Empty); 
}

public int Age
{
    get
    {
         return _age;
    }

    set
    {
         //#3
         _age=value;
         OnAgeChanged();
    }
 }

このアプローチの利点は、クラスから継承したい他のクラスに、必要に応じて動作を変更させることです。

発生している別のスレッドでイベントをキャッチする場合は、別のスレッドで定義されているオブジェクトの状態を変更しないように注意する必要があります。これにより、クロススレッド例外がスローされます。これを回避するには、状態を変更するオブジェクトでInvokeメソッドを使用して、イベントが発生したのと同じスレッドで変更が行われていることを確認するか、Windowsフォームを処理している場合BackgourndWorkerを使用して、並列スレッドで物事を行うことができます。

58
Beatles1692

.NETフレームワークは、実際には、プロパティが変更されたときにサブスクライバーに通知するために使用できるインターフェイスSystem.ComponentModel.INotifyPropertyChangedを提供します。このインターフェイスには、PropertyChangedイベントが1つあります。通常はWPFでバインドに使用されますが、プロパティ変更通知を標準化する方法としてビジネスレイヤーで役立つことがわかりました。

スレッドの安全性の観点から、セッターにロックを設定して、競合状態に陥らないようにします。

コードの私の考えはここにあります:):

public class MyClass : INotifyPropertyChanged
{
    private object _lock;

    public int MyProperty
    {
        get
        {
            return _myProperty;
        }
        set
        {
            lock(_lock)
            {
                //The property changed event will get fired whenever
                //the value changes. The subscriber will do work if the value is
                //1. This way you can keep your business logic outside of the setter
                if(value != _myProperty)
                {
                    _myProperty = value;
                    NotifyPropertyChanged("MyProperty");
                }
            }
        }
    }

    private NotifyPropertyChanged(string propertyName)
    {
        //Raise PropertyChanged event
    }
    public event PropertyChangedEventHandler PropertyChanged;
}


public class MySubscriber
{
    private MyClass _myClass;        

    void PropertyChangedInMyClass(object sender, PropertyChangedEventArgs e)
    {
        switch(e.PropertyName)
        {
            case "MyProperty":
                DoWorkOnMyProperty(_myClass.MyProperty);
                break;
        }
    }

    void DoWorkOnMyProperty(int newValue)
    {
        if(newValue == 1)
        {
             //DO WORK HERE
        }
    }
}

これが役立つことを願っています:)

43
Daniel Sandberg

プロパティを使用するだけです

int  _theVariable;
public int TheVariable{
  get{return _theVariable;}
  set{
    _theVariable = value; 
    if ( _theVariable == 1){
      //Do stuff here.
    }
  }
}
11