Книга: C# для профессионалов. Том II

Класс формы SquareRoot

Класс формы SquareRoot

Мы видели, как C# запускает цикл сообщений, но мы еще не изучили процесс вывода и создания самой формы. Мы также не определились с вопросом о вызове обработчиков событий. Упоминалось, что Windows вызывает такие обработчики событий, как метод OnClickButtonResults(). Но как Windows узнает, что нужно вызвать этот метод? Мы найдем ответы на все наши вопросы в определении класса SquareRootForm и в его базовом классе Form.

Отметим сначала, что класс SquareRootForm имеет достаточно много полей-членов. (Поле-член является выражением C# для переменной, которая определена как член класса. Можно представлять ее как переменную VB, которая имеет областью действия форму, или как переменную VB, которая определена в качестве члена модуля класса. Каждая такая переменная связана с определенным экземпляром класса — определенным объектом — и остается в области действия до тех пор, пока существует содержащий ее объект):

public class SquareRootForm : System.Windows.Forms.Form {
 private System.Windows.Forms.TextBox txtNumber;
 private System.Windows.Forms.TextBox txtSign;
 private System.Windows.Forms.TextBox txtResult;
 private System.Windows.Forms.Button cmdShowResults;
 private System.Windows.Forms.Label label1;
 private System.Windows.Forms.Label label2;
 private System.Windows.Forms.Label label3;
 private System.Windows.Forms.Label label4;

Каждое из этих полей соответствует одному из элементов управления. Можно легко увидеть три текстовых поля и кнопку. Имеются также четыре метки, соответствующие областям текста на форме. Мы не будем ничего делать с этими метками, поэтому не стоит беспокоиться и давать им какие-то более понятные пользователю имена.

Однако каждая из этих переменных является просто ссылкой на объект, поэтому тот факт, что эти переменные существуют, не означает существования никаких экземпляров этих объектов — экземпляры объектов должны быть созданы отдельно. Процесс создания экземпляров этих элементов управления осуществляется с помощью так называемого конструктора. Конструктор в C# является примерным аналогом таким подпрограммам, как Form_Load(), Form_Initialize(), Class_Load() и Class_Initialize(). Это специальный метод, который автоматически вызывается, когда создается экземпляр класса, и он содержит код, необходимый для инициализации экземпляра.

Конструктор в классе легко опознать, так как он всегда имеет такое же имя, как и сам класс. В данном случае мы ищем метод с именем SquareRootForm:

public SquareRootForm() {
 InitializeComponent();
}

Отметим, что так как это — конструктор, а не метод, который можно вызывать, он не определяет никакого возвращаемого типа. Однако после его имени стоят скобки, как и у метода. Можно использовать эти скобки для определения параметров, которые будут передаваться в конструктор (вспомните, что при создании переменной можно передавать параметры в скобках после предложения new). Определение конструктора указывает, нужны ли какие-то параметры для создания экземпляра объекта. Однако здесь нет никаких параметров. Мы увидим конструкторы, которые получают параметры, в примере Employee, рассматриваемом дальше в этом приложении.

В данном случае конструктор просто вызывает метод InitializeComponent(). Это в действительности связано с Visual Studio.NET. Visual Studio NET имеет все те же свойства, что и IDE VB6 для графических манипуляций элементами управления — щелчок мышью для размещения элементов управления на форме и т.д. Однако, так как теперь в C# определения всех элементов управления задаются в исходном коде, Visual Studio.NET должна иметь возможность прочитать исходный код, чтобы определить, какие элементы управления находятся на форме. Она делает это, разыскивая метод InitializeComponent() и определяя, экземпляры каких элементов управления там создаются.

InitializeComponent() является большим методом, поэтому он будет показан здесь полностью. Начинается он следующим образом:

private void InitializeComponent() {
 this.txtNumber = new System.Windows.Forms.TextBox();
 this.txtSign = new System.Windows.Forms.TextBox();
 this.cmdShowResults = new System.Windows.Forms.Button();
 this.label3 = new System.Windows.Forms.Label();
 this.label4 = new System.Windows.Forms.Label();
 this.label1 = new System.Windows.Forms.Label();
 this.label2 = new System.Windows.Forms.Label();
 this.txtResult = new System.Windows.Forms.TextBox();

Показанный код является множеством вызовов для реального создания экземпляров всех элементов управления на форме. Этот фрагмент кода не содержит на самом деле ни одного нового элемента синтаксиса C#, который бы до сих пор не встречался. Следующая часть кода начинает задавать свойства элементов управления:

 //
 // txtNumber
 //
 this.txtNumber.Location = new System.Drawing.Point(160, 24);
 this.txtNumber.Name = "txtNumber";
 this.txtNumber.TabIndex = 0; this.txtNumber.Text = "";
 //
 // txtSign
 //
 this.txtSign.Enabled = false;
 this.txtSign.Location = new System.Drawing.Point(160, 136);
 this.txtSign.Name = "txtSign";
 this.txtSign.TabIndex = 1;
 this.txtSign.Text = "";

Этот код задаёт начальные позиции и начальный текст двух элементов управления, текстового поля ввода и текстового поля, которое выводит знак заданного числа. Новый элемент кода состоит в том что положение относительно верхнего левого угла экрана задается с помощью Point. Point является базовым классом .NET (строго говоря, структурой), который содержит x- и y-координаты. Синтаксис двух строк, задающих Location, является инструктивным. Свойство TextBox.Location является просто ссылкой на Point, поэтому, чтобы задать ему значение, необходимо создать и инициализировать объект Point, содержащий правильные координаты. Это первое использование нами конструктора с параметрами — в данном случае горизонтальной и вертикальной координат Point и, следовательно, элемента управления. Если было бы желательно транслировать одну из этих строк в VB, предполагая, что был определён некоторый модуль класса VB с именем Point, и мы имели бы класс, который имеет такое свойство, то лучшее, что можно было бы сделать, выглядело бы примерно следующим образом:

Dim Location As Point
Set Location = New Point
Location.X = 160
Location.Y = 24
SomeObject.Location = Location

Это сравнимо со следующим кодом на C#:

someObject.Location = new System.Drawing.Point(160, 24);

Относительная компактность эквивалентной инструкции C# должна быть очевидна.

Теперь рассмотрим те же команды для кнопки. В этом случае можно наблюдать задание свойств такого же вида, но здесь имеется другая вещь, которую необходимо выполнить: приказать Windows вызвать наш обработчик событий, когда нажимается кнопка. Это делает последняя строка из нижеследующих.

 this.cmdShowResults.Name = "cmdShowResults";
 this.cmdShowResults.Size = new System.Drawing.Size(88, 23);
 this.cmdShowResults.TabIndex = 3;
 this.cmdShowResults.Text = "Show Results";
 this.cmdShowResults.Click +=

  new System.EventHandler(this.OnClickShowResults);

Здесь происходит следующее. Кнопка, обозначенная как объект кнопки cmdShowResults, содержит событие Click, которое будет инициироваться, когда пользователь на нее нажмет. Надо добавить для этого события собственный обработчик событий. Сейчас C# не разрешает передавать имена методов непосредственно, вместо этого они должны помещаться в так называемый объект делегат. Детали этого здесь не рассматриваются, они приведены в главе 6 данной книги, но это делается для обеспечения безопасности типов. Вследствие такого действия появляется текст new System.EventHandler() в этом коде. Когда имя обработчика событий будет спрятано, мы добавим его к событию, используя оператор +=, который будет рассмотрен ниже.

Арифметические операторы присваивания

Символ += представляет в C# так называемый оператор сложения-присваивания. Он дает удобное сокращение для случаев, когда необходимо добавить некоторую величину к другой величине. Это работает следующим образом. Пусть в VB объявлены два целых числа А и В и необходимо записать следующее выражение:

В = В + А

В C# можно записать похожим образом:

В = В + А;

Однако в C# для этого существует альтернативная сокращенная запись:

B += А;
+=
в действительности означает "сложить значение выражения справа с переменной слева" и это работает для всех числовых типов данных, а не только для целых. Существуют также другие аналогичные операторы *=, /= и -=, которые соответственно умножают, делят и вычитают величину слева из переменной справа. Поэтому, например, чтобы разделить число на 2 и присвоить результат снова В, можно написать:

B /= 2;

Хотя в этом приложении не рассматриваются подробности, но C# имеет другие операторы, представляющие побитовые операции, а также дающие остаток при делении, и почти все они имеют соответствующие операторы операция-присваивание (см. главу 3).

В примере SquareRootForm оператор сложения-присваивания применен к событию, строка:

this.cmdShowResults.Click +=
 new SyBtem.EventHandler(this.OnClickShowResults)

означает: "добавить этот обработчик к событию". Может быть немного удивительным увидеть оператор, подобный +=, который применяется к чему-то, что не является таким простым числовым типом данных, как int или float, но это на самом деле иллюстрирует важный момент в отношении операторов в C# по сравнению с операторами в VB:

Операторы, подобные +, * и т.д. в VB действительно имеют значение, только когда применяются к числовым данным. Но в C# они могут применяться к объектам любого типа.

Приведенное выше утверждение необходимо немного уточнить. Чтобы применять эти операторы к другим типам объектов, необходимо сначала сообщить компилятору, что эти операторы означают для других типов объектов — процесс, называемый перезагрузкой операторов. Он работает примерно следующим образом. Предположим, что необходимо написать класс, который представляет, скажем, математический вектор. В VB это можно закодировать как модуль класса, который позволит написать:

Dim V1 As Vector
Set V1 = New Vector

В математике векторы можно складывать, что будет обеспечено с помощью перезагрузки операторов. Но VB6 не поддерживает перезагрузку, поэтому вместо этого в VB6 вероятно придется определить метод Add для Vector, и, таким образом, сделать следующее:

' V1, V2 и V3 являются векторами
Set V3 = V1. Add(V2)

В VB это лучшее, что можно придумать. Однако в C#, если определить класс Vector, можно добавить в него перезагруженный оператор для +, который является по сути методом, имеющим имя operator+, и который компилятор будет вызывать, если увидит +, примененный к Vector. Это означает, что в C# можно будет написать:

// V1, V2 и V3 являются векторами
V3 = V1 + V2;

Очевидно, что перезагруженные операторы не будут определяться для всех классов. Для большинства классов не будут иметь смысла действия типа сложения или умножения объектов. Однако для классов, для которых это имеет смысл, перезагрузка операторов может сделать код значительно проще для восприятия. Именно это и происходит с событиями. Поскольку имеет смысл говорить о добавлении обработчика к событию, был предоставлен перезагруженный оператор, чтобы позволить делать это, используя интуитивно понятный синтаксис с помощью операторов ++=). Можно также использовать - или -= для удаления обработчика из события.

Оглавление книги


Генерация: 2.212. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз