5.1 Windows Forms и .NET

Это бесплатная глава книги Библия C#. В новом издании эта глава переписана с учетом универсальных при-ложений Windows, а старая версия главы, которая не потеряла еще своей актуаль-ности стала бесплатной и доступной всем.

Начнем с создания пустого приложения и посмотрим, что для нас сгенерирует мастер Visual Studio, чтобы на экране появилось окно программы, и из чего все это состоит. Для создания проекта выполняем команду меню File | New | Project и в открывшемся окне выбираем Windows Forms Application в разделе языка программирования Visual C# | Windows (рис. 5.1). Я назвал свое новое приложение OurFirstVisualApplication.

Давайте посмотрим, какие модули добавлены в решение. Их всего два: Form1.cs (этот модуль состоит из нескольких файлов) и Program.cs. Начнем со второго файла, потому что именно с него начинается выполнение программы, и там находится метод Main(). Код файла вы можете увидеть в листинге 5.1.

Листинге 5.1. Содержимое файла Program.cs

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace OurFirstVisualApplication
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Создание нового проекта в Visual Studio

Рис. 5.1. Окно создания нового проекта (выделен пункт для создания визуального приложения)

Чтобы сэкономить место, я убрал комментарии, но в них всего лишь было написано, что перед нами входная точка приложения. А мы уже и без комментариев знаем, что метод Main() всегда вызывается первым при запуске приложения. Но давайте все по порядку.

Файл Program.cs нужен только в качестве заглушки, в которой объявлен класс с методом Main(). Он не несет в себе никакой логики, кроме создания приложения и отображения главного окна программы. Чаще всего в этот файл вы заглядывать не будете, но знать о его существовании желательно.

5.1.1. Пространства имен

В самом начале файл Program.cs подключает три пространства имен, с которыми будет происходить работа. На самом деле для компиляции программы достаточно только двух пространств: первого и третьего. Второе пространство не нужно, и в данном коде не используется, поэтому мы не будем его пока рассматривать. Это пространство имен относится к коллекциям, а это тема отдельного и очень серьезного разговора главы 8.

Из необходимых остаются два пространства имен:

  • System — мы подключали это пространство имен для всех приложений, которые писали до сих пор, — точнее, мастер подключал его вместо нас. В этом пространстве в .NET объявлены основные типы данных и все, без чего не проживет ни одно приложение .NET, которое хоть что-то делает;
  • System.Windows.Forms — в этом пространстве имен расположено все, что необходимо для функционирования формы. Формами в .NET называют проект будущего окна. Если класс — это спецификация, по которой создается объект, то форма — это спецификация, по которой создается окно. Мы планируем работать с визуальным интерфейсом, поэтому это пространство имен просто необходимо.

Как узнать, какие пространства имен подключать, а какие не нужно? Тут может помочь файл помощи и MSDN, где при описании каждого класса, метода или свойства обязательно указывается, в каком пространстве имен его можно найти. Откройте файл помощи — командой меню Help | Index (Помощь | Индекс) — и введите в строку поиска Look for (Искать) в левой панели открывшегося окна: Application class. Щелкните по найденному имени двойным щелчком, и откроется страница помощи по этому классу (рис. 5.2).

Файл помощи по классу Application

Рис. 5.2. Файл помощи по классу Application

На рис. 5.2 я выделил рамкой тот фрагмент, где как раз и написано, в каком пространстве имен находятся описание и сборка (DLL-файл) с реализацией класса. Нас больше интересует именно пространство имен, а не сборка. Мне ни разу не приходилось использовать файл сборки, по крайней мере этот. Все основные файлы добавляются в раздел References проекта автоматически при создании проекта. Но если вы будете использовать что-либо специфическое, то может потребоваться подключение нужного файла сборки самостоятельно.

Второй метод узнать пространство имен — не думать о нем, а возложить всю головную боль на среду разработки. У Visual Studio голова достаточно хорошая, и она с легкостью решит такую задачу.

Попробуйте сейчас ввести где-нибудь в коде метода Main() слово OleDbConnection. Это класс, который используется для соединения с базами данных, — компилятор не найдет его среди подключенных пространств имен и конечно же подчеркнет. Теперь вы можете щелкнуть правой кнопкой по подчеркнутому имени, в контекстном меню раскрыть пункт Resolve (Разрешить), и в его подменю будут перечислены пространства имен, в которых среда разработки смогла найти указанное слово (рис. 5.3).

 Контекстное меню позволяет решить проблему подключения пространств имен

Рис. 5.3. Контекстное меню позволяет решить проблему подключения пространств имен

В контекстом меню доступны два варианта решения проблемы, между которыми находится разделитель. Выше разделителя указаны варианты, которые добавляют в начало модуля кода оператор using с выбранным пространством имен. Варианты ниже разделителя изменяют короткое имя метода на полное. То есть, в случае с типом данных OleDbConnection, если вы выберете вариант ниже разделителя, то тип данных заменится на System.Data.OleDb.OleDbConnection. Если вы знаете, что это единственное обращение к такому типу данных, то можно использовать полный путь, но если в модуле кода вы станете использовать этот тип данных много раз, то проще будет сразу добавить его в раздел using.

