简体   繁体   English

更改第 3 方库类型的 TypeConverter

[英]Changing TypeConverter of a 3rd party library type

I have a Point3D class in a 3rd party library with its own TypeConverter that formats the point as 10,20,30 .我在第 3 方库中有一个Point3D class ,它有自己的TypeConverter ,将点格式化为10,20,30 I need to change it as 10;20;30 (semicolon in place of the comma).我需要将其更改为10;20;30 (用分号代替逗号)。

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?是否可以以某种方式强制执行不同的TypeConverter

Maybe a different approach to solve my problem exists?也许存在解决我的问题的不同方法?

You can, yes, by hijacking the PropertyDescriptor API and providing a custom TypeDescriptionProvider .是的,您可以通过劫持PropertyDescriptor API 并提供自定义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).以下内容很长 - // your custom code here (其中有两个)。

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM