How do I inject a custom UITypeEditor for all properties of a closed-source type?

前端 未结 3 2002
无人及你
无人及你 2020-12-06 07:12

I want to avoid placing an EditorAttribute on every instance of a certain type that I\'ve written a custom UITypeEditor for.

I can\'t place an EditorAttribute on t

相关标签:
3条回答
  • 2020-12-06 07:30

    You can usually associate editors etc at runtime via TypeDescriptor.AddAttributes. For example (the Bar property should show with a "..." that displays "Editing!"):

    using System;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.Windows.Forms;
    
    class Foo
    {
        public Foo() { Bar = new Bar(); }
        public Bar Bar { get; set; }
    }
    class Bar
    {
        public string Value { get; set; }
    }
    
    class BarEditor : UITypeEditor
    {
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            MessageBox.Show("Editing!");
            return base.EditValue(context, provider, value);
        }
    }
    static class Program
    {
        [STAThread]
        static void Main()
        {
            TypeDescriptor.AddAttributes(typeof(Bar),
                new EditorAttribute(typeof(BarEditor), typeof(UITypeEditor)));
            Application.EnableVisualStyles();
            Application.Run(new Form { Controls = { new PropertyGrid { SelectedObject = new Foo() } } });
        }
    }
    
    0 讨论(0)
  • 2020-12-06 07:33

    Just add an Editor attribute to your class.

    0 讨论(0)
  • 2020-12-06 07:42

    Marc's solution bluntly applies the EditorAttribute to the Bar type globally. If you have a delicate disposition, you might rather annotate properties of a specific instances. Alas, that isn't possible with TypeDescriptor.AddAttributes

    My solution was to write a wrapper ViewModel<T>, which copies properties from T, annotating some with extra attributes. Suppose we have a variable datum of type Report, we'd use it like this

            var pretty = ViewModel<Report>.DressUp(datum);
            pretty.PropertyAttributeReplacements[typeof(Smiley)] = new List<Attribute>() { new EditorAttribute(typeof(SmileyEditor),typeof(UITypeEditor))};
            propertyGrid1.SelectedObject = pretty;
    

    Where ViewModel<T> is defined:

    public class ViewModel<T> : CustomTypeDescriptor
    {
        private T _instance;
        private ICustomTypeDescriptor _originalDescriptor;
        public ViewModel(T instance, ICustomTypeDescriptor originalDescriptor) : base(originalDescriptor)
        {
            _instance = instance;
            _originalDescriptor = originalDescriptor;
            PropertyAttributeReplacements = new Dictionary<Type,IList<Attribute>>();
        }
    
        public static ViewModel<T> DressUp(T instance)
        {
            return new ViewModel<T>(instance, TypeDescriptor.GetProvider(instance).GetTypeDescriptor(instance));
        }
    
        /// <summary>
        /// Most useful for changing EditorAttribute and TypeConvertorAttribute
        /// </summary>
        public IDictionary<Type,IList<Attribute>> PropertyAttributeReplacements {get; set; } 
    
        public override PropertyDescriptorCollection GetProperties (Attribute[] attributes)
        {
            var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>();
    
            var bettered = properties.Select(pd =>
                {
                    if (PropertyAttributeReplacements.ContainsKey(pd.PropertyType))
                    {
                        return TypeDescriptor.CreateProperty(typeof(T), pd, PropertyAttributeReplacements[pd.PropertyType].ToArray());
                    }
                    else
                    {
                        return pd;
                    }
                });
            return new PropertyDescriptorCollection(bettered.ToArray());
        }
    
        public override PropertyDescriptorCollection GetProperties()
        {
            return GetProperties(null);
        }
    }
    

    As defined above, this substitutes properties of a specific type, but you can substitute properties by name if you need the greater resolution.

    0 讨论(0)
提交回复
热议问题