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.
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 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);
}
}
Am trying to work with a Winform Property Grid, and I am not able to format displayed value (mind too strongly tied to wpf now)
So what I want is, there is a drop down in property grid that has its own UITypeEditor, this editor shows values such as
1 - On
2 - Off
3 - Unknown
so the property on that listens to propertyGrid changes is int and for some odd reasons I cant change it to string, so like in wpf can I have a converter sort of thing that converts 1 into 1- On and 1-On to 1 ?
how can I decorate my property or property grid to be this intelligent ?
My property looks like
[LocalizedCategory("Limits", typeof(Api.Properties.Resources))]
[LocalizedDisplayName("Maximum", typeof(Api.Properties.Resources))]
[LocalizedDescription("Maximum", typeof(Api.Properties.Resources))]
[Editor(typeof(TextConversionTypeEditor), typeof(UITypeEditor))]
public int CriticalMaximum
{
get; set;
}
Can I make my property grid display more information than just an int ?
If you can use an Enum as type of your property, then it shows available values in drop-down, otherwise you can create a TypeConverter to provide values for drop-down. To do so you can use either of these options:
Use TypeConverter of an Enum for your int Property
If values are limited and known at design-time, In this case although the property is int, you can use the converter of an Enum for your property, without overriding anything:
public class MyObject
{
[TypeConverter(typeof(MyTypeConverter))]
public int MyProperty { get; set; }
}
public class MyTypeConverter : EnumConverter
{
public MyTypeConverter() : base(typeof(MyValues)) { }
}
public enum MyValues
{
On = 1,
Off,
Unknown
}
Create your own TypeConverter which supports standard values
If you can not have an enum and your standard values are generated at run-time, you can create such TypeConverter:
public class MyTypeConverter : TypeConverter
{
Dictionary<int, string> values;
public MyTypeConverter()
{
values = new Dictionary<int, string> { { 1, "1 - On" }, { 2, "2 - Off" }, { 3, "3 - Unknown" } };
}
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 != null && values.ContainsValue(value.ToString()))
return values.Where(x => x.Value == value.ToString()).FirstOrDefault().Key;
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value != null && value.GetType() == typeof(int))
return values[(int)value];
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(values.Keys);
}
}
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
}
}