Добавление Editor / EditorAttribute во время выполнения (динамически) к свойству объекта - PullRequest
4 голосов
/ 11 января 2010

Как добавить 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))> _

* Решения 1018 * Метод № 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 Более гибкий. Увидеть Николя Кадилхака ответ ниже на Добавление Editor / EditorAttribute во время выполнения (динамически) к свойству объекта . Он использует производные классы CustomTypeDescriptor и TypeDescriptionProvider. Вы должны добавить провайдера только один раз, например, инициализацию приложения.

Ответы [ 3 ]

6 голосов
/ 11 января 2010

После того как я дал вам мой первый ответ, я вспомнил другое решение, данное Марком Гравеллом, которое я даже прокомментировал. Хотите верьте, хотите нет, вам просто нужно вызвать 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.

0 голосов
/ 11 января 2010

Да, можно динамически изменять 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. Что вам на самом деле нужно, так это закрытый StringCollectionEditor в .Net framework. Итак, давайте заменим 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) });
}

Надеюсь, это поможет.

0 голосов
/ 11 января 2010

Вы не можете. Атрибут может быть определен только во время компиляции (если, конечно, вы не генерируете тип динамически)

...