合并连续事件调用的 C#/WPF



>Win2D 具有此函数Invalidate(),调用时将重绘整个控件,并且在快速连续调用时,它们将合并为一个包含以前调用的任何更改的更新。我正在尝试在我自己的应用程序中重新创建它,但我找不到与此描述完全匹配的框架。

假设每次我单击图表时,都会添加一条线。我想发生的是,如果有人连续点击 100 次,它将等到点击完成才能一次添加所有行,而不是一次添加一行。同样,调整窗口大小只应重绘图表一次,而不是每次触发事件时。

我尝试使用System.Reactive,但他们的大多数合并/限制似乎忽略了以前的调用,我不能在事件上使用订阅的OnCompleted()部分,因为它永远不会"完成"。

有没有人有解决此类问题的经验?我正在研究使用计时器来创建一种延迟,但我想知道是否已经有一些东西可以像描述的那样工作。

这是我解决这个问题的方法。 为了便于理解,我将所有这些内容都放在 Mainwindow.xaml 中.cs但您可能希望将逻辑移动到它自己的类中。

private int clickCount;
private DateTime lastClick;
private System.Windows.Threading.DispatcherTimer clickEventTimer;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (clickEventTimer == null || !clickEventTimer.IsEnabled)
{
clickCount = 1;
lastClick = DateTime.Now;
clickEventTimer = new System.Windows.Threading.DispatcherTimer() { Interval = TimeSpan.FromSeconds(1) };
clickEventTimer.Tick += (timer, args) =>
{
if (DateTime.Now - lastClick < TimeSpan.FromSeconds(1))
{
return;
}
else
{
clickEventTimer.Stop();
MessageBox.Show($"Do stuff for the {clickCount.ToString()} click(s) you got.");
}
};
clickEventTimer.Start();
}
else
{
clickCount++;
lastClick = DateTime.Now;
}
}

我尝试使用 System.Reactive,但他们的大多数合并/限制似乎忽略了以前的调用,我不能在事件上使用订阅的 OnComplete() 部分,因为它永远不会"完成"。

我想你错过了一些,比如Buffer运算符:

Button button = new Button();
...
var subscription = button
.ButtonClicks()
.Buffer(TimeSpan.FromSeconds(0.5), 100) // Perform action  after 100 clicks or after half a second, whatever comes first
.Select(buffer => buffer.Count)
.Subscribe(clickCount =>
{
// Do something with clickCount
})

帮助程序类:

public static class Extensions
{
public static IObservable<EventPattern<RoutedEventArgs>> ButtonClicks(this Button control)
{
return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(
h => control.Click += h,
h => control.Click -= h);
}
}

在应用程序结束时:

subscription.Dispose();

当然,缓冲区有一些重载:

Buffer(TimeSpan.FromSeconds(1))-> 缓冲一秒钟,然后执行操作(与接受的答案相同的结果)

Buffer(100)-> 点击 100 次后执行操作

这在 Rx 中非常简单。这是您需要的:

IObservable<long> query =
source
.Select(t => Observable.Timer(TimeSpan.FromMilliseconds(100.0)))
.Switch();

因此,只要source是每当用户执行操作时生成值的IObservable<T>,则此可观察量仅在自最后一个值以来有100.0毫秒的非活动时间时生成值。

现在,您可能希望整理它,以便查询生成原始值并封送回调度程序。这也很容易。

试试这个:

IObservable<T> query =
source
.Select(t =>
Observable
.Timer(TimeSpan.FromMilliseconds(100.0))
.Select(_ => t))
.Switch()
.ObserveOnDispatcher();

简单。

相关内容

  • 没有找到相关文章

最新更新