Have you ever tried getting authors to enter
date and time values in a regular textbox? Even with well-placed
instructions showing the proper format for the date (such as
MM/DD/YYYY), you will often find that dates collected are invalid. Here
are some real-life examples taken from a website that provided textboxes
for entering the promotion start and end dates of a product:
Dates entered | Why it’s not valid |
---|
Start Date: Immediate! End Date: 31 February 2004 07:00 AM | The word “immediate” isn’t a valid date and 31 February 2004 does not exist, not even in a leap year! |
Start Date: 1 January 2005 :00:00 AM End Date: 31 December 2005 (or while stocks last!) | While the start date is valid, the start time is missing the hour component.
The end date appears valid, but it has extra text, or while stocks last, appended to it—making it invalid. |
Start Date: 1 January 2005 End Date: 31/05/2005 | In the start date, the word “January” is misspelled. The month and day fields in the end date are mixed up. |
To ensure that date and time fields are entered
correctly, authors can be provided with a date-time picker control,
instead of a textbox. The date-time picker control includes a
single-line, read-only textbox that displays the selected date and time.
As the textbox is read-only, authors can’t amend its contents—making it
impossible for authors to enter invalid dates.
Dates are selected by clicking on a Pick Date
button, located next to the textbox. When it is clicked, a dialog for
picking a date and time opens. The dialog contains a calendar for
selecting the date and two dropdowns for choosing the time values.
In presentation view, the selected date and time appears on screen.
To make it almost impossible for invalid dates to
be saved in the database, the contents of date-time picker control are
usually validated before being saved.
MCMS does not ship with a date-time picker placeholder control, so let’s build one from scratch.
The DateTimePickerPlaceholderControl Class
Let’s begin building the date-time picker placeholder control by adding a class file named DateTimePickerPlaceholderControl.cs to the UsefulPlaceholderControls project.
The control requires the use of methods from the namespaces highlighted below, so add them to the class file.
using System;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Microsoft.ContentManagement.Publishing;
using Microsoft.ContentManagement.Publishing.Extensions.Placeholders;
using Microsoft.ContentManagement.WebControls.Design;
using Microsoft.ContentManagement.WebControls;
namespace UsefulPlaceholderControls
{
. . . code continues . . .
}
As the selected date and time is a single-line value, it will be easiest to store it as text within an HtmlPlaceholder (alternatively, you could store it in an XmlPlaceholder—however,
that also means that you will have to extract the information from the
saved XML later, which requires a little more code). The control will
therefore support HtmlPlaceholderDefinitions. In addition, as
none of the placeholder controls that ship with MCMS resembles a
date-time picker, we will build the control from the ground up and have
it inherit from the BasePlaceholderControl class:
namespace UsefulPlaceholderControls
{
[SupportedPlaceholderDefinitionType(typeof(HtmlPlaceholderDefinition))]
public class DateTimePickerPlaceholderControl : BasePlaceholderControl
{
public DateTimePickerPlaceholderControl()
{
}
}
}
Loading the Controls for Authoring
In authoring mode, the date-time picker placeholder will include:
A textbox for displaying the selected date and time.
A button for picking the date. When the button is clicked, a dialog appears for the author to pick the date and time.
We will use a table to arrange the TextBox and
Button controls side by side. Below the table, we will add a Label for
showing any exceptions that may occur during the loading process. Here’s
the completed control in authoring mode:
Let’s start by adding the table to the authoring container. Override the CreateAuthoringChildControls() method as shown below. The table consists of a single row with two cells.
protected override void CreateAuthoringChildControls
(BaseModeContainer authoringContainer)
{
// Add a table to help in the layout of the controls
Table table = new Table();
TableRow tr = new TableRow();
table.Rows.Add(tr);
TableCell td1 = new TableCell();
TableCell td2 = new TableCell();
tr.Cells.Add(td1);
tr.Cells.Add(td2);
// Add the table to the authoring container
authoringContainer.Controls.Add(table);
}
Now, let’s add the read-only TextBox control to the cell on the left-hand side. The TextBox control will be given an ID of SelectedDateTime. We define the instance of the TextBox as a class-wide variable as we will be accessing it from other methods within the class.
private TextBox txtAuthoring;
protected override void CreateAuthoringChildControls
(BaseModeContainer authoringContainer)
{
. . . code continues . . .
// Add a Textbox
txtAuthoring = new TextBox();
txtAuthoring.ID = "SelectedDateTime";
txtAuthoring.ReadOnly = true;
td1.Controls.Add(txtAuthoring);
}
Next, we will add the Pick Date
button. When the button is clicked, it calls up the dialog for
selecting the date and time. Attached to the dialog’s URL are a couple
of querystring parameters:
CallingControl
stores the name of the TextBox control to which the dialog will write
the selected date and time. This is the client ID of the TextBox, as
dynamically generated by ASP.NET when the page is displayed. If you
actually run the control, you will find that its client ID is the
concatenation of all the parent controls’ IDs:
DateTimePickerPlaceholderControl1_AuthoringModeControlsContainer_SelectedD
ateTime
InitialValue stores the previously selected date and time values that will be used as default values by the dialog.
The code snippet below assumes that the URL of the date-time picker dialog is /tropicalgreen/dialogs/datetimepicker.aspx. If you plan to store the dialog somewhere else, simply adjust this value accordingly.
protected override void CreateAuthoringChildControls
(BaseModeContainer authoringContainer)
{
. . . code continues . . .
// Add a Button that shows a pop up when clicked
HtmlButton b = new HtmlButton();
b.ID = "SelectedDateTime";
b.InnerText = "Pick Date";
string url = "";
url = "/tropicalgreen/dialogs/datetimepicker.aspx?"
+ "CallingControl=" + txtAuthoring.ClientID + "&"
+ "InitialValue=\' + document.all. " + txtAuthoring.ClientID
+ ".value +\'";
b.Attributes.Add("onclick","window.open('" + url + "');");
td2.Controls.Add(b);
}
Finally,
we add a Label control to the authoring container. The Label will be
used to display error messages that may occur along the way. Like the
TextBox, we will make it a class-wide variable as we will be using it
within other methods.
private TextBox txtAuthoring;
private Label lblMessage;
protected override void CreateAuthoringChildControls
(BaseModeContainer authoringContainer)
{
. . . code continues . . .
// Add a label for displaying messages
lblMessage = new Label();
authoringContainer.Controls.Add(lblMessage);
}