简体   繁体   中英

Using an Event Handler in C#

I am trying to watch a value in c#, and trigger a function when it changes. Based on reading examples, I have:

//event watcher

private int _currentFrame =1;
public event System.EventHandler FrameChanged;

protected virtual void OnFrameChanged()
{
    if (FrameChanged != null) FrameChanged(this, EventArgs.Empty);
}

public int Age
{
    get
    {
        return _currentFrame;
    }

    set
    {
        //#3
        _currentFrame = value;
        OnFrameChanged();
    }
}

and in my main function:

_currentFrame += _currentFrame;

As I understand it, this should trigger the event watcher, but it does not. What have i missed?

Thanks.

您尚未为FrameChanged分配任何事件。

yourInstance.FrameChanged+= () => DoSomething();

There are two things you need to do in order to get an event handler to be called.

  1. You need to hook the event handler to the event
  2. You need to fire the event

You have neglected to show the first item in your code. If you haven't hooked up an event handler to your event you need to do that. You could do it like this:

someObject.FrameChanged += SomeObjectFrameChanged;

...

private void SomeObjectFrameChanged(object sender, EventArgs e)
{
    ... code here
}

The second looks OK on the surface, the property calls OnFrameChanged.

By the way, your OnFrameChanged is not the recommended way to implement event handler fire methods, you should use this template:

protected virtual void OnFrameChanged()
{
    var evt = FrameChanged;
    if (evt != null) evt(this, EventArgs.Empty);
}

The reason for this change, lifting the event value into a local variable is that if you're in a multithreaded environment, after you've checked that the event has at least one event handler ( != null ), another thread could unsubscribe the last event handler. Nitpicking but you should still change it.

In C# 6 you can change the above method to this:

protected virtual void OnFrameChanged()
{
    FrameChanged?.Invoke(this, EventArgs.Empty);
}

As this will do all the same things.


But here we come to the real bug in your code and expectations:

_currentFrame += _currentFrame;

You expect this to fire your event, but this is incorrect.

You're accessing the backing field directly, which bypasses all the code in the property, thus there is no code here that calls OnFrameChanged and thus the event will not be fired.

Instead you should access the property :

Age += Age;

Minor nitpicking #2 is that you should ensure that PropertyChanged is only fired if the property actually changed:

Age = 1;
Age = 1; // did not change, do not fire PropertyChanged

And thus you should implement your property setter like this:

set
{
    if (_currentFrame == value) return;

    //#3
    _currentFrame = value;
    OnFrameChanged();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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