Не обнаружил проекты, которые используются в примерах в лекции, также не увидел список задач. |
Организация интерфейса и рисование в формах
Организация интерфейса
Практически все проекты, построенные в наших лекциях, были консольными приложениями. В реальной жизни консольные проекты - это большая редкость. Причина, по которой из 12 возможных типов проектов мы выбирали наименее используемый, понятна. Нашей целью являлось изучение свойств языка, классов библиотеки FCL, для этих целей консольный проект вполне подходит, позволяя избегать введения не относящихся к сути дела деталей. Теперь цель достигнута - основные средства языка C# рассмотрены, учебный курс завершается. Остались важные темы, требующие более подробного рассмотрения, такие, как, например, работа с атрибутами, создание собственных атрибутов, класс Reflection, работа с файлами и базами данных; но все это предмет будущего курса. Тем не менее, нельзя окончить этот курс, не посвятив две последние лекции Windows-приложениям. Мне бы хотелось, чтобы активные слушатели (читатели) все консольные проекты переделали в Windows-проекты, построив подходящий для них интерфейс.
Первое знакомство с Windows-проектами состоялось в лекции 2, я настоятельно рекомендую перечитать ее, прежде чем продолжить чтение данной лекции. Вкратце напомню, как создается и выполняется Windows-проект. По умолчанию он содержит класс Form1 - наследника класса Form. Этот класс содержит точку входа в проект - процедуру Main, вызывающую статический метод Run класса Application, который создает объект класса Form1 и открывает форму - видимый образ объекта - для интерактивной работы пользователя. Открываемая форма содержит пользовательский интерфейс - окошки, кнопки, списки, другие элементы управления, меню . Все эти элементы способны реагировать на события, возникающие при выполнении пользователем каких-либо действий - нажатии кнопок, ввода текста, выбора пунктов меню.
Форма и элементы управления
Как населить форму элементами управления? Чаще всего, это делается вручную в режиме проектирования. Доступные элементы управления, отображаемые на специальной панели (Toolbox), перетаскиваются на форму. Этот процесс поддерживается особым инструментарием - дизайнером форм (Designer Form). Как только на этапе проектирования вы сажаете на форму элемент управления, немедленно в тексте класса появляются соответствующие строки кода (в лекции 2 об этом подробно рассказано). Конечно, все можно делать и программно - появление соответствующих строк кода приводит к появлению элементов управления на форме. Нужно понимать, что форма - это видимый образ класса Form, а элементы управления, размещенные на форме - это видимые образы клиентских объектов соответствующих классов, наследников класса Control. Так что форма с ее элементами управления есть прямое отражение программного кода.
Каждый вид элементов управления описывается собственным классом. Библиотека FCL содержит большое число классов, задающих различные элементы управления. Одним из типов проектов, доступных на C#, является проект, создающий элемент управления, так что ничто не мешает создавать собственные элементы управления и размещать их на формах наряду со встроенными элементами. Многие фирмы специализируются на создании элементов управления - это один из видов повторно используемых компонентов.
В каких отношениях находятся класс Form, класс Control, классы элементов управления? На рис. 24.1 показана иерархия отношений, связывающих эти классы.
Естественно, все эти классы являются потомками прародителя - класса Object. Заметьте, класс Control в иерархии классов занимает довольно высокое положение, хотя и у него есть два важных родительских класса - класс Component, определяющий возможность элементам управления быть компонентами, и класс MarshalByRefObject, задающий возможность передачи элементов управления по сети. Класс Control задает важные свойства, методы и события, наследуемые всеми его потомками. Все классы элементов управления являются наследниками класса Control. Чаще всего, это прямые наследники, но иногда они имеют и непосредственного родителя, которым может быть абстрактный класс - это верно для кнопок, списков, текстовых элементов управления. Может показаться удивительным, но класс Form является одним из потомков класса Control, так что форма - это элемент управления со специальными свойствами. Будучи наследником классов ScrollableControl и ContainerControl, форма допускает прокрутку и размещение элементов управления.
Взаимодействие форм
Обычное Windows-приложение всегда содержит несколько форм. Одни открываются в процессе работы, другие закрываются. В каждый текущий момент на экране может быть открыта одна или несколько форм, пользователь может работать с одной формой или переключаться по ходу работы с одной на другую.
Следует четко различать процесс создания формы - соответствующего объекта, принадлежащего классу Form или наследнику этого класса, - и процесс показа формы на экране. Для показа формы служит метод Show этого класса, вызываемый соответствующим объектом; для скрытия формы используется метод Hide. Реально методы Show и Hide изменяют свойство Visible объекта, так что вместо вызова этих методов можно менять значение этого свойства, устанавливая его либо в true, либо в false.
Заметьте разницу между сокрытием и закрытием формы - между методами Hide и Close. Первый из них делает форму невидимой, но сам объект остается живым и невредимым. Метод Close отбирает у формы ее ресурсы, делая объект отныне недоступным; вызвать метод Show после вызова метода Close невозможно, если только не создать объект заново. Открытие и показ формы всегда означает одно и то же - вызов метода Show. У формы есть метод Close, но нет метода Open. Формы, как и все объекты, создаются при вызове конструктора формы при выполнении операции new.
Форма, открываемая в процедуре Main при вызове метода Run, называется главной формой проекта. Ее закрытие приводит к закрытию всех остальных форм и завершению Windows-приложения. Завершить приложение можно и программно, вызвав в нужный момент статический метод Exit класса Application. Закрытие других форм не приводит к завершению проекта. Зачастую главная форма проекта всегда открыта, в то время как остальные формы открываются и закрываются (скрываются). Если мы хотим, чтобы в каждый текущий момент была открыта только одна форма, то нужно принять определенные меры, чтобы при закрытии (скрытии) формы открывалась другая. Иначе возможна клинчевая ситуация - все формы закрыты, предпринять ничего нельзя, а приложение не завершено. Конечно, выход всегда есть - всегда можно нажать магическую тройку клавиш CTRL+ALT+DEL и завершить любое приложение.
Можно создавать формы как объекты класса Form. Однако такие объекты довольно редки. Чаще всего создается специальный класс FormX - наследник класса Form. Так, в частности, происходит в Windows-приложении, создаваемом по умолчанию, когда создается класс Form1 - наследник класса Form. Так происходит в режиме проектирования, когда в проект добавляется новая форма с использованием пункта меню Add Windows Form. Как правило, каждая форма в проекте - это объект собственного класса. Возможна ситуация, когда вновь создаваемая форма во многом должна быть похожей на уже существующую, и тогда класс новой формы может быть сделан наследником класса формы существующей. Наследование форм мы рассмотрим подробнее чуть позже.
Модальные и немодальные формы
Первичным является понятие модального и немодального окна. Окно называется модальным, если нельзя закончить работу в открытом окне до тех пор, пока оно не будет закрыто. Модальное окно не позволяет, если оно открыто, временно переключиться на работу с другим окном. Выйти из модального окна можно, только закрыв его. Немодальные окна допускают параллельную работу в окнах. Форма называется модальной или немодальной в зависимости от того, каково ее окно. Метод Show открывает форму как немодальную, а метод ShowDialog - как модальную. Название метода отражает основное назначение модальных форм - они предназначены для организации диалога с пользователем, и пока диалог не завершится, покидать форму не разрешается.
Передача информации между формами
Часто многие формы должны работать с одним и тем же объектом, производя над ним различные операции. Как это реализуется? Обычная схема такова: объект создается в одной из форм, чаще всего, в главной. При создании следующей формы глобальный объект передается конструктору новой формы в качестве аргумента. Естественно, одно из полей новой формы должно представлять ссылку на объект соответствующего класса, так что конструктору останется только связать ссылку с переданным ему объектом. Заметьте, все это эффективно реализуется, поскольку объект создается лишь один раз, а разные формы содержат ссылки на этот единственный объект.
Если такой глобальный объект создается в главной форме, то можно передавать не объект, требуемый другим формам, а содержащий его контейнер - главную форму. Это удобнее, поскольку при этом можно передать несколько объектов, можно не задумываться над тем, какой объект передавать той или иной форме. Иметь ссылку на главную форму часто необходимо, хотя бы для того, чтобы при закрытии любой формы можно было бы открывать главную, если она была предварительно скрыта.
Представим себе, что несколько форм должны работать с объектом класса Books. Пусть в главной форме такой объект объявлен:
public Books myBooks;
В конструкторе главной формы такой объект создается:
myBooks = new Books(max_books);
где max_books - заданная константа. Пусть еще в главной форме объявлена форма - объект класса NewBook:
public NewBook form2;
При создании объекта form2 его конструктору передается ссылка на главную форму:
form2 = new NewBook(this);
private Form1 mainform; private Books books;
а его конструктор следующий код:
mainform = form; books = mainform.myBooks;
Теперь объекту form2 доступны ранее созданные объекты, задающие книги и главную форму, так что в обработчике события Closed, возникающего при закрытии формы, можно задать код:
private void NewBook_Closed(object sender, System.EventArgs e) { mainform.Show(); }