Silverlight 3 DataForm Control Mapping - Add Extensibility
An earlier posting explains how to perform basic modifications to the Silverlight 3 DataForm control.
http://weblogs.asp.net/naughton/archive/2009/08/01/silverlight-3-dataform-control-mapping-basic-modifications.aspx
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 Members
protected 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
}