The following examples are consumers of this custom data
field class described above. The first one is a field that represents date/time
values. In read-only mode, it renders the date in the cell. In edit mode,
depending on a value of the Display property, it renders with a calendar or a
textbox. This control binds a single value, a date, through the DataField
property.
To setup the control, the SetupEditControl appears below.
Listing 8
public override Control SetupEditControl()
{
if (this.Display == CalendarDataFieldDisplay.Calendar)
{
Calendar cal = new Calendar();
cal.SelectedDate = DateTime.Today;
return cal;
}
else if (this.Display == CalendarDataFieldDisplay.CalendarPopup)
{
return new DateTextBoxSelector();
}
else if (this.Display == CalendarDataFieldDisplay.Editor)
{
return new DateTextBox();
}
else
throw new InvalidOperationException();
}
Depending on the value of the Display property, the
respective control reference is returned. Notice that some controls need some
setting up with default values, and for most it does not matter. This control
is added to the cell's control collection (shown in the implementation above).
Below is the method that extracts the value out of the control returned above.
Listing 9
public override string GetEditControlValue(TableCell cell)
{
if (this.Display == CalendarDataFieldDisplay.Calendar)
return this.ExtractControl < Calendar > (cell)
.SelectedDate.ToShortDateString();
else if (this.Display == CalendarDataFieldDisplay.CalendarPopup)
return this.ExtractControl < DateTextBoxSelector > (cell).Text;
else if (this.Display == CalendarDataFieldDisplay.Editor)
return this.ExtractControl < DateTextBox > (cell).Text;
else
return null;
}
The GetEditControlValue method is in charge of getting a
reference of the editing control, and returns the edited value in a string
format. Because the primitive class cannot automatically determine what control
is actually representing the interface, this method makes that determination
based on the enumerated value. The ExtractControl method finds the control
reference by index, and returns the reference in a strongly-typed fashion.
When in edit or insert mode, the BindEditControl method
binds the control with data in the underlying data source. The following is the
approach in this example.
Listing 10
public override void BindEditControl(object control, bool insertMode)
{
if (this.Display == CalendarDataFieldDisplay.Calendar)
{
Calendar cal = (Calendar)control;
if (!insertMode)
cal.SelectedDate = this.GetDataItemValue < DateTime >
(cal.NamingContainer, this.DataField);
else
cal.SelectedDate = DateTime.Today;
}
else if (this.Display == CalendarDataFieldDisplay.CalendarPopup)
{
DateTextBoxSelector selector = (DateTextBoxSelector)control;
if (!insertMode)
selector.Value = this.GetDataItemValue < DateTime >
(selector.NamingContainer, this.DataField);
}
else if (this.Display == CalendarDataFieldDisplay.Editor)
{
DateTextBox box = (DateTextBox)control;
if (!insertMode)
box.Value = this.GetDataItemValue < DateTime > (box.NamingContainer,
this.DataField);
}
}
When in edit mode, the GetDataItemValue method gets the
actual value from the data source; otherwise, insert mode renders an empty (or
default) value. Because an enumeration determines which control is created as
the editing interface, a more winded approach is required in this situation.
But you can see it is still a simplified approach in comparison.
The last method defined, not mentioned much above, is
GetDataItemFieldName, which seems redundant or unnecessary. However, in the
final implementation, I did not want to force someone to use a DataField
property directly; instead, this allows flexibility to use a different name
like DataTextField, DataSelectedValueField, or something else. What this means
is that even though multiple fields can affect the interface, only one field
represents the actual underlying data source.
Listing 11
protected override string GetDataItemFieldName()
{
return this.DataField;
}