In my sample I have used a PropertyGrid control and fetched my all properties and values.
When I change one property to an invalid value, like "123456789008765" for an integer field, it throws the following error:
I need to avoid this error, and if the given value is invalid I need to assign a default value (in this case 13, 13
). How can I do this?
Short Answer
The PropertyGrid
uses the TypeConverter
to convert a string
to your property value and convert your property value to a string
.
The error message is raised by the type converter of Size
when converting the string to size value.
You need to change the behavior for your property when converting from string.
You should create a custom type converter and register it for your property to handle the exception when converting from string to your property value.
Path to solution
Here is the main problems that you should solve:
- Let the user type in the property grid.
- Show the string representation of the property in property grid.
- Let the user expand the property.
- Instead of showing a message box, use the default value when the string can not be converted to your property value.
What you should know
The PropertyGrid
uses the TypeConverter
to convert a string
to your property value and convert your property value to a string
.
To customize the behavior of the property grid when converting a string to your property, you should Implement a Type Converter.
- To convert a string to your property type, you should override
CanConvertFrom
and ConvertFrom
. When you say the type can convert from string
then you will allow the user to type in property grid.
- To convert your property to string, you should override
ConvertTo
. This way you provide string representation of your property value.
- To let the user to expand the property, you should derive your custom converter from
ExpandableObjectConverter
.
- To register a converter for a property, you can use a
TypeConverter
attribute.
- To get the a converter for a type, for example the default type converter for
Size
you can use TypeDescriptor.GetConverter(typeof(Size));
Solution
The error message is raise by the type converter of Size
. So we need to change the behavior for your property when converting from string.
Based on above information we implement a custom type converter for your property. In the implementation we inherit from ExpandableObjectConverter
, then in constructor we get the default converter for Size
and use it when overriding the mentioned methods.
The main requirement is implemented in ConvertFrom
and there we try to convert the string to Size
and when an exception occurs instead we use the DefaultValue
that you set using an attribute an if there is no default value, we use 0,0
as value.
Implementation
Create a converter:
public class CustomSizeConverter : ExpandableObjectConverter
{
TypeConverter converter;
public CustomSizeConverter()
{
converter = TypeDescriptor.GetConverter(typeof(Size));
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return converter.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
try
{
return converter.ConvertFrom(context, culture, value);
}
catch (Exception)
{
var d= context.PropertyDescriptor.Attributes.OfType<DefaultValueAttribute>().FirstOrDefault();
if (d != null)
return d.Value;
else
return new Size(0,0);
}
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
return converter.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return converter.CanConvertTo(context, destinationType);
}
}
And here is your class that contains a Size
property with new converter:
public class MyObject
{
public MyObject() { SomeSize = new Size(13, 13); }
public string SomeText { get; set; }
[TypeConverter(typeof(CustomSizeConverter))]
[DefaultValue(typeof(Size), "13,13")]
public Size SomeSize { get; set; }
}
Don't forget to include required usings:
using System;
using System.Linq;
using System.Drawing;
using System.ComponentModel;