Планшеты

Виндовс формы c. Программирование в.NET Framework

Виндовс формы c. Программирование в.NET Framework

Последнее обновление: 31.10.2015

Для создания графических интерфейсов с помощью платформы.NET применяются разные технологии - Window Forms, WPF, приложения для магазина Windows Store (для ОС Windows 8/8.1/10). Однако наиболее простой и удобной платформой до сих пор остается Window Forms или формы. Данное руководство ставит своей целью дать понимание принципов создания графических интерфейсов с помощью технологии WinForms и работы основных элементов управления.

Создание графического приложения

Для создания графического проекта нам потребуется среда разработки Visual Studio. Поскольку наиболее распространенная пока версия Visual Studio 2013, то для данного руководства я буду использовать бесплатную версию данной среды Visual Studio Community 2013 которую можно найти на странице https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx .

После установки среды и всех ее компонентов, запустим Visual Studio и создадим проект графического приложения. Для этого в меню выберем пункт File (Файл) и в подменю выберем New - > Project (Создать - > Проект). После этого перед нами откроется диалоговое окно создания нового проекта:

В левой колонке выберем Windows Desktop , а в центральной части среди типов проектов - тип Windows Forms Application и дадим ему какое-нибудь имя в поле внизу. Например, назовем его HelloApp . После этого нажимаем OK.

После этого Visual Studio откроет наш проект с созданными по умолчанию файлами:

Большую часть пространства Visual Studio занимает графический дизайнер, который содержит форму будущего приложения. Пока она пуста и имеет только заголовок Form1. Справа находится окно файлов решения/проекта - Solution Explorer (Обозреватель решений). Там и находятся все связанные с нашим приложением файлы, в том числе файлы формы Form1.cs .

Внизу справа находится окно свойств - Properties. Так как у меня в данный момент выбрана форма как элемент управления, то в этом поле отображаются свойства, связанные с формой.

Теперь найдем в этом окне свойство формы Text и изменим его значение на любое другое:

Таким образом мы поменяли заголовок формы. Теперь перенесем на поле какой-нибудь элемент управления, например, кнопку. Для этого найдем в левой части Visual Studio вкладку Toolbox (Панель инструментов) . Нажмем на эту вкладку, и у нас откроется панель с элементами, откуда мы можем с помощью мыши перенести на форму любой элемент:

Найдем среди элементов кнопку и, захватив ее указателем мыши, перенесем на форму:

Это визуальная часть. Теперь приступим к самому программированию. Добавим простейший код на языке C#, который бы выводил сообщение по нажатию кнопки. Для этого мы должны перейти в файл кода, который связан с этой формой. Если у нас не открыт файл кода, мы можем нажать на форму правой кнопкой мыши и в появившемся меню выбрать View Code (Посмотреть файл кода):

Однако воспользуемся другим способом, чтобы не писать много лишнего кода. Наведем указатель мыши на кнопку и щелкнем по ней двойным щелчком. Мы автоматически попадаем в файл кода Form1.cs , который выглядит так:

Using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace HelloApp { public partial class Form1: Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { } } }

Добавим вывод сообщения по нажатию кнопки, изменив код следующим образом:

Using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace HelloApp { public partial class Form1: Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("Привет"); } } }

Запуск приложения

Чтобы запустить приложение в режиме отладки, нажмем на клавишу F5 или на зеленую стрелочку на панели Visual Studio. После этого запустится наша форма с одинокой кнопкой. И если мы нажмем на кнопку на форме, то нам будет отображено сообщение с приветствием.

После запуска приложения студия компилирует его в файл с расширением exe. Найти данный файл можно, зайдя в папку проекта и далее в каталог bin/Debug или bin/Release

Рассмотрев вкратце создание проекта графического приложения, мы можем перейти к обзору основных компонентов и начнем мы с форм.

