Если вы только начинаете изучать C#, то, возможно, вам будет полезна книга
Самоучитель C#
Книга представляет собой учебник по программированию на языке C# в Microsoft Visual C# для начинающих. Рассмотрен процесс создания консольного приложения от кодирования до отладки и тестирования. Дано описание типов и инструкций языка программирования, структур данных. Рассмотрены задачи работы с массивами, списками, файлами. В объеме, необходимом начинающему программисту, рассмотрены вопросы создания и использования объектов, уделено внимание технологии LINQ.Для начинающих программистов.
Об авторе
Никита Культин – к.т.н., доц., автор книг по программированию в Delphi, Microsoft Visual С#, Microsoft Visual С++ и др., которые были выпущены издательством БХВ-Петербург и разошлись общим тиражом более 450 тыс. экз.Первый проект
Замечание. Первый проект это - глава из моей книги Самоучитель Microsoft Visual C# 2015. Книгу Самоучитель Microsoft Visual C# 2015 - Задачи и примерыможно загрузить из магазина приложений Windows,
Из магазина приложений Google Play можно загрузить книгу
Самоучитель Microsoft Visual C# 2013.
Процесс разработки программы в Microsoft Visual C# рассмотрим на примере — создадим приложение (программы, предназначенные для решения прикладных задач, принято называть приложениями), позволяющее посчитать доход по вкладу (рис. 2.1).

