在 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();
要调用事件处理程序,您需要做两件事。
- 您需要将事件处理程序挂接到事件
- 您需要触发事件
您忘记显示代码中的第一项。如果您还没有将事件处理程序连接到您的事件,则需要这样做。你可以这样做:
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();
}
我正在尝试观察 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();
要调用事件处理程序,您需要做两件事。
- 您需要将事件处理程序挂接到事件
- 您需要触发事件
您忘记显示代码中的第一项。如果您还没有将事件处理程序连接到您的事件,则需要这样做。你可以这样做:
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();
}