Если вы захотите писать программы, похожие на привычные приложения Windows, то наверняка воспользуетесь классами из пространства имен System.Windows.Forms . Они позволяют задействовать кнопки, списки, текстовые поля, меню, окна сообщений и множество других "элементов управления". Элементы управления - это то, что вы помещаете в форму. Они нужны для вывода информации, например, текстовой (элемент управления Label ) или графической (элемент управления PictureBox ), либо для выполнения определенных действий, например, выбора значения или перехода к другой форме после нажатия кнопки. Все элементы управления помещаются на форму.

Понятие "форма", принятое в программировании, родственно понятию "форма анкеты" или "форма документа" из обычной жизни. На форме можно в определенном порядке расположить различные элементы (текст , картинки, поля для заполнения и т. д.). Когда нам дают готовую форму документа и просят ее заполнить , мы обычно читаем содержащуюся в ней типовую информацию, а затем вписываем недостающие данные в определенные строки.

В программировании понятие формы во многом похоже: форма позволяет размещать текст, изображения, поля ввода, кнопки и т. п., добиваясь их точного расположения на экране. В консольном приложении на экран выводятся только строки текста.

Компания Майкрософт предоставила в составе библиотеки классов.NET Framework огромное количество "элементов управления", которые можно помещать на формы. Освоив этот инструмент, вы сможете быстро создавать эффектные приложения.

Некоторые полезные классы из пространства имен System.Windows.Forms

Вот некоторые элементы управления, которые можно размещать на формах:

  • Label (Надпись).
  • Button (Кнопка).
  • ListBox (Список).
  • CheckBox (Флажок).
  • RadioButton (Переключатель).
  • MessageBox (Окно сообщений).
  • Menu (Меню).
  • TabControl (Управление вкладками).
  • Toolbar (Панель инструментов).
  • TreeView (Дерево).
  • DataGrid (Сетка данных).
  • PictureBox (Изображение).
  • RichTextBox (Текстовое поле с поддержкой формата RTF ).

Работа с примерами программ Windows Forms в Visual C# Express

Возможно, вы предпочтете не использовать уже заготовленные примеры проектов, а разрабатывать их "с нуля" . В таком случае нужно учесть, что для каждого проекта C# Express сразу же создает два файла (с именами Form1.cs и Program.cs ) и наполняет их исходным кодом на языке C#, то есть вы изначально получаете простейшую, но полноценную программу. Предлагаемый нами способ работы с уже полученным проектом состоит в выполнении следующих действий:

  • Удалите файл Form1.cs.
  • Замените код в файле Program.cs на код примера, с которым вы работаете.

Оба этих действия не понадобятся, если вы открываете программы с помощью команды "Открыть проект" в меню "Файл" и находите нужный проект в той папке, куда его поместили после разархивации.

Пример программы 3.3

Рассмотрим пример простейшего приложения Windows Forms. Оно всего лишь создает новую форму и выводит определенный текст в заголовок окна формы.

