Say I have a particular type that I want to make available to the Windows Forms designer...
public class Style
{
public CustomBrush Brush { get; set; }
}
And CustomBrush
is implemented like so...
public abstract CustomBrush
{
...
}
public SolidCustomBrush : CustomBrush
{
...
}
public GradientCustomBrush : CustomBrush
{
...
}
Is there a way at design time that I can choose from any of the types derived from CustomBrush
, instantiate an instance of the selected type, and modify it via the designer?
So far the only way I've though of to be able to do this is using an enum
enum BrushType
{
Solid,
Gradient
}
When the enum
changes, so does type underlying the Brush
property, but I don't like this approach...it's dirty!
As an option you can create a custom TypeConverter
that provides a list of standard values to show in PropertyGrid
.
A type converter can provide a list of values for a type in a Properties window control. When a type converter provides a set of standard values for a type, the value entry field for a property of the associated type in a Properties window control displays a down arrow that displays a list of values to set the value of the property to when clicked.
Since you want to be able to edit also sub properties of the CustomBrush
in property grid, you should derive from ExpandableObjectConverter
.
Result
Implementation
Create a CustomBrushConverter
class and derive from ExpandableObjectConverter
. Then override these methods:
GetStandardValuesSupported
: return true
to show a dropdown.GetStandardValuesExclusive
: return true
to limit supported values to dropdown list.GetStandardValues
: return a list of available options to show in dropdown. All values should be the same type of the property you are editing (here CustomBrush
type).CanConvertFrom
: return true
if the sourceType
parameter is of type string
.ConvertFrom
: return one of standard values based on the string value
parameter.using System;
using System.ComponentModel;
using System.Linq;
class CustomBrushConverter : ExpandableObjectConverter
{
CustomBrush[] standardValues = new CustomBrush[] { new SolidCustomBrush(), new GradientCustomBrush() };
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
var result = standardValues.Where(x => x.ToString() == value).FirstOrDefault();
if (result != null)
return result;
return base.ConvertFrom(context, culture, value);
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(standardValues);
}
}
Then decorate the Brush
property with TypeConverterAttribute
this way:
public class Style /*: Component */
{
[TypeConverter(typeof(CustomBrushConverter))]
public CustomBrush Brush { get; set; }
}
You can override ToString
method of your CustomBrush
classes to provide more friendly names to show in dropdown list in PropertyGrid
. For example:
public class GradientCustomBrush : CustomBrush
{
public Color Color1 { get; set; }
public Color Color2 { get; set; }
public override string ToString()
{
return "Gradient";
}
}