Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom TextBox that Delays the TextChanged Event

0.00/5 (No votes)
17 Aug 2007 1  
Textbox that inherits the base textbox control that delays the text changed event

Introduction

Although I've been browsing The Code Project for sometime, this is my first article so take it easy on me!

I was creating another control, a pager control to be exact, and ran into a problem. The problem was that when a user would type in for example 100 to navigate to that page, I was trapping the TextChanged event and it would first go to page 1, then page 10, then page 100(get the mental picture). I didn't want this to happen for a couple of reasons but the main one is because I'm not storing data of each page in memory and it gets populated when the page is selected from a SQL server, so I wanted to eliminate 3 queries when one is needed for the example previously mentioned.

So I decided that instead of adding a "go" or "refresh" button to my pager control, I would delay the TextBox TextChanged event so as long as the user was typing it would not fire the event until he/she was done(delay threshold was met).

Hope it is useful for someone!

Using the Control

Using the control is trivial because there isn't anything different about the TextBox other than when the TextChanged Event is fired. The only added property is for the Delay and you would set it like this, assuming you already have the control added to your form.

// Delay in number of milliseconds, the delay gets reset after a key press

// if it hasn't already elapsed

delTextBox1.Delay = 1000;
delTextBox1.TextChanged += new EventHandler(delTextBox1_TextChanged);

Explaining the Source

There are only a few main parts, but could be somewhat confusing for a beginner so I will do my best explaining them.

The first thing to create is a new Control that inherits the base TextBox control, add the timer, and the Delay property. The timer will be used to control the TextChanged event that will be discussed later.

...
using System.Timers;

namespace MyControl
{
     public class DelayTextBox : TextBox
     {
           System.Timers.Timer delayTimer;
       private int _threshold = 1000;   // default it 1 second



       // Delay Property to set the amount of time the control

       // waits before firing the TextChanged Event.

           public int Delay
           {
        set{ _threshold = value; }
           }

       public DelayTextBox()
       {
        delayTimer = new System.Timers.Timer( _threshold );
           }
     }
}

The next thing I did was override the KeyPress Event, I needed this to indicate to the TextChanged event that something was being typed into the TextBox.

private bool KeysPressed = false;

protected override void OnKeyPress(KeyPressEventArgs e)
{

   // check if timer has been started, if not start

   // if it has, restart it.

   if (!DelayTimer.Enabled)
   {
      DelayTimer.Enabled = true;
   }
   else
   {
      DelayTimer.Enabled = false;
      DelayTimer.Enabled = true;
   }

   // used to indicate the text was changed because a key was pressed

   // and not just setting the text property.

   KeysPressed = true;

   // execute base code as usual

   base.OnKeyPress(e);
}

Now we need to override the TextChanged event so we can prevent it from firing everytime it actually changes, until the timer elapses.

// set to true in the Timer_Elapsed event.

private bool TimerElapsed = false;

protected override void OnTextChanged(EventArgs e)
{
   // if the timer elapsed or text was changed by something 

   // besides a keystroke

   // fire base.OnTextChanged

   if ( TimerElapsed || !KeysPressed )
   {
       TimerElapsed = false;  // reset

       KeysPressed = false;   // reset

       base.OnTextChanged(e); // run base TextChanged event code.

   }
}

Finally the code for the Timer_Elapsed Event. This part was a little more tricky than the rest because the Timer runs in its own thread so using the Invoke method to make the event fire is required or else it will cause problems in your parent form or control.

public delegate void DelayOverHandler();

public void DelayOver()
{
    // call on textchanged.

    OnTextChanged(new EventArgs());
}

void delayTimer_Elapsed(object sender, EventArgs e)
{
    // stop timer.

    DelayTimer.Enabled = false;

    // set TimerElapsed to true, so the OnTextChange executes its base code.

    TimerElapsed = true;

    // use invoke to get back on the UI thread.

    this.Invoke(new DelayOverHandler(DelayOver), null);
}

This control seems to fit my needs, and I hope someone can use it for something. I plan on adding a keypress filter to only allow numbers, but there are plenty of articles on the topic here to accomplish that.

History

  • 16th August, 2007: Original article posted

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here