2012-04-26 2 views
1

У меня есть абстрактный класс, который используется для получения десятков других классов, каждый класс делает похожие, но немного разные вещи. Этот класс загружается Reflection и отображается пользователю, чтобы выбрать, какой из них ему нужно запустить.Вызвать унаследованный метод из его базового класса

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

Моя проблема в том, что мне нужно показать пользовательский интерфейс для каждого из этих производных классов. Я думал создать пользовательский UserControl для каждого из них. У этих элементов управления будет метод puclic, который возвращает мне значение, основанное на том, что пользователь сделал на нем. Затем я создаю этот элемент управления во время выполнения, пользователь устанавливает то, что необходимо, и я вызываю метод return из этого элемента управления, и я могу, наконец, передать i методу Run Run из класса, который пользователь выбрал и выполнил.

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

Из-за этого, я думаю, мне пришлось бы создавать эти настраиваемые элементы управления в форме как общий класс UserControl, а затем использовать их как действительный тип. Но есть ли способ сделать это, только зная, что контроль был получен из UserControl?

Я могу создать публичное свойство в базовом классе для хранения своего настраиваемого элемента управления, но обратно в основной код можно ли использовать общий пользовательский элемент управления как тип, хранящийся в этом свойстве?

Кроме того, будет проблема с дизайном здесь? Могу ли я использовать другие подходы для этого?

Я надеюсь, что это не звучит очень запутанным :(

+1

Есть ли существующие плагины? (т. е. вам нужно беспокоиться о обратной совместимости?) – Cameron

+2

Это более чем возможно, и вы на правильном пути - с помощью дженериков вы можете избежать многих проблем с кастом (посмотрите на общие ограничения) и разрешите пользователю определять пользовательский интерфейс usercontrol (им нужно будет указать ascx в классе, который они создали, который использовал ваш класс Generic Base в качестве шаблона) –

+0

Не можете ли вы просто потребовать от своих пользовательских элементов управления реализовать интерфейс? Затем вы можете заранее знать, какой метод вызывать для получения данных. – Tejs

ответ

3

я бы понял вас, но это то, что я имею в виду:

public abstract class BaseClass<T> where T: UserControl, IMyControl 
{ 
    private Page _page; 
    protected T Control { get; private set;} 

    public BaseClass(Page page, string controlPath) 
    { 
     _page = page; 
     Control = (T)page.LoadControl(controlPath); 
     _page.Controls.Add(Control); 
    } 

    public void Run() 
    { 
     var data = Control.GetData(); 
    } 
} 

public interface IMyControl 
{ 
    object GetData(); 
} 
+0

Я попытался использовать ваш код, но System.Windows.Controls.Page не имеет метода LoadControl. Только System.Web.Ui.Page имеет. Поскольку я уже работаю с пространством имен System.Windows, будет ли вред смешать оба? – RBasniak

+0

Если я понял ваш код, я должен создать страницу внутри окна (которая покажет мои пользовательские элементы управления), тогда я передам ссылку этой страницы на мой базовый класс, который загрузит элемент управления на этой странице Object. Правильно? – RBasniak

+0

Yeh, этот пример кода предназначен для веб-приложения, поскольку вы не указали. Но я уверен, что вы можете использовать тот же принцип для приложения win forms. – Magnus

1

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

Затем вы можете добавить этот UserControl в Панель или какой-либо другой контейнер фактически не заботясь о том, какой именно UserControl он имеет. Если есть определенные методы, которые вы хотите использовать для этого UserControl, например Save или Load, вы можете добавить их как виртуальные методы в свой базовый класс, который происходит из UserControl.

+0

Я подумал об этом, но тогда на моем абстрактном базовом классе мне этот метод придется возвращать тип UserControl, потому что базовый класс не знает имя управляемого элемента управления. Поскольку я вызываю все методы из базового класса, у меня не будет доступа к методу CreateControl из типа UserControl. Я правильно понял? – RBasniak

+0

Почему базовому классу необходимо знать имя управляемого элемента управления? – Nick

+0

Потому что ему нужно вызвать метод, который существует только в производном элементе управления. Или, может быть, есть способ вызвать метод на производном классе? – RBasniak

0

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

Каждый класс, производный от BaseClass имеет переопределение метода GetControl. Этот метод возвращает новый экземпляр UserControl, разработанный специально для этого класса.

Когда пользователь выбирает производный класс, я вызываю метод GetControl, и я добавляю этот элемент управления в форму. Затем отображается разработанный пользовательский интерфейс для класса. Этот элемент управления удаляется, если другой класс выбирается, и новый пользовательский интерфейс создается для этого другого класса.

Чтобы прочитать настройки, сделанные пользователем в элементе управления, я применил метод ReadData для каждого UserControl.Чтобы вызвать этот метод с уровня объекта, я использовал отражение:

Object ui = FindControlByName("SelectedClassUI"); 
Type t = ui.GetType(); 
MethodInfo m = t.GetMethod("ReadData"); 
Object userSetup = m.Invoke(ui, null); 

<... do something with userSetup ...> 
Смежные вопросы