Using System.Windows.Forms; class SimpleWindowsForm: Form { // Метод-конструктор нашего класса public SimpleWindowsForm() { // Указываем заголовок окна this.Text = "Это простая форма с заголовком"; } static void Main() { // Создаем новый экземпляр класса //и запускаем его на выполнение // В результате на экране дисплея откроется форма Application.Run(new SimpleWindowsForm()); } } Листинг 3.3.


Пример программы 3.4

Следующий пример тоже достаточно прост, но мы делаем шаг вперед - размещаем на форме кнопку.

Using System.Windows.Forms; class SimpleWindowsFormWithButton: Form { Button button1; // Метод-конструктор нашего класса public SimpleWindowsFormWithButton() { // Указываем заголовок окна this.Text = "Форма с командной кнопкой"; // Добавляем кнопку в коллекцию элементов управления формы // Хотя на кнопке написано: "Нажми меня!", // пока при нажатии ничего не происходит! button1 = new Button(); button1.Text = "Нажми меня!"; button1.Top = 100; button1.Left = 100; button1.Height = 50; button1.Width = 70; this.Controls.Add(button1); } static void Main() { // Создаем и запускаем форму Application.Run(new SimpleWindowsFormWithButton()); } } Листинг 3.4.


Пример программы 3.5

Кнопку на форму мы поместили, но при нажатии на нее ничего не происходит. Это скучно.

Нам нужно описать метод, который будет выполнять какое-либо действие при нажатии на кнопку. Пусть при этом текст в заголовке окна будет меняться. Поскольку такой метод отслеживает наступление некоторого события (в нашем случае – нажатие на кнопку) и затем каким-то образом обрабатывает его, он, напомним, называется "обработчик события". Кроме того, надо привязать обработчик события к соответствующему событию, то есть к нажатию на кнопку.

Using System; using System.Windows.Forms; using System.Drawing; class FormWithWorkingButton: Form { Button mrButton; // Метод-конструктор нашего класса public FormWithWorkingButton() { // Указываем заголовок окна this.Text = "Форма с работающей кнопкой!"; // Добавляем кнопку и привязываем ее к обработчику события mrButton = new Button(); mrButton.Text = "Нажми меня"; mrButton.Top = 100; mrButton.Left = 100; mrButton.Height = 50; mrButton.Width = 70; mrButton.Click += new System.EventHandler(mrButton_Click); this.Controls.Add(mrButton); } static void Main() { // Создаем и запускаем форму Application.Run(new FormWithWorkingButton()); } // Обработчик события, срабатывающий при нажатии кнопки void mrButton_Click(object sender, EventArgs e) { // Изменяем текст mrButton.Text = "Кнопка была нажата!"; } } Листинг 3.5.


Пример программы 3.6

Мы добились успеха: наша программа умеет выполнять основные действия. Теперь добавим на форму несколько новых элементов управления, аккуратно разместим их и немного поработаем с ними. Возьмем элементы управления 4-х типов: Button, ListBox, MessageBox и PictureBox.

Обратите внимание: кроме System.Windows.Forms в этом примере упоминается пространство имен System.Drawing . Дело в том, что мы используем элемент управления PictureBox , а для работы с изображениями требуются классы Drawing .

Using System.Windows.Forms; using System.Drawing; class MyForm: Form { // Объявим элемент ListBox как поле класса: // нам придется обращаться к нему из разных методов ListBox listBox1; // Метод-конструктор нашего класса public MyForm() { //Размеры формы this.Size = new Size(400, 400); // Создадим элемент PictureBox, поместим в него изображение, // добавим его на форму PictureBox pictureBox1 = new PictureBox(); pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; Bitmap image1 = new Bitmap ("..//..//images//Zakat.jpg"); pictureBox1.ClientSize = new Size(this.Width, 150); pictureBox1.Image = (Image)image1; this.Controls.Add(pictureBox1); // Создаем объект Button, определяем некоторые из его свойств Button button1 = new System.Windows.Forms.Button(); button1.Location = new Point(150, 160); button1.Size = new Size(100, 30); button1.Text = "Нажми меня"; button1.Click += new System.EventHandler(button1_Click); this.Controls.Add(button1); // Создаем ListBox, определяем свойства и добавляем на форму listBox1 = new System.Windows.Forms.ListBox(); listBox1.Location = new System.Drawing.Point(20, 200); listBox1.Size = new Size(100, 100); listBox1.Items.Add("Лес"); listBox1.Items.Add("Степь "); listBox1.Items.Add("Озеро"); listBox1.Items.Add("Море"); listBox1.Items.Add("Океан"); listBox1.SelectedIndex = 2; this.Controls.Add(listBox1); } // Обработчик события, срабатывающий при нажатии кнопки void button1_Click(object sender, System.EventArgs e) { // Выводим сообщение с указанием выбранного в списке пункта MessageBox.Show(this, "Вы выбрали " + listBox1.SelectedItem, "Уведомление", MessageBoxButtons.OK); } static void Main() { // Создаем и запускаем форму Application.Run(new MyForm()); } private void InitializeComponent() { this.SuspendLayout(); // // MyForm // this.BackColor = System.Drawing.SystemColors.Control; this.ClientSize = new System.Drawing.Size(292, 273); this.Name = "MyForm"; this.ResumeLayout(false); } } Листинг 3.6.

Сегодня я хочу рассказать о том, как создать проект Windows Forms на C++ в IDE Visual Studio 2013. Дело в том, что, начиная с VS 2012, в списке проектов, которые можно создать, убрали пункт Приложение Windows Forms. Я сейчас говорю о том, который на C++, создать такой проект на C# можно, выбрав соответствующий пункт в разделе создаваемых проектов. Однако тот факт, что такой проект нельзя выбрать из списка, не говорит о том, что его нельзя создать самому. Именно об этом я и хочу рассказать в этой статье.

Первое, что потребуется сделать - запустить Visual Studio. Как только VS запустили, нажимаем последовательно Файл > Создать > Проект

После этого в открывшемся окне будет предложено выбрать тип проекта. Нам необходимо выбрать в разделе Visual C++ подраздел CLR и выбрать пункт Пустой проект CLR.

Когда проект будет создан, в обозревателе решений кликаем правой кнопкой мыши по созданному проекту. В открывшемся контекстном меню последовательно выбираем Добавить > Создать элемент и в открывшемся меню в разделе UI выбираем Форма Windows Forms

Когда форма будет добавлена, в обозревателе решений выбираем файл MyForm.cpp. Перед вами откроется новая вкладка с единственной строчкой кода:

#include "MyForm.h"

В этот файл нам необходимо добавить следующий код:

Using namespace System; using namespace System::Windows::Forms; void Main(array^ args) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); Project1::MyForm form; Application::Run(%form); }

После этого в свойствах проекта. Выбираем подраздел Система раздела Компоновщик и в строке Подсистема из выпадающего меню выбираем Windows (/SUBSYSTEM:WINDOWS) и нажимаем Применить.

Не закрывая окно свойств проекта, переходим в подраздел Дополнительно и в строке Точка входа пишем Main и после этого нажимаем клавишу ОК.
На этом настройки проекта заканчиваются. Для редактирования внешнего вида формы, необходимо перейти во вкладку MyForm.h [Конструктор], кликнув дважды по файлу MyForm.h в обозревателе решений.

Доброго времени суток!
Model-View-Presenter - довольно известный шаблон проектирования. С первого взгляда все выглядит просто: есть Модель (Model), которая содержит всю бизнес-логику экрана; Вид/Представление (View), который знает, как отобразить те или иные данные; Представитель (Presenter), который является связующий звеном - реагирует на действия пользователя во View, изменяя Model, и наоборот.
Сложность начинается, когда количество форм в проекте становится более одной.
В данной статье рассматривается:
- немножко теории;
- общие проблемы реализации MVP (а именно Passive View) под Windows Forms;
- особенности реализации переходов между формами и передача параметров, модальные окна;
- использование IoC-контейнера и шаблона Dependency Injection - DI (а именно Сonstructor Injection);
- некоторые особенности тестирования MVP приложения (с использованием NUnit и NSubstitute);
- все это будет происходить на примере мини-проекта и постарается быть наглядным.
В статье затрагивается:
- применение шаблона Адаптер (Adapter);
- простенькая реализация шаблона Контроллер приложения (Application Controller).
Для кого эта статья?
Главным образом для начинающих разработчиков на Windows Forms, которые слышали, но не пробовали, или пробовали, но не получилось. Хотя уверен, что некоторые приемы применимы и для WPF, и даже для веб-разработки.

Постановка задачи

Придумаем простую задачу - реализовать 3 экрана:
1) экран авторизации;
2) главный экран;
3) модальный экран изменения имени пользователя.
Должно получиться что-то вроде этого:

