如何在变量值改变时触发事件?

Jam*_*ndy 90 c# silverlight event-handling visual-studio windows-phone-7

我目前正在使用Visual Studio在C#中创建一个应用程序.我想创建一些代码,以便当变量的值为1时,执行某段代码.我知道我可以使用if语句,但问题是该值将在异步进程中更改,因此从技术上讲,if语句可以在值更改之前被忽略.

是否可以创建事件处理程序,以便在变量值更改时触发事件?如果是这样,我该怎么做?

完全有可能我误解了if语句是如何工作的!任何帮助将非常感激.

Jon*_*ood 114

在我看来,你想要创建一个属性.

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

private int _myProperty;
Run Code Online (Sandbox Code Playgroud)

这允许您在属性值更改时运行一些代码.如果你愿意的话,你可以在这里举办活动.


Bea*_*692 61

只要字段的值发生变化,您就可以使用属性设置器来引发事件.

您可以拥有自己的EventHandler委托,也可以使用着名的System.EventHandler委托.

通常有这样的模式:

  1. 使用事件处理程序委托(具有EventArgs类型的参数)定义公共事件.
  2. 定义名为OnXXXXX的受保护虚拟方法(例如OnMyPropertyValueChanged).在此方法中,您应检查事件处理程序委托是否为null,如果不是,则可以调用它(这意味着有一个或多个方法附加到事件委托).
  3. 只要您想通知订阅者某些内容已发生变化,请调用此受保护的方法.

这是一个例子

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();
    }
 }
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是,如果需要,您可以让任何其他想要从您的类继承的类更改行为.

如果要捕获正在引发的其他线程中的事件,则必须注意不要更改在另一个线程中定义的对象的状态,这将导致抛出跨线程异常.要避免这种情况,您可以在要更改其状态的对象上使用Invoke方法,以确保更改发生在事件已引发的同一个线程中,或者您正在处理Windows窗体时可以使用BackgourndWorker在并行线程中做很好的事情.

  • 整个网络上最好的解释之一。我想我终于了解了自定义事件处理。感谢这篇文章。 (3认同)

小智 43

.NET框架实际上提供了一个接口,可用于在属性发生更改时通知订户:System.ComponentModel.INotifyPropertyChanged.此接口有一个事件PropertyChanged.它通常在WPF中用于绑定,但我发现它在业务层中用作标准化属性更改通知的方法.

在线程安全方面,我会在setter中设置一个锁,这样你就不会遇到任何竞争条件.

以下是我在代码中的想法:):

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这有用:)

  • 包含另一个答案省略的锁定的+1. (6认同)
  • @LodeVlaeminck它可以防止在处理事件时更改属性的值。 (2认同)

Rus*_*est 12

只是使用一个属性

int  _theVariable;
public int TheVariable{
  get{return _theVariable;}
  set{
    _theVariable = value; 
    if ( _theVariable == 1){
      //Do stuff here.
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


And*_*rew 5

2022年

您可以使用泛型类:

class Wrapped<T>  {
    private T _value;

    public Action WillChange;
    public Action DidChange;

    public T Value
    {
        get => _value;

        set
        {
            if ( _value != value )
            {
                OnWillChange();
                _value = value;
                OnDidChanged();
            }
        }
    }

    protected virtual void OnWillChange() => WillChange?.Invoke();
    protected virtual void OnDidChange() => DidChange?.Invoke();
}
Run Code Online (Sandbox Code Playgroud)

并将能够执行以下操作:

var i = new Wrapped<int>();

i.WillChange += () => { Console.WriteLine("will be changed!"); };
i.DidChange += () => { Console.WriteLine("changed!"); };

i.Value = 10;
i.Value = 11;
i.Value = 10;
i.Value = 11;

Console.ReadKey();
Run Code Online (Sandbox Code Playgroud)

结果:

will be changed!
changed!
will be changed!
changed!
will be changed!
changed!
will be changed!
changed!
Run Code Online (Sandbox Code Playgroud)

  • 在引发更改事件之前,我会亲自检查一下新值是否与旧值不同 (3认同)
  • 我个人不喜欢在更改值之前如何调用“OnValueChanged();”。似乎是一个会破坏您的代码的编程错误 (2认同)