Абстрактное наследование UserControl в дизайнере Visual Studio

abstract class CustomControl : UserControl { protected abstract int DoStuff(); } class DetailControl : CustomControl { protected override int DoStuff() { // do stuff return result; } } 

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

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

 class CustomControl : UserControl { protected virtual int DoStuff() { throw new InvalidOperationException("This method must be overriden."); } } class DetailControl : CustomControl { protected override int DoStuff() { // do stuff return result; } } 

У кого-нибудь есть лучшая идея о том, как решить мою проблему?

Вы можете использовать TypeDescriptionProviderAttribute, чтобы обеспечить конкретную реализацию времени исполнения для вашего абстрактного базового classа. Подробнее см. http://wonkitect.wordpress.com/2008/06/20/using-visual-studio-whidbey-to-design-abstract-forms/ .

Что мы хотим

Сначала давайте определим последний class и базовый абстрактный class.

 public class MyControl : AbstractControl ... public abstract class AbstractControl : UserControl // Also works for Form ... 

Теперь нам нужен поставщик описания .

 public class AbstractControlDescriptionProvider : TypeDescriptionProvider { public AbstractControlDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(TAbstract))) { } public override Type GetReflectionType(Type objectType, object instance) { if (objectType == typeof(TAbstract)) return typeof(TBase); return base.GetReflectionType(objectType, instance); } public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { if (objectType == typeof(TAbstract)) objectType = typeof(TBase); return base.CreateInstance(provider, objectType, argTypes, args); } } 

Наконец, мы просто применяем атрибут TypeDescriptionProvider к элементу управления Abstract.

 [TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider))] public abstract class AbstractControl : UserControl ... 

Вот и все. Не требуется никакого среднего контроля.

И class провайдера может быть применен к множеству абстрактных баз, которые мы хотим в одном решении.

Другой способ решить эту проблему – использовать директивы предварительной обработки.

 #if DEBUG public class UserControlAdmonEntidad : UserControl, IAdmonEntidad #else public abstract class UserControlAdmonEntidad : UserControl, IAdmonEntidad #endif { ... #if DEBUG public virtual object DoSomething() { throw new NotImplementedException("This method must be implemented!!!"); } #else public abstract object DoSomething(); #endif ... } 

См. Эту ссылку для получения дополнительной информации по этой теме: Наследование формы из абстрактного classа (и внесение его работы в конструктор)

