Исправить встроенные ресурсы для универсального UserControl - PullRequest
23 голосов
/ 27 октября 2009

Во время рефакторинга я добавил параметр общего типа в MyControl, класс, производный от UserControl . Так что мой класс сейчас MyControl<T>.

Теперь я получаю сообщение об ошибке, в котором говорится, что встроенный файл ресурсов MyControl & # x60; 1.resources не найден. Быстрый просмотр .NET Reflector показывает, что файл ресурсов на самом деле называется MyControl.resources , без & # x60; 1 .

В начале метода MyControl<T>.InitializeComponent есть строка, которая, вероятно, вызывает проблемы:

 System.ComponentModel.ComponentResourceManager resources =
    new System.ComponentModel.ComponentResourceManager(
       typeof(MyControl<>));

Как заставить ComponentResourceManager использовать встроенный файл ресурсов MyControl.resources? Другие способы решения этой проблемы также приветствуются.

Ответы [ 4 ]

18 голосов
/ 27 октября 2009

Оказывается, вы можете переопределить имя файла ресурса для загрузки, наследуя от ComponentResourceManager следующим образом:

   using System;
   using System.ComponentModel;

   internal class CustomComponentResourceManager : ComponentResourceManager
   {
      public CustomComponentResourceManager(Type type, string resourceName)
         : base(type)
      {
         this.BaseNameField = resourceName;
      }
   }

Теперь я могу убедиться, что менеджер ресурсов загружает MyControl.resources следующим образом:

 System.ComponentModel.ComponentResourceManager resources =
    new CustomComponentResourceManager(typeof(MyControl<>), "MyControl");

Кажется, это работает.

edit : строка выше перезаписывается, если вы используете конструктор, потому что она находится в сгенерированный код региона. Я избегаю конструктора и использую инструменты контроля версий, чтобы отменить любые нежелательные изменения, но решение не идеальное.

16 голосов
/ 13 февраля 2013

В дополнение к технике Вима вы также можете объявить неуниверсальный базовый элемент управления с тем же именем, что и у вашего универсального класса, и получить ваш универсальный элемент управления / форму из этого неуниверсального базового класса.

Таким образом, вы можете обмануть и проектировщика, и компилятор в использовании файла ресурсов из вашего универсального класса, и вы получите постоянную поддержку конструктора после настройки базового класса без необходимости перебирать файл .designer при каждой перестройке:

// Empty stub class, must be in a different file (added as a new class, not UserControl 
// or Form template)
public class MyControl : UserControl
{
}

// Generic class
public class MyControl<T> : MyControl
{
     // ...
}

Единственным требованием является наличие точно одного и того же имени для вашего универсального класса и его базового класса, и что базовый класс должен находиться в другом файле класса, в противном случае дизайнер жалуется на отсутствие одного из два класса.

PS. Я проверил это с формами, но оно должно работать так же с элементами управления.

4 голосов
/ 27 октября 2009

На моем Visual Studio 2008 У меня есть эта ошибка:

System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager (typeof (MyControl));

Для использования универсального типа «WindowsFormsApplication1.UserControl1» требуются аргументы типа «1».

Обратите внимание, что в моем случае код был создан без скобок, <>, после имени класса.

Это становится интересным, см. ImageList автоматически генерирует некомпилируемый код в универсальном пользовательском элементе управления .

То, что они сказали:

Сообщение от Microsoft 6.07.2005 в 14:49

Это интересная ошибка. Вы столкнулись с общим scneario, который мы не поддерживаем в конструкторе Windows Forms. Мы не сможем добавить поддержку для этого в выпуске Whidbey (моя заметка: Visual Studio 2008?). Мы рассмотрим это для будущей версии. В качестве обходного пути вы можете использовать конструктор для создания не универсального UserControl с открытым свойством Type, а затем создать универсальный класс, который наследуется от него и передает T в свойство Type базовых классов.

Полагаю, этот элемент управления также нельзя спроектировать в конструкторе форм Visual Studio.

3 голосов
/ 12 августа 2013

Самый простой и легкий обходной путь - создать фиктивный класс для автоматически сгенерированного typeof(). Вам не нужно наследовать от него или даже выставлять его наружу:

// Non-generic name so that autogenerated resource loading code is happy
internal sealed class GridEditorForm
{
}

(По моему опыту, время, затрачиваемое дизайнером на то, чтобы обойти дженерики, не стоило идеальной крутости, которую могут обеспечить дженерики. Я больше не буду использовать универсальные формы или элементы управления окнами.)

...