The problem: When coding, you often need to implement a functionality that requires to be automatically performed after the text inside a text-box has changed. This can easily be implemented using the TextChanged event of a TextBox control.
However, there are cases in which the application needs to perform a certain action only after the user has stopped typing inside the TextBox control, for example:
For filtering a collection by a value the user types inside the text field (without the user pressing any button for applying the filter)
– In case the filtering is performed in the TextChanged event handler, this would cause the application to be very slow, as it would filter the entries every time the user types-in a letter.
For navigating to a certain page inside a data grid
– Same as above, this would be very slow, as the navigation would occur on every digit typed-in by the user.
Possible solutions:
A solution to this problem is to implement a text-box which throws a custom event after the user has stopped typing. We’ll implement a class called DelayTextBox that will extend the TextBox class and will implement this additional functionality.
I’m going to detail 2 possible approaches for implementing a DelayTextBox in a Windows Forms solution in .NET 4.0 (however, the solutions still stand for web applications in ASP.NET):
1. Solution #1 – Implementing the DelayTextBox using a timer.
2. Solution #2 – Implementing the DelayTextBox using the IObservable interface from ReactiveExtensions (for more details about the ReactiveExtensions library, please see http://msdn.microsoft.com/en-us/data/gg577609 )
Solution #1 – Implementing a DelayTextBox using a timer
In order to implement this, we’ll create a new class called DelayTextBox which inherits the System.Windows.Forms.TextBox class.
The class will contain a member of type System.Timers.Timer class, and the TextChangeCompleted event needs to be raised after the Elapsed event of the timer has been raised (for details about the System.Timers.Timer class, please see http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx ). Sample code:
public DelayTextBox()
mDelayTimer = new System.Timers.Timer(Constants.DefaultDelayDelta);
InitializeEventHandlers();
private void InitializeEventHandlers()
mDelayTimer.Elapsed += new System.Timers.ElapsedEventHandler(mDelayTimer_Elapsed);
private void mDelayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
OnTimerElapsed();
private void OnTimerElapsed()
mDelayTimer.Stop();
BeginInvoke(new MethodInvoker(OnTextChangeCompleted));
public event EventHandler<ItemEventArgs<string>> TextChangeCompleted;
protected void OnTextChangeCompleted()
if (TextChangeCompleted != null)
TextChangeCompleted(this, new ItemEventArgs(this.Text));
Note: The Constants.DefaultDelayDelta is a constant value which represents the timer’s interval in milliseconds (more precisely, in the current context this represents the time for the control to wait the user’s input before raising the TextChangeCompleted custom event). However, this value can be adjusted, for example the DelayTextBox class can have a property for getting / setting this, as below:
public double Delay
get
return mDelayTimer.Interval;
set
mDelayTimer.Interval = value;
Note: The ItemEventArgs is a class which inherits the EventArgs class and has a generic member of type T (this class can be used for event arguments consisting of a single reference / value). In our case, the event arguments represent the text inside the control.
Also, the OnTextChanged method needs to be overridden, and the timer needs to be reset, as this method is called every time the user types inside the text-box. Sample code:
protected override void OnTextChanged(EventArgs e)
if (!mDelayTimer.Enabled)
mDelayTimer.Start();
else
ResetTimer();
base.OnTextChanged(e);
private void ResetTimer()
mDelayTimer.Stop();
mDelayTimer.Start();
At this point, you can use the DelayTextBox in your form/user control and you would only need to handle the TextChangeCompleted event. Sample code:
textBoxInput.TextChangeCompleted += new EventHandler<ItemEventArgs<string>>(textBoxInput_TextChangeCompleted);
void textBoxInput_TextChangeCompleted(object sender, ItemEventArgs<string> e)
OnTextChangeCompleted(e.Item);
private void OnTextChangeCompleted(string textItem)
// TODO perform operations
Note: in this example, textBoxInput is of type DelayTextBox.
This is all for now. I will come back soon with a different solution for implementing the DelayTextBox (using the IObservable interface from ReactiveExtensions).
The problem: When coding, you often need to implement a functionality that requires to be automatically performed after the text inside a text-box has changed. This can easily be implemented using the TextChanged event of a TextBox control.
However, there are cases in which the application needs to perform a certain action only after the user has stopped typing inside the TextBox control, for example:
For filtering a collection by a value the user types inside the text field (without the user pressing any button for applying the filter)
– In case the filtering is performed in the TextChanged event handler, this would cause the application to be very slow, as it would filter the entries every time the user types-in a letter.
For navigating to a certain page inside a data grid
– Same as above, this would be very slow, as the navigation would occur on every digit typed-in by the user.
Possible solutions:
A solution to this problem is to implement a text-box which throws a custom event after the user has stopped typing. We’ll implement a class called DelayTextBox that will extend the TextBox class and will implement this additional functionality.
I’m going to detail 2 possible approaches for implementing a DelayTextBox in a Windows Forms solution in .NET 4.0 (however, the solutions still stand for web applications in ASP.NET):
1. Solution #1 – Implementing the DelayTextBox using a timer.
2. Solution #2 – Implementing the DelayTextBox using the IObservable interface from ReactiveExtensions (for more details about the ReactiveExtensions library, please see http://msdn.microsoft.com/en-us/data/gg577609 )
Solution #1 – Implementing a DelayTextBox using a timer
In order to implement this, we’ll create a new class called DelayTextBox which inherits the System.Windows.Forms.TextBox class.
The class will contain a member of type System.Timers.Timer class, and the TextChangeCompleted event needs to be raised after the Elapsed event of the timer has been raised (for details about the System.Timers.Timer class, please see http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx ). Sample code:
public DelayTextBox()
mDelayTimer = new System.Timers.Timer(Constants.DefaultDelayDelta);
InitializeEventHandlers();
private void InitializeEventHandlers()
mDelayTimer.Elapsed += new System.Timers.ElapsedEventHandler(mDelayTimer_Elapsed);
private void mDelayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
OnTimerElapsed();
private void OnTimerElapsed()
mDelayTimer.Stop();
BeginInvoke(new MethodInvoker(OnTextChangeCompleted));
public event EventHandler<ItemEventArgs<string>> TextChangeCompleted;
protected void OnTextChangeCompleted()
if (TextChangeCompleted != null)
TextChangeCompleted(this, new ItemEventArgs(this.Text));
Note: The Constants.DefaultDelayDelta is a constant value which represents the timer’s interval in milliseconds (more precisely, in the current context this represents the time for the control to wait the user’s input before raising the TextChangeCompleted custom event). However, this value can be adjusted, for example the DelayTextBox class can have a property for getting / setting this, as below:
public double Delay
get
return mDelayTimer.Interval;
set
mDelayTimer.Interval = value;
Note: The ItemEventArgs is a class which inherits the EventArgs class and has a generic member of type T (this class can be used for event arguments consisting of a single reference / value). In our case, the event arguments represent the text inside the control.
Also, the OnTextChanged method needs to be overridden, and the timer needs to be reset, as this method is called every time the user types inside the text-box. Sample code:
protected override void OnTextChanged(EventArgs e)
if (!mDelayTimer.Enabled)
mDelayTimer.Start();
else
ResetTimer();
base.OnTextChanged(e);
private void ResetTimer()
mDelayTimer.Stop();
mDelayTimer.Start();
At this point, you can use the DelayTextBox in your form/user control and you would only need to handle the TextChangeCompleted event. Sample code:
textBoxInput.TextChangeCompleted += new EventHandler<ItemEventArgs<string>>(textBoxInput_TextChangeCompleted);
void textBoxInput_TextChangeCompleted(object sender, ItemEventArgs<string> e)
OnTextChangeCompleted(e.Item);
private void OnTextChangeCompleted(string textItem)
// TODO perform operations
Note: in this example, textBoxInput is of type DelayTextBox.
This is all for now. I will come back soon with a different solution for implementing the DelayTextBox (using the IObservable interface from ReactiveExtensions).