Рис. 2.1. Окно программы Доход
Начало работы над проектом
Чтобы начать работу над новым проектом, надо: - В меню Файл выбрать команду Создать проект.
- В открывшемся окне Создание проекта выбрать тип приложения —Приложение Windows Forms Visual C#.
- В поле Имя ввести название проекта — profit и нажать кнопку OK (рис. 2.2).
Форма
Работа над приложением начинается с создания стартовой формы — главного окна программы. Форма создается путем добавления на заготовку формы необходимых компонентов и изменения значений свойств самой формы.Сначала нужно установить требуемые значения свойств формы, затем — поместить на форму необходимые компоненты (поля ввода информации, командные кнопки, поля отображения текста и др.) и выполнить.
Настройка формы (а также компонентов) осуществляется путем изменения значений свойств. Свойства объекта (формы, компонента) определяют его вид и поведение. Например, свойство Text определяет текст заголовка окна, а свойство StartPosition — положение окна в момент появления его на экране.
Основные свойства формы (объекта Form) приведены в табл. 2.1.
Таблица 2.1. Свойства формы (объекта Form)
| Свойство | Описание |
|---|---|
| Name | Имя формы |
| Text | Текст в заголовке |
| Size | Размер формы. Уточняющее свойство Width определяет ширину, свойство Heigh — высоту |
| StartPosition | Положение формы в момент первого появления на экране. Форма может находиться в центре экрана (CenterScreen), в центре родительского окна (CenterParent). Если значение свойства равно Manual, то положение формы определяется значением свойства Location |
| Location | Положение формы на экране. Расстояние от верхней границы формы до верхней границы экрана задает уточняющее свойство Y, расстояние от левой границы формы до левой границы экрана — уточняющее свойство X |
| FormBorderStyle | Тип формы (границы). Форма может представлять собой обычное окно (Sizable), окно фиксированного размера (FixedSingle, Fixed3D), диалог (FixedDialog) или окно без кнопок Свернуть и Развернуть (SizeableToolWindow, FixedToolWindow). Если свойству присвоить значение None, у окна не будет заголовка и границы |
| ControlBox | Управляет отображением системного меню и кнопок управления окном. Если значение свойства равно False, то в заголовке окна кнопка системного меню, а также кнопки Свернуть, Развернуть, Закрыть не отображаются |
| MaximazeBox | Кнопка Развернуть. Если значение свойства равно False, то находящаяся в заголовке окна кнопка Развернуть недоступна |
| MinimazeBox | Кнопка Свернуть. Если значение свойства равно False, то находящаяся в заголовке окна кнопка Свернуть недоступна |
| Icon | Значок в заголовке окна |
| Font | Шрифт, используемый по умолчанию компонентами, находящимися на поверхности формы. Изменение значения свойства приводит к автоматическому изменению значения свойства Font всех компонентов формы (при условии, что значение свойства компонента не было задано явно) |
| ForeColor | Цвет, наследуемый компонентами формы и используемый ими для отображения текста. Изменение значения свойства приводит к автоматическому изменению соответствующего свойства всех компонентов формы (при условии, что значение свойства Font компонента не было задано явно) |
| BackColor | Цвет фона. Можно задать явно (выбрать на вкладке Custom или Web) или указать элемент цветовой схемы (выбрать на вкладке System) |
| Opacity | Степень прозрачности формы. Форма может быть непрозрачной (100%) или прозрачной. Если значение свойства меньше 100%, то сквозь форму видна поверхность, на которой она отображается |
Для изменения значений свойств объектов используется окно Свойства. В левой колонке окна перечислены свойства объекта, выбранного в данный момент, в правой — указаны значения свойств. Имя выбранного объекта отображается в верхней части окна Свойства.
Чтобы в заголовке окна программы отображалось название программы (слово Доход), надо изменить значение свойства Text формы. Чтобы это сделать, надо в окне Свойства щелкнуть левой кнопкой мыши в поле значение свойства Text (в поле появится курсор) и ввести в поле редактирования текст Доход (рис. 2.3).
Рис. 2.3. Изменение значения свойства Техt путем ввода нового значения
При выборе некоторых свойств, например FormBorderStyle, справа от текущего значения свойства появляется значок раскрывающегося списка. Очевидно, что значение таких свойств можно задать путем выбора из списка (рис. 2.4).
Рис. 2.4. Установка значения свойства путем выбора из списка
Некоторые свойства являются сложными. Они представляют собой совокупность других (уточняющих) свойств. Например, свойство Size, определяющее размер формы, представляет собой совокупность свойств Width и Height. Перед именами сложных свойств стоит плюс, в результате щелчка на котором раскрывается список уточняющих свойств (рис. 2.5). Значение уточняющего свойства можно задать (изменить) обычным образом — ввести нужное значение в поле редактирования.
Рис. 2.5. Изменение значения уточняющего свойства
Размер формы можно изменить и с помощью мыши, точно так же, как и любого окна, т. е. путем перемещения границы. По окончании перемещения границы значения свойств Width и Height будут соответствовать установленному размеру формы.
В результате выбора некоторых свойств, например Font, в поле значения свойства отображается кнопка, на которой изображены три точки. Это значит, что задать значение свойства можно в дополнительном диалоговом окне, которое появится в результате щелчка на этой кнопке. Например, значение свойства Font можно задать путем ввода значений уточняющих свойств (Name, Size, Style и др.), а можно воспользоваться стандартным диалоговым окном Шрифт, которое появится в результате щелчка на кнопке с тремя точками (рис. 2.6).
Рис. 2.6. Чтобы задать свойства шрифта, щелкните на кнопке с тремя точками
В табл. 2.2 приведены значения свойств формы программы "Доход". Значения остальных свойств формы оставлены без изменения и поэтому в таблице не представлены. Обратите внимание, в именах некоторых свойств есть точка. Это значит, что это значение уточняющего свойства.
Таблица 2.2. Значения свойств стартовой формы
| Свойство | Значение | Комментарий |
|---|---|---|
| Text | Доход | |
| Size.Width | 365 | |
| Size.Height | 215 | |
| FormBorderStyle | FixedSingle | Тонкая граница формы. Во время работы программы пользователь не сможет изменить размер окна путем захвата и перемещения его границы |
| StartPosition | CenterScreen | Окно программы появится в центре экрана |
| MaximizeBox | False | В заголовке окна не отображать кнопку Развернуть |
| Font.Name | Tahoma | |
| Font.Size | 10 |
После того как будут установлены значения свойств формы, она должна выглядеть так, как показано на рис. 2.7. Теперь на форму надо добавить компоненты.
Рис. 2.7. Форма после изменения значений свойств
Элементы
Поля ввода-редактирования текста, поля отображения текстовой информации, командные кнопки, списки, переключатели и другие элементы, обеспечивающие взаимодействие пользователя с программой, называют элементами или компонентами пользовательского интерфейса. Они находятся в окне Панель элементов на вкладке Стандартные элементы.Программа "Доход" должна получить от пользователя исходные данные — сумму и срок вклада. Ввод данных с клавиатуры обеспечивает компонент TextBox. Таким образом, на форму разрабатываемого приложения нужно поместить два компонента TextBox (рис. 2.8).
Рис. 2.8. Компонент TextBox — поле редактирования
Чтобы добавить на форму компонент TextBox, надо:
- В панели элементов (окно Панель элементов) раскрыть вкладку Стандартные элементы.
- Сделать щелчок на значке компонента TextBox.
- Установить указатель мыши в ту точку формы, в которой должен быть левый верхний угол компонента и сделать щелчок левой кнопкой мыши.
Рис. 2.9. Результат добавления на форму компонента TextBox
Каждому компоненту среда разработки автоматически присваивает имя, которое состоит из названия компонента и его порядкового номера. Например, первый добавленный на форму компонент TextBox получает имя textBox1, второй — textBox2. Программист путем изменения значения свойства Name может поменять имя компонента. Однако в простых программах имена компонентов, как правило, не меняют.
Основные свойства компонента TextBox приведены в табл. 2.3.
Таблица 2.3. Свойства компонента TextBox
| Свойство | Описание |
|---|---|
| Name | Имя компонента |
| Text | Текст, который находится в поле редактирования |
| Location | Положение компонента на поверхности формы |
| Size | Размер компонента |
| Font | Шрифт, используемый для отображения текста в поле компонента |
| ForeColor | Цвет текста, находящегося в поле компонента |
| BackColor | Цвет фона поля компонента |
| BorderStyle | Вид рамки (границы) компонента. Граница компонента может быть обычной (Fixed3D), тонкой (FixedSingle) или отсутствовать (None) |
| TextAlign | Способ выравнивания текста в поле компонента. Текст в поле компонента может быть прижат к левой границе компонента (Left), правой (Right) или находиться по центру (Center) |
| MaxLength | Максимальное количество символов, которое можно ввести в поле компонента |
| Multiline | Разрешает (True) или запрещает (False) ввод нескольких строк текста |
| ReadOnly | Разрешает (True) или запрещает (False) редактирование отображаемого текста |
| Lines | Массив строк, элементы которого содержат текст, находящийся в поле редактирования, если компонент находится в режиме MultiLine. Доступ к строке осуществляется по номеру. Строки нумеруются с нуля |
| ScrollBars | Задает отображаемые полосы прокрутки: Horizontal — горизонтальная; Vertical — вертикальная; Both — горизонтальная и вертикальная; None — не отображать |
На рис. 2.10 приведен вид формы программы "Доход" после добавления двух компонентов. Один из компонентов выбран — выделен рамкой. Свойства именно этого (выбранного) компонента отображаются в окне Свойства.
Рис. 2.10. Форма с двумя компонентами TextBox
Чтобы увидеть и, если надо, изменить свойства другого компонента, нужно этот компонент выбрать — щелкнуть левой кнопкой мыши на изображении компонента в форме или выбрать его имя в раскрывающемся списке, который находится в верхней части окна Свойства (рис. 2.11).
Рис. 2.11. Выбор компонента в окне Свойства
Чтобы изменить положение компонента, необходимо установить курсор мыши на его изображение, нажать левую кнопку мыши и, удерживая ее нажатой, переместить компонент в нужную точку формы (рис. 2.12).
Рис. 2.12. Изменение положения компонента
Для того чтобы изменить размер компонента, необходимо сделать щелчок на его изображении (в результате чего компонент будет выделен), установить указатель мыши на один из маркеров, помечающих границу компонента, нажать левую кнопку мыши и, удерживая ее нажатой, изменить положение границы компонента (рис. 2.13).
Рис. 2.13. Изменение размера компонента
В табл. 2.4 приведены значения свойств компонентов textBox1 и textBox2 (прочерк показывает, что значением свойства Text является пустая строка). Значения остальных свойств компонентов оставлены без изменения и поэтому в таблице не показаны. Компонент textBox1 предназначен для ввода суммы вклада, textBox2 — срока. Так как значения свойства Font компонентов TextBox не были изменены, то во время работы программы текст в полях редактирования будет отображаться шрифтом, заданным для формы. Компоненты TextBox, как и другие компоненты, находящиеся на форме, наследуют значение свойства Font формы (если значение свойства Font компонента не было задано явно). Поэтому если изменить значение свойства Font формы, автоматически изменятся значения свойств Font компонентов, находящихся на форме. Если требуется, чтобы текст в поле компонента отображался другим шрифтом, нужно явно задать значение свойства Font этого компонента.
Форма программы "Доход" после настройки компонентов TextBox приведена на рис. 2.14.
Таблица 2.4. Значения свойств компонентов TextBox
| Компонент | Свойство | Значение |
|---|---|---|
| textBox1 | Location.X | 107 |
| Location.Y | 16 | |
| Size.Width | 100 | |
| Size.Height | 23 | |
| Text | - | |
| TabIndex | 0 | |
| textBox2 | Location.X | 107 |
| Location.Y | 45 | |
| Size.Width | 57 | |
| Size.Height | 23 | |
| Text | - | |
| TabIndex | 1 |
Отображение текста на поверхности формы (подсказок, результата расчета) обеспечивает компонент Label (рис. 2.15).
Рис. 2.15. Компонент Label — поле отображения текста
Добавляются компоненты Label на форму точно так же, как и поля редактирования.
Основные свойства компонента Label приведены в табл. 2.5.
Таблица 2.5. Свойства компонента Label
| Свойство | Описание |
|---|---|
| Name | Имя компонента. Используется в программе для доступа к свойствам компонента |
| Text | Отображаемый текст |
| Location | Положение компонента на поверхности формы |
| AutoSize | Признак автоматического изменения размера компонента. Если значение свойства равно True, то при изменении значения свойства Text (или Font) автоматически изменяется размер компонента |
| Size | Размер компонента (области отображения текста). Определяет (если значение свойства AutoSize равно False) размер компонента (области отображения текста) |
| Font | Шрифт, используемый для отображения текста |
| ForeColor | Цвет текста, отображаемого в поле компонента |
| BackColor | Цвет закраски области вывода текста |
| TextAlign | Способ выравнивания (расположения) текста в поле компонента. Всего существует девять способов расположения текста. На практике наиболее часто используют выравнивание по левой верхней границе (TopLeft), посередине (TopCentre) и по центру (MiddleCenter) |
На форму разрабатываемого приложения надо добавить три компонента Label. В полях label1 и label2 отображается информации о назначении полей ввода, поле label3 используется для вывода результата расчета.
Значения свойств компонентов Label приведены в табл. 2.6.
Таблица 2.6. Значения свойств компонентов Label
| Компонент | Свойство | Значение |
|---|---|---|
| label1 | Location.X | 13 |
| Location.Y | 19 | |
| AutoSize | False | |
| Sise.Width | 88 | |
| Size.Height | 20 | |
| Text | Сумма (руб.): | |
| TextAlign | MiddleRight | |
| label2 | Location.X | 13 |
| Location.Y | 45 | |
| AutoSize | False | |
| Sise.Width | 88 | |
| Size.Height | 20 | |
| Text | Срок (мес.): | |
| TextAlign | MiddleRight | |
| label3 | Location.X | 23 |
| Location.Y | 122 | |
| AutoSize | False | |
| Sise.Width | 299 | |
| Size.Height | 50 | |
| Text | - |
После настройки компонентов Label форма приложения Доход должна выглядеть так, как показано на рис. 2.16.
Рис. 2.16. Вид формы после настройки полей отображения текста
Следующее, что надо сделать на этапе создания формы, — добавить на форму командную кнопку Расчет. Назначение этой кнопки очевидно.
Командная кнопка, компонент Button (рис. 2.17), добавляется на форму точно так же, как и другие компоненты.
Рис. 2.17. Командная кнопка — компонент Button
Основные свойства компонента Button приведены в табл. 2.7.
Таблица 2.7. Свойства компонента Button
| Свойство | Описание |
|---|---|
| Name | Имя компонента. Используется для доступа к компоненту и его свойствам |
| Text | Текст на кнопке |
| TextAlign | Положение текста на кнопке. Текст может располагаться в центре кнопки (MiddleCenter), быть прижат к левой (MiddleLeft) или правой (MiddleRight) границе. Можно задать и другие способы размещения надписи (TopLeft, TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight) |
| FlatStyle | Стиль. Кнопка может быть стандартной (Standard), плоской (Flat) или "всплывающей" (Popup) |
| Location | Положение кнопки на поверхности формы. Уточняющее свойство X определяет расстояние от левой границы кнопки до левой границы формы, уточняющее свойство Y — от верхней границы кнопки до верхней границы клиентской области формы (нижней границы заголовка) |
| Size | Размер кнопки |
| Enabled | Признак доступности кнопки. Кнопка доступна, если значение свойства равно True, и недоступна, если значение свойства равно False (в этом случае нажать кнопку нельзя, событие Click в результате щелчка на ней не возникает) |
| Visible | Позволяет скрыть кнопку (False) или сделать ее видимой (True) |
| Cursor | Вид указателя мыши при позиционировании указателя на кнопке |
| Image | Картинка на поверхности кнопки. Рекомендуется использовать gif-файл, в котором определен прозрачный цвет |
| ImageAlign | Положение картинки на кнопке. Картинка может располагаться в центе (MiddleCenter), быть прижата к левой (MiddleLeft) или правой (MiddleRight) границе. Можно задать и другие способы размещения картинки на кнопке (TopLeft, TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight) |
| ImageList | Набор изображений, из которых может быть выбрано то, которое будет отображаться на поверхности кнопки. Представляет собой объект типа ImageList. Чтобы задать значение свойства, в форму приложения нужно добавить компонент ImageList |
| ImageIndex | Номер (индекс) изображения из набора ImageList, которое отображается на кнопке |
| ToolTip | Подсказка, появляющаяся рядом с указателем мыши при его позиционировании на кнопке. Чтобы свойство стало доступно, в форму приложения нужно добавить компонент ToolTip |
После того как на форму будут добавлены кнопки, нужно выполнить их настройку. Значения свойств компонентов Button приведены в табл. 2.8, окончательный вид формы показан на рис. 2.18.
Таблица 2.8. Значения свойств компонента button1
| Свойство | Значение |
|---|---|
| Location.X | 26 |
| Location.Y | 84 |
| Size.Width | 75 |
| Size.Height | 23 |
| Text | Расчет |
Завершив работу по созданию формы, можно приступить к программированию — созданию функций обработки событий.
Событие
Вид формы программы "Доход" подсказывает, как работает программа. Очевидно, что пользователь должен ввести в поля редактирования исходные данные и сделать щелчок на кнопке Расчет. Щелчок на изображении командной кнопки — это пример того, что называется событием.Событие (event) — это то, что происходит во время работы программы. Например, щелчок кнопкой мыши — это событие Click, двойной щелчок мышью — событие DblClick.
В табл. 2.9 приведены некоторые события, возникающие в результате действий пользователя.
Таблица 2.9. События
| Событие | Описание |
|---|---|
| Click | Щелчок кнопкой мыши |
| DoubleClick | Двойной щелчок кнопкой мыши |
| MouseDown | Нажатие кнопки мыши |
| MouseUp | Отпускание нажатой кнопки мыши |
| MouseMove | Перемещение указателя мыши |
| KeyPress | Нажатие клавиши |
| KeyDown | Нажатие клавиши. События KeyDown и KeyPress — это чередующиеся, повторяющиеся события, которые происходят до тех пор, пока не будет отпущена удерживаемая клавиша (в этот момент происходит событие KeyUp) |
| KeyUp | Отпускание нажатой клавиши |
| TextChanged | Признак, указывающий изменился ли текст, находящийся в поле редактирования (изменилось значение свойства Text) |
| Load | Загрузка формы. Функция обработки этого события обычно используется для инициализации переменных, выполнения подготовительных действий |
| Paint | Событие происходит при появлении окна на экране в начале работы программы, после появления части окна, которая, например, была закрыта другим окном |
| Enter | Получение фокуса элементом управления |
| Leave | Потеря фокуса элементом управления |
Следует понимать, что одни и те же действия, но выполненные над разными объектами, вызывают разные события. Например, нажатие клавиши (событие KeyPress) в поле ввода/редактирования Сумма и нажатие клавиши (также событие KeyPress) в поле Срок — это два разных события.
Функция обработки события
Реакцией на событие должно быть какое-либо действие. В Visual C# реакция на событие реализуется как функция обработки события. Таким образом, для того чтобы программа в ответ на действия пользователя выполняла некоторую работу, программист должен написать функцию (метод) обработки соответствующего события.Процесс создания функции обработки события рассмотрим на примере обработки события Click для кнопки Расчет.
Чтобы создать функцию обработки события, сначала надо выбрать компонент, для которого создается функция обработки события. Для этого в окне конструктора формы надо сделать щелчок левой кнопкой мыши на нужном компоненте. Затем в окне Свойства щелчком на кнопке События (рис. 2.19) нужно открыть вкладку События.
Рис. 2.19. Кнопка События
Рис. 2.20. На вкладке События перечислены события, которые может воспринимать компонент
Для того чтобы создать функцию обработки события, нужно на вкладке События сначала выбрать событие (сделать щелчок мышью на имени события), затем установить указатель мыши в поле, находящееся рядом с именем события и сделать двойной щелчок левой кнопкой мыши. В результате среда разработки создаст функцию обработки события, сформировав ее имя из имени компонента и имени события (рис. 2.21). Имя функции обработки события можно задать «вручную» - ввести имя в поле редактирования и нажать клавишу <Enter>.
Рис. 2.21. Рядом с именем события отображается имя функции обработки события
В результате описанных действий в модуль формы (cs-файл) будет добавлена функция обработки события (метод класса формы) и станет доступным окно редактора кода (рис. 2.22), в котором можно набирать инструкции, реализующие функцию обработки события.
Функция обработки события Click для кнопки Расчет (button1) приведена в листинге 2.1.
Листинг 2.1. Обработка события Click для кнопки Расчет
private void button1_Click(object sender, EventArgs e)
{
double sum; // сумма
int period; // срок
double percent; // процентная ставка
double profit; // доход
sum = System.Convert.ToDouble(textBox1.Text);
period = System.Convert.ToInt32(textBox2.Text);
if (sum < 10000)
percent = 7.5;
else
percent = 9;
profit = sum * (percent / 100 / 12) * period;
label3.Text =
"Процентная ставка: " + percent.ToString("n") + "%\n" +
"Доход: " + profit.ToString("c");
}
Функция button1_Click вычисляет доход по вкладу и выводит результат расчета в поле компонента label3. Исходные данные (сумма и срок вклада) вводятся из полей редактирования textBox1 и textBox2 путем обращения к свойству Text. Значением свойства Text является строка, которая находится в поле редактирования. Свойство Text строкового типа, поэтому для преобразования строк в числа используются принадлежащие пространству имен System.Convert функции ToDouble() и ToInt32(). Следует обратить внимание, что функция ToDouble() возвращает результат только в том случае, если строка, переданная ей в качестве параметра, является изображением дробного числа, что предполагает использование запятой в качестве десятичного разделителя (при стандартной для России настройке операционной системы). Аналогично, параметр функции ToInt32() должен представлять собой строку, являющуюся изображением целого числа.
Другие функции преобразования строк приведены в табл. 2.10.
Таблица 2.10. Функции преобразования строк
| Функция | Значение |
|---|---|
| ToSingle(s), ToDouble(s) | Дробное типа Single, Double |
| ToByte(s), ToInt16(s), ToInt32(s), ToInt64(s), | Целое типа Byte, Int16, Int32, Int64 |
| ToUInt16(s), ToUInt32(s), ToUInt64(s) | Целое типа UInt16, UInt32, UInt64 |
Пространство имен
Концепция пространства имен является развитием концепции модулей. Пространство имен позволяет избежать конфликта имен, дает программисту свободу в выборе идентификаторов. Так, например, при объявлении функции можно не заботиться об уникальности ее имени, достаточно объявить эту функцию в новом пространстве имен.
В приведенной в листинге 2.1 функции для преобразования строки в дробное число используется функция ToDouble(). Она принадлежит пространству имен System.Convert, на что указывает префикс перед именем функции (строго говоря, функция ToDouble() — это методом объекта Convert, который принадлежит пространству имен System).
Пространство имен (namespace) — это контейнер (модуль), который предоставляет программе, использующей этот модуль, свои объекты (типы, функции, константы и т. д.). Например, пространство имен System.Windows.Forms содержит объекты Label, TextBox, Button и др.
Каждый объект является элементом какого-либо пространства имен. Например, поле редактирования, объект типа TextBox, является элементом или, как принято говорить, принадлежит пространству имен System.Windows.Forms.
Пространства имен, которые использует программа, указывается в инструции using. Например, в начале модуля форы (cs-файл) есть ссылки на пространства имен System, System.Windows.Forms, System.Drawing и др.
Для того чтобы получить доступ к объекту пространства имен (например, методу или константе), следует перед именем объекта указать идентификатор пространства имен, которому принадлежит объект, разделив идентификатор и имя объекта точкой.
Например, инструкция
n = System.Convert.ToSingle(TextBox1.Text);
Вычисленные значения процентной ставки и величины дохода выводятся в поле label3 путем присваивания значения свойству Text. Для преобразования дробного числа в строку (свойство Text строкового типа) используется функция (метод) ToString(). Параметр метода ToString() задает формат строки-результата: "с" — финансовый (от англ. currency); "n" — числовой (от англ. number). Следует обратить внимание, что при использовании финансового формата после числового значения выводится обозначение денежной единицы (в соответствии с настройкой операционной системы). В табл. 2.11 приведены возможные форматы представления числовой информации.
Таблица 2.11. Форматы представления чисел
| Параметр функции ToString | Формат | Пример |
|---|---|---|
| "c" | Currency — финансовый (денежный). Используется для представления денежных величин. Обозначение денежной единицы, разделитель групп разрядов, способ отображения отрицательных чисел определяют соответствующие настройки операционной системы | 55 055,28 р. |
| "e" | Scientific (exponential) — научный. Используется для представления очень маленьких или очень больших чисел. Разделитель целой и дробной частей числа задается в настройках операционной системы | 5,50528+E004 |
| "f" | Fixed — число с фиксированным десятичным разделителем. Используется для представления дробных чисел. Количество цифр дробной части, способ отображения отрицательных чисел определяют соответствующие настройки операционной системы | 55 055,28 |
| "n" | Number — числовой. Используется для представления дробных чисел. Количество цифр дробной части, символ-разделитель групп разрядов, способ отображения отрицательных чисел определяют соответствующие настройки операционной системы | 55 055,28 |
| "g" | General — универсальный формат. Похож на Number, но разряды не разделены на группы | 55055,275 |
| "r" | Roundtrip — без округления. В отличие от формата N, этот формат не выполняет округления (количество цифр дробной части зависит от значения числа) | 55 055,2775 |
Структура проекта
Проект представляет собой совокупность файлов, которые компилятор использует для создания выполняемого файла. Структура проекта отображается в окне Обозреватель решений (рис. 2.23).
Рис. 2.23. Структура проекта
Основными элементами проекта являются:
- главный модуль приложения (файл Program.css);
- модули форм.
Главный модуль
В главном модуле находится функция Main, с которой начинается выполнение программы. Функция Main создает стартовую форму (имя класса стартовой формы указывается в качестве параметра метода Run) в результате чего на экране появляется окно программы.Главный модуль программы "Доход" приведен в листинге 2.2.
Листинг 2.2. Главный модуль программы "Доход" (Program.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace profit
{
static class Program
{
/// <summary>
/// Главная точка входа для приложения.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Модуль формы
Модуль формы содержит объявление класса формы. Физически модуль формы разделен на два файла: Form1.cs и Form1.Designer.cs (листинги 2.3 и 2.4 соответственно). В файле Form1.cs находятся функции (методы класса формы) обработки событий формы и ее компонентов. В файле Form1.Designer.cs (чтобы его увидеть, надо в окне Solution Explorer сделать двойной щелчок на имени файла) находится объявление класса формы, в том числе сформированная дизайнером формы функция InitializeComponent, обеспечивающая создание и настройку компонентов. Следует обратить внимание на секцию Windows Form Designer generated code (секция — фрагмент кода, находящийся между директивами #region и #endregion). В ней находится функция InitializeComponent, обеспечивающая непосредственно создание и инициализацию формы и компонентов.Листинг 2.3. Модуль формы (файл 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 profit
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
double sum; // сумма
int period; // срок
double percent; // процентная ставка
double profit; // доход
sum = System.Convert.ToDouble(textBox1.Text);
period = System.Convert.ToInt32(textBox2.Text);
if (sum < 10000)
percent = 7.5;
else
percent = 9;
profit = sum * (percent / 100 / 12) * period;
label3.Text = "Процентная ставка: " + percent.ToString("n") + "%\n" +
"Доход: " + profit.ToString("c");
}
}
}
Листинг 2.4. Модуль формы (файл Form1.Desidner.cs)
namespace profit
{
partial class Form1
{
/// <summary>
/// Обязательная переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором форм Windows
/// <summary>
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(123, 36);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 0;
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(126, 77);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(100, 20);
this.textBox2.TabIndex = 1;
//
// button1
//
this.button1.Location = new System.Drawing.Point(68, 122);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 2;
this.button1.Text = "Расчет";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(55, 34);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(35, 13);
this.label3.TabIndex = 3;
this.label3.Text = "label1";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(349, 176);
this.Controls.Add(this.label3);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MinimizeBox = false;
this.Name = "Form1";
this.Text = "Доход";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label3;
}
}
Компиляция
Процесс преобразования исходной программы в выполняемую называется сборкой. Укрупнено процесс сборки программы можно представить как последовательность двух этапов: компиляция и компоновка. На этапе компиляции выполняется перевод исходной программы (модулей) в некоторое внутреннее представление. На этапе компоновки — объединение модулей в единую программу.Процесс построения программы активизируется в результате выбора в меню Сборка команды Собрать решение, а также в результате запуска программы из среды разработки (меню Отладка, команда Начать отладку), если с момента последней компиляции (или запуска) в программу были внесены изменения.
Результат компиляции отражается в окнах Вывод и Список ошибок. Если в программе нет ошибок, то по завершении процесса компиляции окно Вывод выглядит так, как показано на рис. 2.25.
Рис. 2.25. Результат сборки
Если в процессе построения в программе обнаруживаются ошибки, то в окне Список ошибок выводится их список (рис. 2.26). Чтобы перейти к фрагменту кода, содержащего ошибку, надо сделать двойной щелчок левой кнопкой мыши в строке сообщения об этой ошибке.
Ошибки
Компилятор генерирует выполняемую программу (exe-файл) только в том случае, если в исходной программе (в тексте) нет ошибок.Если в программе есть ошибки, то программист должен их устранить. Процесс устранения ошибок носит итерационный характер. Обычно сначала устраняются наиболее очевидные ошибки, например, объявляются не объявленные переменные, затем, после выполнения повторной компиляции, — остальные.
В табл. 2.12 приведены сообщения компилятора о типичных ошибках.
Таблица 2.12. Сообщения компилятора об ошибках
| Сообщение компилятора | Вероятная причина ошибки |
|---|---|
| The name идентификатор does not exist in the current context (В текущем контексте имя не существует) | 1. Используемая в программе переменная не объявлена. 2. Ошибка при записи имени переменной. Например, объявлена переменная sum, а в тексте программы написано: Sum |
| Cannot implicitly convert type type1 to type2 (Невозможно преобразовать значение типа type1 в значение типа type2) Пример: Cannot implicitly convert type 'double' to 'int' | В инструкции присваивания тип выражения не соответствует типу переменной, которой присваивается значение. Например, если переменные n и m целого типа, то инструкция n = m/12 неверная, т. к. выражение m/12 дробное |
| Use of unassigned local variable (Используется локальная переменная, которой не присвоено начальное значение) | В программе нет инструкции, присваивающей переменной начальное значение |
| Пространство_имен does not contain definition for Идентификатор (Пространство имен Пространство_имен не содержит определение идентификатора Идентификатор) | Неправильно (например, не в том регистре) записано имя пространства имен или идентификатор (например, имя функции) ему принадлежащий. Пример: System.Convert.toint32(textBox1.Text) — неправильно записано имя функции. Должно быть ToInt32 |
| ';' expected (ожидается символа "точка с запятой") | После инструкции нет символа "точка с запятой" |
Предупреждения
В программе могут быть не только ошибки, но и неточности. Например, инструкция присваивания целой переменной дробного значения формально является верной. Присвоить значение переменной можно, но что делать с дробной частью? Отбросить или округлить? Что хотел сделать программист, записав эту инструкцию?При обнаружении в программе неточностей компилятор выводит предупреждения — Warnings. Например, при обнаружении не объявленной, но не используемой переменной выводится сообщение: unreferenced local variable. Действительно, зачем объявлять переменную и не использовать ее?
В табл. 2.13 приведены предупреждения и подсказки компилятора о типичных неточностях в программе.
Таблица 2.13. Предупреждения и подсказки компилятора
| Сообщение | Причина |
|---|---|
| The variable ... is declared but never used | Переменная объявлена, но не используется |
| The variable ... is assigned but its value is never used | Переменной присвоено значение, но оно не используется |
Запуск программы
Пробный запуск программы можно выполнить из Visual Studio, не завершая работу со средой разработки. Для этого в меню Отладка надо выбрать команду Начать отладку. Можно также сделать щелчок на находящейся в панели инструментов Отладка кнопке Пуск (рис. 2.27) или нажать клавишу <F5>.Исключения
Ошибки, возникающие во время работы программы, называют исключениями. В большинстве случаев причиной исключений (exception) являются неверные данные. Например, если запустить программу Доход, ввести в поле Сумма, скажем, 100.50 и сделать щелчок на кнопке Расчет, то возникнет исключение FormatException (неверный формат). В результате среда разработки выведет сообщение о возникновении исключения и в окне редактора кода выделит инструкцию, при выполнении которой возникло исключение (рис. 2.28).
Рис. 2.28. Пример сообщения об исключении — ошибке, произошедшей во время работы программы (программа запущена из среды разработки)Причина возникновения исключения в рассматриваемом примере в следующем. Преобразование строки в число выполняет функция ToDouble(). Эта функция работает правильно, если ее параметром действительно является строковое представление дробного числа, что, при стандартной для России настройке операционной системы, предполагает использование в качестве десятичного разделителя запятой. В рассматриваемом примере строка 100.50 не является строковым представлением дробного числа, т. к. в качестве десятичного разделителя указана точка, и, поэтому, возникает исключение FormatException — ошибка формата. Исключение "ошибка формата" произойдет и в том случае, если в поле Срок будет введено дробное значение. Причина — попытка преобразовать в целое значение строку, которая не является изображением целого числа. Это же исключение произойдет и в том случае, если какое-либо из полей ввода оставить незаполненным.
Для того чтобы остановить программу, во время работы которой возникло исключение, нажать кнопку Остановить отладку или в меню Отладка выбрать команду Остановить отладку (<Shift>+<F5>).
Если программа запущена из операционной системы, то при возникновении исключения так же, как и в случае запуска программы из среды разработки, выводится сообщение о возникновении исключения (рис. 2.29). Чтобы остановить работу программы, надо нажать кнопку Выход. Щелчок на кнопке Продолжить разрешает продолжить выполнение программы, несмотря на возникшую ошибку.
Обработка исключения
По умолчанию обработку исключений берет на себя автоматически добавляемый в выполняемую программу код, который обеспечивает вывод сообщения об ошибке и завершение работы программы. Вместе с тем программист может поместить в программу код, который выполнит обработку исключения.В простейшем случае инструкция обработки исключения в общем виде выглядит так:
try
{
// здесь инструкции, при выполнении
// которых может возникнуть исключение
}
catch (ТипИсключения ex)
{
// инструкции обработки исключения
};
В табл. 2.14 перечислены некоторые из возможных исключений и указаны вероятные причины их возникновения.
Таблица 2.14. Типичные исключения
| Исключение | Возникает |
|---|---|
| FormatException — ошибка формата (преобразования) | При выполнении преобразования, если преобразуемая величина не может быть приведена к требуемому типу. Наиболее часто возникает при преобразовании строки символов в число |
| IndexOutOfRangeException — выход значения индекса за допустимые границы | При обращении к несуществующему элементу массива |
| ArgumentOutOfRangeException — выход значения аргумента за допустимые границы | При обращении к несуществующему элементу данных, например, при выполнении операций со строками |
| OverflowException — переполнение | Если результат выполнения операции выходит за границы допустимого диапазона, а также при выполнении операции деления, если делитель равен нулю |
В качестве примера обработки исключения в листинге 2.5 приведена функция обработки события Click для кнопки Расчет программы Доход. При возникновении исключения FormatException программа определяет причину (какое из полей формы не заполнено или содержит неверные данные) и выводит соответствующее сообщение (рис. 2.30).
Листинг 2.5. Щелчок на кнопке Расчет (пример обработки исключения)
// щелчок на кнопке OK
private void button1_Click(object sender, EventArgs e)
{
double sum; // сумма
int period; // срок
double percent; // процентная ставка
double profit; // доход
try
{
sum = Convert.ToDouble(textBox1.Text);
period = Convert.ToInt32(textBox2.Text);
if (sum < 10000)
percent = 7.5;
else
percent = 8;
profit = sum * (percent / 100 / 12) * period;
label3.Text =
"Процентная ставка: " + percent.ToString("n") + "%\n" +
"Доход: " + profit.ToString("c");
}
catch (FormatException ex)
{
// MessageBox.Show(ex.Message);
if ((textBox1.Text.Length == 0) || (textBox1.Text.Length == 0))
MessageBox.Show("Ошибка в исходных данных.\nОба поля должны быть заполнены.",
"Доход",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
else
MessageBox.Show("Ошибка в исходных данных\n"+
"В поле Сумма надо ввести целое или дробное число (десятичный "+
"разделитель - запятая), в поле Срок - целое число.",
"Доход",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
};
}
r = MessageBox.Show(Сообщение, Заголовок, Кнопки, ТипСообщения, КнопкаПоУмолчанию)
- Сообщение — текст сообщения;
- Заголовок — текст в заголовке окна сообщения;
- Кнопки — кнопки, отображаемые в окне сообщения (табл. 2.15);
- Тип — тип сообщения. Сообщение может быть информационным, предупреждающим или сообщением об ошибке. Каждому типу сообщения соответствует значок (табл. 2.16);
- КнопкаПоУмолчанию — порядковый номер кнопки, на которой находится фокус при появлении окна сообщения на экране (табл. 2.17).
Таблица 2.15. Идентификаторы кнопок
| Значение параметра | Кнопки, отображаемые в окне сообщения |
|---|---|
| MessageBoxButtons.OK | OK |
| MessageBoxButtons.YesNo | Yes, No (Да, Нет) |
| MessageBoxButtons.YesNoCancel | Yes, No, Cancel (Да, Нет, Отменить) |
Таблица 2.16. Тип сообщения
| Сообщение | Тип сообщения | Значок |
|---|---|---|
| Warning — Внимание | MessageBoxIcon.Warning | |
| Error — Ошибка | MessageBoxIcon.Error | |
| Information — Информация | MessageBoxIcon.Information |
Таблица 2.17. Активная кнопка
| Значение параметра | Номер активной кнопки |
|---|---|
| System.Windows.Forms.MessageBoxDefaultButton.Button1 | 1 |
| System.Windows.Forms.MessageBoxDefaultButton.Button2 | 2 |
| System.Windows.Forms.MessageBoxDefaultButton.Button3 | 3 |
Таблица 2.18. Значения функции MessageBox.Show
| Значение | Нажата кнопка |
|---|---|
| System.Windows.Forms.DialogResult.Yes | Yes |
| System.Windows.Forms.DialogResult.No | No |
| System.Windows.Forms.DialogResult.Cancel | Cancel |
Внесение изменений
Программу "Доход" можно усовершенствовать. Например, сделать так, чтобы в поля редактирования пользователь мог ввести только числа (в поле Сумма — дробное число, в поле Срок — целое), чтобы в результате нажатия клавиши <Enter> в поле Сумма курсор переходил в поле Срок, а при нажатии этой же клавиши в поле Срок становилась активной кнопка Расчет. Кроме этого, можно сделать так, чтобы кнопка Расчет становилась доступной только после ввода данных в оба поля редактирования.Чтобы внести изменения в программу, нужно открыть соответствующий проект. Для этого надо в меню Файл выбрать команду Открыть проект/Решение или проект, в появившемся окне Открыть проект открыть папку проекта и сделать щелчок на значке файла проекта (рис. 2.31).
Чтобы программа "Доход" работала так, как было описано ранее, надо создать функции обработки событий KeyPress и TextChanged для полей редактирования (компонентов textBox1 и textBox2). Функция обработки события KeyPress (для каждого компонента своя) фильтрует символы, вводимые пользователем. Она проверяет символ нажатой клавиши (символ передается в процедуру обработки события через параметр e) и, если символ "запрещен", присваивает значение True свойству Handled. В результате "запрещенный" символ в поле редактирования не появляется. Процедура обработки события TextChanged (событие возникает, если текст, находящийся в поле редактирования, изменился, например, в результате нажатия какой-либо клавиши в поле редактирования) управляет доступностью кнопки Расчет. Она проверяет, есть ли данные в полях редактирования, и, если в каком-либо из полей данных нет, присваивает свойству Enabled кнопки button1 значение false (тем самым, делает кнопку недоступной). Следует обратить внимание, что действие, которое надо выполнить, если изменилось содержимое поля textBox1, ничем не отличается от действия, которое надо выполнить, если изменилось содержимое поля textBox2. Поэтому обработку события TextChanged для обоих компонентов может выполнить одна функция. Чтобы одна функция могла обрабатывать события разных компонентов, сначала надо создать функцию обработки события для одного компонента, а затем указать эту функцию в качестве обработчика соответствующего события другого компонента (рис. 2.32).
Рис. 2.32. Выбор функции обработки события: обработку события TextChanged компонента textBox2 выполнит функция обработки этого же события компонента textBox1
Функции обработки указанных событий приведены в листинге 2.6. Обратите внимание, теперь в функции обработки события Click кнопки Расчет нет инструкций обработки исключений, они не нужны. Исключения не могут возникнуть, потому что пользователь не сможет ввести в поля редактирования неверные данные, а кнопка Расчет становится доступной только после того, как будут заполнены оба поля.
Листинг 2.6. Функции обработки событий
// щелчок на кнопке Расчет
private void button1_Click(object sender, EventArgs e)
{
double sum; // сумма
int period; // срок
double percent; // процентная ставка
double profit; // доход
sum = Convert.ToDouble(textBox1.Text);
period = Convert.ToInt32(textBox2.Text);
if (sum < 10000)
percent = 7.5;
else
percent = 8;
profit = sum * (percent / 100 / 12) * period;
label3.Text =
"Процентная ставка: " + percent.ToString("n") + "%\n" +
"Доход: " + profit.ToString("c");
}
// нажатие клавиши в поле Сумма
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if ((e.KeyChar >= '0') && (e.KeyChar <= '9')) // цифра
return;
// "Правильный" десятичный разделитель — запятая.
// Заменим точку запятой
if (e.KeyChar == '.') e.KeyChar = ',';
if (e.KeyChar == ',')
{
// Нажата запятая. Проверим,
// может, запятая уже есть в поле редактирования
if ((textBox1.Text.IndexOf(',') != -1) || (textBox1.Text.Length == 0))
{
// Зпаятая уже есть.
// Запретить ввод еще одной
e.Handled = true;
}
return;
}
if (Char.IsControl(e.KeyChar))
{
if (e.KeyChar == (char)Keys.Enter)
{
// Нажата клавиша <Enter>.
// Переместить курсор в поле Срок
textBox2.Focus();
}
return;
}
// остальные символы запрещены
e.Handled = true;
}
// нажатие клавиши в поле Срок
private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
{
// в поле Срок можно ввести только целое число
if ((e.KeyChar >= '0') && (e.KeyChar <= '9'))
// цифра
return;
if (Char.IsControl(e.KeyChar))
{
if (e.KeyChar == (char)Keys.Enter)
{
// Нажата клавиша <Enter>.
// Переместить фокус на кнопку Расчет
button1.Focus();
}
return;
}
// остальные символы запрещены
e.Handled = true;
}
// Эта функция обрабатывает событие TextChanged (изменился
// текст в поле редактирования) обоих компонентов TextBox.
// Сначала надо обычным образом создать фукцию
// обработки события TextChanged для компонента
// textBox1, затем - указать ее в качестве
// обработчика события TextChanged для компонета textBox2
private void textBox1_TextChanged(object sender, EventArgs e)
{
label3.Text = ""; // очистить поле отображения результата расчета
if ((textBox1.Text.Length == 0) || (textBox2.Text.Length == 0))
// В поле редактирования нет данных.
// Сделать кнопку Расчет недоступной
button1.Enabled = false;
else
// Сделать кнопку Расчет доступной
button1.Enabled = true;
}
Завершение работы над проектом
После того как приложение будет отлажено, можно выполнить его окончательную сборку. Для этого надо задать конфигурацию решения Realise (рис. 2.33) и в меню Сборка выбрать команду Собрать решение. В результате описанных действий в папке bin\Release каталога проекта будет создан выполняемый (exe) файл.Рис. 2.33. Выбор конфигурации решения
Для завершения работы над проектом надо в меню Файл выбрать команду Закрыть решение.
Установка приложения на другой компьютер
В простейшем случае приложение Windows Forms представляет собой один-единственный exe-файл (в .NET-терминологии — сборку). Таким образом, чтобы установить созданное в Microsoft Visual C# приложение на другой компьютер, достаточно перенести (например, при помощи флешки) exe-файл. Вместе с тем, необходимо понимать: для того чтобы .NET-приложение могло работать на другом компьютере, на нем должна быть установлена платформа .NET Framework соответствующей версии (по умолчанию проекты Nicrosoft Visual Studio 2015 компилируются в режиме использования Microsoft .NET Framework 4.5). Если на компьютере пользователя платформа .NET Framework не установлена, то при запуске приложения будет выведено сообщение о необходимости установить .NET Framework требуемой версии.Профессиональный подход к разработке программного обеспечения предполагает, что программист создает не только приложение, но и установщик — программу, обеспечивающую установку (развертывание) приложения на компьютер пользователя.


