Чаще всего в этом подменю будет приведен только один вариант — и до разделителя, и после, но некоторые имена могут быть объявлены как для Windows, так и для Web. В таких случаях требуется выбрать нужную сборку. Это не сложно, потому что для Интернета чаще всего используется пространство имен System.Web. Например, класс Application для интернет-программирования находится в пространстве имен Microsoft.Web.Administration. Это определяется ключевым словом Web, которое находится в середине.

Обратите также внимание, что мастер создания проекта поместил весь код нашего проекта в пространство имен, идентичное имени проекта. Всегда обрамляйте код в пространство имен.

Пространство имен по умолчанию для вашего проекта можно изменить. Для этого щелкните правой кнопкой мыши по имени проекта и выберите в контекстном меню пункт Properties, чтобы изменить свойства проекта. Здесь в разделе Application в поле Default namespace (Пространство имен по умолчанию) вы можете изменить имя пространства имен. При этом уже существующий код останется в старом пространстве имен. То есть, существующий код изменяться автоматически не будет, а вот новые файлы, которые будут добавляться в проект, станут попадать уже в новое пространство. Если вам нужно перенести существующий код в новое пространство, то следует сделать это руками, изменяя текущее пространство имен на новое. Можно оставить и старое имя, потому что в одной сборке могут быть и два, и три разных пространства имен, если вас это устраивает.

5.1.2. Потоки

Обратите внимание, что перед методом Main() в квадратных скобках стоит ключевое слово STAThread (см. листинг 5.1). Оно указывает на то, что модель разделения потоков для приложения будет одиночная (Single Thread Apartment model). Такой атрибут должен быть указан для всех точек входа в WinForms-приложения. Если он будет отсутствовать, то компоненты Windows могут работать некорректно.

Дело в том, что без атрибута STAThread приложение будет пытаться использовать многопоточную модель разделения MTAThread (Multi Threaded Apartment model), которая не поддерживается для Windows Forms.

5.1.3. Класс Application

В листинге 5.1 в методе Main() все строки кода являются обращением к классу Application, который предоставляет статичные свойства и методы (это значит, что не нужно создавать экземпляр класса, чтобы их вызвать) для поддержки работы приложения. Основными методами являются запуск и останов приложения, а также обработка сообщений Windows. При возникновении каких-либо ситуаций ОС отправляет окну событие, и окно должно отработать это событие. Например, если пользователь нажал на кнопку закрытия окна, то этому окну направляется событие WM_CLOSE (если мне не изменяет память). Поймав это событие, окно должно отреагировать, освободить запрошенные ресурсы и приготовиться к уничтожению. Любой ввод пользователя, включая нажатие клавиш на клавиатуре и движение курсора мыши, обрабатывает ОС, а потом с помощью сообщений отправляет изменения в приложение.

Чтобы отлавливать сообщения, которые направляет приложению операцион- ная система, в приложении должен быть запущен цикл. В таких языках, как С/С++, цикл получает от ОС сообщение, обрабатывает его и ожидает следующего сообщения. Этот цикл продолжается до тех пор, пока не произойдет выхода из программы.

Класс Application берет на себя всю ответственность за получение сообщений от системы и перенаправление их в окна, чтобы вы могли эти сообщения обработать. Чуть позже мы научимся ловить сообщения, а пока нам нужно знать, что за подготовку сообщения для обработки отвечает именно класс Application.

Рассмотрим методы, которые вызываются в классе, который сгенерировал нам мастер Visual Studio. Первый метод класса Application, который мы вызываем:

EnableVisualStyles(). Этот метод включает отображение в стилях ОС, на которой запущено приложение. Если удалить эту строку и запустить программу, то все элементы управления будут выглядеть в стиле Windows 9x с квадратными углами даже в Windows 7. Не вижу смысла возвращаться в доисторические времена визуального интерфейса, но если вам вдруг это понадобится, теперь вы знаете, какую строку нужно удалить.

Следующий метод приложения, который вызывает программа: SetCompatibleTextRenderingDefault(). Некоторые элементы управления могут отображать текст с помощью старых функций GDI или с помощью новых функций GDI+. Если методу SetCompatibleTextRenderingDefault() передать значение false, то будут использоваться функции GDI+.

Это все были подготовительные методы, а последний метод: Run() является наиболее важным. Этот метод запускает скрытый цикл обработки сообщений ОС и делает видимой форму, которая передается в качестве параметра. В нашем примере в качестве параметра передается инициализация объекта класса Form1, для чего вызывается конструктор класса с помощью оператора new, как мы это делали ранее. Просто мы всегда присваивали результат выполнения new переменной, а в этом случае нам переменная не нужна, и мы больше не будем использовать объект в методе Мain(), поэтому, нигде ничего не сохраняя, сразу передаем новый объект методу. То же самое можно было написать так:

   Form1 form = new Form1();
   Application.Run(form);

Все исходные коды главы 5 Библии C#

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне