views:

208

answers:

5

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?

A: 

Some views can be found here: http://stackoverflow.com/questions/545533/c-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

k_b
+2  A: 

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.

Andrew Anderson
A: 

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.

Simon Chadwick
+1  A: 

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.

Loren Pechtel
+1  A: 

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.

Kirk
A bad idea--that Stop should be at the front of the procedure--what happens if a timer interval runs while you're doing the search?? I also think the timer should remain in existence, not be continually created and destroyed.
Loren Pechtel