A long time ago while developing a custom control, I wrote a piece of code which allows a developer to enter “Auto” as string to a custom property of type double. Yesterday, I was in a need to use the same functionality in one of my control.
That reminds me the previous implementation and fortunately I was able to get it from TFS repository. Thus I thought to share the same with you in case you need it in future.
If you are building a custom control, you might want to add a double type property to set a specific height or width of the control and in that case, you might want to give user (I mean the developer who is using this control in his/her application) the option to set “Auto” value as the Height and Width properties of Framework Element does.
If you set the string value “Auto” to your custom double type property, you will get the following error: “Cannot convert source type ‘string’ to target type ’double’”. This is a real fact. You can not implicitly type cast a string literal to a double value.
You might be wonder then how the double type properties like Height and Width are accepting the string literal from XAML? Wait a minute, if you try this out from code, you will get the same error message. So what to do if I need the same in my code? Because in my custom property of double type, it is failing in the XAML page itself.
Writing the Type Converter
So here comes my code which will be useful to you in many or most of the cases. First you need to create a class inherited from System.ComponentModel.TypeConverter and that should be System.IConvertible. The class declaration will look like this:
public class AutoToDoubleTypeConverter<T> : TypeConverter where T : IConvertible
{
}
Then you have to override four methods of the base class “TypeConverter” named “CanConvertFrom(…)”, “CanConvertTo(…)”, “ConvertFrom(…)” and “ConvertTo(…)”. Our main logic will go in the ConvertFrom method where we will check for the entered value. If it is of double type, it will directly return the value as it’s of same type. Else, it will encounter a FormatException. Once you catch the exception, you have to check whether the value is “Auto”. If so, just return double.NaN and in other case, pass the exception to the outer model.
Here is the sample code of the said implementation:
// Returns whether the type converter can convert an object from the specified type
// to the type of this converter.
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType.GetInterface("IConvertible", false) != null;
}
// Returns whether the type converter can convert an object to the specified type.
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType.GetInterface("IConvertible", false) != null;
}
// Converts from the specified value to the intended conversion type of the converter.
// If user enters "Auto" as the double value, it will return double.NaN else throw Exception.
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{
try
{
var convertible = (IConvertible)value;
if (convertible != null) return convertible.ToType(typeof(T), culture);
}
catch (FormatException)
{
if (value != null && value.ToString().Equals(AUTO))
{
return double.NaN;
}
throw;
}
return null;
}
// Converts the specified value object to the specified type.
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture,
object value, Type destinationType)
{
return ((IConvertible)value).ToType(destinationType, culture);
}
Do you need the complete code? I am sharing the whole code file here which you can download freely and use it in your project. Make sure that, you are using the code as it is with the header and proper credit to me “Copyright © Kunal Chowdhury, 2012-2013”. Also drop a line below so that, I will know that this code helped you.
How to use it?
Now once the custom type converter is ready, you need to apply it to your custom property. To do this, just set the TypeConverter attribute to the property where you want to apply the same. In our example, we are assigning the type converter to a double type custom property named “CustomHeight” and hence here is the code:
[TypeConverter(typeof(AutoToDoubleTypeConverter<double>))]
public double CustomHeight
{
get { return (double)GetValue(CustomHeightProperty); }
set { SetValue(CustomHeightProperty, value); }
}
Unless you mark your custom property of the type converter that we created, you will not be able to set a string to the property; neither from code nor from XAML. Once you set the property, you will see that now you are able to set a string literal to the property. As per the implementation, it will accept string literal as “Auto” but will throw exception in case you provide a different string value.
I hope the post was helpful and the code too. Connect with me on Twitter, Facebook and Google+ to get technical updates and participate in the discussion. Also subscribe to my blog’s RSS Feed and Email Newsletter to get the notification sent directly to your inbox. Happy Coding.