Концепция кода, управляемого событиями, является необычайно плодотворной, однако, как и в случае любой другой абстракции, при этом теряется низкоуровневая картина того, что происходит. Вы имеете право говорить о том, что поведение приложения вам понятно, лишь в том случае, если хорошо представляете себе, в каком порядке и с какой частотой запускаются события, заставляющие выполняться код вашего приложения. С этим могут быть связаны не только проблемы производительности, но и проблемы надежности приложений. Поэтому стоит не пожалеть времени и составить для себя надежную и подробную картину того, где и когда именно в вашем приложении запускаются события.
На рис. 11.4 и в листинге 11.4 представлен пример приложения, демонстрирующий использование как средств контроля выполнения кода, так и модели состояний для того, чтобы избежать выполнения кода обработки событий пользовательского интерфейса в тех случаях, когда эти события связаны с обновлением пользовательского интерфейса. Для создания данного примера приложения необходимо выполнить следующие действия:
Пример приложения Pocket PC, демонстрирующий работу средств контроля запуска событий
Рис. 11.4. Пример приложения Pocket PC, демонстрирующий работу средств контроля запуска событий
1. Начните новый проект Smart Device в Visual Studio .NET, выбрав в качестве целевой платформы Pocket PC.
2. Добавьте в форму Form элементы управления TextBox, RadioButton, ListBox и Button (на рис. 11.4 показано, как должна выглядеть форма).
3. Дважды щелкните на кнопке Button в окне конструктора форм. В результате этого будет создан и подключен к кнопке приведенный ниже обработчик событий button1_Click. Введите соответствующий код из листинга 11.4, который будет реагировать на это событие.
4. Дважды щелкните на элементе управления TextBox в окне конструктора форм. В результате этого будет создан и подключен к текстовому окну приведенный ниже обработчик событий textBox1_TextChanged. Введите соответствующий код из листинга 11.4, который будет реагировать на это событие.
5. Дважды щелкните на элементе управления RadioButton1 в окне конструктора форм. В результате этого будет создан и подключен к переключателю приведенный ниже обработчик событий radioButton1_Click. Введите соответствующий код из листинга 11.4, который будет реагировать на это событие.
6. Измените имя второй кнопки с button2 на buttonShowEventLog и дважды щелкните на кнопке Button в окне конструктора форм. В результате этого будет создан и подключен к кнопке приведенный ниже обработчик событий buttonShowEventLog_Click. Введите соответствующий код из листинга 11.4, который будет реагировать на это событие
7. Введите оставшуюся часть приведенного ниже кода, включая операторы #if и #endif и переменные уровня класса.
8. В самом начале файла класса формы Form добавьте оператор #define EVENTINSTRUMENTATION. Это позволит вам использовать условную компиляцию кода.
9. Скомпилируйте пример и запустите его на выполнение. Щелкните на кнопке Button1, введите текст в текстовом поле TextBox и щелкните на кнопке ShowEventLog, чтобы увидеть список событий, которые были запущены.
10. Завершив выполнение приложения, удалите символы комментария в строке m_userInterfaceUpdateOccuring = true; кода обработчика событий Button_Click и повторно запустите приложение на выполнение. Обратите внимание, что установка этого флага предотвратила нежелательное выполнение кода приложения при запуске обработчиков событий в результате программного доступа к свойствам элементов управления.
Листинг 11.4. Использование модели состояний для обновления интерфейса и контроль запуска событий с целью более глубокого изучения процесса обработки событий и управления им
//-------------------------------------------------------
//Поместить данную директиву #define в начале определения
//класса, если требуется регистрация событий
//#define EVENTINSTRUMENTATION
//-------------------------------------------------------
//-----------------------------------------------------------------------
//Флаг, указывающий обработчикам событий, должен ли из них осуществляться
//выход без выполнения каких-либо действий
//-----------------------------------------------------------------------
bool m_userInterfaceUpdateOccuring;
//Счетчики событий
private int m_radioButton1ChangeEventCount;
private int m_textBox1ChangeEventCount;
//-------------------------------------------------------------------------
//Код, который следует включать лишь в том случае, если приложение
//выполняется в режиме контроля запуска событий. Этот код характеризуется
//относительно высокими накладными расходами, и его следует компилировать и
//выполнять только тогда, когда выполняется диагностика.
//-------------------------------------------------------------------------
#if EVENTINSTRUMENTATION
private System.Collections.ArrayList m_instrumentedEventLog;
//------------------------------------------------------------------------
//Заносит записи о возникновении событий в массив, который мы
//можем просмотреть
//Примечание: Не делается никаких попыток ограничить размерность массива
// регистрационных записей, поэтому, чем дольше выполняется
// приложение, тем больше становится размер массива
//------------------------------------------------------------------------
private void instrumented_logEventOccurrence(string eventData) {
//Создать журнал событий, если он еще не был создан
if (m_instrumentedEventLog == null) {
m_instrumentedEventLog = new System.Collections.ArrayList();
}
//Зарегистрировать событие
m_instrumentedEventLog.Add(eventData);
}
//------------------------------------------------------------------------
//Отобразить список возникших событий
//Примечание: Этот вариант реализации довольно груб.
// Целесообразнее отображать список событий