C# для профессионалов. Том II - Симон Робинсон
Шрифт:
Интервал:
Закладка:
Важная деталь — в .NET события могут иметь более одного обработчика. Это означает, что если создать другой делегированный метод, соединить его с помощью нового экземпляра System.EventHandler, то оба метода будут вызываться в момент порождения события. Конечно, методы не вызываются одновременно, так как фактически получится мультипоточное приложение, а это не то, что хотелось бы случайно получить.
Мы не определили, как выглядит наша функция AddToLog,— сделаем это сейчас:
// AddToLog — обновляет представление журнала ...
private void AddToLog(String buf) {
// обновляет элемент управления журнала ...
txtLog.Text = (buf + "rn" + txtLog.Text);
}
Теперь давайте попробуем выполнить приложение и понажимать на кнопки:
Другие обработчикиОбработчики, которые отвечают на другие события в DynamicButton, могут быть добавлены аналогичным образом. Прежде всего для каждого из них создается метод:
// DynamicButton_Enter ...
protected void DynamicButton_Enter(object sender, System.EventArgs e) {
// преобразовать sender в button ...
DynamicButton button = (DynamicButton)sender;
// msgbox ...
AddToLog("Enter " + button.DynamicId);
}
// DynamicButton_Leave ...
protected void DynamicButton_Leave(object sender, System.EventArgs e) {
// преобразовать sender в button ...
DynamicButton button = (DynamicButton)sender;
// msgbox ...
AddToLog("Left " + button.DynamicId);
}
Затем можно добавить обработчики для каждого из них:
// соединить обработчик
newButton.Click +=
new System.EventHandler(this.DynamicButton_Click);
newButton.MouseEnter +=
new System.EventHandler(this.DynamicButton_Enter);
newButton.MouseLeave +=
new System.EventHandler(this.DynamicButton_Leave);
Теперь, если снова выполнить приложение, в журнал будут добавляться сообщения по мере перемещения по кнопкам.
Другой пример
Разобрав пример создания динамических элементов управления, давайте посмотрим, как эта техника может использоваться в приложениях.
Динамические элементы управления можно использовать для настройки интерфейса пользователя приложения в зависимости от некоторых данных среды выполнения. Классическим примером этого является добавление новых возможностей в панель инструментов, когда в каталог приложения вносятся новые дополнительные средства (plug-ins) или модули. Например, установка Adobe Acrobat на компьютере может автоматически добавлять в панель инструментов Word кнопку для создания документа Acrobat.
Другим примером может быть утилита администрирования базы данных. Когда утилита соединяется с базой данных, в интерфейс пользователя должна быть добавлена кнопка, представляющая каждую имеющуюся внутри базы данных таблицу. Или можно создать множество элементов управления текстовых полей с именами всех файлов XML, содержащихся в определенном каталоге, и т.д.
В этом примере мы собираемся создать приложение, загружающее с диска сборку, просматривающее сборку в поисках типов данных, которые наследуют от System.Windows.Forms.Control, и выводящее кнопку в форме для каждого найденного типа. Нажатие на кнопку будет вызывать экземпляр элемента управления и выводить его в форму.
Создание проектаСоздадим новый проект Visual C# — Windows Application и назовем его ControlLoader. В самом начале мы не будем размещать в новой форме никаких элементов управления, но можем изменить свойство Text на что-нибудь типа "Control Container".
Итак, добавим следующие члены в форму:
public class Form1 : System.Windows.Forms.Form {
// члены ...
private ArrayList _buttons = new ArrayList();
private int _nextY = ButtonSpacing;
private Control _containedControl;
// константы ...
const int ButtonHeight = 25;
const int ButtonSpacint = 5;
const int ButtonWidth = 200;
Мы имеем список кнопок, которые добавляются в ArrayList с именем _buttons. При добавлении каждой кнопки к форме необходимо разместить ее в правильной у-координате, т.е. _nextY. Рассмотрим только один элемент управления в конкретный момент, который будет содержаться в _containedControl. Наконец, мы используем метрику, которая описывает компоновку кнопок, и она задается тремя константами внизу.
Сами кнопки будут создаваться из нового класса, производного от System.Windows.Forms.Button. Этот новый класс называется TypeButton и имеет дополнительное свойство ControlType, которое содержит объект System.Type. Этот объект Type представляет элемент управления в загружаемой сборке. Создадим новый класс с именем TypeButton и добавим ссылку на пространство имен System.Windows.Forms.
using System;
using System.Windows.Forms;
Затем добавим код:
public class TypeButton System.Windows.Forms.Button {
public Type _controlType;
public TypeButton() {
}
// ControlType — получить или задать свойство ...
public Type ControlType {
get {
return _controlType;
}
set {
_controlType = value;
this.Text = _controlType.FullName;
}
}
}
Как можно видеть, задавая свойство ControlType, мы изменяем текст кнопки, чтобы он стал полным названием типа.
Метод, который нужен для создания TypeButton, создает экземпляр элемента управления. Добавим этот метод, использующий System.Activator для создания экземпляра класса и преобразующий его в System.Windows.Forms.Control:
// CreateInstance — создание экземпляра типа данных ...
public Control CreateInstance() {
// возвращает экземпляр нового элемента управления ...
return (Control)Activator.CreateInstance(ControlType);
}
Добавление кнопокДля первого проверочного запуска добавим TypeButton, который представляет экземпляр элемента управления System.Windows.Forms.DataGrid. Это позволит протестировать логику того, что делается, не вдаваясь в дополнительные трудности, связанные с загрузкой сборки и просмотром типов данных.
Метод Form1.AddType будет получать объект System.Type и добавлять новый объект TypeButton в форму. Во-первых, необходимо создать экземпляр TypeButton и задать его свойство ControlType новым типом:
// AddType - добавить кнопку типа в компоновку ...
public void AddType(Type ControlType) {
// первое: создать новую кнопку типа ...
TypeButton button = new TypeButton();
button.ControlType = ControlType;
Во-вторых, нужно добавить TypeButton в ArrayList, который содержит список кнопок:
// второе: добавить эту кнопку в массив
_buttons.Add(button);
После этого можно поместить в форму кнопку и добавить ее в список элементов управления формы:
// теперь разместим кнопку
button.Left = ButtonSpacing;
button.Width = ButtonWidth;
button.Top = _nextY;
button.Height = ButtonHeight;
// настроить следующее значение у ...
_nextY += (ButtonHeight + ButtonSpacing);
// вывести кнопку ...
this.Controls.Add(button);
Наконец, необходимо присоединить событие click (нажатие) кнопки таким образом, чтобы мы могли иметь экземпляр элемента управления, который он представляет:
// затем присоединяем обработчик события ...
button.Click += new EventHandler(this.ButtonClick);
}
Пока еще мы не создали ButtonClick, — сделаем это сейчас:
// ButtonClick — вызывается всякий раз при нажатии кнопки ...
protected void ButtonClick(object sender, System.EventArgs e) {
// преобразовать sender в кнопку типа ...
TypeButton button = (TypeButton)sender;
Нашей первой задачей является преобразование sender в TypeButton. Это позволит использовать CreateInstance для создания элемента управления. Если мы уже имеем элемент управления, необходимо сначала удалить его из списка элементов управления формы:
// если уже имеется содержащийся элемент управления, удалим его ...
if (_containedControl != null)
Controls.Remove(_containedControl);
Создаем элемент управления:
// создать экземпляр нового элемента управления...
_containedControl = button.CreateInstance();
Наконец, мы можем поместить элемент управления в форму.
// поместить элемент управления на форме ...
_containedControl.Left = ButtonWidth + (3 * ButtonSpacing);
_containedControl.Top = ButtonSpacing;
_containedControl.Width = this.Width - _containedControl.Left - (4 * ButtonSpacing);
_containedControl.Height = this.Height - (8 * ButtonSpacing);
this.Controls.Add(_containedControl);
}
Тестирование полученного кодаПрежде чем можно будет увидеть окончательный вариант сделанного, необходимо добавить кнопку в форму. Используем элемент управления System Windows.Forms.DataGrid. Добавим следующий код в Form1: