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.
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;
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)
{
if (!DelayTimer.Enabled)
{
DelayTimer.Enabled = true;
}
else
{
DelayTimer.Enabled = false;
DelayTimer.Enabled = true;
}
KeysPressed = true;
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.
private bool TimerElapsed = false;
protected override void OnTextChanged(EventArgs e)
{
if ( TimerElapsed || !KeysPressed )
{
TimerElapsed = false;
KeysPressed = false;
base.OnTextChanged(e);
}
}
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()
{
OnTextChanged(new EventArgs());
}
void delayTimer_Elapsed(object sender, EventArgs e)
{
DelayTimer.Enabled = false;
TimerElapsed = true;
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