开发者

Delay KeyUp Action if User is Typing (C#)

I have a function that is being called when the user开发者_开发百科 is typing in a search box. I want to wait for the user to finish typing before I actually execute the function. I know how to easily accomplish this in JavaScript with timeouts, but how would I go about doing the same thing in C#? Also, how long should I wait before I assume the user is done typing? 100ms?


If you're comfortable using the Reactive (Rx) framework, then you could implement this functionality using its built in throttling extremely quickly.

Here is an article on the subject: Rx Can Improve UI Responsiveness

And some code stolen & modified from the article:

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);
   });

As stated in the article (which is worth reading in full), this will fire the code in the lambda expression whenever half a second elapses without the user typing anything.

I'll clean the example up tomorrow when I'm in front of my development PC, but this should give you a starting point now.


Here's my working code based on Loren's input:

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();
}
}

And the event handler:

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;
}

If anyone plays with this code, let me know if you tweak the time intervals I put in. I don't think they are optimal quite yet.


Set a timer for the desired delay interval. Start the timer on the key up event. If the timer trips you stop the timer and run your search.

100ms is NOT a good interval, though!! That's about 100wpm even if the typing is absolutely even.


One suggestion is to not surprise the user. This is generally a good UI design principle. So only perform the actual search when the textbox loses focus. It is one thing to show incrementally matching search strings as a user types (like Google), but another to surprise the user with an unsolicited search after some keyboard delay. Personally I would find this irritating, as I often pause to think about a search string while entering it.


Here is a code sample to solve this

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");
            });
        }
    }
}


Some views can be found here: Delayed function calls

Record the timestamp of every keyup event, and use the Timer class to delay the execution of a method. Inside that method, you can consider whether the user has stopped typing, comparing the current time to the last keyup event timestamp. You could experiment with the interval, ensuring responsiveness. It's also smart to limit the hits, and only allow searches for a minimum of i.e. 3 characters.

Timer: http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