Китай |
Опубликован: 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
- Запустите приложение и убедитесь, что оба способа определения пользовательского события работают одинаково, но в последнем способе мы можем контролировать процесс добавления обработчиков