Silverlight 3 DataForm Control Mapping - Add Extensibility
An earlier posting explains how to perform basic modifications to the Silverlight 3 DataForm control.
It's convenient if such features are available for extensibility.
This can be achieved in a straightforward fashion too. (A modified DataForm project is attached.)
The DataForm implements the GenerateField method, which calls the two methods that affect Control mapping.Control control = GetControlFromType(propertyType);
DependencyProperty dependencyProperty = GetBindingPropertyFromType(propertyType);
We can refactor this area, by introducing a Control Mapping interface (IControlMapper) and a default implementation (ControlMapper).
Note: I wanted access to the Custom Attributes on each Property, since Custom Attributes may contain information that influences the Control Mapping process. As such, I tweaked the GenerateField method signature to accept the PropertyInfo for the current Property.
We add a property to DataForm:
public IControlMapper ControlMapper { get; set; }
The GenerateField calling code then changes to the following:
private bool GenerateField(PropertyInfo propertyInfo, Type propertyType, string propertyName, BindingMode bindingMode, Panel panel)
...
IControlMapper controlMapper = this.ControlMapper;if (null == controlMapper){
controlMapper = new ControlMapper();
}
controlMapper.PropertyInfo = propertyInfo;
controlMapper.PropertyType = propertyType;
Control control = controlMapper.GetControl();DependencyProperty dependencyProperty = controlMapper.GetBindingProperty();
...
We can now define a derived DataForm class that supplies a different implementation of IControlMapper that performs the required mapping.
public interface IControlMapper
{
PropertyInfo PropertyInfo { get; set; }Type PropertyType { get; set; }
Control GetControl(); DependencyProperty GetBindingProperty();}
Here is the refactored ControlMapper base class:
public class ControlMapper : IControlMapper
{
#region IControlMapper Membersprotected PropertyInfo propertyInfo;
public PropertyInfo PropertyInfo{
get
{
return this.propertyInfo;}
set
{
this.propertyInfo = value;}
}
protected Type propertyType;public Type PropertyType{
get
{
return this.propertyType;}
set
{
this.propertyType = value;}
}
public virtual Control GetControl(){
Type type = this.PropertyType;Debug.Assert(type != null, "The type must not be null.");
if (type == typeof(bool)){
return new CheckBox();}
else if (type == typeof(bool?)){
CheckBox checkBox = new CheckBox();checkBox.IsThreeState = true;
return checkBox;}
else if (type == typeof(DateTime) || type == typeof(DateTime?)){
return new DatePicker();}
else if (type.IsEnum){
ComboBox comboBox = new ComboBox();FieldInfo[] valueFieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.Static);
List<string> valueList = new List<string>();foreach (FieldInfo valueFieldInfo in valueFieldInfos){
Enum value = valueFieldInfo.GetValue(null) as Enum;
if (value != null){
valueList.Add(value.ToString());
}
}
comboBox.ItemsSource = valueList;
return comboBox;}
else
{
return new TextBox();}
}
public virtual DependencyProperty GetBindingProperty(){
Type type = this.PropertyType;Debug.Assert(type != null, "The type must not be null.");
if (type == typeof(bool) || type == typeof(bool?)){
return CheckBox.IsCheckedProperty;}
else if (type == typeof(DateTime) || type == typeof(DateTime?)){
return DatePicker.SelectedDateProperty;}
else if (type.IsEnum){
return ComboBox.SelectedItemProperty;}
else
{
return TextBox.TextProperty;}
}
#endregion
}