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

Using an Event Handler in C#

我正在尝试观察 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;

据我了解,这应该会触发事件观察器,但实际上并没有。我错过了什么?

谢谢。

您还没有为 FrameChanged 分配任何事件。

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

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

  1. 您需要将事件处理程序挂接到事件
  2. 您需要触发事件

您忘记显示代码中的第一项。如果您还没有将事件处理程序连接到您的事件,则需要这样做。你可以这样做:

someObject.FrameChanged += SomeObjectFrameChanged;

...

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

第二个表面上看起来不错,属性 调用 OnFrameChanged。

顺便说一句,您的 OnFrameChanged 不是实现事件处理程序触发方法的推荐方式,您应该使用此模板:

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;

第二个小问题是您应该确保 PropertyChanged 仅在 属性 实际更改时才触发:

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

因此你应该像这样实现你的 属性 setter:

set
{
    if (_currentFrame == value) return;

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