Передать управление форме-владельцу можно следующим образом:
public delegate void SearchModuleDelegate(int recordCount); public class MyPage : System.UI.WebControls.Page { protected SeachModule SeachModule1; public void PageLoad() { // подключение делегата к компоненту SeachModule1.Action = new SearchModuleDelegate(DoSearchModuleAction); } private void DoSearchModuleAction(int recordCount) { // здесь выполняется реальная работа } } public class SeachModule : System.UI.WebControls.Control { public SearchModuleDelegate Action = null; private void Button1_Click() { if (Action != null) Action(Search()); } private int Search() { return 0; } }
Некоторые пояснения:
-
в качестве делегата выступает приватный метод DoSearchModuleAction; в общем случае может использоваться не только метод экземпляра класса формы, но и статический метод формы или даже метод другого класса;
-
подключение делегата к компоненту выполняется в методе PageLoad формы-владельца.
Интересная возможность, присущая делегатам, - подключать несколько делегатов:
delegate void D(int x); class C { public static void M1(int i) { /* ... */ } public static void M2(int i) { /* ... */ } } class Test { static void Main() { D cd1 = new D(C.M1); // M1 D cd2 = new D(C.M2); // M2 D cd3 = cd1 + cd2; // M1 + M2 D cd4 = cd3 + cd1; // M1 + M2 + M1 D cd5 = cd4 + cd3; // M1 + M2 + M1 + M1 + M2 } }
Примечание: Пример взят из раздела 15.1 спецификации языка C#.
Генерация событий
Использование событий мало чем отличается от рассмотренного выше варианта, т.к. обработчики событий представляют собой не что иное, как стандартизованные (по типу возвращаемого значения и набору параметров) делегаты:
public delegate void SearchEventHandler(object sender, SearchEventArgs e); public class SearchEventArgs : System.EventArgs { public readonly int RecordCount; public SearchEventArgs(int recordCount) : base() { RecordCount = recordCount; } } public class MyPage : System.UI.WebControls.Page { protected SeachModule SeachModule1; public void PageLoad() { // подключение обработчика события к компоненту SeachModule1.Action += new SearchEventHandler(DoSearchModuleAction); } private void DoSearchModuleAction(object sender, SearchEventArgs e) { // здесь выполняется реальная работа } } public class SeachModule : System.UI.WebControls.Control { public event SearchEventHandler Action; private void Button1_Click() { if (Action != null) Action(this, new SearchEventArgs(Search())); } private int Search() { return 0; } }
Отличия от использования делегатов:
-
обработчик события представляет собой делегат SearchEventHandler; для обработчиков событий: тип возвращаемого значения void, параметр sender - объект, сгенерировавший событие, параметр e - аргументы события;
-
для передачи в событии специфических данных создается класс аргументов события SearchEventArgs, наследованный от System.EventArgs;
-
подключение делегата к компоненту выполняется в методе PageLoad формы-владельца; при этом используется специальный синтаксис подключения обработчика - оператор +=
-
точка подключения обработчика события Action в компоненте описывается с использованием ключевого слова event; в результате вне класса SeachModule можно использовать только операторы += и -=, что исключает, например, случайное обнуление.
Как недостаток, - при использовании стандартной схемы обработки событий может возникать необходимость в написании специализированных классов-наследников от System.EventArgs. Впрочем, написания специализированных аргументов события можно избежать, если использовать, например, свойства компонента (ниже приводится модифицированный пример обработчика события):
public class MyPage : System.UI.WebControls.Page { protected SeachModule SeachModule1; public void PageLoad() { // подключение обработчика события к компоненту SeachModule1.Action += new EventHandler(DoSearchModuleAction); } private void DoSearchModuleAction(object sender, EventArgs e) { int recordCount = (sender is SeachModule) ? ((SeachModule) sender).RecordCount : -1; // TODO: add code to interpret recordCount } } public class SeachModule : System.UI.WebControls.Control { public event EventHandler Action; private int recordCount = -1; private void Button1_Click() { if (Action != null) { recordCount = Search(); Action(this, null); } } private int Search() { // TODO: add code to search person return 0; } public int RecordCount { get { return recordCount; } } }
Выводы
Обработчики событий являются "стандартом де-факто", поэтому их использование в большинстве случаев должно быть понятно любому стороннему разработчику, что является очевидным преимуществом с точки зрения сопровождения или отчуждения исходного текста.
В некоторых случаях, например, если программный продукт разрабатывается не для отчуждения и внутренние стандарты компании предусматривают соответствующие решения, можно использовать более простые схемы: делегаты и/или интерфейсы.
Использование механизма наследования для реализации взаимодействия компонентов и форм не рекомендуется.