在C#中使用事件处理程序

时间:2016-02-18 10:15:35

标签: c# eventhandler

我正在尝试在c#中观察一个值,并在它发生变化时触发一个函数。基于阅读示例,我有:

//事件观察者

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();
    }
}

在我的主要功能中:

_currentFrame += _currentFrame;

据我了解,这应该触发事件观察者,但事实并非如此。我错过了什么?

感谢。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

要使事件处理程序被调用,您需要做两件事。

  1. 您需要将事件处理程序挂钩到事件
  2. 您需要解雇活动
  3. 您忽略了显示代码中的第一项。如果您还没有将事件处理程序连接到事件,则需要执行此操作。你可以这样做:

    someObject.FrameChanged += SomeObjectFrameChanged;
    
    ...
    
    private void SomeObjectFrameChanged(object sender, EventArgs e)
    {
        ... code here
    }
    

    第二个表面看起来没问题,属性调用OnFrameChanged。

    顺便说一下,你的OnFrameChanged不是实现事件处理程序fire方法的推荐方法,你应该使用这个模板:

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

    此更改的原因是将事件值提升为局部变量,如果您处于多线程环境中,则在检查事件至少有一个事件处理程序(!= null)之后,另一个线程可以取消订阅最后一个事件处理程序。挑剔,但你仍然应该改变它。

    在C#6中,您可以将上述方法更改为:

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

    因为这会做同样的事情。

    但是,我们在这里遇到了代码和期望中的真正错误:

    _currentFrame += _currentFrame;
    

    您希望这会触发您的活动,但这是不正确的。

    您正在直接访问支持字段,该字段绕过属性中的所有代码,因此此处没有调用OnFrameChanged的代码,因此不会触发该事件。

    相反,您应该访问属性

    Age += Age;
    

    轻微的挑剔#2是你应该确保PropertyChanged只有在财产实际改变的情况下被解雇:

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

    因此你应该像这样实现你的属性设置器:

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