Немного теории

MVP, как и его родитель, MVC (Model-View-Controller) придуман для удобства разделения бизнес-логики от способа ее отображения.

На просторах интернета можно встретить целое множество реализаций MVP. По способу доставки данных в представление их можно разделить на 3 категории:
- Passive View: View содержит минимальную логику отображения примитивных данных (строки, числа), остальным занимается Presenter;
- Presentation Model: во View могут передаваться не только примитивные данные, но и бизнес-объекты;
- Supervising Controller: View знает о наличии модели и сам забирает из нее данные.

Далее будет рассматриваться модификация Passive View. Опишем основные черты:
- интерфейс Представления (IView), который предоставляет некий контракт для отображения данных;
- Представление - конкретная реализация IView, которая умеет отображать саму себя в конкретном интерфейсе (будь то Windows Forms, WPF или даже консоль) и ничего не знает о том, кто ей управляет. В нашем случае это формы;
- Модель - предоставляет некоторую бизнес-логику (примеры: доступ к базе данных, репозитории, сервисы). Может быть представлена в виде класса или опять же, интерфейса и реализации;
- Представитель содержит ссылку на Представление через интерфейс (IView), управляет им, подписывается на его события, производит простую валидацию (проверку) введенных данных; также содержит ссылку на модель или на ее интерфейс, передавая в нее данные из View и запрашивая обновления.

