wpf 限制事件处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28017498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Throttle an Event Handler
提问by Darius
In my WPF application, I have an event handler that gets called on the MouseEnter event of my UI element:
在我的 WPF 应用程序中,我有一个事件处理程序,它在我的 UI 元素的 MouseEnter 事件上被调用:
myUiElement.MouseEnter += myEventHandler
I would like to throttle myEventHandler so it doesn't get called more than once every second. How can I do this? Is Rx the best approach just for this? I'm using .NET 4.0 if it makes a difference.
我想限制 myEventHandler 这样它不会每秒被调用多次。我怎样才能做到这一点?Rx 是最好的方法吗?我正在使用 .NET 4.0,如果它有所不同的话。
Also, I need to make sure that the MouseLeave event always gets called before the next MouseEnter event; do I need to manage this on my own? Or is the framework already designed so that MouseLeave events will always be called before the next MouseEnter event? What if I have asynchronous code in these event handlers?
另外,我需要确保 MouseLeave 事件总是在下一个 MouseEnter 事件之前被调用;我需要自己管理吗?或者框架是否已经设计为总是在下一个 MouseEnter 事件之前调用 MouseLeave 事件?如果我在这些事件处理程序中有异步代码怎么办?
采纳答案by Justin Pihony
Using Rx, you want to use the Sample methodor Throttle.
使用 Rx,您想使用Sample 方法或 Throttle。
Something like this should work (untested):
这样的事情应该工作(未经测试):
Observable
.FromEventPattern<TextChangedEventArgs>(myUiElement, "MouseEnter");
.Sample(TimeSpan.FromSeconds(1));
.Subscribe(x=>...Do Stuff Here...);
The difference between Sample and Throttle is that Sample will take a value every 1 second no matter when the last value was taken, whereas Throttle will take a value and then wait another 1 second before taking another.
Sample 和 Throttle 的区别在于,无论最后一个值是什么时候取的,Sample 都会每 1 秒取一个值,而 Throttle 会取一个值,然后再等 1 秒再取另一个。
It probably depends on what you are shooting for...
这可能取决于您要拍摄的内容......
回答by kindasimple
You could use reactive extensions, but you could accomplish this just as easily with a timer.
您可以使用反应式扩展,但您可以使用计时器轻松完成此操作。
Set a flag along with a Timer. When the timer tick event fires, set the flag to false, disable the timer, and run the code for your event. Then, in your control event handlers, have the handler code skipped if the flag is set.
设置一个标志和一个计时器。当计时器滴答事件触发时,将标志设置为 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
}
Reactive extensions introduces an extra dependency, but they are a bit of fun. If you are interested, go for it!
响应式扩展引入了额外的依赖项,但它们有点有趣。如果你有兴趣,就去吧!
回答by Steven Rands
Another approach would be to use a private field to keep track of the "time" when the last mouse event occurred, and only continue processing if that time was more than one second ago.
另一种方法是使用私有字段来跟踪上次鼠标事件发生的“时间”,并且只有在该时间超过一秒之前才继续处理。
DateTime _lastMouseEventTime = DateTime.UtcNow;
void OnMouseEnter(object sender, MouseEventArgs e)
{
DateTime now = DateTime.UtcNow;
if (now.Subtract(_lastMouseEventTime).TotalSeconds >= 1)
{
// do stuff...
}
_lastMouseEventTime = now;
}
This ensures that "stuff" gets done at least one second apart, which is what I thinkyou were asking for.
这确保“东西”至少相隔一秒钟完成,这就是我认为您所要求的。

