| Китай |
Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 24:
Пользовательские компоненты
Тестирование компонента AlarmClock
-
Поместите
новый компонент AlarmClock из панели Toolbox на
форму Form1 приложения ComponentTest,
выделите его экземпляр alarmClock1 и через
панель Properties в режиме Events создайте обработчик для
события Alarm
-
Обработчик,
добавленный в класс Form1 приложения ComponentTest,
заполните следующим кодом
private void alarmClock1_Alarm(object sender, AlarmClock.AlarmEventArgs e)
{
// Если оператор выключения будильника поставить после
// вызова модального диалогового окна, то генерация
// событий прекратиться только после закрытия
// очередного модального окна, поскольку только тогда
// управление дойдет до этого оператора
alarmClock1.Enabled = false;// Останавливаем системный таймер
int hour = alarmClock1.CurrentTime.Hour;
int minute = alarmClock1.CurrentTime.Minute;
int second = alarmClock1.CurrentTime.Second;
MessageBox.Show(String.Format("Сработал будильник!!!\n"
+ "Текущее время: {0} ч. {1} м. {2} с.", hour, minute, second),
"Доцент Снетков В.М.");
}
Листинг
24.15.
Обработчик события Alarm в тестирующем классе Form1
-
Добавьте
в конец конструктора формы Form1 код установки времени срабатывания
будильника и запуска системного таймера
// Конструктор формы
public Form1()
{
InitializeComponent();
// Заполнение списка планетами
for (int i = 0; i <= planets1.MaxIndex; i++)
{
listPlanets.Items.Add(String.Format(
"{0}) {1}", i, planets1[i]));
}
listPlanets.SelectedIndex = 0;
// Устанавливаем время срабатывания будильника
// через 5 сек. после запуска системного таймера
alarmClock1.AlarmTime = DateTime.Now.AddSeconds(5d);
alarmClock1.Enabled = true;// Запускаем системный таймер
}
Листинг
24.16.
Конструктор формы Form1 файла Form1.cs приложения ComponentTest
-
Запустите
приложение и убедитесь, что обработчик нашего события Alarm срабатывает
через 5 секунд после запуска системного таймера, генерируя
окно с примерно следующим сообщением
Добавление в компонент пользовательского события расширенным способом
Рассмотрим другой способ работы с событиями, использующий базовое поле типа делегата. Для этого модифицируем наш компонент таким образом, чтобы будильник срабатывал два раза: по первому и второму событию. Но второе событие определим по иному.
-
Перейдите
в режим редактирования компонента AlarmClock.cs [Design] и
добавьте из панели Toolbox двойным щелчком
кнопки мыши еще один системный таймер Timer
-
Выделите
экземпляр таймера timer2 и в панели Properties установите свойство Interval=1000
-
Создайте
для объекта timer2 обработчик события Tick с
именем TimerHandlerExt,
который переместите в отдельную часть класса AlarmClock в
файле AlarmClock.cs. Заполните эту часть
следующим кодом
// Часть 5
namespace MyCompany.MyComponents
{
// Часть класса с определением обработчика события Tick
// системного таймера System.Windows.Forms.Timer timer2
partial class AlarmClock
{
// Объявляем внутренние поля
bool alarmFiredExt = false; // Состояние будильника (запущен/незапущен)
DateTime alarmTimeExt = DateTime.Now; // Хранит время запуска будильника
// Свойство для чтения и установки времени запуска будильника
public DateTime AlarmTimeExt
{
get { return alarmTimeExt; }
set
{
if (value != alarmTimeExt)
{
alarmTimeExt = value;
alarmFiredExt = false;
}
}
}
// Свойство для проверки состояния хода второго
// системного таймера, его остановки и запуска
public bool EnabledExt
{
get { return timer2.Enabled; }
set
{
timer2.Enabled = value;
if (value)
alarmFiredExt = false;
}
}
// Обработчик события срабатывания второго системного таймера
private void TimerHandlerExt(object sender, EventArgs e)
{
DateTime now; // Текущее системное время
AlarmEventArgs args;
// В режиме разработки не выполнять
if (!this.DesignMode)
{
now = DateTime.Now;
// Если будильник не запущен и пришла пора запускать
if (!alarmFiredExt && now >= alarmTimeExt)
{
// Создаем объект для передачи аргументов в событии
args = new AlarmEventArgs();
// Заполняем объект текущим временем
args.Time = now;
// Вызываем метод диспетчеризации события AlarmExt
this.OnAlarmExt(args);
// Поднимаем флаг "Будильник запущен"
alarmFiredExt = true;
}
}
}
}
}
Листинг
24.17.
Часть класса с обработчиком таймера timer2 в файле AlarmClock.cs
-
Создайте
часть класса компонента, объявляющего пользовательское событие
на базе внутреннего поля-ссылки на экземпляр делегата, который
будет содержать список зарегистрированных обработчиков этого
события
// Часть 6 Extension
namespace MyCompany.MyComponents
{
// Часть класса с определением собственного события
// стандартным способом без использования базового поля
partial class AlarmClock
{
// Закрытое поле-ссылка на экземпляр делегата
// Для объявления поля решили использовать уже существующий
// делегат, но можно объявить и другой делегат с той же сигнатурой
private AlarmHandler m_AlarmExt;
// Объявляем пользовательское событие
// с возможностью контроля доступа к нему
public event AlarmHandler AlarmExt
{
// Эта функция будет вызвана при попытке
// добавления обработчика в список вызова события
add
{
// Здесь что-то можно проконтролировать, например, что
// произошла попытка добавить обработчик в список вызова события
Console.WriteLine("Добавлен обработчик в список события AlarmExt");
// Расширяем список объекта-делегата, ссылающегося на обработчики события
m_AlarmExt += value;
}
// Эта функция будет вызвана при попытке
// изъятия обработчика из списка вызова события
remove
{
// Здесь что-то можно проконтролировать, например, что
// произошла попытка изъять обработчик из списка вызова события
Console.WriteLine("Изъят обработчик из списка события AlarmExt");
// Удалим обработчик из списка объекта-делегата
m_AlarmExt -= value;
}
}
// Метод диспетчеризации события. Виртуальный и защищенный
// для возможности переопределения в будущих потомках
protected virtual void OnAlarmExt(AlarmEventArgs args)
{
// Проверяем наличие зарегистрированных обработчиков
// и генерируем событие через поле-делегат
if (m_AlarmExt != null)
m_AlarmExt(this, args);
}
}
}
Листинг
24.18.
Часть файла AlarmClock.cs объявления события с контролем списка делегата
-
Откомпилируйте
библиотеку наших компонентов, выполнив команду Build/Build
MyComponents
-
Перейдите
в файл Form1.cs [Design] и добавьте
в конструктор класса тестового приложения код настройки второго
системного таймера экземпляра компонента alarmClock1
// Конструктор формы
public Form1()
{
InitializeComponent();
// Заполнение списка планетами
for (int i = 0; i <= planets1.MaxIndex; i++)
{
listPlanets.Items.Add(String.Format(
"{0}) {1}", i, planets1[i]));
}
listPlanets.SelectedIndex = 0;
// Устанавливаем время срабатывания будильника
// через 5 сек. после запуска системного таймера
alarmClock1.AlarmTime = DateTime.Now.AddSeconds(5d);
alarmClock1.Enabled = true;// Запускаем системный таймер
// Настраиваем второй системный таймер компонента
alarmClock1.AlarmTimeExt = DateTime.Now.AddSeconds(10d);
alarmClock1.EnabledExt = true;// Запускаем системный таймер
}
Листинг
24.19.
Конструктор формы Form1 файла Form1.cs приложения ComponentTest
-
На
форме Form1 приложения ComponentTest
выделите экземпляр alarmClock1 и через
панель Properties в режиме Events создайте
обработчик для события AlarmExt
-
Обработчик
заполните следующим кодом
private void alarmClock1_AlarmExt(object sender, AlarmClock.AlarmEventArgs e)
{
alarmClock1.EnabledExt = false;// Останавливаем второй системный таймер
int hour = alarmClock1.CurrentTime.Hour;
int minute = alarmClock1.CurrentTime.Minute;
int second = alarmClock1.CurrentTime.Second;
MessageBox.Show(String.Format("Сработал будильник!!!\n"
+ "Текущее время: {0} ч. {1} м. {2} с.", hour, minute, second),
"Доцент Снетков В.М.");
// Для генерации сообщения в консольный вывод
alarmClock1.AlarmExt -= alarmClock1_AlarmExt;
}
Листинг
24.20.
Обработчик события AlarmExt в тестирующем классе Form1
-
В панели Solution Explorer вызовите контекстное меню
для узла приложения ComponentTest и выполните команду Properties
-
В появившемся
окне настроек оболочки выберите вкладку Application и в
раскрывающемся списке Output type включите окно консольного
вывода Console Application
-
Запустите
приложение и убедитесь, что оба способа определения пользовательского
события работают одинаково, но в последнем способе мы можем
контролировать процесс добавления обработчиков



