Объектно - ориентированное программирование различает два способа агрегирования (укрупнения) кода: наследование (сцепление) и композиция (включение). В первом случае создается новый класс, в который передаются все данные и методы базового класса так, как будто-бы они были созданы в производном классе. Производный класс считается расширением базового класса. Во втором случае в новом классе создаются объекты других классов как члены-данные этого класса. Класс, который разрабатывается на основе включения других объектов, называется контейнером (родителем), а включенные в него объекты являются дочерними. Чаще всего при разработке новых класов применяют сочетание этих двух способов.
Объект Form по умолчанию содержит строку заголовка с системным меню слева и системными кнопками справа. По периметру окна проходит рамка определения размеров окна. Внутри окна расположена клиентская область - в ней отображается информация и содержатся инструменты для пользователя. Окна могут отображать текст и графику, получать команды с клавиатуры и мыши. Но в большинстве современных окон клиентская область размещает дочерние элементы управления, с помощью которых пользователь управляет программой.
Элементы управления могут быть стандартными (библиотечными, базовыми) или разработанными самим программистом (пользовательскими). В этой части мы изучим стандартные элементы управления, обеспечивающие требуемый графический интерфейс пользователя ( GUI ).
Все элементы, которыми визуальная среда проектирования позволяет манипулировать, размещая их на форме, называются компонентами. Те компоненты, которые остаются видимыми и во время выполнения программы, называются визуальными, и это, как правило, элементы управления пользовательского интерфейса. Те компоненты, которые не видимы во время выполнения - называются невизуальными, или просто - компонентами.
Обычно элементы управления занимают прямоугольную область, хотя могут быть и непрямоугольными и даже скрытыми, тем не менее исправно выполнять свои обязанности. Все элементы управления чувствительны к событиям мыши и клавиатуры и сами способны генерировать ряд событий. Превращая информацию о действиях пользователя в простые
Все элементы управления должны иметь своего родителя, определяемого свойством Parent. Только элементы управления, имеющие родителя, будут отображены на экране. Родителем может быть не только форма, но и другой элемент управления (это случается сравнительно редко). Положения элемента управления всегда задается относительно родителя и отображается на его поверхности. Часть элемента управления, выходящая за края родителя, не видна.
Класс Form, как наследник класса Control, тоже имеет свойство Parent, но оно обычно имеет значение null. Считается, что родителем формы по умолчанию является рабочий стол, и в этом случае свойство Form.TopLevel (верхний уровень) имеет значение true. Но форма может выступать потомком любого другого элемента управления при значении TopLevel = false, в том числе каркаса MDI - приложения.
Если в свойстве Form.Owner определена ссылка на другую форму, то форма имеет владельца, располагается всегда поверх него и сворачивается или закрывается вместе с ним. Такое поведение полезно при создании немодальных диалоговых окон.
Для того, чтобы элемент управления размещался на форме, сначала нужно создать саму форму как объект, затем создать как объект элемент управления, затем присвоить его свойству Parent ссылку на объект формы (назначить родителя) или выполнить метод свойства Controls.Add() объекта формы. Эти действия по регистрации элемента управления в форме являются равнозначными.
Например, при создании кнопки на форме в конструкторе формы нужно прописать такой код
Button dtn = new Button(); btn.Parent = this; или this.Controls.Add(btn);
Свойство Controls наследуется формой от класса Control и является объектом класса ControlCollection. Оно содержит в себе все дочерние элементы формы. Методы Controls.Add() и Controls.Remove() управляют составом этого набора. Коды this.Controls.Remove(btn) и btn.Parent = null
Приведем пример.
Командой File/New/Project создайте пустой проект с именем MyProject
Командой Project/Add Reference добавьте к проекту ссылки на базовые сборки System.dll и System.Windows.Forms.dll
Командой Project/Add New Item добавьте два пустых файла MainForm.cs и Program.cs
Заполните файлы следующим кодомusing System;
using System.Windows.Forms;
namespace MyProject
{
class MainForm : Form
{
const int MAX_BUTTON = 5; // Число кнопок
public MainForm()
{
// Настраиваем консольное окно
Console.ForegroundColor = ConsoleColor.White;
// Регистрируем событие загрузки формы
this.Load += new EventHandler(MainForm_Load);
}
// Создаем элементы управления в обработчике события Load формы
void MainForm_Load(object sender, EventArgs e)
{
// Создаем кнопки
for (int i = 0; i < MAX_BUTTON; i++)
{
Button btn = new Button(); // Создали кнопку
this.Controls.Add(btn);// Отдали кнопку форме
}
Console.WriteLine("Создано кнопок:
{0}", this.Controls.Count);
// Уничтожаем кнопки
int count = 0; // Локальная переменная
Control[] control = new Control[this.Controls.Count];
// Проводим предварительное обследование коллекции в foreach
foreach (Control ctrl in this.Controls)
{
if (ctrl is Button)
{
control[count] = ctrl;// Сохраняем ссылку в массиве
count++;
}
}
// Уничтожаем кнопки по найденым ссылкам
for (int i = 0; i < count; i++)
this.Controls.Remove(control[i]);
Console.WriteLine("Удалено кнопок: {0}", count);
// Еще раз создаем кнопки
for (int i = 0; i < MAX_BUTTON + 1; i++)
{
Button btn = new Button(); // Создали кнопку
btn.Parent = this; // Отдали форме другим способом
}
Console.WriteLine("\nСоздано кнопок:
{0}", this.Controls.Count);
// Уничтожаем кнопки
count = 0; // Сбросили счетчик
control = new Control[this.Controls.Count];// Переназначили массив
// Проводим предварительное обследование коллекции в for
for (int i = 0; i < this.Controls.Count; i++)
{
Control ctrl = this.Controls[i];
if (ctrl is Button)
{
control[count] = ctrl;
count++;
}
}
// Уничтожаем кнопки по найденым ссылкам
for (int i = 0; i < count; i++)
control[i].Parent = null;// Уничтожаем другим способом
Console.WriteLine("Удалено кнопок: {0}", count);
for (int i = 0; i < MAX_BUTTON + 2; i++)
{
Button btn = new Button(); // Создали кнопку
btn.Click += btn_Click;// Зарегистрировали общий обработчик
btn.Parent = this; // Отдали форме
}
Console.WriteLine("\nСоздано кнопок:
{0}", this.Controls.Count);
}
// Уничтожение кнопок интерактивно
int count = 0; // Поле
void btn_Click(object sender, EventArgs e)
{
this.Controls.Remove((Control)sender);
Console.WriteLine("{0}) Удалили кнопку
щелчком на ней", ++count);
}
}
}
using System;
using System.Windows.Forms;
namespace MyProject
{
class EntryPoint
{
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
}
}
Результат работы приведенного кода будет таким

Поскольку все элементы управления произошли от класса Control, а он определяет свойство Controls, то любой элемент управления имеет это родительское свойство и может быть родителем. Но не многие наследники Control используются программистами в качестве родителей. Обычно элементы управления используются в качестве дочерних элементов формы.
Class Control имеет булево свойство TabStop, которое позволяет контейнерным элементам управлять фокусом ввода своих дочерних элементов с помощью клавиши Tab. Фокус ввода способны получать только те дочерние объекты, у которых свойство TabStop установлено в true. Порядок получения фокуса определяется свойством Control.TabIndex дочерних элементов контейнера или выполняется в порядке их расположения в
коллекции (в порядке их добавления в набор, Z -порядок: последний добавленный видится верхним). Элемент управления сдвигается в Z -последовательности на первое или последнее место своими методами BringToFront() или SendToBack() соответственно.

Дочерние элементы управления одного контейнера (родителя) называются родственными.
По умолчанию все элементы управления рождаются видимыми и доступными пользователю. Видимость элемента управления определяется свойством Visible, а доступность - Enabled. Те же свойства родителя (контейнера) влияют сразу на все дочерние элементы. Невидимым или недоступным элемент становится только для пользователя, но в составе программы остается полноценным элементом и продолжает работать под ее контролем.
Каждому элементу управления может задаваться положение его левого верхнего угла относительно левого верхнего угла клиентской области родителя. Оно определяется свойством Location элемента управления, которое ожидает ссылку на экземпляр класса Point(x, y), где x и y означают количество пикселов смещения. Размер элемента задается через свойство Size, которое ожидает ссылку на объект класса Size(width, height). Ширина и высота также означают количество пикселов относительно точки привязки элемента управления.

Если в элементе управления (например, кнопке) установить булево свойство AutoSize = true, то установленный размер Size игнорируется и элемент управления подгоняет свои размеры под размер надписи, определяемой свойством Text.
Свойство Dock (причал) элемента управления используется для растягивания и выравнивания по внутренней стороне родителя. Его значение определяется перечислением DockStyle: None, Left, Right, Top, Bottom, Fill. Свойство Anchor (якорь) заставляет элемент управления замораживать привязку к сторонам родителя (при изменении размеров последнего) на том расстоянии, которое он занимал до изменения размеров родителя. Свойство Anchor принимает значения перечисления AnchorStyles: : None, Left, Right, Top, Bottom и допускает их побитовое сложение ( по умолчанию Anchor = Left | Top).
Порядок создания объектов в программе следующий: вначале создается главный контейнер, затем создаются все дочерние элементы и присоединяются к контейнеру через ссылки. Если дочерний элемент, в свою очередь, является контейнером, то он создается вперед своих дочерних элементов и ждет, когда к нему будут присоединены ссылки на них. При создании дочерних элементов им неявно передаются значения одноименных свойств контейнера. Главный контейнер приложения получает значения этих свойств от операционной системы и передает их вниз по иерархической цепочке. Если в любом контейнере этой цепочки свойствам назначить другие значения, то новые значения одноименных свойств получат все дочерние элементы.
Класс Color передает элементам управления свойство Text, которые используют его соответствующим их специализации способом. Например, в форме это заголовок окна, в кнопке это надпись, а полоса прокрутки вообще не использует это свойство. Наследники класса Control получают от него, также, свойства Font, ForeColor и BackColor, которые задают шрифт, его размер, стиль и цвет, а также цвет клиентской области. Если дочерний элемент явно не задает значение этого свойства, то оно перенимает значение контейнера.
Для иллюстрации сказанного переделаем предыдущий пример.
Замените в последнем проекте MyProject код файла MainForm.cs на следующийusing System;
using System.Windows.Forms;
using System.Drawing;
namespace MyProject
{
class MainForm : Form
{
const int MAX_BUTTON = 5; // Число кнопок
public MainForm()
{
// Настраиваем консольное окно
Console.ForegroundColor = ConsoleColor.White;
// Регистрируем событие загрузки формы
this.Load += new EventHandler(MainForm_Load);
}
// Создаем элементы управления в обработчике события Load формы
void MainForm_Load(object sender, EventArgs e)
{
this.Text = "Щелкайте на кнопках!";
// Автоматически показывать полосу прокрутки,
// когда не помещаются дочерние элементы
this.AutoScroll = true;
// При запуске с консольным окном сделать верхней
this.Activate();
// Переопределяем свойство контейнера,
// которое неявно передастся дочерним элементам
this.ForeColor = Color.Red;
// Создаем и настраиваем дочерние элементы
int x = 0, y = 0; // Размещение кнопок
for (int i = 0; i < MAX_BUTTON; i++)
{
Button btn = new Button(); // Создали кнопку
btn.Click += btn_Click;// Зарегистрировали общий обработчик
btn.Parent = this; // Отдали форме
// Продолжаем настройку, пока не потеряли адрес
btn.Text = "Кнопка " + (i + 1).ToString();
btn.AutoSize = true;
// Настраиваем плоский стиль кнопки (для Flat)
btn.FlatStyle = FlatStyle.Flat;
btn.FlatAppearance.BorderColor = Color.Blue;
btn.FlatAppearance.BorderSize = 5; // В пикселах
// Вычисляем точку размещения
if ((i + 3) % 2 == 1) // Первая колонка нечетные
{
x = 0;
if (i != 0)// Начальные не смещать
y += btn.Size.Height * 2;
}
else // Вторая колонка четные
{
x = btn.Size.Width * 2;
btn.TabStop = false; // Четные лишаем фокуса ввода
}
// Позиционируем дочерний элемент относительно родителя
btn.Location = new Point(x, y);
// Переопределяем свойство дочернего элемента.
// Стиль шрифта побитово суммируем
btn.Font = new System.Drawing.Font(
"Times New Roman", 14,
FontStyle.Italic | FontStyle.Bold);
btn.BackColor = Color.Yellow;
}
// Назначение фокуса ввода
int indexFocus, count = this.Controls.Count;
indexFocus = (count + 2) % 2 == 1 ? count - 1 : count;
if (indexFocus >= 0) // Проверка на случай пустого контейнера
this.Controls[indexFocus].Focus();
// Активируем последний в первой колонке
Console.WriteLine("Создано кнопок:
{0}", this.Controls.Count);
}
// Уничтожение пользователем кнопок интерактивно
void btn_Click(object sender, EventArgs e)
{
Control ctrl = sender as Control;
this.Controls.Remove(ctrl);
Console.WriteLine("\"" +
ctrl.Text + "\" удалена!");
// Меняем заголовок окна, когда кончились кнопки
if (this.Controls.Count == 0)
{
this.Text = "Все кнопки удалены !!!!!!";
}
}
}
}
Графическое окно, созданное классом-контейнером MainForm, будет выглядеть так

Цвет надписи кнопка получила от родителя, а шрифт и цвет фона были для нее установлены явно. Обратите внимание на то, как мы программно установили для коллекции дочерних элементов фокус ввода и порядок управления фокусом ввода по клавише Tab. Кнопка, имеющая фокус ввода, реагирует на нажатие клавиш Enter или Space ( пробела - такая са-а-амая длинная!) как на щелчок мыши.
Запустите и опробуйте это ...Форма может иметь много дочерних элементов управления. Если это каркас приложения, то взаимодействовать с элементом можно через его события. Но когда это диалоговое окно со сложными настройками, которое при закрытии должно передавать выбор пользователя со всех своих элементов, то здесь может потребоваться программный опрос всех элементов. Естественно, что вызывающей стороне нужен доступ ко всем элементам дочерней формы.
Существует много способов для решения такой задачи. Можно, например, объявить в дочернем контейнере именные ссылки на свои элементы как общедоступные поля или свойства и адресоваться через них. Но чаще применяют другой способ, учитывая, что все ссылки на элементы хранятся в коллекции Controls контейнера. Если в дочернем контейнере промаркировать его элементы в свойствах Name (ожидает тип string ) или Tag (принимает любой тип, поскольку объявлено как object ), то найти такой элемент в коллекции по его уникальному признаку не составит труда.
Коллекция Controls, начиная с версии .NET Framework 2.0, способна вести себя как ассоциативный массив, в котором ключ доступа к элементам представляет собой пару " целое_число-строка ". Строка представляет собой значение, заданное в свойстве Name дочернего элемента. Это означает, что адресоваться к элементу в контейнере можно либо по индексу, либо по имени, которое присвоено свойству Name (при условии, что оно уникально в рамках одной коллекции).
Свойство Controls является экземпляром класса Control.ControlCollection, который имеет методы Contains() и Find(). Метод Contains() возвращает true, если проверяемый объект является членом коллекции. Метод Find() проверяет свойство Name всех элементов коллекции на соответствие заданному значению и возвращает массив ссылок найденных элементов. Вторым аргументом метода Find() является булев флаг, устанавливающий режим поиска: искать до первого найденного или продолжать поиск до конца.
Чтобы проиллюстрировать рассмотренные
Прежде, чем приступать к использованию визуальных средств IDE, уместно сделать одно важное замечание. Когда программист создает интерфейс пользователя через визуальный конструктор оболочки, то последний генерирует код по своей собственной схеме. И желательно своими действиями по прямому редактированию кода интерфейса в этот порядок не вмешиваться, а все делать через графический редактор и вспомогательные панели среды проектирования. Хотя разбираться в этом вопросе следует (но не обязательно).
В IDE C++Builder код компоновки интерфейса формы хранится в текстовом файле с расширением frm, а рабочий код размещен в паре h - и cpp -файлов. В Visual Studio 2005 код формы хранится в текстовом файле с расширением Designer.cs, а рабочий код размещен в файле с расширением cs и файле с точкой входа Program.cs.
Создадим приложение, в котором из главного окна будет вызываться диалоговое окно с элементами управления. После закрытия диалогового окна выполним опрос его элементов и выведем полученную информацию в клиентской области главного окна. Требуемые элементы управления будем переносить на форму проекта из панели инструментов Toolbox оболочки.
Выполните команду File/New/Project и создайте проект типа Windows Application с именем FirstWinApp
Мастер создания заготовки приложения создаст дерево каталогов проекта со вспомогательными файлами и сгенерирует в них необходимый код

Сгенерированная мастером форма будет главной формой нашего примера
В панели Solution Explorer переименуйте файл Form1.cs в MainForm.csОбратите внимание, что оболочка переименовала вспомогательные файлы и класс главной формы.
Перенесите из панели Toolbox на главную форму и настройте через панель Properties элементы управления в соответствии с приведенной ниже таблицей свойств| Элемент | Свойство | Значение | Описание |
|---|---|---|---|
Form |
Text |
Главное окно приложения | Текст строки заголовка |
FormBorderStyle |
Sizable |
С изменяемым интерактивно размером | |
Size |
600, 450 | Размеры окна в пикселах с соотношением 4/3 (640/480, 800/600, 1024/768) | |
Icon |
Иконка системного меню в заголовке окна (прилагается) | ||
StartPosition |
CenterScreen |
Начальная позиция при запуске | |
Button |
Name |
btnCreateDialogBox |
Программное имя кнопки вызова диалогового окна |
Anchor |
Bottom |
Сохранять постоянным растояние до нижнего края родителя | |
|
True |
Подстраивать размер кнопки под надпись | |
Text |
Диалог | Надпись на кнопке | |
TextBox |
Name |
txtShowProperties |
Имя объекта для отображения свойств диалогового окна |
Dock |
Top |
Приклеиться к верхнему краю клиентской области родителя по всей ширине | |
Multiline |
True |
Многострочный техт | |
ScrollBars |
Vertical |
Отображать вертикальную полосу прокрутки |
На этом проектирование интерфейсной части главного окна приложения завершена. Приступим к проектированию диалогового окна.
Выполните команду Window/Close All Documents, чтобы закрыть все окна редактируемых файлов проекта в рабочей области оболочки. При необходимости сохраните изменения
Выполните команду Project/Add Windows Form, чтобы создать форму диалогового окна с именем MyModalDialogBox
Разместите на форме будущего диалогового окна элементы управления и настройте их в соответствии с таблицей свойств (дочерние элементы внутренних контейнеров в таблице отображены составными именами)| Элемент | Свойство | Значение | Описание |
|---|---|---|---|
Form |
Text |
Модальное диалоговое окно | Текст строки заголовка |
FormBorderStyle |
FixedDialog |
С неизменяемыми размерами и без иконки системного меню в строке заголовка | |
Size |
600, 450 | Размеры окна в пикселах со стандартным соотношением 4/3 | |
AutoScaleMode |
Font |
Для подстройки размеров под величину шрифта | |
ControlBox |
False |
Без системных кнопок в строке заголовка | |
ShowInTaskbar |
False |
Не отображать в панели задач рабочего стола Windows |
|
StartPosition |
CenterParent |
Начальная позиция при запуске в центре родителя | |
|
Name |
grBoxRadioButton |
Контейнер для радиокнопок |
Text |
Выберите радиокнопку | Заголовок контейнера переключателей | |
|
Text |
Радиопереключатель1 | Надпись радиокнопки |
Checked |
True |
Изначально включена | |
|
Text |
Радиопереключатель2 | Надпись радиокнопки |
|
Text |
Радиопереключатель3 | Надпись радиокнопки |
|
Text |
Радиопереключатель4 | Надпись радиокнопки |
|
Text |
Радиопереключатель5 | Надпись радиокнопки |
Label |
Text |
Укажите свои ФИО | Надпись текстовой метки |
Font.Bold |
True |
Полужирный шрифт надписи | |
Font.Size |
10 | Размер шрифта надписи | |
ForeColor |
Red |
Цвет текста | |
TextBox |
Name |
Фамилия | Идентификатор русский !!! |
Text |
Иванов | ||
TextBox |
Name |
Имя | Идентификатор русский !!! |
Text |
Петр | ||
TextBox |
Name |
Отчество | Идентификатор русский !!! |
Text |
Сидорович | ||
Panel |
Name |
panelCheckBox |
|
BackColor |
White |
Фон белый | |
| Panel.CheckBox | Text |
Флажок 1 | |
| Panel.CheckBox | Text |
Флажок 2 | |
Tag |
Важный | Наша метка | |
| Panel.CheckBox | Text |
Флажок 3 | |
Tag |
Важный | Наша метка | |
CheckedListBox |
Name |
checkedListBox |
Идентификатор списка флажков |
Items |
Списковый флажок 1 Списковый флажок 2 Списковый флажок 3 Списковый флажок 4 Списковый флажок 5 Списковый флажок 6 Списковый флажок 7 |
Элементы списка | |
Button |
Name |
btnOK |
|
|
True |
Подстройка под размер надписи | |
DialogResult |
OK |
Устанавливает значение свойства DialogResult=OK диалогового окна и закрывает окно |
|
Text |
OK |
Надпись на кнопке | |
Button |
Name |
btnCancel |
|
|
True |
Подстройка под размер надписи | |
DialogResult |
Cancel |
Устанавливает значение свойства DialogResult=Cancel диалогового окна и закрывает окно |
|
Text |
Cancel |
Надпись на кнопке |
После проведенных настроек форма диалогового окна должна стать такой

Теперь нужно написать код, который свяжет разработанные формы вместе и позволит опросить состояние всех элементов диалоговой формы после ее использования.
Создайте обработчик события Click кнопки в главном диалоговом окне и заполните его такprivate void btnCreateDialogBox_Click(object sender, EventArgs e)
{
txtShowProperties.Text = "";
MyModalDialogBox dlg = new MyModalDialogBox();
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Диалоговое окно еще существует, опрашиваем его
foreach (Control ctrl0 in dlg.Controls)
{
ShowProperties("", ctrl0);
if (ctrl0.Controls.Count > 0)
foreach (Control ctrl1 in ctrl0.Controls)
{
ShowProperties("\t", ctrl1);
}
}
}
else
txtShowProperties.Text = "Пользователь установки не менял";
dlg.Dispose(); // Освободили явно ссылку на диалоговое окно
}
private void ShowProperties(string str, Control ctrl)
{
txtShowProperties.Text += str + "Name: " +
ctrl.Name + "\r\n";
if (!(ctrl is Panel) !(ctrl is CheckedListBox))
txtShowProperties.Text += str + "Text: " +
ctrl.Text + "\r\n";
if(ctrl is CheckedListBox)
{
CheckedListBox check = (CheckedListBox)ctrl;
for (int i = 0; i < check.Items.Count; i++)
txtShowProperties.Text += "\t" +
check.Items[i].ToString() + "\r\n";
}
if ((String)ctrl.Tag == "Важный")
txtShowProperties.Text += "!!!Помеченный нами в
свойстве Tag!!!" + "\r\n";
}
Многие классы не являются элементами управления как таковыми, а предназначены для хранения множества объектов и управления ими. Такие классы представляют собой
ImageList - это набор объектов Image, включающий в себя растровые рисунки и и метафайлы (Иконки) одного размера и глубины цвета. Основным свойством ImageList является объект Images типа ImageList.ImageCollection, который имеет ряд методов, в том числе Add() для добавления рисунков в коллекцию.
Пусть в текущем с приложением каталоге имеются два растровых изображения MyPicture1.bmp и MyPicture2.bmp, которые нужно упаковать в контейнер. Фрагмент кода программы может выглядеть так
using System.Windows.Forms;
...
// Создаем пустую коллекцию рисунков
ImageList imglst = new ImageList();
// Наполняем коллекцию рисунками
Bitmap bmp = new Bitmap("MyPicture1.bmp");// Загрузили первый рисунок
imglst.Images.Add("key1", bmp); // Пометили и отдали в коллекцию
bmp = new Bitmap("MyPicture2.bmp");// Загрузили второй рисунок
imglst.Images.Add("key2", bmp); // Пометили и отдали в коллекцию
...
// Где-то в программе используем рисунки, сохраненные в коллекции
Bitmap bmp1, bmp2;
bmp1 = (Bitmap)imglst.Images[0]; // Извлекли по индексу
bmp2 = (Bitmap)imglst.Images["key2"];// Извлекли по ключу
using System;
using System.Drawing;
using System.Windows.Forms;
class MyClass : Form
{
ImageList imageList;
public MyClass()
{
this.Icon = new Icon("1.ICO");
this.Text = "Графическое окно";
imageList = new ImageList();
imageList.Images.Add("bmp",
Image.FromFile("Photo.bmp"));
imageList.Images.Add("jpg",
Image.FromFile("Photo.jpg"));
imageList.Images.Add("png",
Image.FromFile("Photo.png"));
int width = 250;
imageList.ImageSize = new Size(width, width / 4 * 3);
this.Click += new EventHandler(MyClass_Click);
}
void MyClass_Click(object sender, EventArgs e)
{
// Получаем указатель на холст формы
Graphics graphics = Graphics.FromHwnd(this.Handle);
// Цикл для листания рисунков
for (int count = 0; count < imageList.Images.Count; count++)
{
// Рисуем изображение на холсте формы
imageList.Draw(graphics, new Point(0, 0), count);
// Инициируем перерисовку формы (одно из предложенных)
Application.DoEvents();
//this.Invalidate();
// Усыпляем поток на две секунды
System.Threading.Thread.Sleep(2000);
}
}
}
Класс ToolTip не является элементом управления, но тесно взаимодействует с ними. Он хранит всплывающие подсказки для элементов управления, которые обычно появляются, когда на элемент управления наводится курсор мыши.
Сначала в конструкторе формы нужно создать экземпляр класса ToolTip, затем каждому (если нужно) элементу управления привязать всплывающую подсказку с помощью
// Создаем элементы управления
Button btn1 = new Button();
Button btn2 = new Button();
CheckBox check1 = new CheckBox();
CheckBox check2 = new CheckBox();
TextBox txt = new TextBox();
// Настраиваем элементы управления
btn1.Location = new Point(5, 50);
btn2.Location = new Point(20, 50);
check1.Text = "Флажок 1";
//..........................
// Создаем экземпляр контейнера ToolTip
ToolTip tips = new ToolTip();
// Привязываем посказки к одному
// или нескольким элементам управления
tips.SetToolTip(btn1, "Это кнопка OK");
tips.SetToolTip(btn2, "Это кнопка Cancel");
tips.SetToolTip(check1, "Это флажок 1");
tips.SetToolTip(check2, "Это флажок 2");
tips.SetToolTip(txt, "Это текстовое поле");
//...........................
В классе ToolTip имеется несколько свойств, настраивающих контейнер всплывающих подсказок. Вот некоторые из них
Этот контейнер наследует класс Control и сам является видимым элементом управления (рамка с надписью в свойстве Text ), используемым при формировании пользовательского графического интерфейса. Главное его применение - организовать согласованную работу радиокнопок. Он объединяет их в группы и все переключатели, принадлежащие одной группе, становятся взаимоисключающими. Класс GroupBox не наследует, в отличие от Form, класс ContainerControl, где переход между дочерними элементами выполняется нажатием клавиши Tab. Навигация между радиокнопками внутри GroupBox выполняется клавишами-стрелками.
Этот элемент управления является (как и Form ) потомком класса ScrollableControl, поэтому имеет полосы прокрутки. Он также имеет визуальное представление и может служить контейнером элементов управления при формировании пользовательского интерфейса.
Она отображает нередактируемый текст, заданный в свойстве Text. Хотя метка может выводить многострочный текст, если увеличить ее размер по высоте, но она не выводит полос прокрутки, если текст не умещается в элементе управления.
Кроме текста метка может отображать объекты типа Image. Один из способов состоит в присвоении свойству Image загруженного файла, например (проект Test )
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
class MyClass : Form
{
public MyClass()
{
// Создание и настройка элементов управления
Label lblBmp = new Label();
lblBmp.Parent = this;
lblBmp.Dock = DockStyle.Fill;
lblBmp.Image = Image.FromFile("Photo.bmp");
lblBmp.Tag = "Рисунок bmp";
Label lblJpg = new Label();
lblJpg.Parent = this;
lblJpg.Dock = DockStyle.Fill;
lblJpg.Image = Image.FromFile("Photo.jpg");
lblJpg.Tag = "Рисунок jpg";
Label lblPng = new Label();
lblPng.Parent = this;
lblPng.Dock = DockStyle.Fill;
lblPng.Image = Image.FromFile("Photo.png");
lblPng.Tag = "Рисунок png";
lblBmp.BringToFront();// Меняем Z-последовательность
this.Text = (string)lblBmp.Tag;// Заголовок окна
// Подписываем на событие Click
lblBmp.Click += new EventHandler(lbl_Click);
lblJpg.Click += lbl_Click;
lblPng.Click += lbl_Click;
}
void lbl_Click(object sender, EventArgs e)
{
Control ctrl = sender as Control;
if (ctrl == null)
{
MessageBox.Show("Не могу привести типы");
return;
}
this.Controls.Remove(ctrl);
if (this.Controls.Count > 0)
{
this.Text = (string)this.Controls[0].Tag;
this.Controls[0].BringToFront();
}
else
this.Text = "Меток больше нет";
}
}
}
Файлы с картинками должны быть помещены в один каталог со сборкой, иначе нужно указать путь у файлу (абсолютный или относительный). Одна из картинок, выводимых этим кодом, будет такой (это, конечно же, опять я - любимый!)

Кроме того, в метке можно использовать изображения, созданные в качестве ресурсов и прикрепленные к исполняемому файлу программы.
Этот элемент обладает свойствами традиционной HTML -гиперссылки Hyperlink. Помимо наследуемых от Control свойств BackColor и ForeColor метка-ссылка имеет характерные для Hyperlink свойства:
Метка-ссылка определяется свойством Text, но активная ее часть, воспринимаемая как гиперссылка, задается свойством LinkArea. Это свойство представляет собой структуру LinkArea с общедоступными полями Start и Length типа int. Например
using System;
using System.Drawing;
using System.Windows.Forms;
class MyClass : Form
{
public MyClass()
{
this.Font = new Font("Arial", 14);
LinkLabel linkLabel = new LinkLabel();
this.Controls.Add(linkLabel);
linkLabel.Dock = DockStyle.Fill;
linkLabel.Text = "Щелкните здесь
для появления сообщения";
linkLabel.LinkArea = new LinkArea(9, 5);
linkLabel.LinkBehavior = LinkBehavior.SystemDefault;
linkLabel.LinkClicked += new LinkLabelLinkClickedEventHandler(linkLabel_LinkClicked);
}
void linkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
MessageBox.Show("Вы щелкнули на метке-ссылке");
}
}
Поведение ссылки задается свойством LinkBehavior, ожидающим одно из значений одноименного перечисления System.Windows.Forms.LinkBehavior. По умолчанию установлено LinkBehavior=SystemDefault, определяющее поведение ссылки как в Microsoft Internet Explorer.
Одной метке можно назначить несколько ссылок с помощью свойства Links, которое является объектом составного класса LinkLabel.LinkCollection. Щелчок на ссылке LinkLabel инициирует событие LinkClicked, обработчик которого определяется делегатом LinkLabelLinkClickedEventHandler. Объект типа LinkLabelLinkClickedEventArgs, сопровождающий обработчик, является экземпляром составного класса LinkLabel.Link и несет данные активированной ссылки ( URL или имя файла) в свойстве LinkData типа Object.
Приведем пример, в котором программа Windows Forms отвечает на нажатие ссылки запуском другого процесса, используя метод System.Diagnostics.Process.Start().
using System;
using System.Drawing;
using System.Windows.Forms;
using Return = System.Environment;// Псевдоним класса
class MyClass : Form
{
public MyClass()
{
this.Font = new Font("Arial", 14);
this.Width = 2 * this.Height;
this.Text = "Элемент управления LinkLabel";
LinkLabel linkLabel = new LinkLabel();
linkLabel.Parent = this;
linkLabel.Dock = DockStyle.Fill;
linkLabel.Text = "Из этого приложения
Вы можете:" + Return.NewLine
+ "\n1. Подключиться к сайту корпорации
\"Майкрософт\"" + Return.NewLine
+ "2. Запустить графический редактор \"
Microsoft Paint\"" + Return.NewLine
+ "3. Запустить игру \"
Косынка\"" + Return.NewLine
+ "4. Запустить текстовый редактор \"
Блокнот\"" + Return.NewLine;
string subStr = "Майкрософт";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "http://www.microsoft.com");
subStr = "Microsoft Paint";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "msPaint");
subStr = "Косынка";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "Sol");
subStr = "Блокнот";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "Notepad");
linkLabel.LinkClicked +=
new LinkLabelLinkClickedEventHandler(linkLabel_LinkClicked);
}
void linkLabel_LinkClicked(object sender,
LinkLabelLinkClickedEventArgs e)
{
string strLink = e.Link.LinkData as string;
if (strLink != null)
try
{
System.Diagnostics.Process.Start(strLink);
}
catch (Exception err)
{
string strError = "Не могу выполнить процесс !!!\n"
+ "Ошибка: " + err.Message;
MessageBox.Show(strError);
}
}
}
Результат выполнения примера будет таким

