1

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.

1
  • 3
    Why should it trigger the event handler? You're not changing the property, you're changing the backing field. There is no monitoring of backing fields, the only thing you have is the code in your property. So try Age += Age or Age++ instead. Commented Feb 18, 2016 at 10:19

2 Answers 2

1

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();
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! exactly the explanation I needed.
1

You haven't assigned no event to FrameChanged.

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

3 Comments

... += (sender, e) => DoSomething();
The event handler won't fire if he changes the backing field directly.
Thank you! That makes sense.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.