I have created a TypeConverter for a custom type so I can edit properties of that type from the Property Designer. However, I don't want new objects of that type to be instantiated and just use predefined object Constants. I noticed that ColorConverter does exactly what I want -- it sets the color property to a constant ... something like:
target.ColorProperty = Color.Red rather than doing
Color c = new Color(); Color.Property = something; target.ColorProperty = c;Anyway, I was wondering how I can achieve the same trick. And since I don't have access to the .NET source code, maybe some of you geniuses here might know how to do this.
The code that I have so far is:
Discriminator is a simple type that I want to edit in the Property designer. I wanted it to look just like an enum in the Property Designer where the designer will be just picking one of the available values from a dropdown list. However, the reason I didn't use an enum was that the Property Designer will show enum values with the same value as the default (i.e. firts) enum name. For example, the following enum
Code Snippet
enum something
{
one = 1,
two = 2,
three = 1
}
Will show in the property designer as:
Whereas I want it to show "three" in the last option.
So here is the class. It's a real simple Name-Value structure that I actually wanted for it to have only
private constructors, but the typeconverter wasn't working with private constructors. The strings that will be displayed in the property designer are simply the names of the constants:
Code Snippet
public class Discriminator
{
int value;
string name;
#region Static DiscriminatorValue Objects
public static readonly Discriminator D1 = new Discriminator(0x1, "D1");
public static readonly Discriminator D2 = new Discriminator(0x2, "D2");
public static readonly Discriminator D3 = new Discriminator(0x4, "D3");
#endregion
#region Constructors
public Discriminator()
{
}
public Discriminator(int v, string n)
{
value = v;
name = n;
}
#endregion
#region Properties
public int Value
{
get { return value; }
set { this.value = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
#endregion
#region Instance Methods
public override string ToString()
{
return this.Name;
}
#endregion
}
Here is the Converter Code
Code Snippet
public class DiscriminatorConverter : TypeConverter
{
private static readonly StandardValuesCollection defaultRelations;
static DiscriminatorConverter()
{
if (defaultRelations == null)
{
System.Reflection.FieldInfo[] fields = typeof(Discriminator).GetFields();
string[] strings = new string[fields.Length + 1];
strings[0] = "blah";
for (int i = 0; i < fields.Length; i++)
{
strings[i + 1] = fields[i].Name;
}
defaultRelations = new StandardValuesCollection(strings);
}
}
//returns the discriminator Constant names
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return defaultRelations;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
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)
{
if (value is string)
{
if (value == null || (string)value == "" || (string)value == "blah")
return (Discriminator)null;
try
{
Discriminator d = (Discriminator)typeof(Discriminator).GetField((string)value).GetValue(null);
return d;
}
catch { }
throw new ArgumentException("Can not convert '" + (string)value + "' to type DiscriminatorValue");
}
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value is Discriminator)
{
if (value == null) return "blah";
return ((Discriminator)value).Name;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
So the Property designer displays the properties (Constants) fine and it assigns properties correctly, but it is doing like this:
Code Snippet
Discriminator d = new Discriminator();
d.Name = "D1";
d.Value = 1;
target.Disc = d;
But I want it to use the Constant values instead thus allowing me to make the Discriminator constructors private and prevent other discriminators to be created. So ideally, the generated code by the property designer should be:
Code Snippet
target.Disc = Discriminator.D1;
Sorry for the length of this post, but I wanted to be as thorough as possible.
Thanks for all your help!