Типичная реализация Представителя

public class Presenter { private readonly IView _view; private readonly IService _service; public Presenter(IView view, IService service) { _view = view; _service = service; _view.UserIdChanged += () => UpdateUserInfo(); } private void UpdateUserInfo() { var user = _service.GetUser(_view.UserId); _view.Username = user.Username; _view.Age = user.Age; } }


Какие плюсы нам дает малая связанность классов (использование интерфейсов, событий)?
1. Позволяет относительно свободно менять логику любого компонента, не ломая остального.
2. Большие возможности при unit-тестировании. Поклонники TDD должны быть в восторге.
Начнем!

Как организовать проекты?

Условимся, что решение будет состоять из 4х проектов:
- DomainModel - содержит сервисы и всевозможные репозитории, одним словом - модель;
- Presentation - содержит логику приложения, не зависящую от визуального представления, т.е. все Представители, интерфейсы Представлений и остальные базовые классы;
- UI - Windows Forms приложение, содержит только лишь формы (реализацию интерфейсов Представлений) и логику запуска;
- Tests - unit-тесты.

Что писать в Main()?

Стандартная реализация запуска Windows Forms приложения выглядит так:

Private static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); // непосредственный запуск формы (представления) }
Но мы условились, что Представители будут управлять Представлениями, следовательно хотелось бы, чтобы код выглядел как-то так:

Private static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); var presenter = new LoginPresenter(new LoginForm(), new LoginService()); // Dependency Injection presenter.Run(); }
Попробуем реализовать первый экран:

Базовые интерфейсы

// общие методы для всех представлений public interface IView { void Show(); void Close(); } // контракт, по которому представитель будет взаимодействовать с формой public interface ILoginView: IView { string Username { get; } string Password { get; } event Action Login; // событие "пользователь пытается авторизоваться" void ShowError(string errorMessage); } public interface IPresenter { void Run(); } // глупейший сервис авторизации public interface ILoginService { bool Login(User user); // true - успешная авторизация, иначе false }


Представление

