【问题标题】:Changing TypeConverter of a 3rd party library type更改第 3 方库类型的 TypeConverter
【发布时间】:2020-06-25 08:07:00
【问题描述】:

我在第 3 方库中有一个 Point3D 类,它有自己的 TypeConverter,它将点格式化为 10,20,30。我需要将其更改为10;20;30(用分号代替逗号)。

有什么方法可以改变我在应用程序属性网格中的显示方式吗?是否可以以某种方式强制执行不同的TypeConverter

也许存在解决我的问题的不同方法?

【问题讨论】:

    标签: c# .net visual-studio winforms formatting


    【解决方案1】:

    是的,您可以通过劫持PropertyDescriptor API 并提供自定义TypeDescriptionProvider。现在,这里有 很多 移动部件,但您可以作弊并使用“装饰器”方法,以便将原始版本用于您不想更改的位。以下是长篇——寻找// 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}";
    }
    

    在自定义提供程序中完成实际工作:

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

    【讨论】:

      猜你喜欢
      • 2012-12-05
      • 2011-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-27
      • 1970-01-01
      相关资源
      最近更新 更多