【问题标题】:How do I inject a custom UITypeEditor for all properties of a closed-source type?如何为闭源类型的所有属性注入自定义 UITypeEditor?
【发布时间】:2010-10-25 08:28:58
【问题描述】:

我想避免在我为其编写自定义 UITypeEditor 的特定类型的每个实例上放置 EditorAttribute。

我无法在类型上放置 EditorAttribute,因为我无法修改源代码。

我有一个要使用的唯一 PropertyGrid 实例的引用。

我可以告诉 PropertyGrid 实例(或所有实例)在遇到特定类型时使用自定义 UITypeEditor 吗?

Here 是一篇 MSDN 文章,提供了如何在 .NET 2.0 或更高版本中执行此操作的起点。

【问题讨论】:

    标签: c# .net propertygrid uitypeeditor


    【解决方案1】:

    您通常可以在运行时通过TypeDescriptor.AddAttributes 关联编辑器等。例如(Bar 属性应显示“...”,显示“正在编辑!”):

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

    【讨论】:

    • 马克,干得好。我会建议创建一个自定义类型描述符和提供者来发布它,但是你的方法是在幕后注册提供者并注入编辑器的好捷径!学到了一些东西。
    • 哇,这在实践中非常简单。谢谢!
    • 这太完美了!我正在开发一个绘图库,并希望为对象提供 PropertyGrid 编辑器支持,而不需要从对象库中依赖 Windows 窗体来装饰属性。这个解决方案允许我在核心库之外创建编辑器并在运行时添加它们。
    【解决方案2】:

    Marc 的解决方案直截了当地将 EditorAttribute 应用于 Bar 类型。如果您有一个微妙的性格,您可能宁愿注释特定实例的属性。唉,TypeDescriptor.AddAttributes 不可能做到这一点

    我的解决方案是编写一个包装器ViewModel<T>,它从 T 复制属性,用额外的属性注释一些。假设我们有一个报表类型的变量datum,我们会像这样使用它

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

    ViewModel&lt;T&gt; 的定义位置:

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

    如上所述,这会替换特定类型的属性,但如果您需要更高的分辨率,可以按名称替换属性。

    【讨论】:

    • 既然认为这太过分了,所以使用更简单的全局解决方案。
    • 重新使用它,但警告它可能与实现 ICustomTypeDescriptor 的对象不兼容
    【解决方案3】:

    只需将Editor attribute 添加到您的班级即可。

    【讨论】:

    • 好主意,但我忘了提到我无法在类型上放置 EditorAttribute,因为我无法修改源代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 2011-05-03
    • 2016-06-18
    相关资源
    最近更新 更多