Щелчки на ссылках запускают соответствующие программы. Для подстраховки мы отлавливаем возможные исключения Windows.
Этот элемент служит для отображения растров или метафайлов. Изображение задается свойством Image. Свойство SizeMode задает режим отображения с помощью перечисления System.Windows.Forms.PictureBoxSizeMode, которое имеет следующие значения
Вот пример, для выполнения которого нужно разместить рисунки (прилагаются в каталоге Pictures ) в одной папке с исполнимым файлом.
using System;
using System.Drawing;
using System.Windows.Forms;
class MyClass : Form
{
PictureBox pictureBox;
string[] photo = {
"Photo.bmp",
"Photo.jpg",
"Photo.png"
};
public MyClass()
{
// Загрузили иконку
this.Icon = new Icon("1.ICO");
// Текст заголовка окна
this.Text = "Испытание элемента PictureBox";
// Подписались на события формы
this.Click += FormClick;
this.Paint += BeginPaint;
pictureBox = new PictureBox();// Создали элемент
pictureBox.Parent = this;// Назначили родителя
// Распахнули на всю форму
pictureBox.Dock = DockStyle.Fill;
// Масштабировать без искажений
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
// Чтобы не заслонял текстовое сообщение на форме
pictureBox.Visible = false;
// Подписываем на щелчки элемента тот же обработчик
pictureBox.Click += FormClick;
}
void BeginPaint(object sender, PaintEventArgs e)
{
// Создаем и настраиваем точку привязки текстового блока
StringFormat strfrm = new StringFormat();
strfrm.Alignment = StringAlignment.Center;// Центр по горизонтали
strfrm.LineAlignment = StringAlignment.Center;// Центр по вертикали
// Создаем временный объект для доступа к контексту устройства
Graphics gr = Graphics.FromHwnd(this.Handle);
gr.DrawString("Щелкайте на форме", // Текст сообщения
new Font("Arial", 14, FontStyle.Bold), // Шрифт сообщения
new SolidBrush(Color.Red), // Цвет шрифта
this.ClientSize.Width / 2, // Центр клиентской области по горизонтали
this.ClientSize.Height / 2, // Центр клиентской области по вертикали
strfrm); // Передаем точку привязки текстового блока
gr.Dispose();// Освободили контекст устройства
}
int count = 0;// Счетчик
bool clickFlag = false; // Устанавливается при первом щелчке
void FormClick(object sender, EventArgs e)
{
if (!clickFlag)
{
pictureBox.Visible = true;
this.Paint -= BeginPaint;// Разрегистрируем обработчик
clickFlag = true;
}
//pictureBox.Image = Image.FromFile(photo[count++]);
pictureBox.Load(photo[count++]);
count = count < photo.Length ? count : 0;// Однострочное условие
}
}
Метод Load() принимает URL или имя файла. Метод LoadAsync() выполняет загрузку в фоновом режиме, создавая дополнительный поток, и информирует о завершении событием LoadCompleted, например,
pictureBox.LoadAsync(@"http://localhost/print.jpg");
Если изображение загружается долго, то можно задать дежурную картинку в свойстве InitialImage, а также картинку в свойстве ErrorImage, выводимую в случае ошибки загрузки. Событие LoadProgressChanged в своем аргументе типа ProgressChangedEventArgs передает информацию о загрузке изображения в процентах. Эту информацию можно использовать в обработчике для отображения с помощью индикатора выполнения ProgressBar, например,
void pictureBox_LoadProgressChanged(object sender,
ProgressChangedEventArgs e)
{ progressBar.Value = e.ProgressPercentage;}
Основные свойства ProgressBar - это целочисленные Minimum, Maximum, Value. Индикатор процесса напрямую связан со свойством Value, значение которого можно увеличивать несколькими способами:
Приведем пример, в котором движком процесса является таймер. Код является несколько избыточным, чтобы продемонстрировать побольше из бесконечного числа особенностей объектно-ориентированного программирования.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
class MyClass : Form
{
ProgressBar progressBar = new ProgressBar();
Timer timer;
const int INTERVAL_TIME = 1000; // Миллисекунды
public MyClass()
{
// Настройка формы
this.Icon = new Icon("1.ICO");
this.Text = "Испытание элемента ProgressBar ";
// Настройка индикатора
progressBar.Parent = this;
progressBar.Width = this.ClientSize.Width;
int y = (this.ClientSize.Height - progressBar.Height) / 2;
progressBar.Location = new Point(0, y);
progressBar.Minimum = 0;
progressBar.Maximum = 20;
progressBar.Step = 1;
progressBar.Style = ProgressBarStyle.Continuous;
// Настройка кнопки
Button btn = new Button();
btn.Parent = this;
btn.Text = "Start/Stop";
btn.AutoSize = true;
btn.Font = new Font("Arial", 12, FontStyle.Italic);
int x = (this.ClientSize.Width - btn.Width) / 2;
y = this.ClientSize.Height - btn.Height - 20;
btn.Location = new Point(x, y);
btn.Click += new EventHandler(btn_Click);
// Настройка таймера
timer = new Timer();
timer.Interval = INTERVAL_TIME;
timer.Tick += new EventHandler(timer_Tick);
}
// Обработчик кнопки управления таймером
bool startTimerFlag = false;
void btn_Click(object sender, EventArgs e)
{
if (!startTimerFlag)
timer.Start();
else
timer.Stop();
startTimerFlag = !startTimerFlag;
}
// Обработчик тиков таймера
void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value < progressBar.Maximum)
{
progressBar.PerformStep();
}
else
{
timer.Stop();
}
}
// Деструктор, доступ не управляется
~MyClass()
{
if (startTimerFlag)
timer.Stop();
}
}
}
Объектно - ориентированное программирование различает два способа агрегирования (укрупнения) кода: наследование (сцепление) и композиция (включение). В первом случае создается новый класс, в который передаются все данные и методы базового класса так, как будто-бы они были созданы в производном классе. Производный класс считается расширением базового класса. Во втором случае в новом классе создаются объекты других классов как члены-данные этого класса. Класс, который разрабатывается на основе включения других объектов, называется контейнером (родителем), а включенные в него объекты являются дочерними. Чаще всего при разработке новых класов применяют сочетание этих двух способов.
Объект Form по умолчанию содержит строку заголовка с системным меню слева и системными кнопками справа. По периметру окна проходит рамка определения размеров окна. Внутри окна расположена клиентская область - в ней отображается информация и содержатся инструменты для пользователя. Окна могут отображать текст и графику, получать команды с клавиатуры и мыши. Но в большинстве современных окон клиентская область размещает дочерние элементы управления, с помощью которых пользователь управляет программой.
Элементы управления могут быть стандартными (библиотечными, базовыми) или разработанными самим программистом (пользовательскими). В этой части мы изучим стандартные элементы управления, обеспечивающие требуемый графический интерфейс пользователя ( GUI ).
Все элементы, которыми визуальная среда проектирования позволяет манипулировать, размещая их на форме, называются компонентами. Те компоненты, которые остаются видимыми и во время выполнения программы, называются визуальными, и это, как правило, элементы управления пользовательского интерфейса. Те компоненты, которые не видимы во время выполнения - называются невизуальными, или просто - компонентами.
Обычно элементы управления занимают прямоугольную область, хотя могут быть и непрямоугольными и даже скрытыми, тем не менее исправно выполнять свои обязанности. Все элементы управления чувствительны к событиям мыши и клавиатуры и сами способны генерировать ряд событий. Превращая информацию о действиях пользователя в простые
Все элементы управления должны иметь своего родителя, определяемого свойством Parent. Только элементы управления, имеющие родителя, будут отображены на экране. Родителем может быть не только форма, но и другой элемент управления (это случается сравнительно редко). Положения элемента управления всегда задается относительно родителя и отображается на его поверхности. Часть элемента управления, выходящая за края родителя, не видна.
Класс Form, как наследник класса Control, тоже имеет свойство Parent, но оно обычно имеет значение null. Считается, что родителем формы по умолчанию является рабочий стол, и в этом случае свойство Form.TopLevel (верхний уровень) имеет значение true. Но форма может выступать потомком любого другого элемента управления при значении TopLevel = false, в том числе каркаса MDI - приложения.
Если в свойстве Form.Owner определена ссылка на другую форму, то форма имеет владельца, располагается всегда поверх него и сворачивается или закрывается вместе с ним. Такое поведение полезно при создании немодальных диалоговых окон.
Для того, чтобы элемент управления размещался на форме, сначала нужно создать саму форму как объект, затем создать как объект элемент управления, затем присвоить его свойству Parent ссылку на объект формы (назначить родителя) или выполнить метод свойства Controls.Add() объекта формы. Эти действия по регистрации элемента управления в форме являются равнозначными.
Например, при создании кнопки на форме в конструкторе формы нужно прописать такой код
Button dtn = new Button(); btn.Parent = this; или this.Controls.Add(btn);
Свойство Controls наследуется формой от класса Control и является объектом класса ControlCollection. Оно содержит в себе все дочерние элементы формы. Методы Controls.Add() и Controls.Remove() управляют составом этого набора. Коды this.Controls.Remove(btn) и btn.Parent = null
Приведем пример.
Командой File/New/Project создайте пустой проект с именем MyProject
Командой Project/Add Reference добавьте к проекту ссылки на базовые сборки System.dll и System.Windows.Forms.dll
Командой Project/Add New Item добавьте два пустых файла MainForm.cs и Program.cs
Заполните файлы следующим кодомusing System;
using System.Windows.Forms;
namespace MyProject
{
class MainForm : Form
{
const int MAX_BUTTON = 5; // Число кнопок
public MainForm()
{
// Настраиваем консольное окно
Console.ForegroundColor = ConsoleColor.White;
// Регистрируем событие загрузки формы
this.Load += new EventHandler(MainForm_Load);
}
// Создаем элементы управления в обработчике события Load формы
void MainForm_Load(object sender, EventArgs e)
{
// Создаем кнопки
for (int i = 0; i < MAX_BUTTON; i++)
{
Button btn = new Button(); // Создали кнопку
this.Controls.Add(btn);// Отдали кнопку форме
}
Console.WriteLine("Создано кнопок:
{0}", this.Controls.Count);
// Уничтожаем кнопки
int count = 0; // Локальная переменная
Control[] control = new Control[this.Controls.Count];
// Проводим предварительное обследование коллекции в foreach
foreach (Control ctrl in this.Controls)
{
if (ctrl is Button)
{
control[count] = ctrl;// Сохраняем ссылку в массиве
count++;
}
}
// Уничтожаем кнопки по найденым ссылкам
for (int i = 0; i < count; i++)
this.Controls.Remove(control[i]);
Console.WriteLine("Удалено кнопок: {0}", count);
// Еще раз создаем кнопки
for (int i = 0; i < MAX_BUTTON + 1; i++)
{
Button btn = new Button(); // Создали кнопку
btn.Parent = this; // Отдали форме другим способом
}
Console.WriteLine("\nСоздано кнопок:
{0}", this.Controls.Count);
// Уничтожаем кнопки
count = 0; // Сбросили счетчик
control = new Control[this.Controls.Count];// Переназначили массив
// Проводим предварительное обследование коллекции в for
for (int i = 0; i < this.Controls.Count; i++)
{
Control ctrl = this.Controls[i];
if (ctrl is Button)
{
control[count] = ctrl;
count++;
}
}
// Уничтожаем кнопки по найденым ссылкам
for (int i = 0; i < count; i++)
control[i].Parent = null;// Уничтожаем другим способом
Console.WriteLine("Удалено кнопок: {0}", count);
for (int i = 0; i < MAX_BUTTON + 2; i++)
{
Button btn = new Button(); // Создали кнопку
btn.Click += btn_Click;// Зарегистрировали общий обработчик
btn.Parent = this; // Отдали форме
}
Console.WriteLine("\nСоздано кнопок:
{0}", this.Controls.Count);
}
// Уничтожение кнопок интерактивно
int count = 0; // Поле
void btn_Click(object sender, EventArgs e)
{
this.Controls.Remove((Control)sender);
Console.WriteLine("{0}) Удалили кнопку
щелчком на ней", ++count);
}
}
}
using System;
using System.Windows.Forms;
namespace MyProject
{
class EntryPoint
{
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
}
}
Результат работы приведенного кода будет таким

Поскольку все элементы управления произошли от класса Control, а он определяет свойство Controls, то любой элемент управления имеет это родительское свойство и может быть родителем. Но не многие наследники Control используются программистами в качестве родителей. Обычно элементы управления используются в качестве дочерних элементов формы.
Class Control имеет булево свойство TabStop, которое позволяет контейнерным элементам управлять фокусом ввода своих дочерних элементов с помощью клавиши Tab. Фокус ввода способны получать только те дочерние объекты, у которых свойство TabStop установлено в true. Порядок получения фокуса определяется свойством Control.TabIndex дочерних элементов контейнера или выполняется в порядке их расположения в
коллекции (в порядке их добавления в набор, Z -порядок: последний добавленный видится верхним). Элемент управления сдвигается в Z -последовательности на первое или последнее место своими методами BringToFront() или SendToBack() соответственно.

Дочерние элементы управления одного контейнера (родителя) называются родственными.
По умолчанию все элементы управления рождаются видимыми и доступными пользователю. Видимость элемента управления определяется свойством Visible, а доступность - Enabled. Те же свойства родителя (контейнера) влияют сразу на все дочерние элементы. Невидимым или недоступным элемент становится только для пользователя, но в составе программы остается полноценным элементом и продолжает работать под ее контролем.
Каждому элементу управления может задаваться положение его левого верхнего угла относительно левого верхнего угла клиентской области родителя. Оно определяется свойством Location элемента управления, которое ожидает ссылку на экземпляр класса Point(x, y), где x и y означают количество пикселов смещения. Размер элемента задается через свойство Size, которое ожидает ссылку на объект класса Size(width, height). Ширина и высота также означают количество пикселов относительно точки привязки элемента управления.

Если в элементе управления (например, кнопке) установить булево свойство AutoSize = true, то установленный размер Size игнорируется и элемент управления подгоняет свои размеры под размер надписи, определяемой свойством Text.
Свойство Dock (причал) элемента управления используется для растягивания и выравнивания по внутренней стороне родителя. Его значение определяется перечислением DockStyle: None, Left, Right, Top, Bottom, Fill. Свойство Anchor (якорь) заставляет элемент управления замораживать привязку к сторонам родителя (при изменении размеров последнего) на том расстоянии, которое он занимал до изменения размеров родителя. Свойство Anchor принимает значения перечисления AnchorStyles: : None, Left, Right, Top, Bottom и допускает их побитовое сложение ( по умолчанию Anchor = Left | Top).
Порядок создания объектов в программе следующий: вначале создается главный контейнер, затем создаются все дочерние элементы и присоединяются к контейнеру через ссылки. Если дочерний элемент, в свою очередь, является контейнером, то он создается вперед своих дочерних элементов и ждет, когда к нему будут присоединены ссылки на них. При создании дочерних элементов им неявно передаются значения одноименных свойств контейнера. Главный контейнер приложения получает значения этих свойств от операционной системы и передает их вниз по иерархической цепочке. Если в любом контейнере этой цепочки свойствам назначить другие значения, то новые значения одноименных свойств получат все дочерние элементы.
Класс Color передает элементам управления свойство Text, которые используют его соответствующим их специализации способом. Например, в форме это заголовок окна, в кнопке это надпись, а полоса прокрутки вообще не использует это свойство. Наследники класса Control получают от него, также, свойства Font, ForeColor и BackColor, которые задают шрифт, его размер, стиль и цвет, а также цвет клиентской области. Если дочерний элемент явно не задает значение этого свойства, то оно перенимает значение контейнера.
Для иллюстрации сказанного переделаем предыдущий пример.
Замените в последнем проекте MyProject код файла MainForm.cs на следующийusing System;
using System.Windows.Forms;
using System.Drawing;
namespace MyProject
{
class MainForm : Form
{
const int MAX_BUTTON = 5; // Число кнопок
public MainForm()
{
// Настраиваем консольное окно
Console.ForegroundColor = ConsoleColor.White;
// Регистрируем событие загрузки формы
this.Load += new EventHandler(MainForm_Load);
}
// Создаем элементы управления в обработчике события Load формы
void MainForm_Load(object sender, EventArgs e)
{
this.Text = "Щелкайте на кнопках!";
// Автоматически показывать полосу прокрутки,
// когда не помещаются дочерние элементы
this.AutoScroll = true;
// При запуске с консольным окном сделать верхней
this.Activate();
// Переопределяем свойство контейнера,
// которое неявно передастся дочерним элементам
this.ForeColor = Color.Red;
// Создаем и настраиваем дочерние элементы
int x = 0, y = 0; // Размещение кнопок
for (int i = 0; i < MAX_BUTTON; i++)
{
Button btn = new Button(); // Создали кнопку
btn.Click += btn_Click;// Зарегистрировали общий обработчик
btn.Parent = this; // Отдали форме
// Продолжаем настройку, пока не потеряли адрес
btn.Text = "Кнопка " + (i + 1).ToString();
btn.AutoSize = true;
// Настраиваем плоский стиль кнопки (для Flat)
btn.FlatStyle = FlatStyle.Flat;
btn.FlatAppearance.BorderColor = Color.Blue;
btn.FlatAppearance.BorderSize = 5; // В пикселах
// Вычисляем точку размещения
if ((i + 3) % 2 == 1) // Первая колонка нечетные
{
x = 0;
if (i != 0)// Начальные не смещать
y += btn.Size.Height * 2;
}
else // Вторая колонка четные
{
x = btn.Size.Width * 2;
btn.TabStop = false; // Четные лишаем фокуса ввода
}
// Позиционируем дочерний элемент относительно родителя
btn.Location = new Point(x, y);
// Переопределяем свойство дочернего элемента.
// Стиль шрифта побитово суммируем
btn.Font = new System.Drawing.Font(
"Times New Roman", 14,
FontStyle.Italic | FontStyle.Bold);
btn.BackColor = Color.Yellow;
}
// Назначение фокуса ввода
int indexFocus, count = this.Controls.Count;
indexFocus = (count + 2) % 2 == 1 ? count - 1 : count;
if (indexFocus >= 0) // Проверка на случай пустого контейнера
this.Controls[indexFocus].Focus();
// Активируем последний в первой колонке
Console.WriteLine("Создано кнопок:
{0}", this.Controls.Count);
}
// Уничтожение пользователем кнопок интерактивно
void btn_Click(object sender, EventArgs e)
{
Control ctrl = sender as Control;
this.Controls.Remove(ctrl);
Console.WriteLine("\"" +
ctrl.Text + "\" удалена!");
// Меняем заголовок окна, когда кончились кнопки
if (this.Controls.Count == 0)
{
this.Text = "Все кнопки удалены !!!!!!";
}
}
}
}
Графическое окно, созданное классом-контейнером MainForm, будет выглядеть так

Цвет надписи кнопка получила от родителя, а шрифт и цвет фона были для нее установлены явно. Обратите внимание на то, как мы программно установили для коллекции дочерних элементов фокус ввода и порядок управления фокусом ввода по клавише Tab. Кнопка, имеющая фокус ввода, реагирует на нажатие клавиш Enter или Space ( пробела - такая са-а-амая длинная!) как на щелчок мыши.
Запустите и опробуйте это ...Форма может иметь много дочерних элементов управления. Если это каркас приложения, то взаимодействовать с элементом можно через его события. Но когда это диалоговое окно со сложными настройками, которое при закрытии должно передавать выбор пользователя со всех своих элементов, то здесь может потребоваться программный опрос всех элементов. Естественно, что вызывающей стороне нужен доступ ко всем элементам дочерней формы.
Существует много способов для решения такой задачи. Можно, например, объявить в дочернем контейнере именные ссылки на свои элементы как общедоступные поля или свойства и адресоваться через них. Но чаще применяют другой способ, учитывая, что все ссылки на элементы хранятся в коллекции Controls контейнера. Если в дочернем контейнере промаркировать его элементы в свойствах Name (ожидает тип string ) или Tag (принимает любой тип, поскольку объявлено как object ), то найти такой элемент в коллекции по его уникальному признаку не составит труда.
Коллекция Controls, начиная с версии .NET Framework 2.0, способна вести себя как ассоциативный массив, в котором ключ доступа к элементам представляет собой пару " целое_число-строка ". Строка представляет собой значение, заданное в свойстве Name дочернего элемента. Это означает, что адресоваться к элементу в контейнере можно либо по индексу, либо по имени, которое присвоено свойству Name (при условии, что оно уникально в рамках одной коллекции).
Свойство Controls является экземпляром класса Control.ControlCollection, который имеет методы Contains() и Find(). Метод Contains() возвращает true, если проверяемый объект является членом коллекции. Метод Find() проверяет свойство Name всех элементов коллекции на соответствие заданному значению и возвращает массив ссылок найденных элементов. Вторым аргументом метода Find() является булев флаг, устанавливающий режим поиска: искать до первого найденного или продолжать поиск до конца.
Чтобы проиллюстрировать рассмотренные
Прежде, чем приступать к использованию визуальных средств IDE, уместно сделать одно важное замечание. Когда программист создает интерфейс пользователя через визуальный конструктор оболочки, то последний генерирует код по своей собственной схеме. И желательно своими действиями по прямому редактированию кода интерфейса в этот порядок не вмешиваться, а все делать через графический редактор и вспомогательные панели среды проектирования. Хотя разбираться в этом вопросе следует (но не обязательно).
В IDE C++Builder код компоновки интерфейса формы хранится в текстовом файле с расширением frm, а рабочий код размещен в паре h - и cpp -файлов. В Visual Studio 2005 код формы хранится в текстовом файле с расширением Designer.cs, а рабочий код размещен в файле с расширением cs и файле с точкой входа Program.cs.
Создадим приложение, в котором из главного окна будет вызываться диалоговое окно с элементами управления. После закрытия диалогового окна выполним опрос его элементов и выведем полученную информацию в клиентской области главного окна. Требуемые элементы управления будем переносить на форму проекта из панели инструментов Toolbox оболочки.
Выполните команду File/New/Project и создайте проект типа Windows Application с именем FirstWinApp
Мастер создания заготовки приложения создаст дерево каталогов проекта со вспомогательными файлами и сгенерирует в них необходимый код

Сгенерированная мастером форма будет главной формой нашего примера
В панели Solution Explorer переименуйте файл Form1.cs в MainForm.csОбратите внимание, что оболочка переименовала вспомогательные файлы и класс главной формы.
Перенесите из панели Toolbox на главную форму и настройте через панель Properties элементы управления в соответствии с приведенной ниже таблицей свойств| Элемент | Свойство | Значение | Описание |
|---|---|---|---|
Form |
Text |
Главное окно приложения | Текст строки заголовка |
FormBorderStyle |
Sizable |
С изменяемым интерактивно размером | |
Size |
600, 450 | Размеры окна в пикселах с соотношением 4/3 (640/480, 800/600, 1024/768) | |
Icon |
Иконка системного меню в заголовке окна (прилагается) | ||
StartPosition |
CenterScreen |
Начальная позиция при запуске | |
Button |
Name |
btnCreateDialogBox |
Программное имя кнопки вызова диалогового окна |
Anchor |
Bottom |
Сохранять постоянным растояние до нижнего края родителя | |
|
True |
Подстраивать размер кнопки под надпись | |
Text |
Диалог | Надпись на кнопке | |
TextBox |
Name |
txtShowProperties |
Имя объекта для отображения свойств диалогового окна |
Dock |
Top |
Приклеиться к верхнему краю клиентской области родителя по всей ширине | |
Multiline |
True |
Многострочный техт | |
ScrollBars |
Vertical |
Отображать вертикальную полосу прокрутки |
На этом проектирование интерфейсной части главного окна приложения завершена. Приступим к проектированию диалогового окна.
Выполните команду Window/Close All Documents, чтобы закрыть все окна редактируемых файлов проекта в рабочей области оболочки. При необходимости сохраните изменения
Выполните команду Project/Add Windows Form, чтобы создать форму диалогового окна с именем MyModalDialogBox
Разместите на форме будущего диалогового окна элементы управления и настройте их в соответствии с таблицей свойств (дочерние элементы внутренних контейнеров в таблице отображены составными именами)| Элемент | Свойство | Значение | Описание |
|---|---|---|---|
Form |
Text |
Модальное диалоговое окно | Текст строки заголовка |
FormBorderStyle |
FixedDialog |
С неизменяемыми размерами и без иконки системного меню в строке заголовка | |
Size |
600, 450 | Размеры окна в пикселах со стандартным соотношением 4/3 | |
AutoScaleMode |
Font |
Для подстройки размеров под величину шрифта | |
ControlBox |
False |
Без системных кнопок в строке заголовка | |
ShowInTaskbar |
False |
Не отображать в панели задач рабочего стола Windows |
|
StartPosition |
CenterParent |
Начальная позиция при запуске в центре родителя | |
|
Name |
grBoxRadioButton |
Контейнер для радиокнопок |
Text |
Выберите радиокнопку | Заголовок контейнера переключателей | |
|
Text |
Радиопереключатель1 | Надпись радиокнопки |
Checked |
True |
Изначально включена | |
|
Text |
Радиопереключатель2 | Надпись радиокнопки |
|
Text |
Радиопереключатель3 | Надпись радиокнопки |
|
Text |
Радиопереключатель4 | Надпись радиокнопки |
|
Text |
Радиопереключатель5 | Надпись радиокнопки |
Label |
Text |
Укажите свои ФИО | Надпись текстовой метки |
Font.Bold |
True |
Полужирный шрифт надписи | |
Font.Size |
10 | Размер шрифта надписи | |
ForeColor |
Red |
Цвет текста | |
TextBox |
Name |
Фамилия | Идентификатор русский !!! |
Text |
Иванов | ||
TextBox |
Name |
Имя | Идентификатор русский !!! |
Text |
Петр | ||
TextBox |
Name |
Отчество | Идентификатор русский !!! |
Text |
Сидорович | ||
Panel |
Name |
panelCheckBox |
|
BackColor |
White |
Фон белый | |
| Panel.CheckBox | Text |
Флажок 1 | |
| Panel.CheckBox | Text |
Флажок 2 | |
Tag |
Важный | Наша метка | |
| Panel.CheckBox | Text |
Флажок 3 | |
Tag |
Важный | Наша метка | |
CheckedListBox |
Name |
checkedListBox |
Идентификатор списка флажков |
Items |
Списковый флажок 1 Списковый флажок 2 Списковый флажок 3 Списковый флажок 4 Списковый флажок 5 Списковый флажок 6 Списковый флажок 7 |
Элементы списка | |
Button |
Name |
btnOK |
|
|
True |
Подстройка под размер надписи | |
DialogResult |
OK |
Устанавливает значение свойства DialogResult=OK диалогового окна и закрывает окно |
|
Text |
OK |
Надпись на кнопке | |
Button |
Name |
btnCancel |
|
|
True |
Подстройка под размер надписи | |
DialogResult |
Cancel |
Устанавливает значение свойства DialogResult=Cancel диалогового окна и закрывает окно |
|
Text |
Cancel |
Надпись на кнопке |
После проведенных настроек форма диалогового окна должна стать такой

Теперь нужно написать код, который свяжет разработанные формы вместе и позволит опросить состояние всех элементов диалоговой формы после ее использования.
Создайте обработчик события Click кнопки в главном диалоговом окне и заполните его такprivate void btnCreateDialogBox_Click(object sender, EventArgs e)
{
txtShowProperties.Text = "";
MyModalDialogBox dlg = new MyModalDialogBox();
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Диалоговое окно еще существует, опрашиваем его
foreach (Control ctrl0 in dlg.Controls)
{
ShowProperties("", ctrl0);
if (ctrl0.Controls.Count > 0)
foreach (Control ctrl1 in ctrl0.Controls)
{
ShowProperties("\t", ctrl1);
}
}
}
else
txtShowProperties.Text = "Пользователь установки не менял";
dlg.Dispose(); // Освободили явно ссылку на диалоговое окно
}
private void ShowProperties(string str, Control ctrl)
{
txtShowProperties.Text += str + "Name: " +
ctrl.Name + "\r\n";
if (!(ctrl is Panel) !(ctrl is CheckedListBox))
txtShowProperties.Text += str + "Text: " +
ctrl.Text + "\r\n";
if(ctrl is CheckedListBox)
{
CheckedListBox check = (CheckedListBox)ctrl;
for (int i = 0; i < check.Items.Count; i++)
txtShowProperties.Text += "\t" +
check.Items[i].ToString() + "\r\n";
}
if ((String)ctrl.Tag == "Важный")
txtShowProperties.Text += "!!!Помеченный нами в
свойстве Tag!!!" + "\r\n";
}
Многие классы не являются элементами управления как таковыми, а предназначены для хранения множества объектов и управления ими. Такие классы представляют собой
ImageList - это набор объектов Image, включающий в себя растровые рисунки и и метафайлы (Иконки) одного размера и глубины цвета. Основным свойством ImageList является объект Images типа ImageList.ImageCollection, который имеет ряд методов, в том числе Add() для добавления рисунков в коллекцию.
Пусть в текущем с приложением каталоге имеются два растровых изображения MyPicture1.bmp и MyPicture2.bmp, которые нужно упаковать в контейнер. Фрагмент кода программы может выглядеть так
using System.Windows.Forms;
...
// Создаем пустую коллекцию рисунков
ImageList imglst = new ImageList();
// Наполняем коллекцию рисунками
Bitmap bmp = new Bitmap("MyPicture1.bmp");// Загрузили первый рисунок
imglst.Images.Add("key1", bmp); // Пометили и отдали в коллекцию
bmp = new Bitmap("MyPicture2.bmp");// Загрузили второй рисунок
imglst.Images.Add("key2", bmp); // Пометили и отдали в коллекцию
...
// Где-то в программе используем рисунки, сохраненные в коллекции
Bitmap bmp1, bmp2;
bmp1 = (Bitmap)imglst.Images[0]; // Извлекли по индексу
bmp2 = (Bitmap)imglst.Images["key2"];// Извлекли по ключу
using System;
using System.Drawing;
using System.Windows.Forms;
class MyClass : Form
{
ImageList imageList;
public MyClass()
{
this.Icon = new Icon("1.ICO");
this.Text = "Графическое окно";
imageList = new ImageList();
imageList.Images.Add("bmp",
Image.FromFile("Photo.bmp"));
imageList.Images.Add("jpg",
Image.FromFile("Photo.jpg"));
imageList.Images.Add("png",
Image.FromFile("Photo.png"));
int width = 250;
imageList.ImageSize = new Size(width, width / 4 * 3);
this.Click += new EventHandler(MyClass_Click);
}
void MyClass_Click(object sender, EventArgs e)
{
// Получаем указатель на холст формы
Graphics graphics = Graphics.FromHwnd(this.Handle);
// Цикл для листания рисунков
for (int count = 0; count < imageList.Images.Count; count++)
{
// Рисуем изображение на холсте формы
imageList.Draw(graphics, new Point(0, 0), count);
// Инициируем перерисовку формы (одно из предложенных)
Application.DoEvents();
//this.Invalidate();
// Усыпляем поток на две секунды
System.Threading.Thread.Sleep(2000);
}
}
}
Класс ToolTip не является элементом управления, но тесно взаимодействует с ними. Он хранит всплывающие подсказки для элементов управления, которые обычно появляются, когда на элемент управления наводится курсор мыши.
Сначала в конструкторе формы нужно создать экземпляр класса ToolTip, затем каждому (если нужно) элементу управления привязать всплывающую подсказку с помощью
// Создаем элементы управления
Button btn1 = new Button();
Button btn2 = new Button();
CheckBox check1 = new CheckBox();
CheckBox check2 = new CheckBox();
TextBox txt = new TextBox();
// Настраиваем элементы управления
btn1.Location = new Point(5, 50);
btn2.Location = new Point(20, 50);
check1.Text = "Флажок 1";
//..........................
// Создаем экземпляр контейнера ToolTip
ToolTip tips = new ToolTip();
// Привязываем посказки к одному
// или нескольким элементам управления
tips.SetToolTip(btn1, "Это кнопка OK");
tips.SetToolTip(btn2, "Это кнопка Cancel");
tips.SetToolTip(check1, "Это флажок 1");
tips.SetToolTip(check2, "Это флажок 2");
tips.SetToolTip(txt, "Это текстовое поле");
//...........................
В классе ToolTip имеется несколько свойств, настраивающих контейнер всплывающих подсказок. Вот некоторые из них
Этот контейнер наследует класс Control и сам является видимым элементом управления (рамка с надписью в свойстве Text ), используемым при формировании пользовательского графического интерфейса. Главное его применение - организовать согласованную работу радиокнопок. Он объединяет их в группы и все переключатели, принадлежащие одной группе, становятся взаимоисключающими. Класс GroupBox не наследует, в отличие от Form, класс ContainerControl, где переход между дочерними элементами выполняется нажатием клавиши Tab. Навигация между радиокнопками внутри GroupBox выполняется клавишами-стрелками.
Этот элемент управления является (как и Form ) потомком класса ScrollableControl, поэтому имеет полосы прокрутки. Он также имеет визуальное представление и может служить контейнером элементов управления при формировании пользовательского интерфейса.
Она отображает нередактируемый текст, заданный в свойстве Text. Хотя метка может выводить многострочный текст, если увеличить ее размер по высоте, но она не выводит полос прокрутки, если текст не умещается в элементе управления.
Кроме текста метка может отображать объекты типа Image. Один из способов состоит в присвоении свойству Image загруженного файла, например (проект Test )
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
class MyClass : Form
{
public MyClass()
{
// Создание и настройка элементов управления
Label lblBmp = new Label();
lblBmp.Parent = this;
lblBmp.Dock = DockStyle.Fill;
lblBmp.Image = Image.FromFile("Photo.bmp");
lblBmp.Tag = "Рисунок bmp";
Label lblJpg = new Label();
lblJpg.Parent = this;
lblJpg.Dock = DockStyle.Fill;
lblJpg.Image = Image.FromFile("Photo.jpg");
lblJpg.Tag = "Рисунок jpg";
Label lblPng = new Label();
lblPng.Parent = this;
lblPng.Dock = DockStyle.Fill;
lblPng.Image = Image.FromFile("Photo.png");
lblPng.Tag = "Рисунок png";
lblBmp.BringToFront();// Меняем Z-последовательность
this.Text = (string)lblBmp.Tag;// Заголовок окна
// Подписываем на событие Click
lblBmp.Click += new EventHandler(lbl_Click);
lblJpg.Click += lbl_Click;
lblPng.Click += lbl_Click;
}
void lbl_Click(object sender, EventArgs e)
{
Control ctrl = sender as Control;
if (ctrl == null)
{
MessageBox.Show("Не могу привести типы");
return;
}
this.Controls.Remove(ctrl);
if (this.Controls.Count > 0)
{
this.Text = (string)this.Controls[0].Tag;
this.Controls[0].BringToFront();
}
else
this.Text = "Меток больше нет";
}
}
}
Файлы с картинками должны быть помещены в один каталог со сборкой, иначе нужно указать путь у файлу (абсолютный или относительный). Одна из картинок, выводимых этим кодом, будет такой (это, конечно же, опять я - любимый!)

Кроме того, в метке можно использовать изображения, созданные в качестве ресурсов и прикрепленные к исполняемому файлу программы.
Этот элемент обладает свойствами традиционной HTML -гиперссылки Hyperlink. Помимо наследуемых от Control свойств BackColor и ForeColor метка-ссылка имеет характерные для Hyperlink свойства:
Метка-ссылка определяется свойством Text, но активная ее часть, воспринимаемая как гиперссылка, задается свойством LinkArea. Это свойство представляет собой структуру LinkArea с общедоступными полями Start и Length типа int. Например
using System;
using System.Drawing;
using System.Windows.Forms;
class MyClass : Form
{
public MyClass()
{
this.Font = new Font("Arial", 14);
LinkLabel linkLabel = new LinkLabel();
this.Controls.Add(linkLabel);
linkLabel.Dock = DockStyle.Fill;
linkLabel.Text = "Щелкните здесь
для появления сообщения";
linkLabel.LinkArea = new LinkArea(9, 5);
linkLabel.LinkBehavior = LinkBehavior.SystemDefault;
linkLabel.LinkClicked += new LinkLabelLinkClickedEventHandler(linkLabel_LinkClicked);
}
void linkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
MessageBox.Show("Вы щелкнули на метке-ссылке");
}
}
Поведение ссылки задается свойством LinkBehavior, ожидающим одно из значений одноименного перечисления System.Windows.Forms.LinkBehavior. По умолчанию установлено LinkBehavior=SystemDefault, определяющее поведение ссылки как в Microsoft Internet Explorer.
Одной метке можно назначить несколько ссылок с помощью свойства Links, которое является объектом составного класса LinkLabel.LinkCollection. Щелчок на ссылке LinkLabel инициирует событие LinkClicked, обработчик которого определяется делегатом LinkLabelLinkClickedEventHandler. Объект типа LinkLabelLinkClickedEventArgs, сопровождающий обработчик, является экземпляром составного класса LinkLabel.Link и несет данные активированной ссылки ( URL или имя файла) в свойстве LinkData типа Object.
Приведем пример, в котором программа Windows Forms отвечает на нажатие ссылки запуском другого процесса, используя метод System.Diagnostics.Process.Start().
using System;
using System.Drawing;
using System.Windows.Forms;
using Return = System.Environment;// Псевдоним класса
class MyClass : Form
{
public MyClass()
{
this.Font = new Font("Arial", 14);
this.Width = 2 * this.Height;
this.Text = "Элемент управления LinkLabel";
LinkLabel linkLabel = new LinkLabel();
linkLabel.Parent = this;
linkLabel.Dock = DockStyle.Fill;
linkLabel.Text = "Из этого приложения
Вы можете:" + Return.NewLine
+ "\n1. Подключиться к сайту корпорации
\"Майкрософт\"" + Return.NewLine
+ "2. Запустить графический редактор \"
Microsoft Paint\"" + Return.NewLine
+ "3. Запустить игру \"
Косынка\"" + Return.NewLine
+ "4. Запустить текстовый редактор \"
Блокнот\"" + Return.NewLine;
string subStr = "Майкрософт";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "http://www.microsoft.com");
subStr = "Microsoft Paint";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "msPaint");
subStr = "Косынка";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "Sol");
subStr = "Блокнот";
linkLabel.Links.Add(linkLabel.Text.IndexOf(subStr),
subStr.Length, "Notepad");
linkLabel.LinkClicked +=
new LinkLabelLinkClickedEventHandler(linkLabel_LinkClicked);
}
void linkLabel_LinkClicked(object sender,
LinkLabelLinkClickedEventArgs e)
{
string strLink = e.Link.LinkData as string;
if (strLink != null)
try
{
System.Diagnostics.Process.Start(strLink);
}
catch (Exception err)
{
string strError = "Не могу выполнить процесс !!!\n"
+ "Ошибка: " + err.Message;
MessageBox.Show(strError);
}
}
}
Результат выполнения примера будет таким

