Пользовательские компоненты
Упражнение 2. Создание невизуального компонента Planets
В этом примере мы создадим невизуальный компонент Planets, инкапсулирующий в себе названия планет Солнечной системы, и добавим его в нашу библиотеку компонентов сборки MyComponents. Названия планет будут храниться во внутреннем массиве компонента, а доступ к ним будет осуществляться через индексаторы по имени планеты или ее индексу.
- В панели Solution Explorer выделите проект MyComponents и выполните команду меню Project/Add Component, чтобы добавить файл Planets.cs нового компонента
- Дополните содержимое файла, автоматически сгенерированное мастером, следующим кодом
using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Collections; namespace MyCompany.MyComponents { public partial class Planets : Component { public Planets() { InitializeComponent(); } public Planets(IContainer container) { container.Add(this); InitializeComponent(); } } } namespace MyCompany.MyComponents { partial class Planets { // Планеты private string[] PlanetNames ={ "Меркурий", "Венера", "Земля", "Марс", "Юпитер", "Сатурн", "Уран", "Нептун", "Плутон" }; // Вернуть имя private string GetPlanetName(int index) { // Нижняя и верхняя границы массива int lowP = 0, highP = PlanetNames.Length - 1; // Контролирует диапазон индекса планеты и возвращает // ее название или генерирует исключение if (index < lowP || index > highP) { MessageBox.Show(String.Format("Индекс должен находиться в диапазоне {0}-{1}", lowP, highP)); index = 0; } return PlanetNames[index]; } // Вернуть индекс private int GetPlanetPosition(string planetName) { // Сравниваем переданное имя планеты с массивом // PlanetNames. При несовпадении возвращаем -1 int result=-1; for(int i=0; i<PlanetNames.Length;i++) if (String.Compare(planetName, PlanetNames[i], true) == 0) { result = i; break; } return result; } // Свойство - индексатор: возвращает имя планеты по индексу public string this[int index] { get {return GetPlanetName(index); } } // Свойство - индексатор: возвращает индекс планеты по имени public int this[string planetName] { get { return GetPlanetPosition(planetName); } } // Свойство максимального размера массива public int MaxIndex { get { return PlanetNames.Length - 1; } } } }Листинг 24.8. Расширенное содержимое файла Planets.cs
В коде мы объявили массив с планетами и сразу инициализировали его. Создали два внутренних контролирующих метода, возвращающих название планеты по ее индексу и наоборот. Добавили два общедоступных свойства - индексатора, позволяющих работать с экземпляром компонента как с массивом, а также добавили общедоступное свойство максимального размера поля - массива с планетами.
Теперь осталось перекомпилировать сборку MyComponents.dll, в которой в одном пространстве имен MyCompany.MyComponents будут находиться уже два наших компонента, и испытать новый невизуальный компонент.
- В панели Solution Explorer вызовите контекстное меню для узла проекта MyComponets и выполните команду Rebuild, чтобы перекомпилировать проект с компонентами
- Убедитесь, что в панели Toolbox появился новый компонент Planets, который теперь можно перетаскивать на форму также, как и обычный библиотечный компонент
Испытание созданных компонентов
- В проекте ComponentTest настройте пользовательский интерфейс, как показано на рисунке и в таблице (в скобках приведены имена экземпляров компонентов)
- В панели Properties перейдите на вкладку Events и создайте обработчики для элементов согласно таблицы
- Заполните файл Form1.cs следующим кодом
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace ComponentTest { public partial class Form1 : Form { // Конструктор формы public Form1() { InitializeComponent(); // Заполнение списка планетами for (int i = 0; i <= planets1.MaxIndex; i++) { listPlanets.Items.Add(String.Format( "{0}) {1}", i, planets1[i])); } listPlanets.SelectedIndex = 0; } // Обработчики событий private void firstComponent1_Click(object sender, EventArgs e) { // Контролируем пустой ввод if (indexPlanet.Text == String.Empty) return; int index = Convert.ToInt32(indexPlanet.Text); // Контролируем максимальный индекс ввода index = Math.Min(index, planets1.MaxIndex); if (listPlanets.SelectedIndex != index) listPlanets.SelectedIndex = index; else MessageBox.Show(String.Format("Вы выбрали планету {0}", planets1[index])); } private void indexPlanet_KeyPress(object sender, KeyPressEventArgs e) { // Фильтруем цифры, Backspace, Enter (Delete и стрелки по умолчанию) if ((e.KeyChar < Convert.ToChar(Keys.D0) || e.KeyChar > Convert.ToChar(Keys.D9)) && e.KeyChar != Convert.ToChar(Keys.Back) && e.KeyChar != Convert.ToChar(Keys.Enter)) e.Handled = true; // Реакция на клавишу Enter if (e.KeyChar == Convert.ToChar(Keys.Enter)) firstComponent1_Click(null, EventArgs.Empty); } bool loadFlag = true; // Локальное поле-флаг private void listPlanets_SelectedValueChanged(object sender, EventArgs e) { int index = listPlanets.SelectedIndex; indexPlanet.Text = index.ToString(); if (loadFlag) { // При первом запуске не показывать loadFlag = false; return; } else MessageBox.Show(String.Format("Вы выбрали планету {0}", planets1[index])); } } }Листинг 24.9. Код файла Form1.cs
- Откомпилируйте приложение текущего уровня готовности и испытайте его работу