netlib.narod.ru< Назад | Оглавление | Далее >

Идентификация элементов управления

В программе CheckBoxWithLabel определено два массива: один с текстовыми строками для четырех флажков, а второй содержит соответствующие значения перечисления FontStyle. Увы, эти массивы определены в разных областях программы. Если изменить порядок элементов в одном массиве, не изменив порядка в другом, программа будет работать неправильно.

Более того: сравните, как свойство Controls индексируется в методе OnPaint программы CheckBoxDemo и как оно индексируется в методе CheckBoxOnCheckedChanged программы CheckBoxWithLabel. В первой программе индексы находятся в диапазоне от 0 до 3. Во второй первым дочерним элементом формы является Label, и, таким образом, он имеет индекс 0. Элементы управления CheckBox индексируются с 1 до 4.

Если изменить в CheckBoxWithLabel конструктор, так чтобы элемент Label делался дочерним элементом формы после элемента CheckBox, программа будет работать неправильно. Я уж не говорю о том, что индексирование элементов массива Controls в зависимости от порядка их создания — плохой стиль программирования. Для программы с несколькими элементами управления это может быть не так ужасно. Но если элементов много, это может стать настоящим кошмаром.

Отслеживать все создаваемые элементы управления можно несколькими способами. Например, хранить объекты — элементы управления в полях, как в программе TwoButtons. Можно устанавливать отдельный обработчик событий для каждого элемента. Другой подход — использовать для уникальной идентификации свойства (или что-нибудь вроде этого) каждого элемента. Конечно, свойство Text обычно уникально идентифицирует элемент управления, и в обработчике события можно задействовать текст элемента в инструкции switch для определения того, какой элемент вызвал событие. Но при этом, если вам когда-либо понадобится изменить текст элемента управления, вам придется менять как код, присваивающий свойство Text элемента, так и конструкцию switchcase в обработчике события.

Итак, для идентификации объекта свойства Text недостаточно. А что было бы достаточно? Класс Control содержит свойство, которое можно установить равным любому подходящему объекту:


Свойства Control (выборочно)



Тип Свойство Доступ

object Tag Чтение/запись


Это свойство специально предназначено для идентификации элементов управления. При создании элемента управления можно присвоить свойству Tag любой объект. К примеру, приведу частичное определение элемента управления CheckBox, предназначенного для выбора цвета:

  chkbox.Text = "Magenta";
  chkbox.Tag  = Color.Magenta;

В обработчике события прежде всего следует получить элемент управления CheckBox, вызвавший событие:

  CheckBox chkbox = (CheckBox)obj;

а затем привести свойство Tag к объекту Color:

  Color clr = (Color)Tag;

Если Tag не является объектом Color, будет сгенерировано исключение. Пример использования свойства Tag я приведу в программе AutoScaleDemo чуть позже.

Что приятно в объектно-ориентированном программировании вообще (и в Windows Forms в частности), это то, что для идентификации элемента управления вы легко можете добавлять к нему все, что угодно.

В следующей программе создается новый класс — наследник CheckBox, предназначенный для вывода стилей шрифта. В новом классе добавляется всего одно поле — fontstyle типа FontStyle. Вы можете видеть (в конце листинга), что определение этого нового класса требует минимального объема кода.

CustomCheckBox.cs

  //-----------------------------------------------
  // CustomCheckBox.cs (C) 2001 by Charles Petzold
  //-----------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class CustomCheckBox: Form
  {
      public static void Main()
      {
          Application.Run(new CustomCheckBox());
      }
      public CustomCheckBox()
      {
          Text = "Custom CheckBox Demo";

          int      cyText = Font.Height;
          int      cxText = cyText / 2;
          FontStyle[] afs = { FontStyle.Bold,      FontStyle.Italic, 
                              FontStyle.Underline, FontStyle.Strikeout };

          Label label    = new Label();
          label.Parent   = this;
          label.Text     = Text + ": Sample Text";
          label.AutoSize = true;

          for (int i = 0; i < 4; i++)
          {
              FontStyleCheckBox chkbox = new FontStyleCheckBox();
              chkbox.Parent = this;
              chkbox.Text = afs[i].ToString();
              chkbox.fontstyle = afs[i];
              chkbox.Location = new Point(2 * cxText, 
                                              (4 + 3 * i) * cyText / 2);
              chkbox.Size = new Size(12 * cxText, cyText);
              chkbox.CheckedChanged += 
                             new EventHandler(CheckBoxOnCheckedChanged);
          }
      }
      void CheckBoxOnCheckedChanged(object obj, EventArgs ea)
      {
          FontStyle fs = 0;
          Label     label = null;

          for (int i = 0; i < Controls.Count; i++)
          {
              Control ctrl = Controls[i];

              if (ctrl.GetType() == typeof(Label))
                  label = (Label) ctrl;

              else if (ctrl.GetType() == typeof(FontStyleCheckBox))
                  if (((FontStyleCheckBox) ctrl).Checked)
                      fs |= ((FontStyleCheckBox) ctrl).fontstyle;
          }
          label.Font = new Font(label.Font, fs);
      }
  }
  class FontStyleCheckBox: CheckBox
  {
     public FontStyle fontstyle;
  }

В конструкторе определяется массив значений FontStyle. При создании каждого объекта FontStyleCheckBox его полю fontstyle присваивается значение типа FontStyle. В программе не используется массив string. Вместо этого значение FontStyle преобразуется в строку, а свойству Text присваивается эта строка. Хотя массив строк по-прежнему необходим, по крайней мере оба массива определяются в одном фрагменте программы и при необходимости могут быть изменены одновременно.

Метод CheckBoxOnCheckedChanged циклически обрабатывает все элементы управления в массиве Controls и определяет тип каждого из них. Для определения типа объекта можно применять метод GetType, кроме того, можно использовать оператор typeof языка С# с любым именем класса для определения его типа. Если элемент управления имеет тип FontStyleCheckBox, объект приводится к этому типу, и если свойство Checked равно true, метод обращается к его полю fontstyle. Если элемент имеет тип Label, объект Label сохраняется, и обработка события завершается присвоением его свойству Font нового шрифта. Можно изменять значения FontStyle и порядок создания элементов и установления их родительской формы, при этом переделок кода не потребуется.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz