Как WinForms PropertyGrid находит пользовательские преобразователи типов во внешних библиотеках?

У нас есть индивидуальный контроль. Некоторые свойства этого элемента управления используют пользовательские преобразователи типов и редакторы типов пользовательского интерфейса, и они реализованы в отдельной библиотеке DLL времени разработки. Эти преобразователи типов определяются с использованием строкового синтаксиса атрибута TypeConverter и Editor, например:

[TypeConverter("<full class name>, <library name>, Version=<version>")]
public CustomType Property1
{
    // property implementation
}

Когда мы отображаем свойства нашего пользовательского элемента управления в стандартном элементе управления PropertyGrid из пакета WinForms в скомпилированном приложении, соответствующие преобразователи типов и редакторы типов пользовательского интерфейса из нашей DLL времени разработки обнаруживаются только тогда, когда мы помещаем эту DLL в папку, содержащую приложение exe. Мы не хотим дублировать DLL времени разработки в этой папке по некоторым причинам. Есть ли другой способ сообщить элементу управления PropertyGrid, где он может найти библиотеку DLL времени разработки, на которую ссылается этот путь?


person TecMan    schedule 17.05.2019    source источник
comment
Эта DLL должна быть найдена с помощью правил проверки Visual Studio, что очень проблематично. Единственный достойный вариант - поместить его в GAC. Обратите внимание, что вы это уже знали.   -  person Hans Passant    schedule 17.05.2019
comment
@HansPassant, мой предыдущий вопрос касался этой темы о VS IDE, но теперь я спрашиваю о времени выполнения. Думал, может быть какая-то разница, особенно учитывая тот факт, что мы говорим об элементе управления PropertyGrid.   -  person TecMan    schedule 17.05.2019
comment
Используйте событие AppDomain.AssemblyResolve, чтобы помочь CLR найти сборку во время выполнения.   -  person Hans Passant    schedule 17.05.2019
comment
@HansPassant, вы сами подтвердили, что есть разница с IDE :) Кстати, раздел реестра AssemblyFoldersEx и помещение DLL времени разработки в папку VS PrivateAssemblies также не работают в случае скомпилированного exe. Добавьте ко всему этому, что мы разворачиваем наше приложение не под пользователем с правами администратора.   -  person TecMan    schedule 18.05.2019
comment
Просмотрите ‹probing› Элемент и документацию по ‹codeBase› Element и посмотрите, сможете ли вы заставить ее работать в вашем случае использования.   -  person TnTinMn    schedule 18.05.2019


Ответы (1)


Вы можете использовать любой из следующих вариантов:

  • Установите сборку в GAC и украсьте свойство следующим образом (используйте полное имя сборки). Как уже упоминалось в комментариях Ганса, я также считаю, что это самый достойный способ:

    [TypeConverter("MyAssembly.MyClassTypeConverter, MyAssembly, Version=1.0.0.0," +
        " Culture=neutral, PublicKeyToken=8ac69aab03bb290e")]
    public MyClass MyClass { get; set; }
    
  • Скопируйте сборки в папку вашего приложения и украсьте свойство следующим образом.

    [TypeConverter("MyAssembly.MyClassTypeConverter, MyAssembly")]
    public MyClass MyClass { get; set; }
    
  • В случае наличия известного местоположения сборок вы можете обрабатывать AppDomain.AssemblyResolve и загрузите сборку. Например, предполагая, что в папке вашего приложения есть папка assemblies, содержащая сборку, вы можете добавить следующий код в свой основной метод перед Application.Run:

    AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
        Assembly.LoadFrom(Path.Combine(Application.StartupPath,
            "assemblies", $"{e.Name}.dll"));
    

    Я предполагаю, что у вас есть объявление свойства:

    [TypeConverter("MyAssembly.MyClassTypeConverter, MyAssembly")]
    public MyClass MyClass { get; set; }
    
  • Как уже упоминалось в комментариях TnTinMn, в случае наличия известного местоположения для сборок вы также можете загружать сборки без написания кода, зарегистрировав известную папку в своем app.config, используя probing или codebase. Например, предположим, что в папке вашего приложения есть папка assemblies, содержащая сборку:

    <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <probing privatePath="assemblies"/>
      </assemblyBinding>
    </runtime>
    

    Я предполагаю, что у вас есть объявление свойства:

    [TypeConverter("MyAssembly.MyClassTypeConverter, MyAssembly")]
    public MyClass MyClass { get; set; }
    

Примечание. Ни один из приведенных выше вариантов не требует добавления ссылки на сборку, содержащую преобразователь типов.

person Reza Aghaei    schedule 18.05.2019