public class LoginPresenter: IPresenter { private readonly ILoginView _view; private readonly ILoginService _service; public LoginPresenter(ILoginView view, ILoginService service) { _view = view; _service = service; _view.Login += () => Login(_view.Username, _view.Password); } public void Run() { _view.Show(); } private void Login(string username, string password) { if (username == null) throw new ArgumentNullException("username"); if (password == null) throw new ArgumentNullException("password"); var user = new User {Name = username, Password = password}; if (!_service.Login(user)) { _view.ShowError("Invalid username or password"); } else { // успешная авторизация, запуск главного экрана (?) } } }


Создать форму и реализовать в ней интерфейс ILoginView не составит труда, как и написать реализацию ILoginService. Следует только отметить одну особенность:

Public partial class LoginForm: Form, ILoginView { // ... public new void Show() { Application.Run(this); } }
Это заклинание позволит нашему приложению запуститься, отобразить форму, а по закрытии формы корректно завершить приложение. Но к этому мы еще вернемся.

А тесты будут?

С момента написания представителя (LoginPresenter), появляется возможность сразу же его от-unit-тестировать, не реализуя ни формы, ни сервисы.
Для написания тестов я использовал библиотеки NUnit и NSubstitute (библиотека создания классов-заглушек по их интерфейсам, mock).

Тесты для LoginPresenter

Public class LoginPresenterTests { private ILoginView _view; public void SetUp() { _view = Substitute.For(); // заглушка для представления var service = Substitute.For(); // заглушка для сервиса service.Login(Arg.Any()) // авторизуется только пользователь admin/password .Returns(info => info.Arg().Name == "admin" && info.Arg().Password == "password"); var presenter = new LoginPresenter(_view, service); presenter.Run(); } public void InvalidUser() { _view.Username.Returns("Vladimir"); _view.Password.Returns("VladimirPass"); _view.Login += Raise.Event(); _view.Received().ShowError(Arg.Any()); // этот метод должен вызваться с текстом ошибки } public void ValidUser() { _view.Username.Returns("admin"); _view.Password.Returns("password"); _view.Login += Raise.Event(); _view.DidNotReceive().ShowError(Arg.Any()); // а в этом случае все ОК } }


Тесты довольно глупые, как пока и само приложение. Но так или иначе, они успешно пройдены.

Кто и как запустит второй экран с параметром?

Как вы могли заметить, я не написал никакого кода при успешной авторизации. Как же мне запустить второй экран? Первое на ум приходит это:

// LoginPresenter: успешная авторизация var mainPresenter = new MainPresenter(new MainForm()); mainPresenter.Run(user);
Но мы условились, что представители ничего не знают о представлениях кроме их интерфейсов. Что же делать?
На помощь приходит паттерн Application Controller (реализован упрощенно), внутри которого содержится IoC-контейнер, знающий, как по интерфейсу получить объект реализации.
Контроллер передается каждому Представителю параметром конструктора (снова DI) и реализует примерно следующие методы:

Public interface IApplicationController { IApplicationController RegisterView() where TImplementation: class, TView where TView: IView; IApplicationController RegisterService() where TImplementation: class, TService; void Run() where TPresenter: class, IPresenter; }
После небольшого рефакторинга запуск приложения стал выглядеть так:

Private static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // все зависимости теперь регистрируются в одном месте: var controller = new ApplicationController(new LightInjectAdapder()) .RegisterView() .RegisterService() .RegisterView(); controller.Run(); }
Пару слов о new ApplicationController(new LightInjectAdapder()) . В качестве IoC-контейнера я использовал библиотеку LightInject, но не напрямую, а через адаптер (паттерн Adapter), чтобы в случае, если понадобится сменить контейнер на другой, я смог написать другой адаптер и не менять логику контроллера. Все используемые методы есть в большинстве IoC-библиотек, сложностей возникнуть не должно.
Реализуем дополнительный интерфейс IPresenter, отличающийся только тем, что метод Run принимает параметр. Затем унаследуемся от него аналогично первому экрану.
Теперь, не без гордости, запускаем второй экран, передавая туда авторизованного пользователя:

Controller.Run(user); View.Close();

Нельзя просто так взять и закрыть форму...

Один из подводных камней связан со строчкой View.Close() , после которой закрывалась первая форма, а вместе с ней и приложение. Дело в том, что Application.Run(Form) запускает стандартный цикл обработки сообщений Windows и рассматривает переданную форму как главную форму приложения. Это выражается в том, что приложение вешает ExitThread на событие Form.Closed , что и вызывает закрытие приложения после закрытия формы.
Обойти данную проблему можно несколькими способами, один из них - использовать другой вариант метода: Application.Run(ApplicationContext) , затем вовремя подменяя свойство ApplicationContext.MainForm . Передача контекста формам реализована с помощью Контроллера приложения, в котором регистрируется объект (instance) ApplicationContext и затем подставляется в конструктор формы (опять DI) во время запуска Представителя. Методы отображения первых двух экранов теперь выглядят так:

// LoginForm public new void Show() { _context.MainForm = this; Application.Run(_context); } // MainForm public new void Show() { _context.MainForm = this; base.Show(); }

Модальное окно

Реализация модального окна не вызывает затруднений. По кнопке "Сменить имя" выполняется Controller.Run(user) . Единственное отличие этой формы от остальных - она не главная, поэтому форме для показа не требуется ApplicationContext:

Public new void Show() { ShowDialog(); }
Если необходимо открыть обычное окно, метод вообще не требуется определять, так как он уже реализован в классе Form.

Ну и накрутили... Как теперь ЭТО использовать?

Теперь, когда каркас готов, добавление новой формы сводится к следующим шагам:
  1. Пишем интерфейс Представления, интерфейс Модели (если требуется).
  2. Реализуем Представителя, попутно решив, будем ли мы в него передавать какие-то данные или модель.
  3. [Опционально] Пишем тесты для Представителя, убеждаемся, что все нормально.
  4. [Опционально] Реализуем Модель и тесты для нее.
  5. Накидываем формочки и реализуем интерфейс Представления.
Смена IoC-контейнера на ваш любимый происходит путем реализации простого интерфейса IContainer классом-адаптером.

Забрать демонстрационный проект можно c

Последнее обновление: 31.10.2015

Внешний вид приложения является нам преимущественно через формы. Формы являются основными строительными блоками. Они предоставляют контейнер для различных элементов управления. А механизм событий позволяет элементам формы отзываться на ввод пользователя, и, таким образом, взаимодействовать с пользователем.

При открытии проекта в Visual Studio в графическом редакторе мы можем увидеть визуальную часть формы - ту часть, которую мы видим после запуска приложения и куда мы переносим элементы с панели управления. Но на самом деле форма скрывает мощный функционал, состоящий из методов, свойств, событий и прочее. Рассмотрим основные свойства форм.

Если мы запустим приложение, то нам отобразится одна пустая форма. Однако даже такой простой проект с пустой формой имеет несколько компонентов:

Несмотря на то, что мы видим только форму, но стартовой точкой входа в графическое приложение является класс Program, расположенный в файле Program.cs :

Using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; namespace HelloApp { static class Program { static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }

Сначала программой запускается данный класс, затем с помощью выражения Application.Run(new Form1()) он запускает форму Form1. Если вдруг мы захотим изменить стартовую форму в приложении на какую-нибудь другую, то нам надо изменить в этом выражении Form1 на соответствующий класс формы.

Сама форма сложна по содержанию. Она делится на ряд компонентов. Так, в структуре проекта есть файл Form1.Designer.cs , который выглядит примерно так:

Namespace HelloApp { 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, 261); this.Name = "Form1"; this.Text = "Привет мир!"; this.ResumeLayout(false); } #endregion } }

Здесь объявляется частичный класс формы Form1, которая имеет два метода: Dispose() , который выполняет роль деструктора объекта, и InitializeComponent() , который устанавливает начальные значения свойств формы.

При добавлении элементов управления, например, кнопок, их описание также добавляется в этот файл.

Но на практике мы редко будем сталкиваться с этим классом, так как они выполняет в основном дизайнерские функции - установка свойств объектов, установка переменных.

Еще один файл - Form1.resx - хранит ресурсы формы. Как правило, ресурсы используются для создания однообразных форм сразу для нескольких языковых культур.

И более важный файл - Form1.cs , который в структуре проекта называется просто Form1, содержит код или программную логику формы:

Using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace HelloApp { public partial class Form1: Form { public Form1() { InitializeComponent(); } } }

По умолчанию здесь есть только конструктор формы, в котором просто вызывается метод InitializeComponent() , объявленный в файле дизайнера Form1.Designer.cs . Именно с этим файлом мы и будем больше работать.