Using one DateTimePicker for multiple TextBox controls






3.10/5 (11 votes)
Jul 10, 2005
4 min read

107676

1046
Using TextBox controls for dates and using only one DateTimePicker control for all the TextBox controls. DateTimePicker is placed on top of the TextBox the user double-clicked and made visible. User may optionally enter a date without using the DateTimePicker. Basic date validation is implemented.
Introduction
Sometimes we have forms with many TextBox
controls that are used for dates. If you have a form with a TabControl
control and each TabPage
contains many TextBox
controls for dates and you don't want to use a DateTimePicker
for each TextBox
control, then go through this article that describes how to use one DateTimePicker
for all the TextBox
controls. The DateTimePicker
control is hidden until a TextBox
control's DoubleClick
event is raised.
We also need to validate these TextBox
controls, because here I allow the user to manually edit the TextBox.Text
property. The user may want to delete the date or just modify it manually. I wanted to take the advantage of the DateTime
class' built-in validation, so that I need not write a complex date validation procedure. In this demo, I use the DateTime
class in conjunction with simple text validations for the TextBox
controls.
The following code snippets are key to this small application. Comments are interspersed throughout the code for clarification.
Class-level variable
I declare a class-level variable (txtDateBoxSender
) of type TextBox
, so that I can access its attributes from any method:
private System.Windows.Forms.TextBox txtDateBoxSender;
Event Handlers
In the InitializeComponent()
method, I have the following event handlers for all the date TextBox
controls:
DateKeyPressed
DateBox_TextChanged
TextBoxEnter
ValidateDate
this.TextBox3.KeyPress +=
new System.Windows.Forms.KeyPressEventHandler(this.DateKeyPressed);
this.TextBox3.DoubleClick +=
new System.EventHandler(this.DateBox_TextChanged);
this.TextBox3.Enter += new System.EventHandler(this.TextBoxEnter);
this.TextBox3.Leave += new System.EventHandler(this.ValidateDate);
In the InitializeComponent()
method, I have the following event handlers for the DateTimePicker
control:
dtpDatePicker_Leave
dtpDatePicker_ValueChanged
this.dtpDatePicker.Leave +=
new System.EventHandler(this.dtpDatePicker_Leave);
this.dtpDatePicker.ValueChanged +=
new System.EventHandler(this.dtpDatePicker_ValueChanged);
Each of these event handlers will be explained later in this article.
Controls
The DateTimePicker
control has a custom format: dd-MMM-yyyy. The user may enter a date in any of the following formats in the TextBox
controls:
- mm/dd/yyyy
- mm/dd/yy
- mm\dd\yyyy
- mm\dd\yy
- mm-dd-yyyy
- mm-dd-yy
The DateTimePicker
control will change the text to dd-MMM-yyyy format.
this.dtpDatePicker.CustomFormat = "dd-MMM-yyyy";
this.dtpDatePicker.Format =
System.Windows.Forms.DateTimePickerFormat.Custom
As mentioned earlier, the TextBox
controls I'm using for dates have the following events defined:
KeyPress
DoubleClick
Enter
Leave
Methods
DateKeyPressed
is a simple method to validate data entry in the TextBox
controls I use for dates. I allow numbers and the following characters: \, / and -. The KeyPress
event is raised each time the user presses a key in the keyboard. If the key pressed doesn't meet the rules, then the character will not be typed in the textbox.
private void DateKeyPressed(Object o, KeyPressEventArgs e)
{
///
///This event is raised to validate dates.
///Acceptable chracters are numbers, forward
///and back slashes, and dashes.
///Back slashes may not be common in dates
///but the DateTimePicker
///says they are valid.
///
if( !char.IsNumber(e.KeyChar) &&
!(e.KeyChar == Convert.ToChar("-"))
&& !(e.KeyChar == Convert.ToChar("\\"))
&& !(e.KeyChar == Convert.ToChar("/"))
&& !char.IsControl(e.KeyChar) )
e.Handled = true;
}
ValidateDate
method is fired when the user leaves the TextBox
control. This is a simple way to validate dates in TextBox.Text
.
If TextBox.Text
is empty, I exit the method. Otherwise, I assign TextBox.Text
to the DateTimePicker
control. This date assignment is merely to validate the data entry; I really don't need to assign it to the DateTimePicker
at this point. If DateTime.Parse
is unable to convert the text to a valid date, an Exception
is thrown and an appropriate message is displayed.
private void ValidateDate(Object sender, EventArgs e)
{
///
///This event is raised to validate TextBox controls
///being used for storing a date when the User leaves
///the TextBox control.
///
try
{
txtDateBoxSender = (TextBox)sender;
if (this.txtDateBoxSender.Text.ToString().Trim()=="")
{return;}
//This date assignment is merely to test
//the data entry; I really don't
//need to assign it to the DateTimePicker
this.dtpDatePicker.Value =
DateTime.Parse(this.txtDateBoxSender.Text);
//Format the manually edited date in TextBox.Text
txtDateBoxSender.Text =
string.Format("{0:dd-MMM-yyyy}",
this.dtpDatePicker.Value);
}
catch (Exception ex)
{
//You can display the Exception message for
//the User, but I decided not to.
//ex.Message.ToString()
MessageBox.Show("Please enter a valid date." +
"\nAllowed formats: " +
"mm/dd/yyyy, mm/dd/yy, mm-dd-yyyy, mm-dd-yy." +
"\nMinimum value: " +
this.dtpDatePicker.MinDate.ToShortDateString() +
"\nMaximum value: " +
this.dtpDatePicker.MaxDate.ToShortDateString(),
"Date Validation",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
//You may want to do something with the erroneus value
//For example, you could undo the change
// this.txtDateBoxSender.Undo();
// or just blank out the TextBox.
// (Users may not like that.)
// this.txtDateBoxSender.Text = "";
this.txtDateBoxSender.Undo();
//Send the User right back
//to the control they edited
this.txtDateBoxSender.Focus();
}
}
dtpDatePicker_ValueChanged
method is fired when the value of the DateTimePicker
is changed. We assign the date chosen by the user to the TextBox
control that raised the DateBox_TextChanged
event.
private void dtpDatePicker_ValueChanged(object sender, System.EventArgs e)
{
///
///Occurs when value of the DateTimePicker is changed
///
try
{
//assign the date chosen by the User to the textbox control
//that raised the DateBox_TextChanged event
txtDateBoxSender.Text = string.Format("{0:dd-MMM-yyyy}",
this.dtpDatePicker.Value);
this.dtpDatePicker.Visible = false;
/*
if we had to do something different depending
on the control the User is editing, then we would
have to do something like this:
txtDateBoxSender.Text = string.Format("{0:dd-MMM-yyyy}",
this.dtpDatePicker.Value);
switch ((string)txtDateBoxSender.Name)
{
case "TextBox1":
{
//Do something that is unique
//to this TextBox control
break;
}
case "TextBox2":
{
//Do something that is unique
//to this TextBox control
break;
}
etc...
Imagine having to write a Case block
for more than 50 dates!
}
*/
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString() +
"\nAn error occurred in dtp_ValueChanged." +
"\nControl: " + txtDateBoxSender.Name +
".\nContact Systems staff.\nThank you.",
"Date Validation",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
DateBox_TextChanged
method is fired by all the date TextBox
controls.
Points of interest
- In order to place the
DateTimePicker
control in the appropriate location in our form, we need to find out whichTextBox
control raised this event. This event handler has two arguments. I will use theobject
argument to determine the control that raised this event.sender
is the control that raised this event. We need to castsender
before assigning it totxtDateBoxSender
, because it's an object. In this application, I cast it asTextBox
control. Control ctlParent
is the control that is the parent (container) of the control that raised this event.
private void DateBox_TextChanged(object sender, System.EventArgs e)
{
///
///This event is raised by all date TextBoxes.
///
try
{
//txtDateBoxSender is the control that raised this event.
//We need to cast sender, because it's an object.
//In this app, I know to cast it as TextBox control.
txtDateBoxSender = (TextBox)sender;
//ctlParent is the control that is the parent (container) of
//the control that raised this event
Control ctlParent = txtDateBoxSender.Parent;
//We want to place the DateTimePicker control on top of
//the TextBox the User double-clicked.
//Add the DateTimePicker control to the container (parent)
//of the control that raised this event. If you don't do this,
//the Location of your DateTimePicker control will be relative
//to its current parent--in this app, that would be the form--
//and then your DateTimePicker will be located in the wrong
//place. To see what I mean, just comment out the statement
//below:
ctlParent.Controls.Add(this.dtpDatePicker);
//Set DateTimePicker's properties.
if (this.txtDateBoxSender.Text != "")
{
this.dtpDatePicker.Value =
Convert.ToDateTime(this.txtDateBoxSender.Text);
}
//Place the DateTimePicker on top of the control
//that raised this event and make it visible.
this.dtpDatePicker.Location = this.txtDateBoxSender.Location;
this.dtpDatePicker.BringToFront();
this.dtpDatePicker.Visible = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString() +
"\nAn error occurred in DateBox_TextChanged." +
"\nControl: " + txtDateBoxSender.Name + ".",
"Date Validation",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
dtpDatePicker_Leave
method is fired when the DateTimePicker
loses focus. This is where I make the DateTimePicker
invisible when the User leaves the control. This handler is called when dtpDatePicker.Leave
and dtpDatePicker.MouseLeave
events are raised.
private void dtpDatePicker_Leave(object sender, System.EventArgs e)
{
///
///Occurs when DateTimePicker loses focus
///
this.dtpDatePicker.Visible = false;
}
The TextBoxEnter
method reformats a TextBox
date from dd-MMM-yyyy to mm-dd-yyyy. The reason I use dd-MMM-yyyy for displaying dates in textboxes is just a personal preference. Use any format that you like.
private void TextBoxEnter(object sender, System.EventArgs e)
{
///
///This event is fired to reformat a date from dd-MMM-yyyy
///to mm-dd-yyyy, because we do not allow letters in our date
///textboxes.
///
///July 12, 2005
///
txtDateBoxSender = (TextBox)sender;
if (this.txtDateBoxSender.Text != "")
{
txtDateBoxSender.Text =
DateTime.Parse(txtDateBoxSender.Text).ToString("d", null);
}
}
Conclusion
I hope you will find these code snippets useful. I have been programming in C# for 3 months, so I'm sure there is room for improvement. I welcome any feedback.
History
- July 9th, 2005 - Version 1.0.0
- July 11th, 2005 - version 1.0.1
- commented out
MouseLeave
event forDateTimePicker
control. - removed redundant authorship comments.
- added code to update the date format of a manually edited
TextBox
. - removed console (never meant to open a console).
- commented out
- July 12th, 2005 - version 1.0.2:
- added
TextBoxEnter
method for dateTextBox
controls'Enter
event.
- added