节流事件处理程序
Throttle an Event Handler
在我的 WPF 应用程序中,我有一个事件处理程序,它在 UI 元素的 MouseEnter 事件上被调用:
myUiElement.MouseEnter += myEventHandler
我想限制 myEventHandler 以使其每秒调用一次以上。我怎样才能做到这一点? Rx 是最好的方法吗?如果 .NET 4.0 有所不同,我正在使用它。
另外,我需要确保 MouseLeave 事件总是在下一个 MouseEnter 事件之前被调用;我需要自己管理吗?或者框架是否已设计为始终在下一个 MouseEnter 事件之前调用 MouseLeave 事件?如果我在这些事件处理程序中有异步代码怎么办?
您可以使用响应式扩展,但您可以使用计时器同样轻松地完成此操作。
设置一个标志和一个计时器。当计时器滴答事件触发时,将标志设置为 false,禁用计时器,并 运行 事件代码。然后,在您的控件事件处理程序中,如果设置了标志,则跳过处理程序代码。
bool flag;
DispatcherTimer timer;
public constructor()
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (s,e) => {
flag = false;
timer.Stop()
DoThrottledEvent();
}
}
void mouse_enter(object sender, MouseEventArgs args)
{
if(!flag)
{
flag = true;
timer.Start();
}
}
void DoThrottledEvent()
{
//code for event here
}
响应式扩展引入了额外的依赖性,但它们很有趣。有兴趣就去吧!
使用 Rx,您想使用 the Sample method 或 Throttle。
像这样的东西应该可以工作(未经测试):
Observable
.FromEventPattern<TextChangedEventArgs>(myUiElement, "MouseEnter")
.Sample(TimeSpan.FromSeconds(1))
.Subscribe(x => ... Do Stuff Here ...);
Sample和Throttle的区别在于,Sample会每1秒取一个值,不管最后一个取值是什么时候取的,而Throttle会取一个值,然后等1秒再取另一个。
这可能取决于你拍摄的目的...
另一种方法是使用私有字段来跟踪 "time" 最后一次鼠标事件发生的时间,并且仅在该时间超过一秒前才继续处理。
DateTime _lastMouseEventTime = DateTime.UtcNow;
void OnMouseEnter(object sender, MouseEventArgs e)
{
DateTime now = DateTime.UtcNow;
if (now.Subtract(_lastMouseEventTime).TotalSeconds >= 1)
{
// do stuff...
}
_lastMouseEventTime = now;
}
这确保 "stuff" 至少相隔一秒完成,这正是我 认为 你所要求的。
在我的 WPF 应用程序中,我有一个事件处理程序,它在 UI 元素的 MouseEnter 事件上被调用:
myUiElement.MouseEnter += myEventHandler
我想限制 myEventHandler 以使其每秒调用一次以上。我怎样才能做到这一点? Rx 是最好的方法吗?如果 .NET 4.0 有所不同,我正在使用它。
另外,我需要确保 MouseLeave 事件总是在下一个 MouseEnter 事件之前被调用;我需要自己管理吗?或者框架是否已设计为始终在下一个 MouseEnter 事件之前调用 MouseLeave 事件?如果我在这些事件处理程序中有异步代码怎么办?
您可以使用响应式扩展,但您可以使用计时器同样轻松地完成此操作。
设置一个标志和一个计时器。当计时器滴答事件触发时,将标志设置为 false,禁用计时器,并 运行 事件代码。然后,在您的控件事件处理程序中,如果设置了标志,则跳过处理程序代码。
bool flag;
DispatcherTimer timer;
public constructor()
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (s,e) => {
flag = false;
timer.Stop()
DoThrottledEvent();
}
}
void mouse_enter(object sender, MouseEventArgs args)
{
if(!flag)
{
flag = true;
timer.Start();
}
}
void DoThrottledEvent()
{
//code for event here
}
响应式扩展引入了额外的依赖性,但它们很有趣。有兴趣就去吧!
使用 Rx,您想使用 the Sample method 或 Throttle。
像这样的东西应该可以工作(未经测试):
Observable
.FromEventPattern<TextChangedEventArgs>(myUiElement, "MouseEnter")
.Sample(TimeSpan.FromSeconds(1))
.Subscribe(x => ... Do Stuff Here ...);
Sample和Throttle的区别在于,Sample会每1秒取一个值,不管最后一个取值是什么时候取的,而Throttle会取一个值,然后等1秒再取另一个。
这可能取决于你拍摄的目的...
另一种方法是使用私有字段来跟踪 "time" 最后一次鼠标事件发生的时间,并且仅在该时间超过一秒前才继续处理。
DateTime _lastMouseEventTime = DateTime.UtcNow;
void OnMouseEnter(object sender, MouseEventArgs e)
{
DateTime now = DateTime.UtcNow;
if (now.Subtract(_lastMouseEventTime).TotalSeconds >= 1)
{
// do stuff...
}
_lastMouseEventTime = now;
}
这确保 "stuff" 至少相隔一秒完成,这正是我 认为 你所要求的。