【问题标题】:Delay KeyUp Action if User is Typing (C#)如果用户正在键入,则延迟 KeyUp 操作 (C#)
【发布时间】:2011-02-26 04:11:31
【问题描述】:

当用户在搜索框中输入内容时,我有一个函数被调用。我想在实际执行该功能之前等待用户完成输入。我知道如何在 JavaScript 中通过超时轻松完成此操作,但我将如何在 C# 中做同样的事情?另外,在我假设用户完成输入之前我应该​​等待多长时间? 100 毫秒?

【问题讨论】:

    标签: c# wpf visual-studio user-interface


    【解决方案1】:

    如果您习惯使用响应式 (Rx) 框架,那么您可以使用其内置的节流极快地实现此功能。

    这是一篇关于这个主题的文章:Rx Can Improve UI Responsiveness

    还有一些从文章中窃取和修改的代码:

    var textObserver = (from text in Observable.FromEvent<TextChangedEventArgs>(_app.myTextField, "TextChanged")
       select text).Throttle(TimeSpan.FromSeconds(.5));
    
    _searchObserver = textObserver.Subscribe(textChangedEvent =>
       {
          var tb = (TextBox)textChangedEvent.Sender;
          DoMySearch(tb.Text);
       });
    

    如文章中所述(值得完整阅读),只要半秒后用户没有输入任何内容,就会触发 lambda 表达式中的代码。

    明天我会在我的开发 PC 前清理该示例,但这应该现在为您提供一个起点。

    【讨论】:

    • 断开的链接(Rx 可以提高 UI 响应性)
    【解决方案2】:

    这是我根据 Loren 输入的工作代码:

    private void SearchTextBox_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
    if (SearchTextBoxTimer != null)
    {
       Console.WriteLine("The user is currently typing.");
       if (SearchTextBoxTimer.Interval < 750)
       {
           SearchTextBoxTimer.Interval += 750;
           Console.WriteLine("Delaying...");
       }
    }
    else
    {
        Console.WriteLine("The user just started typing.");
        SearchTextBoxTimer = new System.Windows.Forms.Timer();
        SearchTextBoxTimer.Tick += new EventHandler(SearchTextBoxTimer_Tick);
        SearchTextBoxTimer.Interval = 500;
        SearchTextBoxTimer.Start();
    }
    }
    

    以及事件处理程序:

    private void SearchTextBoxTimer_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("The user finished typing.");
        if (SearchTextBox.Text == "")
        {
            ConsoleTextBox.Text = "Searching: All";
        }
        else
        {
            ConsoleTextBox.Text = "Searching: " + SearchTextBox.Text;
        }
        SearchTextBox_TextChanged();
        SearchTextBoxTimer.Stop();
        SearchTextBoxTimer.Dispose();
        SearchTextBoxTimer = null;
    }
    

    如果有人使用此代码,请告诉我是否调整了我输入的时间间隔。我认为它们还不是最佳的。

    【讨论】:

    • 一个坏主意 - Stop 应该在过程的前面 - 如果在您进行搜索时运行计时器间隔会发生什么?我也认为计时器应该保持存在,而不是不断地创建和销毁。
    【解决方案3】:

    为所需的延迟间隔设置一个计时器。在按键事件上启动计时器。如果计时器跳闸,则停止计时器并运行搜索。

    100 毫秒是 不是 一个好的间隔,但是!即使打字绝对均匀,也大约是 100wpm。

    【讨论】:

      【解决方案4】:

      一个建议是不要让用户感到惊讶。这通常是一个很好的 UI 设计原则。因此,仅在文本框失去焦点时执行实际搜索。将增量匹配的搜索字符串显示为用户类型(如谷歌)是一回事,但在一些键盘延迟后通过主动搜索让用户感到惊讶是另一回事。就我个人而言,我会觉得这很烦人,因为我在输入搜索字符串时经常会停下来想一想。

      【讨论】:

        【解决方案5】:

        这是解决此问题的代码示例

        using System;
        using System.Timers;
        using System.Windows.Input;
        using Timer = System.Timers.Timer;
        
        namespace Example
        {
            public partial class OnKeyUpInputExample
            {
                // Timer set to elapse after 750ms
                private Timer _timer = new Timer(750) { Enabled = false };
        
                // Constructor
                public OnKeyUpInputExample()
                {
                    //What to do when _timer elapses
                    _timer.Elapsed += TextInput_OnKeyUpDone;
                }
        
                // Event handler
                private void TextInput_OnKeyUp(object sender, KeyEventArgs e)
                {
                    // You could also put the .Stop() in an OnKeyDown event handler if you need to account for keys being held down
                    _timer.Stop();
                    _timer.Start();
                }
        
                // Function to complement timer elapse
                private void TextInput_OnKeyUpDone(object sender, ElapsedEventArgs e)
                {
                    // If we don't stop the timer, it will keep elapsing on repeat.
                    _timer.Stop();
        
                    this.Dispatcher.Invoke(() =>
                    {
                        //Replace with code you want to run.
                        Console.WriteLine("KeyUp timer elapsed");
                    });
                }
            }
        }
        

        【讨论】:

        • Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =&gt; 如果在 uwp 上,而不是 Invoke
        【解决方案6】:

        一些观点可以在这里找到:Delayed function calls

        记录每个 keyup 事件的时间戳,并使用 Timer 类来延迟方法的执行。在该方法中,您可以考虑用户是否已停止输入,将当前时间与最后一个 keyup 事件时间戳进行比较。您可以对间隔进行试验,以确保响应能力。限制点击也很聪明,只允许搜索最少 3 个字符。

        定时器:http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx

        【讨论】:

        • 链接的解决方案不适用于用户输入有关 keyup 操作。使用上面会导致延迟发生,然后执行,所以会发生的是,如果你键入 5 次击键,它会延迟 x 时间,然后执行 5 次。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-28
        • 2010-12-26
        • 1970-01-01
        相关资源
        最近更新 更多