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

发布于 2024-08-18 00:25:28 字数 1265 浏览 5 评论 0原文

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

我有 My.Settings.ExcludeFiles,它由设置设计器创建为 公共属性 ExcludedFiles() 作为 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

更灵活。参见尼古拉斯·卡迪拉克 回答如下添加编辑器/ EditorAttribute 在运行时(动态)到对象的属性。它使用派生的 CustomTypeDescriptor 和 TypeDescriptionProvider 类。您只需添加一次提供程序,例如应用程序初始化。

How to add the EditorAttribute (Editor) to an object's property at run-time?

I have My.Settings.ExcludeFiles, which is created by the settings designer as Public Property ExcludedFiles() As Global.System.Collections.Specialized.StringCollection. When editing ExcludedFiles via a property grid, the "String Collection Editor" generates a "Constructor on type 'System.String' not found" run-time exception.

I cannot change the attributes of the ExcludeFiles property because they will be overwritten the next time any setting changes are made. Therefore, I must attach/add the Editor/EditorAttribute at run-time.

What I want to do is add the StringCollectionEditor at run-time, shown below as design-time attribute.

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

Solutions

Method #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)))

You only have to add this attribute once, such as application initialization.

Method #2

More flexible. See Nicolas Cadilhac
answer below at Adding Editor / EditorAttribute at Run-time (Dynamically) to an Object's Property. It uses derived CustomTypeDescriptor and TypeDescriptionProvider classes. You only have to add the provider once, such as application initialization.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

許願樹丅啲祈禱 2024-08-25 00:25:28

在给你第一个答案后,我想起了 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)))

所以也许你应该取消选中我之前的答案并确认这个作为解决方案(尽管所有功劳都归于马克)。但当您需要使用 TypeDescriptor 做更复杂的事情时,我的上一篇文章仍然为您提供了一个很好的技术。

After giving you my first answer, I remembered another solution given by Marc Gravell that I even commented. Believe it or not, you just need to call TypeDescriptor.AddAttributes().

This is here: How do I inject a custom UITypeEditor for all properties of a closed-source type?.

For your case it gives:

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

So maybe you should uncheck my previous answer and confirm this one as the solution (although all the credit goes to Marc). But my previous post still gives you a good technique when you need to do more complex stuff with a TypeDescriptor.

我不会写诗 2024-08-25 00:25:28

是的,可以动态更改 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) });
}

我希望这会有所帮助。

Yes it is possible to dynamically change a TypeDescriptor so that you return the UITypeEditor you want. This is explained in this article. But note that it will add it for all properties of this type.

I grabbed the code from here and roughly changed it for the following:

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

Then you register your provider:

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

This works well, except that it will make you discover that you have another issue: MultilineStringEditor is an editor that works with the String type, not with the StringCollection type. What you actually need is the private StringCollectionEditor in the .Net framework. So let's replace GetEditor by:

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

I hope this helps.

灯角 2024-08-25 00:25:28

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

You can't. An attribute can only be defined at compile time (unless you generate the type dynamically of course)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文