仅在 C#/WPF 中的给定时间内未触发事件时才执行事件 [重复]

Posted

技术标签:

【中文标题】仅在 C#/WPF 中的给定时间内未触发事件时才执行事件 [重复]【英文标题】:Execute an event only if it wasn't fired for a given amount of time in C#/WPF [duplicate] 【发布时间】:2021-05-03 17:31:20 【问题描述】:

我有一个带有 MouseWheel 事件的 WPF 应用程序。本次活动的操作相当繁重。因此,我只想在用户停止滚动时执行此事件(即:如果他在给定的时间内没有滚动)。

在 JS 中,这很容易,我可以将 setTimout 放在一个 var 中,然后如果在执行 setTimeout 之前发生另一个滚动,则在该 var 上执行 clearTimeout(这对于例如自动完成)。

如何在c# 中实现这一点?

【问题讨论】:

在事件发生时停止并重新启动 DispatcherTimer。在计时器的 Tick 处理程序上执行最终事件操作。 为此使用的搜索词是“去抖动”。例如,weblog.west-wind.com/posts/2017/jul/02/… 或 docs.microsoft.com/en-us/dotnet/api/… 你为什么用“多线程”标签标记问题?您想在与 UI 线程不同的线程上执行繁重的操作吗? @Clemens,太好了,谢谢,您可以添加您的评论作为回复,以便我接受吗? @TheodorZoulias,不,只是因为与计时器相关的操作通常绑定到一个新线程... 【参考方案1】:

这很容易使用 Microsoft 的响应式框架(又名 Rx) - NuGet System.Reactive.Windows.Threading(用于 WPF)并添加 using System.Reactive.Linq; - 然后你可以这样做:

IObservable<EventPattern<MouseWheelEventArgs>> query =
    Observable
        .FromEventPattern<MouseWheelEventHandler, MouseWheelEventArgs>(
            h => ui.MouseWheel += h, h => ui.MouseWheel -= h)
        .Throttle(TimeSpan.FromMilliseconds(250.0))
        .ObserveOnDispatcher();

IDisposable subscription =
    query
        .Subscribe(x =>
        
            /* run expensive code */
        );

文档对Throttle 这么说:

忽略来自可观察序列的值,这些值在指定源和到期时间的到期时间之前后跟另一个值。

【讨论】:

【参考方案2】:

以下内容可能适合您的需求

public class perRxTickBuffer<T>

    private readonly Subject<T> _innerSubject = new Subject<T>();

    public perRxTickBuffer(TimeSpan? interval = null)
    
        if (interval == null)
        
            interval = TimeSpan.FromSeconds(1);
        

        Output = _innerSubject.Sample(interval.Value);
    

    public void Tick(T item)
    
        _innerSubject.OnNext(item);
    

    public IObservable<T> Output  get; 

创建一个实例,其中 T 是您的事件的事件参数类型。

为您的情况设置一个适当的时间跨度值 - 可能是 1/4 秒。

只需从您的事件处理程序中调用Tick(),然后订阅Output observable 即可获得受监管的“事件”流。

【讨论】:

这不需要给System.Reactive包添加依赖吗? 我不明白...我应该把没有更多滚动时应该执行的代码放在哪里?

以上是关于仅在 C#/WPF 中的给定时间内未触发事件时才执行事件 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

WPF Toolkit DataGrid 列调整大小事件

Flutter BLoC mapEventToState 仅在事件的第一次调用时才被调用,并且不会在下次触发该事件时调用

WPF,`Loaded` 事件仅在第一次视图模型初始化时触发,但不会在后续视图模型初始化时触发

WPF:带有在用户拖动后触发的事件的滑块

以编程方式更改值时触发Dojo Select onChange事件触发

Firefox 的 iframe 内未触发关键事件