Пользовательские компоненты
Файлы к лабораторной работе Вы можете скачать здесь.
Основными вида создания программного продукта являются:
- Создание приложений
- Создание библиотек классов
- Создание компонентов
В данном разделе мы познакомимся с созданием компонентов. Компонент, это программная единица, способная поддерживать технологию визуального программирования. Это не только класс, обладающий нужной функциональностью на этапе выполнения, но и абстракция, поддерживаемая инструментами оболочки на этапе проектирования. В отличие от стандартных библиотечных компонентов, созданных разработчиками среды проектирования, их называют пользовательскими. Пользовательский компонент можно перетаскивать из панели Toolbox на форму, настраивать его свойства и события точно также, как это делается со стандартными компонентами библиотеки .NET Framework.
Этапы разработки компонентов
Стандартная процедура создания пользовательского компонента состоит из следующих шагов:
- Выбор базового класса
- Создание структуры нового класса
- Добавление свойств, методов, событий
- Испытание компонента
- Документирование пользовательского компонента
- Сохранение компонента в DLL
- Добавление компонента в инструментальную панель среды проектирования
Далее мы опробуем большинство из этих этапов на примере создания трех пользовательских компонентов.
Выбор базового класса компонента
В зависимости от выбора базового типа различают следующие компоненты
- Пользовательские элементы управления (user control) - расширение визуальных элементов управления, в основе которых лежит класс Control
- Невизуальные компоненты (nonvisual component) - расширения классов, не имеющих во время выполнения визуального представления
- Специальные элементы управления (custom control) - создание совершенно нового визуального компонента непосредственно из класса Control
Ниже приведен список базовых классов среды .NET Framework, используемых при создании компонентов
Упражнение 1. Создание визуального компонента FirstComponent
Создадим компонент под названием FirstComponent, который будет потомком класса System.Windows.Forms.Control сборки System.Windows.Forms. В свою очередь, этот библиотечный класс Control наследует от класса System.ComponentModel.Component сборки System. Нам понадобятся следующие пространства имен:
Пространство имен | Библиотечная сборка |
---|---|
System.Windows.Forms | System.Windows.Forms.dll |
System.ComponentModel | System.dll |
System.Drawing | System.Drawing.dll |
System | mscorlib.dll |
System.Collections | mscorlib.dll |
- Выполните команду File/New/Project оболочки Visual Studio 2005 и заполните окно мастера так
Мастер создаст каталог решения MySolution для размещения нескольких взаимосвязанных проектов, в который поместит каталог проекта MyComponents и будет автоматически обертывать каждый новый класс проекта при его создании пространством имен MyComponents.
Для тренировки нам нужно настроить оболочку на автоматическое генерирование другого пространства имен для всех файлов проекта, которое бы уникально характеризовало нашу библиотеку компонентов. Для будующих компонентов мы выберем составное пространство имен MyCompany.MyComponents.
- В панели Solution Explorer вызовите контекстное меню для корневого узла проекта MyComponents и выполните команду Properties. Для вкладки Application скорректируйте текстовое поле Default namespace как показано на рисунке
- Удалите автоматически созданный оболочкой файл Class1.cs
- В панели Solution Explorer выделите корневой узел проекта, выполните команду Project/Add Component и задайте имя файла FirstComponent.cs
- В конструкторе файла щелкните на соответствующей ссылке или выполните команду контекстного меню, чтобы перейти в режим редактирования кода
Код заготовки компонента, созданный мастером, будет выглядеть так
using System; using System.ComponentModel; using System.Collections.Generic; using System.Diagnostics; using System.Text; namespace MyCompany.MyComponents { public partial class FirstComponent : Component { public FirstComponent() { InitializeComponent(); } public FirstComponent(IContainer container) { container.Add(this); InitializeComponent(); } } }Листинг 24.1. Код заготовки компонента FirstComponent
Обратите внимание, что класс объявлен как partial (частичный), что позволит для удобства чтения разбить его описание на отдельные части, или даже разместить эти описания в отдельных файлах. Удостоверьтесь, что теперь оболочка автоматически генерирует установленное нами составное пространство имен MyCompany.MyComponents.
-
Выполните
команду Project/Add Reference, перейдите
на вкладку .NET и, удерживая клавишу Ctrl,
добавьте к проекту ссылки на библиотечные сборки (сборка mscorlib.dll подключается автоматически):
- System.dll
- System.Windows.Forms.dll
- System.Drawing.dll
-
Раскройте в панели Solution Explorer узел References и удалите из проекта ссылки на ненужные сборки, автоматически сгенерированные мастером оболочки
- Откройте панель Object Browser, установите раскрывающийся список Browse в значение .NET Framework, раскройте сборку System.Windows.Forms, в которой найдите класс System.Windows.Forms.Control. Убедитесь, что класс Control является потомком класса System.ComponentModel.Component
Это значит, что в своем коде мы можем наследовать класс FirstComponent не от базового класса Component, как это предполагал мастер создания заготовки компонента, а от визуального класса Control. В результате компонент FirstComponent будет иметь визуальное представление на форме как во время проектирования, так и во время выполнения.
- Заполните файл FirstComponent.cs следующим кодом
using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Collections; namespace MyCompany.MyComponents { public partial class FirstComponent : Control { public FirstComponent() { InitializeComponent(); Init(); } public FirstComponent(IContainer container) { container.Add(this); InitializeComponent(); Init(); } } } namespace MyCompany.MyComponents { // Определяем перечисление public enum EnumType { Zero, One, Two, Three }; partial class FirstComponent { // Локальные поля int integerProp; string stringProp = "По умолчанию"; char charProp; bool boolProp = false; EnumType enumProp = EnumType.Zero; SomeObject someObject; // Общедоступные свойства для локальных полей public int IntegerProp { get { return integerProp; } set { integerProp = value; } } public string StringProp { get { return stringProp; } set { stringProp = value; } } public char CharProp { get { return charProp; } set { charProp = value; } } public bool BoolProp { get { return boolProp; } set { boolProp = value; } } public EnumType EnumProp { get { return enumProp; } set { enumProp = value; } } // Сложное свойство - объект public SomeObject SomeObj { get { return someObject; } set { someObject = value; } } void Init() { someObject = new SomeObject(); this.BackColor = System.Drawing.Color.Red; } } } namespace MyCompany.MyComponents { public class SomeObject : Object { int prop1; string prop2; // Свойства public int Prop1 { get { return prop1; } set { prop1 = value; } } public string Prop2 { get { return prop2; } set { prop2 = value; } } // Инициализация полей через конструктор public SomeObject() { prop1 = 2008; prop2 = "Привет"; } } }Листинг 24.2. Модифицированный код файла FirstComponent.cs
В приведенном начальном коде мы добавили в класс компонента публичные свойства разных типов, включая перечисление и экземпляр стороннего класса. Часть полей мы инициализировали начальными значениями.
Мы поменяли базовый класс Component на Control для того, чтобы сделать компонент визуальным. Базовые поля для свойств класса SomeObject мы инициализировали в конструкторе по умолчанию (для разнообразия). В методе Init() мы создали экземпляр класса SomeObject и инициализировали им внутреннюю ссылку, чтобы при создании самого компонента ссылка бы адресовалась к уже существующему объекту. Мы, также, установили цвет фона компонента для его видимости на вызывающей форме.
Вызов метода Init() поместили внутрь перегруженных версий конструктора класса компонента последним. Конструкторы компонента выполняются оболочкой и на этапе проектирования. Для контролируемого доступа к ссылке на объект извне предусмотрели внутри класса компонента общедоступное свойство. Класс компонента мы разбили на отдельные части, упаковав их в одно и то же пространство имен.