WPF TextBox防抖动实现

方案 A:手写一个 20 行不到的防抖器
添加防抖动类Debouncer.cs

using System;
using System.Timers;
using System.Windows.Threading;   // 如果是 WPF 需要回到 UI 线程

public class Debouncer
{
    private readonly Timer _timer;
    private readonly Action _action;

    public Debouncer(TimeSpan dueTime, Action action)
    {
        _action = action;
        _timer = new Timer
        {
            AutoReset = false,
            Interval = dueTime.TotalMilliseconds
        };
        _timer.Elapsed += (_, __) =>
        {
            // 回到 UI 线程(WPF 场景)
            Dispatcher.CurrentDispatcher.Invoke(_action);
        };
    }

    public void Action()
    {
        _timer.Stop();
        _timer.Start();
    }

    public void Cancel() => _timer.Stop();
}

在ViewModel中使用

public class SearchViewModel : Screen
{
    private readonly Debouncer _searchDebouncer;

    private string _searchKeyWordText;
    public string SearchKeyWordText
    {
        get => _searchKeyWordText;
        set
        {
            if (SetAndNotify(ref _searchKeyWordText, value))
                _searchDebouncer.Action();   // 每次输入都会重置防抖计时器
        }
    }

    public SearchViewModel()
    {
        _searchDebouncer = new Debouncer(
            dueTime: TimeSpan.FromMilliseconds(400),
            action: DoSearch);
    }

    private void DoSearch()
    {
        // 真正的搜索逻辑
        Debug.WriteLine($"搜索关键词:{SearchKeyWordText}");
    }

    protected override void OnClose()
    {
        _searchDebouncer.Cancel();   // 防止内存泄漏
        base.OnClose();
    }
}

方案 B:使用 System.Reactive.Linq(需要 NuGet)
如果你愿意多引一个包,代码会更短,功能也更强:

安装
Install-Package System.Reactive.Linq

ViewModel 代码:

using System.Reactive.Linq;
using System.Reactive.Disposables;

public class SearchViewModel : Screen
{
    private readonly IDisposable _subscription;

    private string _searchKeyWordText;
    public string SearchKeyWordText
    {
        get => _searchKeyWordText;
        set => SetAndNotify(ref _searchKeyWordText, value);
    }

    public SearchViewModel()
    {
        _subscription = this.WhenAnyValue(x => x.SearchKeyWordText)
                            .Throttle(TimeSpan.FromMilliseconds(400))
                            .ObserveOnDispatcher()   // 回到 UI 线程
                            .Subscribe(DoSearch);
    }

    private void DoSearch(string keyword)
    {
        Debug.WriteLine($"Rx 搜索关键词:{keyword}");
    }

    protected override void OnClose()
    {
        _subscription?.Dispose();
        base.OnClose();
    }
}
posted @ 2025-08-11 22:08  山水蒙!  阅读(13)  评论(0)    收藏  举报