- •Основы создания оконных приложений Особенности поведения оконных приложений.
- •Первое оконное приложение
- •Элементы управления
- •Событийно-управляемая модель выполнения оконного приложения
- •Принцип распределения ответственности
- •Элемент управления Timer
- •Динамическое управление обработчиками
- •Вопрос 1: Перед тем как оператор
- •Вопрос 2: Можно ли связать с событием несколько обработчиков и что при этом происходит?
- •Вопрос 3: Можно ли выполнить обратную операцию – исключить обработчик из списка?
- •Элемент управления ListBox
- •Параметры событий. Каскад событий
- •Использование визуального дизайнера
- •Редактирование свойств элементов управления
- •Анализ сгенерированного исходного кода
- •Сохранение результатов
- •Управление объектами файловой системы
- •Информация о логических дисках (класс DriveInfo)
- •Работа с каталогами (папками)
- •Работа с файлами
- •Стандартные диалоговые окна
- •Сериализация
- •Объектные графы
- •Формат сериализации
- •Реконструкция объектов
- •Использование SoapFormatter и XmlSerializer
- •Сохранение коллекций объектов
- •Архитектура программных систем
- •Собственные производные классы элементов управления
- •Другие элементы управления
- •Класс Control
- •Использование возможностей класса Control
- •Ответ на события MouseMove
- •Регистрация щелчков кнопок мыши
- •Ответ на события клавиатуры
- •Функциональные возможности класса Form
- •Цикл существования типа Form
- •Form (Форма)
Динамическое управление обработчиками
Вы составили себе представление о том, как операция += связала событие с обработчиком. И тут возникает несколько логичных вопросов:
Вопрос 1: Перед тем как оператор
b1.Click += ButtonClick;
связал с щелчком по кнопке b1 обработчик ButtonClick, был ли список обработчиков пуст?
Ответ 1: Нет. Уже для стандартного класса Form определены обработчики щелчка по кнопкам. Это можно заметить и визуально – щелчки по кнопкам приводят к эффекту «вдавливания» кнопки. Вопрос, который пока останется без ответа – где находятся эти обработчики?
Вопрос 2: Можно ли связать с событием несколько обработчиков и что при этом происходит?
Ответ 2: Связать несколько обработчиков можно путем многократного выполнения оперции +=. В этом случае все обработчики срабатывают последовательно в том порядке, в котором они добавлялись в множество обработчиков события.
Вопрос 3: Можно ли выполнить обратную операцию – исключить обработчик из списка?
Ответ 3: Да, это делается с помощью аналогичной операции -=.
Попробуем продемонстрировать это на примере. Рассмотрим, как работает программа, содержащая следующий класс MainWindow:
class MainWindow:Form
{
. . .
public MainWindow()
{
. . .
b1.Click += ButtonClick;
b1.Click += NewButtonClick;
. . .
b2.Click += ButtonClick;
b2.Click += NewButtonClick;
. . .
}
private void ButtonClick(object sender, EventArgs ea)
{ ((Button)sender).Text = DateTime.Now.ToString(); }
private void NewButtonClick(object sender, EventArgs ea)
{ this.Text=((Button)sender).Text;
if (sender == b1)
b2.Click -= NewButtonClick;
else
b1.Click -= NewButtonClick;
}
}
Первоначально (после создания формы) обе кнопки реагируют на щелчок двумя обработчиками:
первый обработчик выводит на кнопку дату и время;
второй обработчик выводит в заголовок формы надпись на кнопке, по которой щелкнули.
Допустим, сначала пользователь щелкнул по первой кнопке. Тогда условный оператор во втором обработчике исключит этот обработчик из списка обработчиков щелчка второй кнопки. Таким образом, «победила» первая кнопка – теперь только она выводит дату и время и на своей поверхности и в заголовке формы.
Аналогично «победит» вторая кнопка, если пользователь щелкнет сначала по ней.
Элемент управления Timer
Модель выполнения оконного приложения существенно ориентирована на события. Можно говорить, что оконное приложение функционирует только в ответ на происходящие с ним (его элементами) события. Отсюда можно сделать вывод – если пользователь не дотрагивается до «органов управления» компьютером, программа бездействует в ожидании новых событий. Это означало бы, что мы не можем реализовать большое количество задач, которые демонстрируют автономную, независимую от пользователя динамику.
В качестве простого примера рассмотрим решение следующей задачи. В окне приложения находится небольшая квадратная кнопка, которая каждую секунду перемещается в случайное место, оставаясь целиком в пределах окна. Пользователь пытается успеть щелкнуть по поверхности кнопки. Если ему это удается сделать 3 раза, кнопка перестает двигаться.
Для решения этой задачи нужно обеспечить перемещение кнопки независимо от каких-либо действий пользователя. Тем не менее, это перемещение может быть только результатом реакции на некоторое событие. Для разрешения сложившегося противоречия нам нужно событие, которое будет происходить без участия пользователя, и связано с течением времени. Специально для таких задач предусмотрен элемент управления Timer, очень напоминающий обычный будильник. Таймер умеет порождать через указанный интервал времени сигнал – событие Tick. Интервал времени определяется свойством Interval, измеряемым в миллисекундах (1 сек = 1000 миллисекунд). Элемент Timer имеет логическое свойство Enabled: true означает, что Timer включен и генерирует событие Tick, false – Timer выключен. И последнее замечание – Timer не является визуальным элементом. Как следствие, его не нужно помещать в коллекцию Controls объекта-формы.
Далее приведем код класса формы, решающий нашу задачу:
class MyForm:Form
{ private Button target; //кнопка-цель
private Timer timer;
private const int TSize = 50; //размер кнопки
private int lifes; //количество "жизней" кнопки
public MyForm()
{ lifes = 3;
target = new Button();
Jump();
target.Click += TargetClick;
this.Controls.Add(target);
timer = new Timer();
timer.Interval = 1000;
timer.Tick += TimerTick;
timer.Enabled = true;
}
private void TimerTick(object sender, EventArgs ea)
{
Jump();
}
private void TargetClick(object sender, EventArgs ea)
{
lifes--;
if (lifes <=0)
timer.Tick -= TimerTick;
// или timer.Enabled = false;
}
private void Jump()
{
Random r = new Random();
int Left=r.Next(0,this.ClientSize.Width-TSize);
int Top=r.Next(0,this.ClientSize.Height-TSize);
target.Bounds = new Rectangle(Left, Top, TSize, TSize);
}
}
Комментарии