Щелчки на ссылках запускают соответствующие программы. Для подстраховки мы отлавливаем возможные исключения Windows.
Этот элемент служит для отображения растров или метафайлов. Изображение задается свойством Image. Свойство SizeMode задает режим отображения с помощью перечисления System.Windows.Forms.PictureBoxSizeMode, которое имеет следующие значения
Вот пример, для выполнения которого нужно разместить рисунки (прилагаются в каталоге Pictures ) в одной папке с исполнимым файлом.
using System;
using System.Drawing;
using System.Windows.Forms;
class MyClass : Form
{
PictureBox pictureBox;
string[] photo = {
"Photo.bmp",
"Photo.jpg",
"Photo.png"
};
public MyClass()
{
// Загрузили иконку
this.Icon = new Icon("1.ICO");
// Текст заголовка окна
this.Text = "Испытание элемента PictureBox";
// Подписались на события формы
this.Click += FormClick;
this.Paint += BeginPaint;
pictureBox = new PictureBox();// Создали элемент
pictureBox.Parent = this;// Назначили родителя
// Распахнули на всю форму
pictureBox.Dock = DockStyle.Fill;
// Масштабировать без искажений
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
// Чтобы не заслонял текстовое сообщение на форме
pictureBox.Visible = false;
// Подписываем на щелчки элемента тот же обработчик
pictureBox.Click += FormClick;
}
void BeginPaint(object sender, PaintEventArgs e)
{
// Создаем и настраиваем точку привязки текстового блока
StringFormat strfrm = new StringFormat();
strfrm.Alignment = StringAlignment.Center;// Центр по горизонтали
strfrm.LineAlignment = StringAlignment.Center;// Центр по вертикали
// Создаем временный объект для доступа к контексту устройства
Graphics gr = Graphics.FromHwnd(this.Handle);
gr.DrawString("Щелкайте на форме", // Текст сообщения
new Font("Arial", 14, FontStyle.Bold), // Шрифт сообщения
new SolidBrush(Color.Red), // Цвет шрифта
this.ClientSize.Width / 2, // Центр клиентской области по горизонтали
this.ClientSize.Height / 2, // Центр клиентской области по вертикали
strfrm); // Передаем точку привязки текстового блока
gr.Dispose();// Освободили контекст устройства
}
int count = 0;// Счетчик
bool clickFlag = false; // Устанавливается при первом щелчке
void FormClick(object sender, EventArgs e)
{
if (!clickFlag)
{
pictureBox.Visible = true;
this.Paint -= BeginPaint;// Разрегистрируем обработчик
clickFlag = true;
}
//pictureBox.Image = Image.FromFile(photo[count++]);
pictureBox.Load(photo[count++]);
count = count < photo.Length ? count : 0;// Однострочное условие
}
}
Метод Load() принимает URL или имя файла. Метод LoadAsync() выполняет загрузку в фоновом режиме, создавая дополнительный поток, и информирует о завершении событием LoadCompleted, например,
pictureBox.LoadAsync(@"http://localhost/print.jpg");
Если изображение загружается долго, то можно задать дежурную картинку в свойстве InitialImage, а также картинку в свойстве ErrorImage, выводимую в случае ошибки загрузки. Событие LoadProgressChanged в своем аргументе типа ProgressChangedEventArgs передает информацию о загрузке изображения в процентах. Эту информацию можно использовать в обработчике для отображения с помощью индикатора выполнения ProgressBar, например,
void pictureBox_LoadProgressChanged(object sender,
ProgressChangedEventArgs e)
{ progressBar.Value = e.ProgressPercentage;}
Основные свойства ProgressBar - это целочисленные Minimum, Maximum, Value. Индикатор процесса напрямую связан со свойством Value, значение которого можно увеличивать несколькими способами:
Приведем пример, в котором движком процесса является таймер. Код является несколько избыточным, чтобы продемонстрировать побольше из бесконечного числа особенностей объектно-ориентированного программирования.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
class MyClass : Form
{
ProgressBar progressBar = new ProgressBar();
Timer timer;
const int INTERVAL_TIME = 1000; // Миллисекунды
public MyClass()
{
// Настройка формы
this.Icon = new Icon("1.ICO");
this.Text = "Испытание элемента ProgressBar ";
// Настройка индикатора
progressBar.Parent = this;
progressBar.Width = this.ClientSize.Width;
int y = (this.ClientSize.Height - progressBar.Height) / 2;
progressBar.Location = new Point(0, y);
progressBar.Minimum = 0;
progressBar.Maximum = 20;
progressBar.Step = 1;
progressBar.Style = ProgressBarStyle.Continuous;
// Настройка кнопки
Button btn = new Button();
btn.Parent = this;
btn.Text = "Start/Stop";
btn.AutoSize = true;
btn.Font = new Font("Arial", 12, FontStyle.Italic);
int x = (this.ClientSize.Width - btn.Width) / 2;
y = this.ClientSize.Height - btn.Height - 20;
btn.Location = new Point(x, y);
btn.Click += new EventHandler(btn_Click);
// Настройка таймера
timer = new Timer();
timer.Interval = INTERVAL_TIME;
timer.Tick += new EventHandler(timer_Tick);
}
// Обработчик кнопки управления таймером
bool startTimerFlag = false;
void btn_Click(object sender, EventArgs e)
{
if (!startTimerFlag)
timer.Start();
else
timer.Stop();
startTimerFlag = !startTimerFlag;
}
// Обработчик тиков таймера
void timer_Tick(object sender, EventArgs e)
{
if (progressBar.Value < progressBar.Maximum)
{
progressBar.PerformStep();
}
else
{
timer.Stop();
}
}
// Деструктор, доступ не управляется
~MyClass()
{
if (startTimerFlag)
timer.Stop();
}
}
}
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.