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