I have a Point3D
class in a 3rd party library with its own TypeConverter
that formats the point as 10,20,30
. I need to change it as 10;20;30
(semicolon in place of the comma).
Is there any way to change how I display it in my application property grids? Is it possible to enforce a different TypeConverter
in some way?
Maybe a different approach to solve my problem exists?
You can, yes, by hijacking the PropertyDescriptor
API and providing a custom TypeDescriptionProvider
. Now, there are a lot of moving parts here, but you can cheat and use a "decorator" approach so that you use the original versions for the bits you don't want to change. The following is long - look for // your custom code here
(there are two of them).
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
static class P
{
static void Main()
{
// connect our custom handling
MyProvider.Apply();
// show some conversions using *regular* type descriptor APIs
var obj = new Point3D(1, 2, 3);
var converter = TypeDescriptor.GetConverter(obj);
var s = converter.ConvertToString(obj);
Console.WriteLine(s);
var clone = converter.ConvertFromString(s);
Console.WriteLine(clone);
}
}
// this is the external type - note, the version here is imcomplete
// and doesn't declare a type descriptor etc, but that's fine - the
// important thing is that we don't "fix" this by changing this type
readonly struct Point3D
{
public Point3D(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
public int X { get; }
public int Y { get; }
public int Z { get; }
public override string ToString() => $"X={X}, Y={Y}, Z={Z}";
}
with the actual work done in a custom provider:
public sealed class MyProvider : TypeDescriptionProvider
{
private readonly TypeDescriptionProvider _tail;
public static void Apply()
{
var type = typeof(Point3D);
var tail = TypeDescriptor.GetProvider(type);
if (tail is MyProvider) return; // already done
var head = new MyProvider(tail);
TypeDescriptor.AddProvider(head, type);
}
private MyProvider(TypeDescriptionProvider tail) => _tail = tail;
public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
=> _tail.CreateInstance(provider, objectType, argTypes, args);
public override IDictionary GetCache(object instance)
=> _tail.GetCache(instance);
public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance)
=> new WrappedTypeDescriptor(_tail.GetExtendedTypeDescriptor(instance));
public override string GetFullComponentName(object component)
=> _tail.GetFullComponentName(component);
public override Type GetReflectionType(Type objectType, object instance)
=> _tail.GetReflectionType(objectType, instance);
public override Type GetRuntimeType(Type reflectionType)
=> _tail.GetRuntimeType(reflectionType);
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
=> new WrappedTypeDescriptor(_tail.GetTypeDescriptor(objectType, instance));
public override bool IsSupportedType(Type type)
=> _tail.IsSupportedType(type);
private sealed class WrappedTypeDescriptor : ICustomTypeDescriptor
{
private readonly ICustomTypeDescriptor _tail;
public WrappedTypeDescriptor(ICustomTypeDescriptor tail) => _tail = tail;
public AttributeCollection GetAttributes() => _tail.GetAttributes();
public string GetClassName() => _tail.GetClassName();
public string GetComponentName() => _tail.GetComponentName();
public TypeConverter GetConverter() => new MyConverter(_tail.GetConverter());
public EventDescriptor GetDefaultEvent() => _tail.GetDefaultEvent();
public PropertyDescriptor GetDefaultProperty() => _tail.GetDefaultProperty();
public object GetEditor(Type editorBaseType) => _tail.GetEditor(editorBaseType);
public EventDescriptorCollection GetEvents() => _tail.GetEvents();
public EventDescriptorCollection GetEvents(Attribute[] attributes) => _tail.GetEvents(attributes);
public PropertyDescriptorCollection GetProperties() => _tail.GetProperties();
public PropertyDescriptorCollection GetProperties(Attribute[] attributes) => _tail.GetProperties(attributes);
public object GetPropertyOwner(PropertyDescriptor pd) => _tail.GetPropertyOwner(pd);
}
private sealed class MyConverter : TypeConverter
{
private readonly TypeConverter _tail;
public MyConverter(TypeConverter tail)
=> _tail = tail;
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string s)
{
// your custom code here
var parts = s.Split(';');
if (parts.Length == 3)
{
int x = int.Parse(parts[0], culture);
int y = int.Parse(parts[1], culture);
int z = int.Parse(parts[2], culture);
return new Point3D(x, y, z);
}
}
return _tail.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value is Point3D point)
{
// your custom code here
return string.Format(culture, "{0};{1};{2}", point.X, point.Y, point.Z);
}
else
{
return _tail.ConvertTo(context, culture, value, destinationType);
}
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> _tail.CanConvertFrom(context, sourceType);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> _tail.CanConvertTo(context, destinationType);
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
=> _tail.CreateInstance(context, propertyValues);
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
=> _tail.GetCreateInstanceSupported(context);
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
=> _tail.GetProperties(context, value, attributes);
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
=> _tail.GetPropertiesSupported(context);
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
=> _tail.GetStandardValues(context);
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
=> _tail.GetStandardValuesExclusive(context);
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
=> _tail.GetStandardValuesSupported(context);
public override bool IsValid(ITypeDescriptorContext context, object value)
=> _tail.IsValid(context, value);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.