我正在尝试在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;
据我了解,这应该触发事件观察者,但事实并非如此。我错过了什么?
感谢。
答案 0 :(得分:1)
您尚未向FrameChanged分配任何事件。
yourInstance.FrameChanged+= () => DoSomething();
答案 1 :(得分:1)
要使事件处理程序被调用,您需要做两件事。
您忽略了显示代码中的第一项。如果您还没有将事件处理程序连接到事件,则需要执行此操作。你可以这样做:
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();
}