Выбери формат для чтения
Загружаем конспект в формате docx
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
3.1 Визуальные среды разработки
Не секрет, что работать на чистом API Windows весьма проблематично. Да, это себя оправдывает, когда нужно разработать низкоуровневое приложение, критичное к потреблению ресурсов ПК. Однако при разработке этим способом прикладных программ выигрыш в производительности не оправдывает дополнительных расходов, связанных с увеличением времени разработки. Именно поэтому сейчас программы на ассемблере и прочих языках низкого уровня практически никто не пишет.
Используя API Windows, можно работать с множеством типов объектов. Некоторые из них «невидимые», т.е. не имеющие видимого представления на экране ПК. Это потоки, таймеры, файлы (мы можем видеть лишь значок или текст, ассоциированный с файлом, но не сам файл) и т.п. Компоненты, имеющие видимое представление, называются визуальными компонентами. Они делятся на множество классов и подклассов – кнопки, списки, переключатели, поля ввода, меню, окна и т.д.
Концепция объектно-ориентированного программирования не нова, но API Windows все еще остается процедурно-ориентированным. В будущих версиях ОС Windows мы, возможно, увидим объектно-ориентированный API, а пока остается пользоваться различными надстройками («обертками», англ. wrappers), написанными с использованием ООП и инкапсулирующими в себе функциональность API Windows.
Первые шаги в этом направлении предприняла компания Borland. Ее компиляторы Borland C++ 3.1 и Borland Pascal 7.0, представленные в 1992 году, содержали библиотеки классов TurboVision (для разработки консольного интерфейса DOS) и OWL 1.0 (Object Windows Library, для написания Win16-приложений). Параллельно компания Microsoft представила свою объектно-ориентированную библиотеку MFC 1.0 (Microsoft Foundation Classes). В дальнейшем разрабатывались новые версии этих библиотек, они научились создавать Win32-приложения, использовать Unicode, многозадачность и т.д. Однако, написание программы сводилось к редактированию текстовых исходных файлов. При этом создавались исходные файлы на каком-либо языке программирования, содержащие логику программы, и файлы ресурсов, содержащие описание визуальных компонентов. Например, часть файла ресурсов могла выглядеть так:
MyDialog DIALOG 0, 0, 100, 160
CAPTION "Это мой диалог"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
{
PUSHBUTTON "&ОК",
IDOK,
5, 138, 40, 14,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
PUSHBUTTON "&Отмена",
IDCANCEL,
55, 138, 40, 14,
WS_CHILD | WS_VISIBLE | WS_TABSTOP
}
Очевидно, что описывать таким образом визуальные компоненты не очень удобно – пока программа не будет скомпилирована и запущена, невозможно увидеть результат. То есть как будет выглядеть компонент с новыми свойствами, каким будет его положение относительно других компонентов и т.д.
Первой это осознала компания Borland, в 90-е годы прошлого века являвшаяся двигателем прогресса в области разработки сред программирования. В 1995 году она разработала инновационную среду разработки Borland Delphi, являющуюся связкой из компилятора языка программирования Pascal и новой объектно-ориентированной библиотеки VCL (Visual Component Library). Визуальная среда разработки Borland Delphi поддерживала проектирование приложения по принципу WYSIWYG (What You See Is What You Get – что видишь, то и получишь), согласно которому результат разработки отображается в процессе редактирования и выглядит максимально близко похожим на конечный продукт. В дальнейшем появилась среда разработки и для языка C++, Borland C++ Builder. Согласитесь, процесс создания визуального приложения по принципу WYSIWYG гораздо нагляднее, чем редактирование файлов ресурсов (рис. 3.1).
Рис. 3.1 – Редактирование формы в Borland C++ Builder 4.0
В библиотеке VCL было введено понятие формы (Form). Форма соответствует окну Windows и является контейнером с размещенными на ней визуальными и невизуальными компонентами (последние отображаются в виде условных пиктограмм). В режиме редактирования компоненты можно перемещать в рамках формы или с одной формы на другую, изменять их размер и т.д. Форма управляет автоматическим созданием и удалением компонентов, размещенных на ней, их взаимным положением (выравниванием) и т.п. При этом можно управлять не только визуальными компонентами, но и компонентами доступа к данным, компонентами для доступа к сети и т.д.
Расширение компанией Borland языка C++ концепцией свойств (properties) позволило визуально редактировать компоненты через специальный инструмент – инспектор объектов. А расширение языка C++ еще одной концепцией – событиями (events), реализованными в виде универсальных указателей на методы классов, – позволило отказаться от такого ужаса MFC, как карты сообщений (message maps).
Эстафета была подхвачена, и другие компании также начали разработку своих визуальных библиотек. Впрочем, не все они опираются на API Windows, есть и кросс-платформенные разработки (Qt, CLX, LCL, GTK+ и т.д.). И только в 2002 году, вместе с первой версией .NET Framework, представила свое решение для визуальной разработки приложений компания Microsoft (рис. 3.2).
Рис. 3.2 – Редактирование формы в Microsoft Visual Studio 2008
Названо это решение было Windows Forms (WF). Для обеспечения визуальной разработки при помощи окна свойств в .NET также были добавлены концепции свойств и событий. В целом, разработчики .NET при разработке своего продукта заимствовали все удачные концепции языков программирования Java и C++, а также имеющихся визуальных библиотек для них (VCL, Swing и т.п.).
К сожалению, стандартный C++ не является CLR-совместимым языком, и создавать на нем приложения с использованием Windows Forms нельзя. Поэтому язык был переработан – появились новые ключевые слова, операторы, директивы и т.п. Полностью объектным, подобно языку C#, он не стал – процедуры и функции по-прежнему можно описывать вне классов, типы данных являются примитивами, а не классами или структурами, и т.д. С другой стороны, сохранилась совместимость с разработанными ранее классами и библиотеками.
Помимо WF, в .NET Framework 3.0 появилась новая библиотека визуальных компонентов WPF (Windows Presentation Foundation). В отличие от WF, где рисование интерфейса выполняется средствами GDI и GDI+ (Graphics Device Interface, набор графических инструментов, предоставляемый API Windows), интерфейс WPF использует DirectX. Поэтому становятся доступны различные эффекты прозрачности, объема, масштабирования и т.п. При этом для организации интерфейса используется язык XAML (eXtensible Application Markup Language). Это основанный на XML язык разметки приложений, разработанный Microsoft.
3.2 Каркас приложения Windows Forms
Создадим новое приложение Windows Forms и поместим его в папку «ch3\sample01».
Рис. 3.3 – Создание приложения Windows Forms
В среде разработки Visual Studio 2008 для этого выберем пункт меню «Файл» → «Создать» → «Проект…» (комбинация клавиш Ctrl+Shift+N или соответствующая клавиша на панели инструментов). В диалоге создания проекта выбираем категорию «Visual C#» → «Windows», шаблон «Приложение Windows Forms» (рис. 3.3).
Посмотрим, какие новые файлы появились в проекте по сравнению с консольным приложением:
• Файл ресурсов Properties\Resources.resx. В отличие от файлов ресурсов старого формата (.RC), имеющих обычный текстовый формат, ресурсы .RESX имеют формат XML. В данном файле описываются все ресурсы, которые невозможно добавить в проект, используя визуальную среду разработки (или которые удобнее описать в таком формате). При компиляции двоичный файл ресурсов получает расширение .RESOURCES. Для чтения и записи файлов .RESX можно использовать классы ResourceReader и ResourceWriter, для чтения и записи двоичных файлов ресурсов – ResXResourceReader и ResXResourceWriter. Добавить в проект ресурсы строкового типа можно через свойства проекта («Проект» → «Свойства…», закладка «Ресурсы» или двойной щелчок по узлу Resources.resx в обозревателе решений).
• Файл Properties\Resources.Designer.cs. Данный файл генерируется автоматически из файла .RESX, поэтому не следует его модифицировать. Здесь описан класс (по умолчанию имеющий имя Resources) для доступа к ресурсам. Для получения этого файла используется программа Resgen.exe (входящая в состав .NET Framework SDK или встроенная в Visual Studio). С ее помощью также можно конвертировать текстовые файлы ресурсов в двоичные, и наоборот.
• Файл Properties\Settings.settings. Здесь хранятся настройки приложения. Ранее все настройки приложений хранились в различных конфигурационных файлах (с расширением .INI, .CFG и т.п.). В настоящее время Microsoft предлагает все настройки хранить в формате XML. В файл Settings.settings заносятся все параметры приложения, созданные в среде разработки («Проект» → «Свойства…», закладка «Параметры» или двойной щелчок по узлу Settings.settings в обозревателе решений).
• Файл Properties\Settings.Designer.cs. Здесь описан класс (по умолчанию имеющий имя Settings) для доступа к настройкам приложения. Он также генерируется автоматически из файла .SETTINGS, поэтому не следует его модифицировать вручную.
• Файл app.config. В данный файл можно добавлять дополнительные параметры приложения. Помимо этого, в него автоматически добавляются параметры, описанные в файле Settings.settings. После компиляции в той же папке, в которой генерируется исполняемый файл .EXE, будет помещен файл с расширением .EXE.CONFIG, куда будут скопированы все настройки. Пример использования настроек приложения приведем позже, в главе 4.
• Файл Form1.cs. Для каждой формы приложения будет создан отдельный исходный файл на языке C#, имя которого совпадает с именем формы. Посмотрим на его содержимое:
namespace WindowsFormsSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
Наименование пространства имен по умолчанию совпадает с именем решения. Чтобы его изменить, следует вписать новое имя в свойства проекта (закладка «Приложение», поле «Пространство имен по умолчанию») и переименовать пространство имен в исходных файлах Program.cs, Form1.cs и Form1.Designer.cs.
Итак, здесь описан частичный (partial) класс, в котором будет находиться весь код, относящийся к данной форме. В конструкторе инициализируются компоненты, размещенные на форме.
–Файл Form1.Designer.cs. Здесь находится код для управления компонентами формы:
namespace WindowsFormsSample
{
partial class Form1
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором форм Windows
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "Form1";
}
#endregion
}
}
Видим вторую часть класса Form1 и методы для инициализации и удаления компонентов. Вручную данный файл лучше не редактировать, вместо этого пользоваться визуальным редактором формы. При этом в классе будут создаваться поля для каждого добавляемого компонента, а в метод InitializeComponent будет заноситься код для инициализации свойств этих компонентов, значения которых отличаются от значений по умолчанию.
Файл Program.cs редактировать можно, но в этом нет необходимости. Он лишь инициализирует и запускает приложение WF:
namespace WindowsFormsSample
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
3.3 Компоненты приложений Windows Forms
Все доступные компоненты сгруппированы по категориям, и появляются на панели элементов при активации конструктора формы (рис. 3.4.). Изначально компонентов не так много, но это только базовый набор. На панель можно добавлять новые компоненты, находящиеся в различных сборках .NET, библиотеках DLL, COM и т.д. В дальнейшем мы разберемся, как это можно сделать. Если панель элементов не отображается, необходимо выбрать пункт меню «Вид» → «Панель элементов» (комбинация клавиш Ctrl+Alt+X или соответствующая клавиша на панели инструментов). Если панель элементов настроена так, чтобы автоматически скрываться, когда она не активная, то в левой части рабочей области среды разработки будет находиться закладка «Панель элементов». При наведении на нее курсора мыши панель будет развернута.
Рис. 3.4 – Панель элементов
Выделив любой компонент, можно добавить его на форму. При этом включается режим добавления компонента. Если в этом режиме навести указатель мыши на форму, он примет крестообразную форму с изображением миниатюры компонента в правом нижнем углу. Если в этом режиме зажать левую клавишу (правую для левшей) мыши, выделить на форме регион и затем отпустить клавишу мыши, то компонент будет добавлен на форму, а его границы будут соответствовать границам выделенного региона. Необходимо лишь отметить, что есть компоненты, для которых запрещено изменять ширину и/или высоту. В этом случае ширина и/или высота будут иметь предопределенный размер. Если в режиме добавления компонента просто щелкнуть по форме мышью, то компонент также будет добавлен, его левой верхней границей будет указанная точка, а для ширины и высоты будут использованы значения по умолчанию.
Выбор пункта «Указатель» позволяет отменить режим добавления компонента и вернуться к редактированию уже имеющихся на форме компонентов.
Однако даже описание базовых компонентов с их свойствами заняло бы слишком много места, поэтому мы не будем этого делать. Тем более что все компоненты хорошо документированы. В принципе, их названия, а также названия их свойств и событий говорят сами за себя. Также при выборе свойств и событий в нижней части окна свойств появляется их краткое описание. Если и этого недостаточно, справочная система MSDN содержит полное описание с примерами.
Поэтому далее рассмотрим лишь некоторые часто используемые компоненты приложений WF и их основные свойства. Все они являются членами пространства имен System.Windows.Forms.
3.3.1 Элементы управления
Элементом управления называется примитив графического интерфейса, используемый для обработки команд пользователя. То есть, в широком смысле, к элементам управления можно отнести все компоненты, имеющие визуальное представление. В данном разделе мы под элементами управления подразумеваем элементы управления в узком смысле, т.е. компоненты, имеющие графическое представление в конструкторе формы. Иногда для них вводят специальный термин – контрол.
Все компоненты, имеющие графическое (визуальное) представление в конструкторе формы, являются потомками класса Control (полное имя – System.Windows.Forms.Control) и от него наследуют свое поведение.
3.3.1.1 Системы координат
Визуальный компонент использует две системы координат – экранную и клиентскую. Центр экранной системы координат находится в левом верхнем углу экрана. Центр клиентской системы координат находится в левом верхнем углу клиентской области компонента (рис. 3.5). Клиентская область служит для ввода и просмотра информации пользователем и не включает различные рамки, бордюры и пр. элементы оформления.
Рис. 3.5 – Экранная и клиентская системы координат
Границы формы задаются в экранных координатах, а границы других элементов управления – в системе координат их родительских компонентов. Ни один визуальный компонент, кроме формы, не может быть отображен сам по себе. Ему требуется родительский компонент – контейнер, управляющий его размещением, фокусом ввода и т.д. В этом случае сам компонент по отношению к родителю будет являться дочерним. Родительским компонентом может являться форма, а также панель и другие компоненты из категории «Контейнеры» панели элементов (см. рис. 3.4). Родительский компонент соответствует следующему свойству класса Control:
Control Parent { get; set; }
Чтобы получить ссылку на форму, на которой расположен компонент (а родительский компонент – это не всегда форма), используем метод
Form FindForm();
Если Parent = null, то элемент управления не будет отображаться. Продемонстрируем работу этого свойства на примере. Чтобы не создавать отдельное приложение для демонстрации каждого компонента или его свойства, далее будем модифицировать решение «sample01». Для каждого примера создадим отдельную вкладку, используя компонент TabControl. В первую вкладку поместим компонент Panel, который может являться родительским компонентом. Далее на эту вкладку поместим кнопку (Button), а затем еще две кнопки – первую разместим внутри созданной ранее кнопки, а вторую – внутри панели (рис. 3.6). Подробнее данные компоненты рассмотрим ниже.
Рис. 3.6 – Создание дочерних элементов управления
Видим, что кнопка, помещенная на панель, отображается не полностью, т.к. область видимости дочернего компонента ограничена областью родительского компонента. Кнопка, помещенная поверх другой кнопки, отображается полностью. Следовательно, кнопки не могут являться родительскими компонентами (вернее, программно этого можно добиться, а в конструкторе формы – нет). И родителем этих кнопок будет вкладка tabPage1 компонента tabControl1.
Например, для кнопки, расположенной на панели, сделаем следующий обработчик на ее нажатие:
if (button3.Parent == panel1) button3.Parent = tabPage1;
else button3.Parent = panel1;
Теперь при нажатии на эту кнопку ее родительский компонент будет переключаться с вкладки tabPage1 на панель panel1 и обратно. При этом визуально кнопка также будет менять свои координаты, т.к. координаты верхнего левого угла у этих компонентов относительно центра экранных координат отличаются.
Узнать, есть ли у компонента дочерние элементы управления, позволяет свойство HasChildren класса Control, а метод Contains проверяет, является ли указанный элемент дочерним для данного элемента управления:
bool HasChildren { get; }
bool Contains(Control ctl);
Задать границы компонента можно тремя способами:
1. Указав координаты верхнего левого и нижнего правого угла. Для хранения целочисленных координат точки используется структура System.Drawing.Point. Она содержит методы, операторы и свойства, позволяющие совершать различные операции с координатами точки. Сами координаты соответствуют свойствам X и Y:
int X { get; set; }
int Y { get; set; }
2. Указав координаты верхнего левого угла, а также размеры – ширину и высоту. Ширина и высота задаются структурой System.Drawing.Size. Она также содержит различные члены для выполнения операций с размерами. Сами размеры задаются свойствами Width и Height:
int Width { get; set; }
int Height { get; set; }
3. Указав границы прямоугольника, включающего в себя компонент. Для представления прямоугольника с целочисленными координатами используется структура System.Drawing.Rectangle. Аналогично, помимо прочих членов, содержит координаты прямоугольника Left, Top, Right, Bottom:
int Left { get; }
int Top { get; }
int Right { get; }
int Bottom { get; }
Эти свойства доступны только для чтения, а для чтения и записи применяется ряд других свойств структуры Rectangle:
Point Location { get; set; }
int X { get; set; }
int Y { get; set; }
Size Size { get; set; }
int Width { get; set; }
int Height { get; set; }
Свойства Location, X и Y определяют координаты верхнего левого угла, а Size, Width и Height – размеры прямоугольника. При этом:
• Left = X = Location.X;
• Top = Y = Location.Y;
• Right = X + Width;
• Bottom = Y + Height;
• Width = Size.Width;
• Height = Size.Height.
Необходимо отметить, что реальные координаты прямоугольника, использующиеся при рисовании компонента – (Left, Top), (Right – 1, Bottom – 1), т.е. не включают в себя правую и нижнюю границу.
Для преобразования координат из экранной системы в клиентскую и обратно используются следующие методы класса Control:
Point PointToClient(Point p);
Point PointToScreen(Point p);
Rectangle RectangleToClient(Rectangle r);
Rectangle RectangleToScreen(Rectangle r);
Следовательно, преобразовать координаты точки или прямоугольника из клиентской системы компонента c1 в клиентскую систему компонента c2 можно следующим образом:
с2.PointToClient(с1.PointToScreen(<точка>));
с2.RectangleToClient(с1.RectangleToScreen(<прямоугольник>));
Итак, границы компонента задаются во внешней системе координат, а координаты его клиентской области – в клиентской системе координат компонента. Для этого используются следующие свойства класса Control:
Rectangle Bounds { get; set; }
Point Location { get; set; }
int Left { get; set; }
int Top { get; set; }
int Right { get; }
int Bottom { get; }
Size Size { get; set; }
int Width { get; set; }
int Height { get; set; }
Rectangle ClientRectangle { get; }
Size ClientSize { get; set; }
Свойство Bounds задает границы компонента, ClientRectangle – прямоугольник клиентской области, а ClientSize – ее размеры. Остальные свойства имеют тот же смысл, что и аналогичные свойства структуры Rectangle (рис. 3.7). Таким образом, Bounds есть прямоугольник, образованный точками с координатами (Left, Top) и (Right, Bottom), а ClientRectangle – точками (0, 0) и (ClientSize.Width, ClientSize.Height).
Рис. 3.7 – Границы и клиентская область компонента
Не у всех компонентов размеры клиентской области отличаются от размеров всего компонента. Некоторые компоненты, даже обладая рамками, бордюрами и т.п., рисуют их в клиентской области. Например, напишем в классе формы метод ShowCoords, выводящий в текстовое поле textBox1 прямоугольник внешних границ и клиентской области указанного компонента. Будем вызывать этот метод из конструктора формы, а также из обработчиков событий нажатием клавиши мыши на созданных ранее вкладке, панели и трех кнопках (рис. 3.6). Код метода:
void ShowCoords(object obj)
{
Control ctrl = obj as Control;
if (ctrl != null)
{
textBox1.Text = String.Format("Bounds = {0}\r\nClientRectangle = {1}", ctrl.Bounds, ctrl.ClientRectangle);
}
}
При запуске программы отобразятся параметры формы, а далее можно нажимать на другие компоненты, чтобы увидеть их параметры. Изучив работу программы, делаем вывод, что из имеющихся компонентов только форма и панель имеют неклиентскую (non-client) область.
Еще раз отметим, что Point, Size и Rectangle – это структуры. Поэтому, например, следующий код не имеет смысла, т.к. структура возвращается по значению, а не по ссылке:
control.Location.X = 0;
Если нужно изменить только одну координату компонента, лучше использовать свойства Left, Top, Width и Height. Если нужно изменить одновременно левую и верхнюю границы или ширину и высоту, используем свойства Location и Size:
control.Location = new Point(100, 100);
control.Size = new Size(100, 100);
Аналогично можно использовать свойство Bounds, однако есть более удобные методы класса Control:
void SetBounds(int x, int y, int width, int height);
void SetBounds(int x, int y, int width, int height, BoundsSpecified specified);
Вторая версия отличается тем, что позволяет указать, какие именно границы следует изменить.
3.3.1.2 Выравнивание компонента
Любой визуальный компонент имеет следующие дополнительные настройки, влияющие на его отображение относительно других компонентов:
1) Глубина (z-order). Все компоненты, добавляемые на родительский компонент, заносятся в начало списка дочерних компонентов
Control.ControlCollection Controls { get; }
При рисовании компоненты обрабатываются в том порядке, в котором они размещены в этом списке, начиная с его конца, поэтому компоненты, добавленные позже, рисуются поверх компонентов, добавленных ранее. Для изменения положения компонента в списке z-order используются следующие методы класса Control:
void BringToFront();
void SendToBack();
Метод BringToFront помещает компонент в начало списка z-order, а SendToBack – в конец.
В предыдущем примере кнопки button1 или button2 при щелчке по ним перемещались на передний план. Это происходит как раз потому, что в обработчике соответствующего события использован код
(sender as Button).BringToFront();
Также допишем в метод ShowCoords следующий код:
textBox1.AppendText("\r\n\r\nКомпоненты:\r\n");
for (int i = 0; i < tabPage1.Controls.Count; i++)
{
textBox1.AppendText(tabPage1.Controls[i].Name + "\r\n");
}
Здесь в текстовое поле добавляются имена всех дочерних компонентов вкладки tabPage1. Можно видеть, что кнопка button1 или button2 при нажатии действительно перемещается в начало списка Controls. А при нажатии на кнопку button3 она либо добавляется в этот список (если ее родителем становится tabPage1), либо убирается из него (когда возвращается на panel1).
2) Закрепление. Задает позицию и способ закрепления элемента управления в виде константы перечисления System.Windows.Forms.DockStyle (табл. 3.1):
DockStyle Dock { get; set; }
Таблица 3.1 – Элементы перечисления DockStyle
Константа
Описание
None
Элемент управления не закреплен (по умолчанию для большинства компонентов)
Left
Элемент закреплен у левой границы родительского компонента. Его ширина не изменяется, а высота равна высоте свободной области родительского компонента
Top
Элемент закреплен у верхней границы родительского компонента. Его высота не изменяется, а ширина равна ширине свободной области родительского компонента
Right
Элемент закреплен у правой границы родительского компонента. Его ширина не изменяется, а высота равна высоте свободной области родительского компонента
Bottom
Элемент закреплен у нижней границы родительского компонента. Его высота не изменяется, а ширина равна ширине свободной области родительского компонента
Fill
Элемент занимает все доступное пространство родительского компонента
При этом учитывается порядок добавления дочерних компонентов. Сначала размещаются компоненты, расположенные в конце списка Controls. Например, создадим на второй вкладке tabPage2 панель panel2, а на ней три кнопки – button4, button5 и button6 (рис. 3.8). Для первой установим заголовок Left и зададим закрепление по левой границе. При этом свободной остается область справа от этой кнопки, поэтому ширина следующей кнопки, которую мы закрепим у верхней границы (Top), будет равна ширине свободной области. И, наконец, для третьей кнопки установим закрепление на всем доступном пространстве (Fill), она займет всю оставшуюся свободной область.
\\
Рис. 3.8 – Выравнивание компонентов с использованием закрепления
Далее для кнопки button5 установим обработчик на нажатие:
button4.Dock = button4.Dock == DockStyle.Left ? DockStyle.Right :
DockStyle.Left;
button4.Text = button4.Dock.ToString();
Теперь при нажатии на нее она будет менять закрепление с левой границы на правую, и наоборот. Аналогично, для button6
button5.Dock = button5.Dock == DockStyle.Top ? DockStyle.Bottom :
DockStyle.Top;
button5.Text = button5.Dock.ToString();
Теперь при нажатии на нее она будет менять закрепление с верхней границы на нижнюю, и наоборот. Также меняется текст на кнопках соответственно виду закрепления.
Для элемента управления tabControl1 установлено закрепление Fill, поэтому при изменении размеров формы он всегда занимает на ней все доступное пространство.
3) Якоря. Определяют способ изменения размеров элемента управления при изменении размеров его родительского компонента. Задаются свойством
AnchorStyles Anchor { get; set; }
Перечисление System.Windows.Forms.AnchorStyles представляет собой битовую комбинацию констант, перечисленных в табл. 3.2.
Таблица 3.2 – Элементы перечисления AnchorStyles
Константа
Описание
None
Элемент управления не привязан к границам родительского компонента
Left
Расстояние между левой границей элемента управления и левой границей родительского компонента неизменно
Top
Расстояние между верхней границей элемента управления и верхней границей родительского компонента неизменно
Right
Расстояние между правой границей элемента управления и правой границей родительского компонента неизменно
Bottom
Расстояние между нижней границей элемента управления и нижней границей родительского компонента неизменно
По умолчанию установлена привязка к левой и верхней границе родительского компонента.
Добавим к элементу управления tabControl1 третью вкладку tabPage3, на нее – панель panel3. На панели разместим четыре элемента управления типа CheckBox – checkBox1, checkBox2, checkBox3 и checkBox4 (рис. 3.9).
Рис. 3.9 – Выравнивание компонентов с использованием якорей
Далее напишем единый обработчик события на переключение состояния всех этих компонентов:
AnchorStyles anchor = new AnchorStyles();
if (checkBox1.Checked) anchor |= AnchorStyles.Left;
if (checkBox2.Checked) anchor |= AnchorStyles.Top;
if (checkBox3.Checked) anchor |= AnchorStyles.Right;
if (checkBox4.Checked) anchor |= AnchorStyles.Bottom;
panel3.Anchor = anchor;
Таким образом, переключая состояние компонентов CheckBox, мы добавляем или убираем соответствующий якорь. Изменяя после этого размеры формы, видим, что не изменяется расстояние только между теми границами панели panel3 и соответствующими границами вкладки tabPage3, для которых установлены якоря.
Также для текстового поля textBox1 на вкладке tabPage1 и панели panel2 на вкладке tabPage2 установлены якоря для всех границ. Поэтому они меняют свои размеры при изменении размеров формы.
3.3.1.3 Отображение компонента
Визуальные компоненты, наследующиеся от класса Control, имеют следующие методы и свойства для настройки их внешнего вида:
void Hide();
void Show();
bool Visible { get; set; }
Color BackColor { get; set; }
static Color DefaultBackColor { get; }
Color ForeColor { get; set; }
static Color DefaultForeColor { get; }
Font Font { get; set; }
static Font DefaultFont { get; }
string Text { get; set; }
Метод Hide делает компонент невидимым (аналог Visible = false), метод Show – видимым (аналог Visible = true). По умолчанию Visible = true. Свойство BackColor задает цвет фона компонента, значение по умолчанию – DefaultBackColor. Свойство ForeColor задает основной цвет компонента, значение по умолчанию – DefaultForeColor. Свойство Font определяет, каким шрифтом будет отображаться текст в пределах компонента, параметры шрифта по умолчанию содержит свойство DefaultFont. Свойство Text задает текст, ассоциированный с элементом управления.
Цвет инкапсулирован в структуре System.Drawing.Color (табл. 3.3).
Таблица 3.3 – Основные члены структуры Color
Член
Описание
Методы
static Color FromArgb(int argb)
Создает цвет из указанных значений компонентов ARGB (1)
static Color FromArgb(int alpha, Color baseColor)
Создает цвет из базового цвета с новым значением A (0…255)
static Color FromArgb(int red, int green, int blue)
Создает цвет из указанных значений RGB (0…255), при этом A = 255
static Color FromArgb(int alpha, int red, int green, int blue)
Создает цвет из указанных значений компонентов ARGB (0…255)
static Color FromKnownColor(
KnownColor color)
Создает цвет из стандартной цветовой константы (2)
static Color FromName(string name)
Создает цвет по его имени. Допустимы имена констант из перечисления KnownColor
int ToArgb()
Возвращает 32-разрядное значение ARGB
KnownColor ToKnownColor()
Возвращает значение KnownColor
Операторы
static bool operator ==(Color left, Color right)
Проверяет эквивалентность двух цветов
static bool operator !=(Color left, Color right)
Проверяет различие двух цветов
Поля
static readonly Color Empty
Константа, соответствующая не заданному цвету
Свойства
byte A { get; }
Получает значение составляющей альфа
byte B { get; }
Получает значение синего компонента
byte G { get; }
Получает значение зеленого компонента
bool IsKnownColor { get; }
Проверяет, является ли цвет стандартным
bool IsNamedColor { get; }
Проверяет, является ли цвет именованным
bool IsSystemColor { get; }
Определяет, принадлежит ли цвет системной палитре Windows
string Name { get; }
Возвращает имя данного цвета
byte R { get; }
Получает значение красного компонента
Примечания:
(1) Во внутреннем представлении, цвет является 32-битным целым числом в формате ARGB (alpha – альфа-канал или прозрачность, red – красная составляющая, green – зеленая составляющая, blue – синяя составляющая). В шестнадцатеричном виде это число можно представить следующим образом:
0xAARRGGBB,
где AA, RR, GG и BB – байт, содержащий значение соответствующей компоненты (значение от 0x00 до 0xFF). Прозрачность используется не во всех компонентах.
(2) Перечисление System.Drawing.KnownColor содержит две группы констант. Первая группа – константы для самых распространенных цветов (Red, Orange, Yellow, Green, Blue и т.д.). Их очень много, полный перечень можно посмотреть в справочной системе MSDN. Вторая группа – константы цветовой палитры Windows. Например, на рисунках выше все компоненты имеют серый цвет. Но если мы посмотрим в редактор свойств, то увидим, что свойство BackColor для этих компонентов содержит не константу серого цвета (Gray, Silver, LightGray и т.п.), а константу «Control», соответствующую цвету поверхности рельефного объекта. Если мы пишем приложение, использующее стандартный интерфейс Windows, то использование серого цвета (например, Silver) для кнопки было бы неправильным решением. Если это приложение запустить на компьютере, где установлена другая тема оформления Windows, например с бирюзовыми оттенками, то такая кнопка все равно останется серой, выбиваясь из общей картины. Использование же константы Control гарантирует, что какому бы реальному значению ARGB эта константа ни соответствовала, именно это значение будет использовано. В примерах выше она приблизительно соответствовала серому цвету, на другом компьютере может соответствовать любому другому цвету в зависимости от предпочтений пользователя. Чтобы узнать этот цвет, зайдем в диалог свойств экрана, выберем вкладку «Оформление» и нажмем кнопку «Дополнительно» (для Windows XP). Выбрав в появившемся диалоге элемент «Рельефные объекты», увидим, какой цвет ему соответствует (рис. 3.10).
Рис. 3.10 – Оформление элементов управления Windows
Список остальных констант системной палитры Windows также можно посмотреть в справочной системе MSDN.
Также структура Color содержит множество статических свойств типа
static Color Aqua { get; }
Каждое такое поле дает экземпляр структуры с предопределенным цветом. Поэтому следующие записи эквивалентны:
ForeColor = Color.Aqua;
ForeColor = Color.FromKnownColor(KnownColor.Aqua);
Предусмотрены поля только для обычных цветов. Экземпляры же структур с предопределенными системными цветами (палитрой Windows) инкапсулированы в классе System.Drawing.SystemColors. Он содержит ряд статических полей типа
static Color Control { get; }
Они соответствуют цветам, перечисленным в KnownColor с аналогичным именем. Поэтому следующие записи эквивалентны:
BackColor = SystemColors.GradientActiveCaption;
BackColor = Color.FromKnownColor(KnownColor.GradientActiveCaption);
Параметры шрифта (имя начертания, размер, стиль и т.д.) инкапсулированы в классе System.Drawing.Font (табл. 3.4).
Таблица 3.4 – Основные члены класса Font
Член
Описание
Конструкторы
Font(...)
Набор конструкторов для создания нового шрифта
Методы
object Clone()
Реализация интерфейса ICloneable, создает копию экземпляра шрифта
float GetHeight(...)
Ряд методов, возвращающих высоту шрифта в точках
Свойства
bool Bold { get; }
Возвращает значение, определяющее, является ли шрифт полужирным
int Height { get; }
Возвращает значение междустрочного интервала данного шрифта в точках (округленное значение, возвращаемое методом GetHeight)
bool Italic { get; }
Возвращает значение, определяющее, является ли шрифт наклонным
string Name { get; }
Возвращает имя начертания шрифта
float Size { get; }
Возвращает размер шрифта в единицах, указанных свойством Unit
float SizeInPoints { get; }
Возвращает размер шрифта в пунктах
bool Strikeout { get; }
Возвращает значение, указывающее, является ли шрифт зачеркнутым
FontStyle Style { get; }
Возвращает сведения о стиле шрифта (1)
bool Underline { get; }
Возвращает значение, указывающее, является ли шрифт подчеркнутым
GraphicsUnit Unit { get; }
Возвращает единицу измерения шрифта(2)
Примечания:
(1) Перечисление System.Drawing.FontStyle содержит константы Regular (обычный шрифт), Bold (полужирный), Italic (наклонный), Underline (подчеркнутый), Strikeout (зачеркнутый).
(2) Перечисление System.Drawing.GraphicsUnit содержит константы Pixel (единица измерения – точка), Point (пункт, 1/72 дюйма), Inch (дюйм) и др.
3.3.1.4 Управление пользовательским вводом
По умолчанию, только один элемент управления может получать сообщения пользователя, поступающие от мыши и клавиатуры.
Сообщения от клавиатуры поступают тому элементу управления, который обладает фокусом (focus). Фокус – это концептуальное понятие в построении графического пользовательского интерфейса, означающее наличие у определенного элемента управления исключительного права принимать клавиатурный ввод. Если элемент управления имеет поле для ввода данных, то фокус отображается в виде курсора ввода (вертикальная мигающая линия). Если поля для ввода нет, то фокус отображается пунктирной рамкой, цветовым выделением или другим способом (хотя элементы управления WF делают это не всегда). Элемент управления, обладающий фокусом, называется активным.
Рис. 3.11 – Активные и неактивные элементы управления
На рис. 3.11 слева изображена неактивная форма, все компоненты которой также являются неактивными. Справа – активная форма с активными компонентами (это коллаж, т.к. только один элемент управления может быть активным).
Все элементы управления при создании заносятся в список табуляции. Для передачи фокуса следующему по списку элементу управления необходимо нажать клавишу Tab, предыдущему – Shift+Tab. Также можно просто выбрать требуемый элемент мышью или нажать ассоциированную с элементом управления клавишу. Чтобы задать такую клавишу, перед одним из символов в названии элемента управления (если оно есть – например, для компонентов Button, CheckBox и т.п.) необходимо поставить знак «&». Тогда в конструкторе формы этот символ будет подчеркнут, а соответствующая ему клавиша ассоциирована с элементом управления. При нажатии этой клавиши фокус будет перемещен на элемент управления и сгенерировано событие, переключающее состояние компонента. Для подчеркивания горячих клавиш в режиме выполнения программы необходимо нажать клавишу Alt.
Сообщения от мыши поступают тому элементу управления, который осуществил захват мыши (mouse capture), или, если мышь не захвачена, – тому элементу управления, на котором находится указатель мыши.
Методы и свойства класса Control для управления пользовательским вводом:
bool Focus();
void Select();
Control GetNextControl(Control ctl, bool forward);
static bool IsKeyLocked(Keys keyVal);
static bool IsMnemonic(char charCode, string text);
bool CanFocus { get; }
bool CanSelect { get; }
bool Capture { get; set; }
bool ContainsFocus { get; }
bool Enabled { get; set; }
bool Focused { get; }
static Keys ModifierKeys { get; }
static MouseButtons MouseButtons { get; }
static Point MousePosition { get; }
int TabIndex { get; set; }
bool TabStop { get; set; }
Методы Focus и Select перемещают фокус на элемент управления (если это возможно). Метод GetNextControl возвращает следующий или предыдущий элемент управления в списке табуляции. Метод IsKeyLocked проверяет, нажаты ли клавиши Caps Lock, Num Lock и Scroll Lock. Перечисление System.Windows.Forms.Keys содержит константы для всех клавиш на клавиатуре, но в данной функции поддерживается проверка только трех указанных клавиш (константы CapsLock, NumLock и Scroll). Метод IsMnemonic проверяет, является ли символ кодом ассоциированной с элементом управления (имеющим указанный текст) клавиши. Свойства CanFocus и CanSelect проверяют, может ли элемент управления иметь фокус. Свойство Capture позволяет управлять захватом мыши. Свойство ContainsFocus проверяет, обладает ли в настоящий момент элемент управления или его дочерний компонент фокусом. Свойство Enabled определяет, может ли элемент управления отвечать на действия пользователя. Запрещенный компонент не может иметь фокус и отображается специфическим образом (обычно шрифт становится серым и т.п.). Свойство Focused определяет, находится ли фокус на элементе управления. Свойство ModifierKeys показывает, какие из клавиш Ctrl, Shift и Alt нажаты в настоящий момент (None или комбинация констант Control, Shift и Alt перечисления Keys). Свойство MouseButtons показывает, какие нажаты клавиши мыши (константа None, Left, Right и Middle перечисления System.Windows.Forms.MouseButtons или их комбинация). Свойство MousePosition возвращает позицию указателя мыши в экранных координатах. Свойство TabIndex задает позицию элемента управления в списке табуляции. Свойство TabStop определяет, будет ли элемент управления получать фокус при нажатии клавиш Tab или Shift+Tab.
События о действиях пользователя, получаемые элементами управления (наследуемыми от класса Control), и некоторые другие события:
event EventHandler Click;
event EventHandler DoubleClick;
event EventHandler Enter;
event EventHandler GotFocus;
event KeyPressEventHandler KeyPress;
event KeyEventHandler KeyDown;
event KeyEventHandler KeyUp;
event EventHandler Leave;
event EventHandler LostFocus;
event EventHandler Move;
event PaintEventHandler Paint;
event EventHandler Resize;
event EventHandler MouseCaptureChanged;
event MouseEventHandler MouseClick;
event MouseEventHandler MouseDoubleClick;
event MouseEventHandler MouseDown;
event EventHandler MouseEnter;
event EventHandler MouseHover;
event EventHandler MouseLeave;
event MouseEventHandler MouseMove;
event MouseEventHandler MouseUp;
event MouseEventHandler MouseWheel;
Событие Click генерируется при щелчке мышью по элементу управления, DoubleClick – при двойном щелчке, Enter и GetFocus – при получении фокуса элементом управления, KeyPress – при нажатии клавиши для активного элемента управления. События KeyDown и KeyUp позволяют отследить момент нажатия и отпускания клавиши, а также получить больше сведений о комбинации клавиш, чем с помощью события KeyPress. События Leave и LostFocus генерируется, когда фокус ввода покидает элемент управления, Move при перемещении, Paint при перерисовке, Resize при изменении размеров. События для мыши (в порядке перечисления): при потере или получении захвата мыши, щелчке мышью, двойном щелчке, нажатии клавиши, заходе в область элемента управления, задержке и выходе из этой области, перемещении по ней, отпускании клавиши, движении колеса мыши.
Для демонстрации условий и порядка получения событий элементом управления создадим в элементе TabControl четвертую вкладку tabPage4. На ней поместим кнопку button7, получающую некоторые из перечисленных сообщений (не все они доступны для кнопок), компонент ListBox для отображения информации о поступивших событиях и дополнительную кнопку для очистки информации. При получении кнопкой различных сообщений будем вызывать метод
void AddEventInfo(string str, params object[] info)
{
int count = listBox1.Items.Count – 1;
string prev = count >= 0 ? listBox1.Items[count].ToString() : null;
if (count >= 0 && prev.StartsWith(str))
{
str += String.Format(" x{0}", ++Counter);
}
else
{
listBox1.Items.Add("");
count++;
Counter = 0;
}
if (info.Length > 0)
{
str += " [";
for (int i = 0; i < info.Length; i++)
{
str += String.Format("{0}{1}", i == 0 ? "" : "; ", info[i].ToString());
}
str += "]";
}
listBox1.Items[count] = str;
listBox1.SelectedIndex = count;
}
В первом параметре передается наименование сообщения, во втором – список дополнительных аргументов, если они есть. Если несколько одинаковых сообщений приходят подряд, то отображается значение счетчика. Теперь проведение различных манипуляций с клавиатурой, когда кнопка активна, или с мышью, когда ее указатель находится над кнопкой или захвачен ею, будет приводить к отображению информации о поступивших событиях. Захват мыши осуществляется в том случае, если мы нажали какую-либо клавишу мыши и не отпустили ее. В этом случае, даже если указатель мыши переместить за пределы кнопки, она все равно будет получать соответствующие сообщения.
3.3.1.5 Стандартные элементы управления
Мы рассмотрели далеко не все события, свойства и методы, общие для всех элементов управления (их несколько десятков), а только основные. В табл. 3.5 рассмотрены наиболее часто используемые элементы управления и некоторые их специфические члены.
Таблица 3.5 – Некоторые стандартные элементы управления
Название
Описание
Кнопка
Обычная кнопка, которая может содержать текст и/или изображение. Текст задается свойством Text, изображение – свойствами Image или ImageList (экземпляры классов Image или ImageList, о которых ниже). Также можно задать выравнивание текста (TextAlign) и изображения (ImageAlign). Может иметь плоские границы, которые становятся рельефными при наведении указателя мыши (FlatStyle и FlatAppearance). При нажатии генерирует событие Click
Переключатель
По умолчанию может находиться в двух состояниях (свойство Checked – включен или выключен). Свойства CheckAlign и TextAlign определяют взаимное расположение переключателя и текста. Также может иметь плоские границы и изображение. Свойство ThreeState позволяет находиться в трех состояниях (свойство CheckState – включен, выключен, не определено). При переключении генерирует событие CheckedChanged (при изменении свойства Check) или CheckedStateChanged (при изменении свойства CheckState)
Поле ввода
Позволяет вводить текст (в т.ч. с автоматическим завершением ввода – см. свойства, начинающиеся со слов AutoComplete). Текст может быть однострочным или многострочным (определяется свойством Multiline). Сам текст содержится в свойствах Text (тип string, при многострочном содержимом строки отделяются друг от друга символами «\r\n») и Lines (массив строк). Свойство ReadOnly переключает в режим «только для чтения». Свойство ScrollBars позволяет определить, будут ли видны полосы прокрутки в многострочном режиме. Свойство TextAlign – выравнивание текста. Свойство WordWrap задает автоматический перенос слов в многострочном режиме. Свойство AcceptTab позволяет вставлять в текст табуляцию, а не переходить при нажатии Tab к следующему элементу списка табуляции. Свойство AcceptReturn позволяет вставлять в текст переходы на новую строку при нажатии клавиши Enter, а не активировать кнопку по умолчанию (см. в разделе «Диалоги»). Если эти возможности отключены, следует использовать комбинации клавиш Ctrl+Tab и Ctrl+Enter. Доступны операции для работы с буфером обмена. При изменении текста генерируется событие TextChanged
Список выбора
Список, из которого можно выбрать один элемент. Обычно элементы представлены строками, но это могут быть произвольные объекты (картинки и т.п.). Элементы задаются коллекцией Items, текущий элемент – свойством SelectedIndex или SelectedIndices (если выбрано несколько элементов). Метод выделения задается свойством SelectionMode (запрещено, один элемент, последовательность элементов, произвольные элементы). Свойство Sorted позволяет включить сортировку элементов. Также можно задавать вывод элементов в нескольких колонках, форматирование вывода и т.д. При изменении выделения генерируется событие SelectedIndexChanged
Список
переключателей
Комбинация списка выбора и переключателя. Каждый элемент списка имеет переключатель, позволяющий выбрать этот элемент или исключить его из выбора. Узнать положение переключателей для каждого элемента позволяет коллекция CheckedIndices
Выпадающий список
Комбинация поля ввода и списка выбора. Текст можно вводить либо выбирать из выпадающего списка. Свойство DropDownStyle позволяет изменить стиль компонента – настроить его так, чтобы список отображался всегда или чтобы текст нельзя было редактировать
Метка
Компонент предназначен для вывода обычных текстовых меток на форму (свойство Text) с возможностью добавления картинки. Если назначена клавиша быстрого доступа, то свойство UseMnemonic позволяет при ее активации передать фокус следующему элементу управления в списке табуляции (т.к. сама метка не может обладать фокусом). Это позволяет передавать фокус элементам управления, не имеющим возможности задать клавишу быстрого доступа (TextBox, ComboBox и т.п.)
Исключающий переключатель
В группе исключающих переключателей может быть выбран только один из них. В группу объединяются все переключатели, расположенные в одном родительском компоненте, поэтому при необходимости организовать несколько таких групп, каждая из них помещается в свой контейнер. Набор свойств практически такой же, как у обычного переключателя, но может находиться только в двух состояниях – элемент выбран или не выбран (свойство Checked)
Счетчик
Представляет собой текстовое поле, содержащее числовое значение, и две кнопки для уменьшения и увеличения этого значения. Соответственно, имеет много общих свойств с простым полем ввода. Свойство DecimalPlaces определяет количество знаков после десятичной точки, Hexadecimal позволяет отображать значение в шестнадцатеричном виде, ThousandsSeparator определяет, должны ли разделяться группы разрядов. Свойство Increment определяет шаг изменения значения, Minimum и Maximum – границы значений, Value – текущее значение. При изменении значения генерируется событие ValueChanged
Данный обзор не претендует на полноту, дополнительные сведения можно получить в справочной системе MSDN. Некоторые другие элементы управления будут рассмотрены в других главах учебника.
3.3.1.6 Контейнеры
К контейнерам относятся компоненты, которые могут быть родительскими по отношению к другим элементам управления. Они используются для группировки элементов управления на форме. В табл. 3.6 приведены сведения о некоторых компонентах-контейнерах.
Таблица 3.6 – Некоторые компоненты-контейнеры
Название
Описание
Область
группировки
Контейнер, имеющий рамку по краям своей области и заголовок, отображаемый в верхней части рамки. Заголовок задается свойством Text
Панель
Контейнер, который может иметь рамку (определяется свойством BorderStyle) и полосы прокрутки, если дочерние компоненты не помещаются в клиентской области (свойство AutoScroll и др.)
Разделитель
Контейнер, разделенный на две вертикальные или горизонтальные панели (в зависимости от значения свойства Orientation). Пользователь может менять относительные размеры панелей. Для отображения рамки используется свойство BorderStyle
Набор вкладок
Контейнер, имеющий произвольное количество вкладок – экземпляров класса TabPage. Коллекция вкладок представлена свойством TabPages. Каждая вкладка может иметь заголовок, картинку, рамку и т.д. Положение вкладок задается свойством Alignment. Свойство Multiline позволяет располагать вкладки на нескольких строках. Текущая вкладка задается свойством SelectedIndex или SelectedTab
Форма тоже является контейнером, но добавляется в проект не через панель элементов. Подробнее о формах поговорим в пункте «Диалоги».
3.3.2 Диалоговые окна
Диалоговые окна, или просто диалоги в терминах визуального программирования, – это специальный элемент пользовательского интерфейса, представляющий собой окно, служащее для обмена информацией с пользователем и ожидающее от него ответа.
Диалоговые окна подразделяются на модальные и немодальные, в зависимости от того, блокируют ли они возможность взаимодействия пользователя с приложением (или системой в целом) до тех пор, пока не получат от него ответ. Немодальные диалоги позволяют пользователю отложить ввод ответа и сделать активными другие окна приложения. Пример немодального диалога – диалог поиска и замены в Visual Studio, Word и др. программах. Вызвав его (например, комбинацией клавиш Ctrl+F), мы можем продолжать работать с документом или кодом, не закрывая сам диалог. Модальный диалог не позволяет активировать другие окна приложения (если он модальный для приложения) или даже всей системы (если он модальный для системы), пока от пользователя не будет получен ответ. Примеры модальных для приложения диалогов это, например, диалоги «Настройка» и «Параметры» Visual Studio (доступные в меню «Сервис»). Пока эти диалоги активны, мы не можем активировать другие окна Visual Studio.
3.3.2.1 Окна сообщений
Окно сообщения является простейшим случаем диалогового окна. Оно показывает пользователю сообщение, снабженное стандартной графической миниатюрой и набором кнопок, и ожидает от него выбора дальнейшего варианта действий.
В языке C# функциональность окон сообщений инкапсулирована в классе MessageBox, а точнее – его методе Show. У него много реализаций, рассмотрим некоторые из них:
static DialogResult Show(string text);
static DialogResult Show(string text, string caption);
static DialogResult Show(string text, string caption, MessageBoxButtons buttons);
static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon);
Параметр text задает текст сообщения. Параметр caption – заголовок окна сообщения. Параметр buttons – набор кнопок, это одна из констант перечисления System.Windows.Forms.MessageBoxButtons:
• OK – кнопка «ОК»;
• OKCancel – кнопки «ОК» и «Отмена»;
• AbortRetryIgnore – кнопки «Прервать», «Повторить» и «Пропустить»;
• YesNoCancel – кнопки «Да», «Нет» и «Отмена»;
• YesNo – кнопки «Да» и «Нет»;
• RetryCancel – кнопки «Повторить» и «Отмена».
Если кнопки не заданы, отображается одна кнопка «ОК». Если задана кнопка «ОК» или «Отмена», то будет доступна кнопка закрытия в строке заголовка диалога. Параметр icon – графическая миниатюра, это одна из констант перечисления System.Windows.Forms.MessageBoxIcon:
• None – миниатюра отсутствует;
• Hand, Stop или Error – белый крест на фоне красного круга;
• Question – вопросительный знак в баллоне сообщения;
• Exclamation, Warning – восклицательный знак в желтом треугольнике;
• Information, Asterisk – знак информации (i) в баллоне сообщения;
Если миниатюра не задана, то отображаться не будет. Возвращаемый после закрытия диалога результат – одна из констант перечисления System.Windows.Forms.DialogResult:
• None – пока никакая кнопка не нажата, диалог продолжает свою работу. Данная константа не может быть результатом работы метода Show, а используется при программировании диалоговых окон пользователя;
• OK – была нажата кнопка «ОК»;
• Cancel – была нажата кнопка «Отмена»;
• Abort – была нажата кнопка «Прервать»;
• Retry – была нажата кнопка «Повторить»;
• Ignore – была нажата кнопка «Пропустить»;
• Yes – была нажата кнопка «Да»;
• No – была нажата кнопка «Нет».
Также результат OK может быть возвращен при закрытии диалога кнопкой закрытия, если единственной кнопкой в диалоге была «ОК». Результат Cancel может быть возвращен при закрытии диалога, если была задана кнопка «Отмена».
Добавим к компоненту TabControl пятую вкладку tabPage5, на ней поместим groupBox1 и компоненты для указания текста сообщения (textBox2), заголовка окна сообщения (textBox3), набора кнопок (comboBox1) и графической миниатюры (comboBox2). При нажатии на кнопку button9 будем выполнять следующий код:
MessageBoxButtons btns = (MessageBoxButtons)Enum.Parse(typeof(MessageBoxButtons), comboBox1.Text);
MessageBoxIcon icon = (MessageBoxIcon)Enum.Parse(typeof(MessageBoxIcon), comboBox2.Text);
DialogResult res = MessageBox.Show(textBox2.Text, textBox3.Text, btns, icon);
label5.Text = res.ToString();
Теперь можно вызвать окно сообщения с любыми параметрами. Возвращаемый результат отображается в метке label5.
3.3.2.2 Стандартные диалоги
Окна сообщений могут использоваться только для отображения текстового сообщения. Если же диалог должен выполнить более сложные действия, например запросить имя файла, используются специальные компоненты WF – стандартные диалоги. Большая их часть находится на вкладке «Диалоговые окна» панели элементов.
Все стандартные диалоги являются потомками класса CommonDialog. От него они наследуют, в частности, методы
DialogResult ShowDialog();
void Reset();
Первый из них отображает диалог пользователю и ждет его завершения. После этого возвращает программе результат. О перечислении DialogResult мы уже говорили выше. Обычно стандартный диалог имеет всего две кнопки – «ОК» и «Отмена», поэтому результатом вызова данного метода может быть константа OK или Cancel. Второй восстанавливает параметры диалога по умолчанию.
В табл. 3.7 рассмотрены наиболее часто используемые стандартные диалоги.
Таблица 3.7 – Некоторые стандартные диалоги
Название
Описание
Диалог выбора цвета
Стандартный диалог выбора цвета (рис. 3.12). Свойство FullOpen определяет, раскрыт диалог полностью (на рис. справа) или нет (слева), AllowFullOpen – указывает, можно ли раскрывать диалог. Свойство Color задает текущий цвет, CustomColors – массив из 16 дополнительных цветов. Его можно заполнить программно или нажимая кнопку «Добавить в набор» диалога
Диалог выбора папки
Стандартный диалог выбора папки (рис. 3.13). Свойство Description определяет текстовое описание, отображающееся в верхней части диалога, RootFolder – корневой элемент дерева папок (одна из констант перечисления Environment.SpecialFolder), SelectedPath – выделенную папку. Свойство ShowNewFolderButton определяет, будет ли в диалоге отображена кнопка «Создать папку»
Диалог выбора шрифта
Стандартный диалог выбора шрифта (рис. 3.14). Свойство Color задает цвет шрифта, Font – выбранный шрифт, ShowApply позволяет отобразить кнопку «Применить». При нажатии на эту кнопку диалог не закрывается, а генерирует событие Apply. Свойство ShowColor определяет, можно ли в диалоге настроить цвет шрифта
Диалог открытия файла
Диалог сохранения файла
Стандартные диалоги открытия (рис. 3.15) и сохранения файла (выглядит так же, но вместо кнопки «Открыть» имеется кнопка «Сохранить»). Наследуются от общего класса FileDialog (потомка CommonDialog), поэтому имеют ряд общих свойств. Свойство AddExtension определяет, будет ли к имени файла добавлено расширение, если оно не указано, CheckFileExists и CheckPathExists – будет ли выполняться проверка существования файла и папки соответственно. Свойство DefaultExt задает расширение по умолчанию, FileName – имя выбранного файла, FileNames – массив имен выбранных файлов (если их несколько), Filter – фильтр типов отображаемых файлов, FilterIndex – номер текущего фильтра (начиная с 1), InitialDirectory – начальную папку, Title – заголовок диалога. Диалог открытия файла дополнительно содержит свойство Multiselect, позволяющее выбирать несколько файлов сразу, а диалог сохранения файла – свойство CreatePrompt, определяющее, будет ли происходить запрос на создание файла, если файл с указанным именем не существует, и OverwritePrompt – для вывода предупреждения о перезаписи, если файл уже существует
Диалог выбора параметров печати
Стандартный диалог выбора параметров печати. Свойство Document задает документ для печати, PrinterSettings – параметры принтера, UseEXDialog – определяет, будет ли использован стиль Windows XP или старый стиль
Ниже приведены изображения стандартных диалоговых окон:
• Диалога выбора цвета в сокращенном и полном виде (рис. 3.12);
• Диалог выбора папки с кнопкой создания новой папки (рис. 3.13);
• Диалог выбора шрифта с возможностью указания цвета (рис. 3.14);
• Диалог открытия файла с фильтром (рис. 3.15). Фильтр типов файлов в диалогах открытия и сохранения задается в виде
<описание1>|<список_расширений1>[|<описание2>|<список_расширений2>...]
Расширения в списке разделяются точкой с запятой. Например:
Форматированный текст RTF|*.rtf|Текстовые файлы|*.txt|Другие файлы|*.*
Изображения (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|Все файлы (*.*)|*.*
При активации фильтра в диалоге будут отображены только файлы с указанными расширениями.
Рис. 3.12 – Стандартный диалог выбора цвета
Рис. 3.13 – Стандартный диалог выбора папки
Рис. 3.14 – Стандартный диалог выбора шрифта
Рис. 3.15 – Стандартный диалог открытия файла
На вкладке tabPage5 поместим компонент groupBox2, richTextBox1 (о нем ниже; отличается от обычного TextBox тем, что может отображать текст в формате RTF), а также две кнопки – button10 для изменения цвета фона и button11 открытия нового файла. Также добавим на форму диалог выбора цвета colorDialog1 и диалог открытия файла openFileDialog1. Заметим, что они не отображаются на самой форме, а размещаются в специальном контейнере в нижней части конструктора формы. В этот контейнер помещаются все невизуальные компоненты. Диалоги также не являются визуальными компонентами – сам по себе диалог не имеет видимого представления и лишь содержит набор свойств. Только при вызове метода ShowDialog создается визуальное окно диалога, а указанные свойства применяются для настройки его внешнего вида.
В обработчике на нажатие button10 укажем
colorDialog1.Color = richTextBox1.BackColor;
if (colorDialog1.ShowDialog() == DialogResult.OK) richTextBox1.BackColor = colorDialog1.Color;
А в обработчике для button11
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
richTextBox1.LoadFile(openFileDialog1.FileName, openFileDialog1.FilterIndex == 1 ? RichTextBoxStreamType.RichText : (openFileDialog1.FilterIndex == 2 || openFileDialog1.FilterIndex == 4 ? RichTextBoxStreamType.PlainText : RichTextBoxStreamType.UnicodePlainText));
}
В каталоге с проектом лежат три файла – «RTF.rtf», «ASCII.txt» и «Unicode.txt» (в папке Texts). Открывая их и правильно указывая тип, можно просмотреть их содержимое. В тексте содержится ссылка. Чтобы при нажатии на нее происходило открытие указанной страницы в браузере, добавим для текстового поля обработчик события LinkClicked:
System.Diagnostics.Process.Start(e.LinkText);
3.3.2.3 Диалоги пользователя
Если возможностей окон сообщений и стандартных диалогов недостаточно, можно создать свой собственный диалог. Как уже отмечалось, диалоги – это обычные формы с некоторым набором компонентов для ввода или отображения информации и набором кнопок, позволяющим выбрать вариант дальнейших действий.
Функциональность форма приложения Windows Forms инкапсулирована в классе System.Windows.Forms.Form. Формы, как и некоторые другие элементы управления, рассмотренные нами ранее, относятся к контейнерам, т.к. они могут являться родителями для других компонентов. Однако процесс добавления в проект новых форм отличается от добавления обычных контейнеров. Для этого необходимо вызвать диалог добавления в проект нового элемента (пункт меню «Файл» → «Проект» → «Добавить новый элемент…», соответствующая кнопка на панели инструментов или сочетание клавиш Ctrl+Shift+A). В появившемся диалоге (рис. 3.16) выбрать категорию «Window Forms», элемент «Форма Windows Forms» и нажать кнопку «Добавить». Можно сразу задать имя исходного файла.
Для более быстрого добавления формы можно использовать выпадающий список у кнопки на панели инструментов и выбрать в нем пункт «Добавить форму Windows…» или пункт меню «Проект» → «Добавить форму Windows…». Как и для первой формы приложения, будут созданы три файла – «Form2.Designer.cs» с данными о компонентах и их свойствах, добавленных с помощью конструктора формы «Form2.cs» с пользовательским кодом, относящимся к форме и «Form2.resx» с ресурсами формы.
Рис. 3.16 – Добавление в проект новой формы
Если теперь запустить приложение, то форма на экране будет по-прежнему одна. По умолчанию создается только одна форма приложения – главная. Соответствующий код находится в файле «Program.cs»:
Application.Run(new Form1());
Здесь создается новый экземпляр формы Form1, и далее происходит запуск приложения. Если мы хотим сделать другую форму главной, то должны здесь вписать ее имя вместо Form1. Все прочие формы также нужно при необходимости создавать, используя оператор new. При закрытии главной формы работа приложения завершается. Добавим на первой форме вкладку tabPage6 и на ней кнопку button12 со следующим обработчиком на нажатие:
Form2 f = new Form2();
f.Show();
Теперь при каждом нажатии на эту кнопку будет создаваться новый экземпляр формы Form2, а затем отображаться на экране (по умолчанию формы невидимы). Причем для каждой формы будет отображаться отдельная кнопка в панели задач.
Перечислим некоторые полезные методы, свойства и события форм:
void Activate();
static Form ActiveForm { get; }
void AddOwnedForm(Form ownedForm);
void RemoveOwnedForm(Form ownedForm);
Form[] OwnedForms { get; }
Form Owner { get; set; }
void Close();
DialogResult ShowDialog();
DialogResult DialogResult { get; set; }
bool Modal { get; }
IButtonControl AcceptButton { get; set; }
IButtonControl CancelButton { get; set; }
bool ControlBox { get; set; }
bool MaximizeBox { get; set; }
bool MinimizeBox { get; set; }
bool ShowIcon { get; set; }
FormBorderStyle FormBorderStyle { get; set; }
Icon Icon { get; set; }
bool KeyPreview { get; set; }
bool ShowInTaskbar { get; set; }
FormStartPosition StartPosition { get; set; }
bool TopMost { get; set; }
Метод Activate активирует форму, свойство ActiveForm возвращает ссылку на активную в настоящий момент форму. Метод AddOwnedForm делает для указанной формы владельцем текущую форму. Подчиненные формы сворачиваются и закрываются вместе с формой-владельцем, а также всегда отображаются поверх формы-владельца. Метод RemoveOwnedForm убирает форму из списка подчиненных форм данной формы, представленного свойством OwnedForms. Свойство Owner позволяет узнать владельца формы. Метод Close закрывает форму. Метод ShowDialog отображает форму в модальном режиме. Свойство DialogResult задает результат отображения формы в виде диалога. Если форма отображается в модальном режиме, то запись значения, отличного от None, в это свойство приводит к закрытию формы, а метод ShowDialog вернет именно это значение. Также у кнопки есть свое свойство DialogResult. При нажатии на кнопку его значение копируется в данное свойство формы. То есть, если это не None и форма отображается в модальном режиме, то она закроется. Свойство Modal позволяет проверить, отображается ли форма в модальном режиме. Свойство AcceptButton позволяет установить кнопку по умолчанию, т.е. кнопку, которая будет автоматически нажиматься при нажатии клавиши Enter, независимо от того, какой элемент формы имеет фокус в настоящее время. Такая кнопка отображается с утолщенной рамкой. Свойство CancelButton соответственно задает кнопку, реагирующую на нажатие клавиши Esc. Свойство ControlBox определяет, отображаются ли в заголовке формы значок и кнопки (минимизации, максимизации и закрытия формы). Однако даже если кнопки не видны, форму все еще можно закрыть, используя комбинацию клавиш Alt+F4. Свойства MaximizeBox и MinimizeBox определяют, будут ли отображаться кнопки максимизации и минимизации в заголовке формы, а ShowIcon – будет ли отображаться значок. Свойство FormBorderStyle задает стиль бордюра формы. Перечисление System.Windows.Forms.FormBorderStyle содержит константы:
• None – форма отображается без бордюра;
• FixedSingle – изменение размеров формы запрещено;
• Fixed3D – объемная рамка;
• FixedDialog – диалог (нельзя изменять размеры, нет значка);
• Sizable – обычная рамка (по умолчанию);
• FixedToolWindow – окно инструментов (тонкий бордюр);
• SizableToolWindow – окно инструментов, можно изменять размер.
Свойство Icon задает значок для кнопки. Свойство KeyPreview указывает, получает ли форма сообщения от клавиатуры до передачи этих сообщений активному элементу управления. Свойство ShowInTaskbar определяет, будет ли отображаться кнопка для формы в панели задач. Свойство StartPosition задает начальное положение формы на экране (по центру экрана, по центру родительского окна и т.п.), является одной из констант перечисления System.Windows.Forms.FormStartPosition. Свойство TopMost определяет, будет ли форма отображаться поверх всех других окон приложения.
Также наследуются практически все рассмотренные ранее члены класса Control.
Продемонстрируем вышесказанное на примере. Добавим на вкладку tabPage6 компонент checkBox5, позволяющий делать форму Form2 подчиненной по отношению к форме Form1, и comboBox3, позволяющий задавать стиль бордюра формы. Также изменим обработчик на нажатие кнопки button12:
Form2 f = new Form2();
f.FormBorderStyle = (FormBorderStyle)Enum.Parse(typeof(FormBorderStyle), comboBox3.Text);
if (checkBox5.Checked) AddOwnedForm(f);
f.Show();
Теперь можно исследовать поведение формы при изменении этих свойств. Далее на форму Form1 добавим метку label6 для вывода модального результата отображения формы Form2 и кнопку button13 для отображения формы Form2 в модальном режиме. Обработчик на нажатие кнопки button13:
Form2 f = new Form2();
f.FormBorderStyle = FormBorderStyle.FixedDialog;
f.MinimizeBox = false;
f.MaximizeBox = false;
f.StartPosition = FormStartPosition.CenterParent;
DialogResult res = f.ShowDialog();
label6.Text = "Результат: " + res.ToString();
Диалог будет располагаться по центру родительского окна, не иметь кнопок максимизации, минимизации и бордюра диалогового окна (без значка и возможности изменения размеров). На форму Form2 добавим три кнопки, первая из которых имеет значение свойства DialogResult, равное константе Yes, вторая – No, третья – Cancel. При нажатии на эти кнопки в модальном режиме форма закрывается, а метод ShowDialog возвращает соответствующий результат. В немодальном режиме нажатие на эти кнопки не имеет эффекта.
В данном примере форма выполняет две роли – обычного окна и диалогового. Поэтому необходимые значения свойств устанавливаются в коде программы. В большинстве же случаев роль у формы только одна – она заранее проектируется либо как диалог, либо как обычное окно. Поэтому требуемые свойства устанавливаются на этапе проектирования формы в окне свойств.
3.3.3 Изображения
Заголовок элемента управления (кнопки, переключателя и т.п.) или метка (Label) элемента управления, не имеющего заголовка (поля ввода, списка выбора и т.п.), должны предоставлять достаточно информации о назначении данного элемента управления. Однако иногда гораздо более информативным оказывается ассоциация с элементом управления графической миниатюры – изображения. При этом она может соседствовать с заголовком либо вообще заменять его. Поэтому некоторые элементы управления (кнопки, переключатели, метки, вкладки и др.) содержат следующие свойства для добавления изображений:
Image Image { get; set; }
ContentAlignment ImageAlign { get; set; }
int ImageIndex { get; set; }
string ImageKey { get; set; }
ImageList ImageList { get; set; }
Свойство Image – это экземпляр класса System.Drawing.Image, инкапсулирующего изображения различных форматов. Свойство ImageAlign задает выравнивание изображения. Перечисление System.Drawing.ContentAlignment содержит константы для выравнивания изображения (TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter и BottomRight). Свойство ImageIndex задает номер изображения в списке, если указан список изображений. Нумерация начинается с 0, значение – 1 означает, что изображение из списка не берется. Свойство ImageKey предоставляет доступ к изображению из списка не по индексу, а по строковому ключу. Свойство ImageList – это экземпляр класса System.Windows.Forms.ImageList, задает список изображений.
Примечание: вкладки (TabPage) из перечисленных свойств имеют только ImageIndex и ImageKey, а свойство ImageList задается для всего элемента управления TabControl.
Таким образом, можно каждому элементу управления назначить отдельное изображение, а можно все изображения поместить в один список изображений и ассоциировать элементы управления с изображениями из этого списка по индексу или по ключу.
3.3.3.1 Класс Image
Класс Image является абстрактным, и предоставляет члены, необходимые для работы с изображениями. Перечислим некоторые из них:
object Clone();
static Image FromFile(string filename);
void Save(string filename);
int Height { get; }
int Width { get; }
Size Size { get; }
Метод Clone создает копию изображения (реализация интерфейса ICloneable). Метод FromFile загружает изображение из файла. Поддерживаются форматы BMP, EMF, EXIF, GIF, ICO, JPG/JPEG, PNG, TIFF и WMF. Метод Save сохраняет изображение в файл, есть версии этого метода, позволяющие указать выходной формат изображения. Свойство Height возвращает высоту изображения в точках, Width – ширину, Size – обе размерности.
Также этот класс содержит много других членов, в том числе для работы с анимированными и многостраничными изображениями.
От класса Image наследуются два класса – System.Drawing.Bitmap и System.Drawing.Imaging.Metafile. Первый позволяет работать с растровыми изображениями (BMP, EXIF, GIF, ICO, JPG/JPEG, PNG и TIFF), второй – с векторными (EMF и WMF).
Чтобы добавить на форму или другой контейнер изображение, не ассоциированное с элементами управления, используется компонент PictureBox. Он содержит некоторые свойства, общие для других элементов управления, а также свойство Image, позволяющее отобразить на его поверхности изображение.
Добавим на форму Form2 компонент pictureBox1 и загрузим в него изображение. Для этого перейдем к свойству Image и нажмем кнопку «…». Появится диалог выбора ресурса (рис. 3.17). Выбираем локальный ресурс и нажимаем кнопку «Импорт». Далее указываем требуемый файл. Изображение будет сохранено в файле «Form2.resx».
Рис. 3.17 – Диалог добавления в проект ресурса
Загруженное изображение имеет формат GIF с анимацией, анимацию можно увидеть при отображении формы во время выполнения приложения.
3.3.3.2 Класс ImageList
Класс ImageList позволяет управлять коллекцией изображений Image. Все изображения должны иметь одинаковый размер и формат пикселей. Свойства:
ColorDepth ColorDepth { get; set; }
ImageList.ImageCollection Images { get; }
Size ImageSize { get; set; }
Color TransparentColor { get; set; }
Свойство ColorDepth задает глубину цвета для всех изображений в списке. Перечисление System.Windows.Forms.ColorDepth содержит константы для значений глубины, начиная от Depth4Bit и заканчивая Depth32Bit. Свойство Images возвращает коллекцию изображений. Свойство ImageSize задает размер изображений (от 1x1 до 256x256), TransparentColor – цвет, обрабатываемый как прозрачный.
Размер и глубину цвета лучше всего устанавливать один раз, причем до момента добавления изображений в коллекцию.
Итак, в каталоге Picts проекта находятся три изображения, которые необходимо добавить в ImageList. Размер каждого составляет 19x19 пикселей, 16 цветов (4 бита на пиксель), фон – пурпурный (Fuchsia). Добавляем на форму Form2 компонент imageList1, устанавливаем соответствующую глубину цвета (Depth4Bit) и размеры, а прозрачным делаем фоновый цвет изображений. Открываем редактор коллекции изображений и добавляем в нее все три изображения. Далее имеющимся на форме трем кнопкам назначаем список изображений imageList1, выравнивание изображения – MiddleLeft, индексы – последовательно 0, 1 и 2. Получили требуемые изображения с прозрачным фоном на кнопках.
3.3.4 Меню и панели инструментов
При большом количестве команд предусмотреть для каждой из них свою кнопку, переключатель или другой элемент управления затруднительно. Интерфейс пользователя оказывается перегружен элементами. В этом случае удобно организовать ввод команд от пользователя с помощью меню и панелей инструментов. При использовании меню преимущество заключается в том, что не все команды видны сразу. Они организованы по иерархическому принципу, поэтому пользователь видит только те команды, которые расположены в текущей ветки иерархии. На панель инструментов выносят кнопки, соответствующие наиболее часто используемым пунктам меню.
Меню в программе бывают трех видов – системное (одно у каждого окна), главное (одно во всем приложении) и контекстные (их может быть несколько в каждом окне). Системное меню доступно при щелчке левой кнопкой мыши по значку окна или правой кнопкой мыши в его заголовке (если мышь настроена для левшей – то наоборот), а также при нажатии комбинации клавиш Alt+Пробел. В нем находятся команды для управления окном. В главном меню (рис. 3.18) содержатся все команды, относящиеся к функциональности приложения. В контекстных меню (рис. 3.18) содержится только часть команд, относящихся к тому элементу программы, которому они назначены в соответствие. Главное меню всегда отображается в верхней части окна (обычно – главного окна приложения), контекстные отображаются при щелчке по соответствующему элементу программы правой кнопкой мыши (левой, если мышь настроена для левшей).
Рис. 3.18 – Общий вид меню и панелей инструментов
3.3.4.1 Класс ToolStrip
В старых редакциях .NET (1.0, 1.1) для управления командами приложения использовались классы MainMenu (главное меню), ContextMenu (контекстное меню), ToolBar (панель инструментов) и StatusBar (строка состояния):
Начиная с версии .NET 2.0, появились новые объекты, замещающие старые – MenuStrip, ContextMenuStrip, ToolStrip и StatusStrip. Они рисуются с поддержкой новых стилей Windows и Office (темы, поддержка упорядочения и переполнения и т.п.). Старые версии оставлены для совместимости, поэтому их по-прежнему можно использовать, но по умолчанию на панели элементов расположены именно новые версии этих компонентов.
Базовым классом для всех панелей инструментов, меню и сопутствующих компонентов является System.Windows.Forms.ToolStrip:
Помимо членов, наследуемых от класса Control, в нем также определены следующие свойства:
bool CanOverflow { get; set; }
ToolStripGripDisplayStyle GripDisplayStyle { get; }
ToolStripGripStyle GripStyle { get; set; }
ImageList ImageList { get; set; }
ToolStripItemCollection Items { get; }
ToolStripLayoutStyle LayoutStyle { get; set; }
Orientation Orientation { get; }
ToolStripOverflowButton OverflowButton { get; }
ToolStripRenderMode RenderMode { get; set; }
bool ShowItemToolTips { get; set; }
ToolStripTextDirection TextDirection { get; set; }
Свойство CanOverflow определяет, будут ли элементы ToolStrip попадать в меню переполнения (рис. 3.18), если для них не хватает места. Свойство GripDisplayStyle возвращает ориентацию маркера перемещения. Перечисление System.Windows.Forms.ToolStripGripDisplayStyle содержит константы Horizontal и Vertical. Свойство GripStyle задает вид маркера перемещения. Перечисление System.Windows.Forms.ToolStripGripStyle содержит константы Hidden (маркер скрыт) и Visible (маркер видим). Свойство ImageList определяет список изображений для элементов ToolStrip. Свойство Items возвращает ссылку на коллекцию элементов ToolStrip. Свойство LayoutStyle задает стиль размещения элементов ToolStrip. Описание констант перечисления System.Windows.Forms.LayoutStyle:
• StackWithOverflow – элементы располагаются автоматически (горизонтально или вертикально – в зависимости от значения свойства Orientation), маркер перемещения и меню переполнения (при необходимости) отображаются;
• HorizontalStackWithOverflow – элементы располагаются горизонтально, маркер перемещения и меню переполнения (при необходимости) отображаются;
• VerticalStackWithOverflow – элементы располагаются вертикально, маркер перемещения и меню переполнения (при необходимости) отображаются;
• Flow – элементы располагаются друг за другом (горизонтально или вертикально – в зависимости от значения свойства Orientation), маркер перемещения и меню переполнения отсутствуют;
• Table – элементы располагаются по левому краю, маркер перемещения и меню переполнения отсутствуют.
Свойство Orientation получает ориентацию элемента ToolStrip. Перечисление System.Windows.Forms.Orientation содержит константы Horizontal и Vertical. Свойство OverflowButton возвращает ссылку на кнопку переполнения. Свойство RenderMode задает стиль оформления объекта ToolStrip. Перечисление System.Windows.Forms.ToolStripRenderMode содержит константы System (системные цвета и плоский визуальный стиль), Professional (измененная палитра и стиль) и ManagerRenderMode (для рисования используется специальный объект ToolStripRenderer). Свойство ShowItemToolTips определяет, будут ли при наведении курсора мыши на элемент ToolStrip отображаться всплывающие подсказки. Свойство TextDirection задает направление текста. Перечисление System.Windows.Forms.ToolStripTextDirection содержит константы Inherit (направление наследуется от родительского элемента управления), Horizontal (горизонтальная ориентация), Vertical90 (текст повернут на 90°) и Vertical270 (текст повернут на 270°).
Для демонстрации возможностей меню и панелей инструментов создан проект, находящийся в папке «ch3\sample02».