在运行时(动态)将Editor / EditorAttribute添加到Object的属性

时间:2010-01-11 17:29:24

标签: winforms attributes propertygrid my.settings

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

我有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 在Adding Editor / EditorAttribute at Run-time (Dynamically) to an Object's Property处回答以下问题。它使用派生的CustomTypeDescriptor和TypeDescriptionProvider类。您只需添加一次提供程序,例如应用程序初始化。

3 个答案:

答案 0 :(得分:6)

在给出我的第一个答案之后,我记得Marc Gravell给出的另一个解决方案,我甚至评论过。信不信由你,你只需要调用TypeDescriptor.AddAttributes()。

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

对于你的情况,它给出了:

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做更复杂的事情时,我之前的帖子仍然为你提供了一个很好的技巧。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

是的,可以动态更改TypeDescriptor,以便返回所需的UITypeEditor。这在article中有解释。但请注意,它会为此类型的所有属性添加它。

我从这里抓取代码并大致改变了以下内容:

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

我希望这会有所帮助。