4

如何在运行时将 EditorAttribute(编辑器)添加到对象的属性中?

我有My.Settings.ExcludeFiles,它是由设置设计师创建的Public Property ExcludedFiles() As Global.System.Collections.Specialized.StringCollection。通过属性网格进行编辑时ExcludedFiles,“字符串集合编辑器”会生成“未找到类型‘System.String’的构造函数”运行时异常。

我无法更改属性的ExcludeFiles属性,因为下次进行任何设置更改时它们将被覆盖。因此,我必须在运行时附加/添加 Editor/EditorAttribute。

我想要做的是StringCollectionEditor在运行时添加,如下所示作为设计时属性。

    <Editor(GetType(StringCollectionEditor), GetType(UITypeEditor))> _

解决方案

方法#1

TypeDescriptor.AddAttributes( _
    GetType(Specialized.StringCollection), _
    New EditorAttribute( _
        "System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", _
         GetType(System.Drawing.Design.UITypeEditor)))

您只需添加一次此属性,例如应用程序初始化。

方法#2

更灵活。请参阅下面的 Nicolas Cadilhac在运行时将编辑器/编辑器属性添加到对象的属性中的回答(动态地)。它使用派生的 CustomTypeDescriptor 和 TypeDescriptionProvider 类。您只需添加一次提供程序,例如应用程序初始化。

4

3 回答 3

6

在给你我的第一个答案之后,我想起了 Marc Gravell 给出的另一个解决方案,我什至发表了评论。信不信由你,您只需要调用 TypeDescriptor.AddAttributes()。

这是在这里:如何为闭源类型的所有属性注入自定义 UITypeEditor?.

对于您的情况,它给出:

TypeDescriptor.AddAttributes(
    typeof(StringCollection),
    new EditorAttribute("System.Windows.Forms.Design.StringCollectionEditor,
        System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
        typeof(UITypeEditor)))

因此,也许您应该取消选中我之前的答案并确认此答案为解决方案(尽管所有功劳都归于 Marc)。但是,当您需要使用 TypeDescriptor 做更复杂的事情时,我之前的帖子仍然为您提供了一种很好的技术。

于 2010-01-11T20:26:15.817 回答
1

是的,可以动态更改 TypeDescriptor 以便返回所需的 UITypeEditor。本文对此进行了解释。但请注意,它将为这种类型的所有属性添加它。

我从这里抓取了代码,并大致将其更改为以下内容:

private class StringCollectionTypeDescriptor : CustomTypeDescriptor
{
    private Type _objectType;
    private StringCollectionTypeDescriptionProvider _provider;

    public StringCollectionTypeDescriptor(
        StringCollectionTypeDescriptionProvider provider,
        ICustomTypeDescriptor descriptor, Type objectType)
        :
        base(descriptor)
    {
        if (provider == null) throw new ArgumentNullException("provider");
        if (descriptor == null)
            throw new ArgumentNullException("descriptor");
        if (objectType == null)
            throw new ArgumentNullException("objectType");
        _objectType = objectType;
        _provider = provider;
    }

    /* Here is your customization */
    public override object GetEditor(Type editorBaseType)
    {
        return new MultilineStringEditor();
    }
}

public class StringCollectionTypeDescriptionProvider : TypeDescriptionProvider
{
    private TypeDescriptionProvider _baseProvider;

    public StringCollectionTypeDescriptionProvider(Type t)
    {
        _baseProvider = TypeDescriptor.GetProvider(t);
    }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        return new StringCollectionTypeDescriptor(this, _baseProvider.GetTypeDescriptor(objectType, instance), objectType);
    }
}

然后您注册您的提供商:

TypeDescriptor.AddProvider(new StringCollectionTypeDescriptionProvider
    (typeof(System.Collections.Specialized.StringCollection)),
    typeof(System.Collections.Specialized.StringCollection));

这很好用,除了它会让你发现你有另一个问题:MultilineStringEditor 是一个使用 String 类型的编辑器,而不是 StringCollection 类型。您真正需要的是 .Net 框架中的私有 StringCollectionEditor。因此,让我们将 GetEditor 替换为:

public override object GetEditor(Type editorBaseType)
{
    Type t = Type.GetType("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
    return TypeDescriptor.CreateInstance(null, t, new Type[] { typeof(Type) }, new object[] { typeof(string) });
}

我希望这有帮助。

于 2010-01-11T19:24:07.033 回答
0

你不能。属性只能在编译时定义(当然,除非您动态生成类型)

于 2010-01-11T17:40:25.107 回答