Теперь посмотрим на содержимое файла Form1.cs. Если раскрыть ветку формы, то вы увидите, что там есть еще два файла: Form1.Designer.cs и Form.resx. Получается, что форма описана аж в трех файлах? Да, так и есть. Конечно же, все можно было реализовать в одном файле с кодом, но такое разбиение сделано для вашего же удобства
.В RESX-файле хранятся атрибуты файла кода, и с ним работает среда разработки. Мне пока еще ни разу не приходилось редактировать его напрямую, в основном я делал это из среды разработки. Помните, что в нем среда разработки сохраняет параметры формы для внутреннего использования и ресурсы программы.
Но есть глобальный файл ресурсов, с которым вы можете работать без проблем. Он находится в папке Properties проекта и называется Resources.resx. В нем расположены ресурсы приложения, и они могут быть доступны любой форме проекта.
Вы можете создавать в файле RESX ресурсы — такие как строки, изображения и т. д., которые в последующем можно будет использовать в программе.
Попробуйте щелкнуть двойным щелчком по файлу Form1.resx в панели Solution Explorer. Перед вами откроется редактор ресурсов формы (рис. 5.4).
Рис. 5.4. Окно редактирования ресурсов формы
В панели инструментов редактора ресурсов заголовок первой кнопки указывает на тот модуль, который сейчас открыт. На рис. 5.4 открыт модуль редактирования строк (кнопка называется Strings). Если щелкнуть на стрелке вниз справа от кнопки Strings, то появится всплывающее меню, и из него вы можете выбрать тип ресурсов, которые можно редактировать. Существуют следующие типы ресурсов (в скобках указаны горячие клавиши для вызова соответствующего модуля редактирования):
Для добавления нового ресурса такого же типа, что и открытый модуль, достаточно щелкнуть по кнопке Add Resource (Добавить ресурс) на панели инструментов. Чтобы выбрать тип ресурса и метод создания, щелкните по стрелке вниз справа от кнопки Add Resource. В выпадающем меню можно выбрать создание ресурса на основе существующего файла или сделать выбор типа изображения для ресурса типа Image.
Теперь посмотрим на содержимое файла Form1.cs. Если щелкнуть по файлу двойным щелчком, то он откроется в режиме визуального дизайна, где вы можете расставлять компоненты. Чтобы увидеть код формы, нужно нажать клавишу
В самом начале файла, как всегда, осуществляется подключение пространств имен, которые мы можем использовать в модуле. Мастер подключил пространства имен с большим запасом, потому что для компиляции кода, который находится сейчас в модуле, достаточно только System и System.Windows.Forms. Все остальное добавлено, потому что в Microsoft посчитали, что оно вам пригодится.
Пространства имен я опустил, а все остальное показано в следующем коде:
namespace OurFirstVisualApplication { public partial class Form1 : Form { public Form1() { InitializeComponent(); } } }
Сразу же видим, что весь код также объявлен в пространстве имен OurFirstVisualApplication. Внутри этого пространства объявляется открытый класс с именем Form1, который является наследником класса Form. В этом объявлении много чего интересного, что мы еще не рассматривали.
Для начала нужно сказать про класс Form. В .NET этот класс реализует все необходимые для формы свойства и методы. Можно создать экземпляр этого класса и вызвать метод отображения, и вы на экране увидите окно. Вспомните, что экземпляр класса формы был передан методу Run() класса Application. Этот метод запускает цикл обработки и отображает окно, так что нам отображать его не нужно. Если вы будете создавать окно сами, то его нужно будет самому и отображать с помощью метода Show() или ShowDialog(). Такие методы есть у класса Form.
В данном случае у нас не просто экземпляр класса, а его наследник. Просто экземпляра было бы достаточно, если бы мы лишь изменили его свойства и отобразили. Но чем может быть полезно пустое окно? Ничем! Поэтому мы создаем наследника и будем расширять его возможности, добавляя меню, кнопки и панели, а не только изменять свойства.
Вообще-то, создать форму и налепить на нее компоненты можно и без наследования, но мне кажется, что такой подход будет не очень удобным и эффективным. Класс должен быть автономным и должен сам расставлять на поверхности все необходимые компоненты. То, что мы можем поставить компоненты извне, не означает, что это хороший способ. При проектировании класса всегда старайтесь делать его автономным и максимально независящим от внешних факторов.
Очень интересным модификатором в начале объявления класса является partial. Он означает, что объявление класса разбито на несколько файлов с кодом. Перед нами первый из этих файлов, а, забегая вперед, скажу, что продолжение реализации класса находится в файле Form1.Designer.cs. Это очень мощная возможность — когда вы можете разбить реализацию класса на несколько файлов. Например, в одном файле вы реализуете все методы, в другом — все свойства, а в третьем объявляете дополнительные переменные. Для этого нужно, чтобы во всех трех файлах было объявление класса с одним и тем же именем и с модификатором partial.
Внутри класса в файле Form1.cs определяется только конструктор, в котором вызывается метод InitializeComponent(). Что это такое, и откуда взялся этот метод?
В нем инициализируются все свойства формы и компоненты, которые могут быть установлены на форме. Но где он объявлен и как выглядит? Об этом мы узнаем в разд. 5.2.4.
Мы уже говорили, что все переменные нужно именовать понятными словами. Никаких имен типа Form1 в реальных приложениях быть не должно. Но нельзя переименовывать просто так переменную класса, особенно если это форма. Тут лучше переименовать файл.
Щелкните правой кнопкой мыши по имени файла формы в панели Solution Explorer и из контекстного меню выберите пункт Rename (Переименовать). Введите новое имя формы, и будут переименованы не только имена файлов, связанных с формой, но и класс, находящийся внутри. При этом изменения произойдут во всех файлах, где задействована форма, в том числе и в файле Program.cs.
Раньше весь код, который касался формы, находился в одном файле кода. Но это было неудобно, потому что размер файла рос с сумасшедшей скоростью, и управление им становилось неудобным. Сейчас среда разработки разбивает код на два файла. В одном файле (Form1.cs) мы пишем всю свою логику — его мы рассмотрели в разд. 5.2.2, а в другом файле (Form1.Designer.cs) среда разработки сохраняет весь необходимый код для реализации того, что мы сделаем визуально в дизайнере.
Мы пока ничего не делали в дизайнере, но давайте посмотрим, что уже есть в файле Form1.Designer.cs. Для этого щелкните по нему правой кнопкой мыши и из контекстного меню выберите пункт View Code. Код того, что сгенерировал дизайнер в моем случае, показан в листинге 5.2.
Листинг 5.2. Код файла Form1.Designer.cs
namespace OurFirstVisualApplication { partial class Form1 { ////// Required designer variable. /// Переменные, необходимые дизайнеру /// private System.ComponentModel.IContainer components = null; ////// Clean up any resources being used. /// Очистка любых использованных ресурсов /// /// true if managed resources should /// be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); // уничтожить переменную компонентов } base.Dispose(disposing); // вызвать метод базового класса } #region Windows Form Designer generated code ////// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// Метод, который необходим дизайнеру – не изменяйте /// содержимое метода в редакторе кода /// private void InitializeComponent() { this.SuspendLayout(); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(284, 264); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } #endregion } }
В этом файле нет никаких подключений пространств имен, потому что весь код в файле пишется дизайнером автоматически, и мы сюда будем заглядывать очень редко, а редактировать его еще реже. Дизайнер достаточно интеллектуален, поэтому, чтобы ничего не подключать, он просто будет обращаться ко всем методам и типам данных по полному имени с указанием полного пути в пространстве имен.
Итак, в файле Form1.Designer.cs идет продолжение объявления класса Form1. Об этом говорит то, что в самом начале снова идет объявление класса Form1 и указан модификатор partial. То есть все, что будет описано в классе этого модуля, добавится к конструктору, который мы уже рассмотрели в разд. 5.2.2.
В самом начале класса объявляется переменная components, которая является контейнером для всех компонентов, которые не имеют визуального интерфейса, т. е. не видимы на форме. Да, бывают и такие компоненты, и они встроены в .NET в виде компонентов для удобства программирования.
Далее идет метод Dispose(), который будет вызываться системой, когда возникнет необходимость уничтожить объект класса формы. В двух словах поясню, что происходит в этом методе: вызывается метод Dispose() переменной components, чтобы она почистила за собой, и вызывается этот же метод базового класса формы.
После метода Dispose() начинается самое интересное, а именно — вызов метода InitializeComponent(). Вы не видите этого метода? Но вы видите следующую строку, написанную серым цветом?
Windows Form Designer generated code
Если да, то щелкните на крестике, который находится на поле слева от этой строки. Это заставит редактор кода раскрыть регион. Что такое регион? Это блок кода, окруженный ключевыми словами #region xxxxx и #endregion, где xxxx — имя региона. Написав это в коде, на поле слева от строки с #region вы увидите крестик, с помощью которого можно сворачивать весь код, выделенный этими двумя ключевыми словами. Свернув блок кода, вы будете видеть только имя региона.
Вернемся к методу InitializeComponent(). Вспомните разд. 5.2.2, где мы рассматривали конструктор нашей формы. Там мы говорили о том, что в конструкторе вызывается метод с точно таким же именем. Так вот он где находится! И хотя он реализован в другом файле, но, все же, остается частью того же partial-класса.
Несмотря на то, что название метода InitializeComponent() переводится как "инициализировать компонент", метод инициализирует свойства формы, а также создает все элементы управления, которые мы поставим на форму визуально. Да, именно визуально и только визуально. Ручками в этот метод ничего писать не рекомендуется, иначе дизайнер может оказаться не способным понять ваши благие намерения и ваш мегакод, — при попытке открыть форму в дизайнере он вернет ошибку. Если и возникнет необходимость вносить какие-то изменения в метод InitializeComponent(), то делайте это очень аккуратно и осторожно.
Теперь одним глазком посмотрим, что происходит внутри этого метода. В самом начале вызывается метод SuspendLayout() для нашей формы (о том, что вызывается метод именно текущей формы, говорит слово this). Этот метод заставляет систему приостановить реагирование на изменение атрибутов. Дело в том, что при изменении любого атрибута система будет перерисовывать форму. При инициализации чаще всего приходится изменять сразу несколько атрибутов, и после изменения каждого из них реагировать и изменять форму невыгодно. Намного эффективнее изменить все атрибуты, а потом уже пусть форма один раз отреагирует на все изменения и прорисуется в соответствии с изменениями в нужном месте.
Итак, после вызова метода SuspendLayout() для нашего окна оно не будет реагировать и изменять свою форму при изменении атрибутов, а сделает это после вызова метода ResumeLayout().
Далее идет изменение свойств формы. Мы пока не будем рассматривать эти свойства, все придет со временем. Хочу только сказать, что среда разработки и генератор этого кода мудры, как никто более, и помогают нам, как только возможно. Так что, в методе InitializeComponent() появится код для инициализации всех кнопок, которые вы будете располагать на форме, и всех других элементов управления. Чтобы проще было работать с методом, генератор будет группировать код так, чтобы код инициализации одного элемента управления находился в одном месте, а не был разбросан по всему методу InitializeComponent().
К тому же, перед началом инициализации очередного элемента будет вписан комментарий с указанием имени элемента управления, свойства которого будут далее изменяться. В нашем примере нет ничего кроме формы, но, несмотря на это, перед началом изменения ее свойств стоит комментарий. Спасибо разработчикам Visual Studio за то, что не забывают о нас.
Теперь вы можете запустить приложение с помощью клавиши
Чтобы наш пример стал полноценным приложением "Hello World", но только из визуального окна, давайте изменим заголовок окна. Для этого нужно переключиться на визуальную форму, что можно сделать несколькими способами — например, просто щелкнуть двойным щелчком по имени файла Form1.cs в панели Solution Explorer. По умолчанию формы с визуальным интерфейсом открываются именно
в визуальном дизайнере. Если в вашей среде разработки произошло не так, то можно щелкнуть правой кнопкой мыши по имени файла и из контекстного меню выбрать View Designer (Показать дизайнер). Если вы находитесь в окне кода, можно нажать комбинацию клавиш
В дизайнере должна быть выбрана форма, тогда в панели Properties появятся свойства формы (рис. 5.5). Вообще-то, у нас ничего, кроме формы, нет, поэтому суетиться рано, — все равно будут отображаться свойства именно формы, но главное, чтобы панель Properties присутствовала на экране. Если вы ее не видите, выберите в главном меню View | Properties Window.
Рис. 5.5. Панель Properties со свойствами формы
В панели Properties в левом столбце найдите свойство Text и напротив него измените в правом столбце название заголовка на Hello World (по умолчанию оно равно имени класса). Вот теперь можно запускать приложение снова и наблюдать в заголовке окна великую фразу, с которой начинали учиться программированию многие знаменитые программисты.
Мы сделали небольшое изменение, но оно очень важно для нас, потому что мы узнали, как работать со свойствами в визуальном дизайнере, и научились изменять их значения. Теперь можете вернуться в файл Form1.Designer.cs и посмотреть на метод инициализации компонентов. Обратите внимание на следующую строку кода:
this.Text = "Hello World";
В ответ на изменение в визуальном дизайнере среда разработки сгенерировала соответствующий код. Мы могли бы ручками написать этот же код, ведь здесь просто свойству Text текущего объекта присваивается строка, но через визуальный дизайнер это делать интереснее и проще.
Это бесплатная глава книги Библия C#. В новом издании эта глава переписана с учетом универсальных приложений Windows, а старая версия главы, которая не потеряла еще своей актуальности стала бесплатной и доступной всем.