То же самое решение было упомянуто и в этой ветке форума MSDN, вкратце: UserControl, Inherited Control, Abstract class, (C #)

Возможно, это не чистое решение, но оно все же самое короткое, что я нашел.

Ниже приводится общее решение, которое работает для меня, в основном. Он основан на статье из другого ответа. Иногда это будет работать, и я могу создать свой UserControl , а затем позже я открою файл, и он предоставит «Дизайнер должен создать экземпляр типа« MyApp.UserControlBase », но он не может, потому что тип объявлен как абстрактный «. Я думаю, что могу исправить это, очистив, закрыв VS, повторно открыв VS и перестроить. Сейчас это похоже на поведение. Удачи.

 namespace MyApp { using System; using System.ComponentModel; ///  /// Replaces a class of  with a class of ///  during design. Useful for /// replacing abstract s with mock concrete /// subclasses so that designer doesn't complain about trying to instantiate /// abstract classes (designer does this when you try to instantiate /// a class that derives from the abstract . /// /// To use, apply a  to the /// class , and instantiate the attribute with /// SwitchTypeDescriptionProvider{T, TReplace}). /// /// Eg: ///  /// [TypeDescriptionProvider(typeof(ReplaceTypeDescriptionProvider{T, TReplace}))] /// public abstract class T /// { /// // abstract members, etc /// } /// /// public class TReplace : T /// { /// // Implement 's abstract members. /// } ///  /// ///  ///  /// The type replaced, and the type to which the ///  must be /// applied ///  ///  /// The type that replaces . ///  class ReplaceTypeDescriptionProvider : TypeDescriptionProvider { public ReplaceTypeDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(T))) { // Nada } public override Type GetReflectionType(Type objectType, object instance) { if (objectType == typeof(T)) { return typeof(TReplace); } return base.GetReflectionType(objectType, instance); } public override object CreateInstance( IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { if (objectType == typeof(T)) { objectType = typeof(TReplace); } return base.CreateInstance(provider, objectType, argTypes, args); } } } 

Несмотря на то, что этот вопрос лет, я хотел бы добавить то, что нашел.

Если вы не хотите касаться своего абстрактного базового classа, вы можете сделать это:

 abstract class CustomControl : UserControl { protected abstract int DoStuff(); } class BaseDetailControl : CustomControl { protected override int DoStuff() { throw new InvalidOperationException("This method must be overriden."); } } class DetailControl : BaseDetailControl { protected override int DoStuff() { // do stuff return result; } } 

Таким образом, ваша форма наследуется от не абстрактной базовой формы и отображается в дизайнере! И вы сохраняете свою абстрактную форму, но только еще один уровень в наследстве. Странно, не так ли?

Я не мог сделать работу решением «Николь Калиною». Но есть и другой простой способ непосредственно в визуальной студии 🙂

  1. Создать новый проект
  2. Добавьте новый элемент ‘userControl’ и добавьте одну кнопку, например
  3. Добавьте новый элемент ‘userControl’ Inhereted UserControl, затем выберите inhereted userControl.

Подробнее здесь: « http://www.codeproject.com/Articles/20845/How-to-derive-from-a-parent-form

Я просто делаю абстрактный базовый class конкретным, определяя «абстрактные» методы как виртуальные и бросая в них исключение, на всякий случай, когда какие-либо непослушные производные classы пытаются вызвать реализацию Base.

например

  class Base : UserControl { protected virtual void BlowUp() { throw new NotSupportedException("This method MUST be overriden by ALL derived classes."); } class Derived : Base { protected override void BlowUp() { // Do stuff, but don't call base implementation, // just like you wouldn't (can't actually) if the Base was really abstract. // BTW - doesn't blow up any more ;) } 

Основная практическая разница между этим и реальным абстрактным базовым classом заключается в том, что вы получаете ошибки времени выполнения при вызове базовой реализации, тогда как если бы База была фактически абстрактной, компилятор запретил бы случайные вызовы реализации базового classа. Для меня это не очень важно и позволяет мне использовать дизайнера, не беспокоясь о более сложных и трудоемких работах, предлагаемых другими …

PS – Akuma – вы должны иметь возможность редактировать свой абстрактный пользовательский интерфейс в дизайнере. У меня нет времени, чтобы проверить это прямо сейчас, но я понимаю, что дизайнеру нужно только создать экземпляр classа BASE. Пока база classа, который вы проектируете, конкретна, не имеет значения, что такое class разработки.

Я разрешил эту проблему в UWP в своем настраиваемом элементе управления.

Мое дело

 public abstract class BaseModel : DependencyObject { ... } public class MainModel : BaseModel { public bool ShowLabel { get{ return (bool)GetValue(ShowLabelProperty); } set{ SetValue(ShowLabelProperty, value) } } public static readonly DependencyProperty ShowLabelProperty = DependencyProperty.Register("ShowLabel",typeof(bool), typeof(MainModel), new PropertyMetadata(false)); } 

декларация

 < MyCustomControl:MainModel ShowLabel=True /> 

Решение

Просто переопределите фиктивный стиль в общих ресурсах.

  

С Уважением,

Самуил

Я был знаком с этим в UWP, и это приводило меня в бешенство. Я не думал об абстрактном базовом classе для UserControl. Я пошел в другом направлении. Я создал class не-xaml Helper … HBase . Каждый вид, например VContract , имел соответствующего помощника, называемого HContract . Здесь был указан весь код специальности для каждого вида. Разговоры, которые были бы между ViewModel VMContract и View VContract теперь проходят через HContract . Мы можем обеспечить, как HWhatever себя ведет с IHBase . Это не ответ на вопрос OP, но он показывает альтернативный подход. Все Представления теперь являются в основном shellми. Если вы x: VContract к VContract или HContract – это решение для вас. Я выбрал способ VContract , и, в конце концов, я думаю, что это была ошибка.

Проблема UWP с исключениями в режиме проектирования теперь легко фиксируется с помощью:

 if (false == Windows.ApplicationModel.DesignMode.DesignModeEnabled) { HContract = new HContract(this); // Put code here that fails in Design mode but must at run time } 
Interesting Posts

Перетаскивание элементов в RecyclerView с помощью GridLayoutManager

Каков наилучший формат файла / скорость передачи битов для копирования треков с компакт-диска в iTunes?

Что такое «этот» указатель?

как реализовать основную функцию в polymerных приложениях

Как преобразовать / сохранить график d3.js в pdf / jpeg

Является ли создание компьютерного шасси из чистого LEGO опасным?

Отправлять данные по маршрутным маршрутам в Угловом

Управление полосой пропускания при использовании GPRS в Windows 7

Как сохранить пробелы в конце и / или в начале строки?

Терминальный эмулятор с разделенными панелями для Windows 7 (64 бит)

PreparedStatement со списком параметров в предложении IN

Ошибка компиляции Maven: (используйте оператор 7 или выше для включения оператора бриллианта)

Почему изображение Tkinter не отображается, если оно создано в функции?

Получить методы classа с использованием отражения

Как я могу различать эти две ситуации сертификата?

Давайте будем гением компьютера.