Подтвердить что ты не робот

Исправить встроенные ресурсы для общего UserControl

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

Now я get an error at runtime stating that the embedded resource file MyControl`1.resources cannot be found. A quick look with .NET Reflector shows that the resource file is actually called MyControl.resources, without the `1.

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

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

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

4b9b3361

Ответ 1

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

Таким образом, вы можете обмануть как разработчика, так и компилятора в использовании файла ресурсов из вашего универсального класса, и вы получите постоянную поддержку дизайнера после того, как базовый класс настроен без необходимости возиться в файле .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. Я тестировал это с помощью форм, но он должен работать одинаково с элементами управления.

Ответ 2

Оказывается, вы можете переопределить имя файла ресурса для загрузки, наследуя от 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: указанная выше строка перезаписывается, если вы используете конструктор, потому что он находится в сгенерированной области кода. Я избегаю конструктора и использую инструменты управления версиями, чтобы отменить любые нежелательные изменения, но решение не идеально.

Ответ 3

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

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

Использование общего типа "WindowsFormsApplication1.UserControl1" требует аргументов типа "1".

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

Это становится интересным, см. ImageList автоматически генерирует некомпилирующий код в Generic User Control.

Что они сказали:

Отправлено Microsoft 7/6/2005 в 14:49

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

Я полагаю, что этот элемент управления не может быть разработан в дизайнере Visual Studio.

Ответ 4

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

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

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