I have a control that has a complex browsable property, it shows a list of all the controls of that type in the form but I want to allow to copy and paste the name of the control in the combobox.
I used a TypeConverter, but the items of the combobox disappear.
Is there another way of doing that?
Or how I return the default list of items in the GetStandardValues function?
I tried to return the base function, but it doesn't work.
public class SubflowchartConverter : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
FlowChart flowchart = context.Instance as FlowChart;
if (flowchart != null)
return true;
else
return base.GetStandardValuesSupported(context);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return false;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return base.GetStandardValues(context);
}
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, CultureInfo culture, object value)
{
if (value is string)
{
string flowchartName = value.ToString();
if (flowchartName == "(none)")
return null;
FlowChart flowchart = context.Instance as FlowChart;
if (flowchart.Parent.Controls.ContainsKey(flowchartName))
{
return flowchart.Parent.Controls[flowchartName];
}
}
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, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
if (value == null)
return "(none)";
FlowChart flowchart = value as FlowChart;
if (flowchart != null)
return flowchart.Name;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
Related
This question is self-answered. If you have better answer post it.
Specially when dealing with NULL value in TypeConverters if you have better
approach post it
When creating properties like Strings, DateTime, etc.
It appeared well and serialized.
But I need to create a property of Type type.
Actually creating a Type property but it is un-modifiable.
Is there a converter or such task to allow that?
public class MyClass
{
public Type MyType{get;set;}
}
From picture Its grayed. and read-only.
First, Many special thanks to #Reza Aghaei for his awesome answers Thanks to
him much.
"Specified cast is not valid" error in TypeConverter.ConvertTo
How to create TypeConverter which accepts multiple values and serialized to WinForms Form.designer.cs?
TypeConverter Implemented as following:
public class DataTypeConverter : TypeConverter
{
private const string NullString = "<NULL>";
private Type[] types = new Type[] { null, typeof(byte), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(string), typeof(DateTime), typeof(bool) };
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, CultureInfo culture, object value)
{
if (value.ToString() == NullString) return null;
var result = types.FirstOrDefault(x => x?.ToString() == value.ToString());
if (result != null)
return result;
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
if (value == null)
return NullString;
return value.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) => new StandardValuesCollection(types);
public override bool GetStandardValuesSupported(ITypeDescriptorContext context) => true;
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) => true;
}
Result
I am trying to implement localized BooleanConverter. Everything works well so far, but when you double click on the property next message is being shown:
"Object of type 'System.String' cannot be converted to type 'System.Boolean'."
I suppose the problem is in method CreateInstance of TypeConverter which has that boolean property.
public class BoolTypeConverter : BooleanConverter
{
private readonly string[] values = { Resources.BoolTypeConverter_False, Resources.BoolTypeConverter_True };
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value != null)
{
var valueType = value.GetType();
if (valueType == typeof(bool))
{
return values[(bool)value ? 1 : 0];
}
else if (valueType == typeof(string))
{
return value;
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var stringValue = value as string;
if (stringValue != null)
{
if (values[0] == stringValue)
{
return true;
}
if (values[1] == stringValue)
{
return false;
}
}
return base.ConvertFrom(context, culture, value);
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(values);
}
}
The main problem of your code is you are overriding GetStandardValues incorrectly.
In fact you don't need to override GetStandardValues, just remove it and you will get expected result, that acts like original boolean converter while showing your desired strings:
When overriding GetStandardValues you should return a list of supported values of the type that you are creating converter for, then using the ConvertTo you provide string representation values and using ConvertFrom, provide a way to converting the type from string values.
I have a PropertyGrid with Expandable Properties. It looks like this:
http://i.imgur.com/2FhVV41.jpg
It displays the Value and the Measurement Unit. Now, if the user writes in a double value in the root row, the Value property will change, everything else stays unmodified.
I want that if the user clicks in the root row, its text ("5 EUR" on the picture) would change to show only the Value ("5"). But if the user doesn't click in, the text would stay unmodified ("5 EUR").
Now my ExpandableObjectConverter looks like this (only the relevant part):
ObjectProperty oldOP;
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(ObjectProperty))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
ObjectProperty op = (ObjectProperty)value;
oldOP = op;
return op.ValueProp.ToString() + " " + op.MUProp.ToString();
}
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)
{
ObjectProperty op;
double newValue;
if (double.TryParse((string)value, out newValue))
{
op = oldOP;
op.ValueProp = newValue;
return op;
}
else
{
op = oldOP;
return op;
}
}
I'm trying to make a property that will show a different text in its value input each time the user selected an item. But my problem with the values is that they're strings with underscores and lowercase first letters, for example: "naval_tech_school". So I need the ComboBox to display a different value text that will look like this "Naval Tech School" instead.
But the value should remain "naval_tech_school" if trying to access it.
If you just want to change the value (without a special editor) back and forth between the two formats, you just need a custom TypeConverter. Declare the property like this:
public class MyClass
{
...
[TypeConverter(typeof(MyStringConverter))]
public string MyProp { get; set; }
...
}
And here is a sample TypeConverter:
public class MyStringConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
string svalue = value as string;
if (svalue != null)
return RemoveSpaceAndLowerFirst(svalue);
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
string svalue = value as string;
if (svalue != null)
return RemoveUnderscoreAndUpperFirst(svalue);
return base.ConvertTo(context, culture, value, destinationType);
}
private static string RemoveSpaceAndLowerFirst(string s)
{
// do your format conversion here
}
private static string RemoveUnderscoreAndUpperFirst(string s)
{
// do your format conversion here
}
}
public enum eVisualType
{
None = 0, Torch = 1, Rune01, Rune02, Rune03, FireRed01,
LaserBlackWhiteLeft, LaserBlackWhiteRight, LaserBlueRedLeft, LaserBlueRedRight,
Wheel01, Wheel01a, Wheel02, BlinkingStar, MovingPillar
}
public class EnumTypeConverter : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true; // True means show a combobox
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true; // True will limit to list. false will show the list, but allow free-formentry
}
}
public class VisualTypeConverter : EnumTypeConverter
{
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(new eVisualType[] { eVisualType.BlinkingStar, eVisualType.FireRed01, eVisualType.LaserBlackWhiteLeft, eVisualType.LaserBlackWhiteRight, eVisualType.LaserBlueRedLeft, eVisualType.LaserBlueRedRight, eVisualType.MovingPillar, eVisualType.Rune01, eVisualType.Rune02, eVisualType.Rune03, eVisualType.Torch, eVisualType.Wheel01, eVisualType.Wheel01a, eVisualType.Wheel02 });
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if(value is string)
return (eVisualType)Enum.Parse(typeof(eVisualType), value.ToString(), true);
return base.ConvertFrom(context, culture, value);
}
}
Code in propertygrid class:
private eVisualType m_VisualType = eVisualType.FireRed01;
[CategoryAttribute("Basic"), DescriptionAttribute("The visual type.")]
[TypeConverter(typeof(VisualTypeConverter))]
[DisplayName("Visual Type")]
public eVisualType VisualType
{
get { return m_VisualType; }
set { m_VisualType = value; }
}
The above still produces an error when selecting a different value in the propertygrid at runtime: Object of type 'System.String' cannot be converted to type '[project name].eVisualType'.
The question has been asked before once or twice but never in full detail or it was for WPF+binding only. I use Windows Forms.
I'm also not sure if the ConvertFrom(..) is needed at all.
The TypeConverter was bad (I needed to derrive from EnumConverter and not from TypeConverter.
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
namespace [namespace]
{
public class EnumTypeConverter : EnumConverter
{
private Type m_EnumType;
public EnumTypeConverter(Type type)
: base(type)
{
m_EnumType = type;
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
{
return destType == typeof(string);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
{
FieldInfo fi = m_EnumType.GetField(Enum.GetName(m_EnumType, value));
DescriptionAttribute dna =
(DescriptionAttribute)Attribute.GetCustomAttribute(
fi, typeof(DescriptionAttribute));
if (dna != null)
return dna.Description;
else
return value.ToString();
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType)
{
return srcType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
foreach (FieldInfo fi in m_EnumType.GetFields())
{
DescriptionAttribute dna =
(DescriptionAttribute)Attribute.GetCustomAttribute(
fi, typeof(DescriptionAttribute));
if ((dna != null) && ((string)value == dna.Description))
return Enum.Parse(m_EnumType, fi.Name);
}
return Enum.Parse(m_EnumType, (string)value);
}
}
}
http://www.codeproject.com/Articles/22717/Using-PropertyGrid
Try by Reflection:
public static T GetEnumMemberFromName<T>(string name)
{
return (T)Enum.Parse(typeof(T), name);
}
In your code:
public class VisualTypeConverter : EnumTypeConverter
{
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(new eVisualType[] { eVisualType.BlinkingStar, eVisualType.FireRed01, eVisualType.LaserBlackWhiteLeft, eVisualType.LaserBlackWhiteRight, eVisualType.LaserBlueRedLeft, eVisualType.LaserBlueRedRight, eVisualType.MovingPillar, eVisualType.Rune01, eVisualType.Rune02, eVisualType.Rune03, eVisualType.Torch, eVisualType.Wheel01, eVisualType.Wheel01a, eVisualType.Wheel02 });
}
public T GetEnumMemberFromName<T>(string name)
{
return (T)Enum.Parse(typeof(T), name);
}
}
Example:
eVisualType myEnumMember = myVisualTypeConverterInstance.GetEnumMemberFromName<eVisualType>("Torch");