Создание диалоговых окон

Чтобы вывести собственное диалоговое окно, создайте форму, задайте ее свойствам ControlBox, MinimizeBox и MaximizeBox значение False, а свойству Modal — значение True. Форму следует выводить методом ShowDialog в режиме модального диалогового окна. Если при этом задать свойство TopMost равным True, диалоговое окно будет располагаться поверх всех окон на экране (и вам уже не придется использовать функцию API SetWindowPos).

Однако поведение стандартных кнопок несколько изменилось по сравнению с VB6. Свойства Default и Cancel не поддерживаются, поэтому соответствующие элементы-кнопки назначаются свойствам AcceptButton и Cancel Button:

Me.AcceptButton = btnOK Me.Cancel Button = btnCancel

После вызова ShowDialog программа может узнать, какая кнопка была нажата на форме, при помощи свойства Dial ogResult кнопки или самой формы (нажатие кнопки с заданным свойством DialogResul t приводит к автоматическому закрытию формы, на которой эта кнопка находится).

 

Размещение элементов на форме во время выполнения

До выхода VB6 существовал лишь один способ размещения элементов на форме во время выполнения программы — массивы элементов. В VB6 появился более удобный режим динамического добавления элементов, но и в этом случае не обходилось без проблем с обработкой событий для добавленных элементов. В VB .NET этот процесс подвергся существенным изменениям. Например, создайте новое приложение Windows и включите в него следующий фрагмент:

1 Private Sub Forml_Load(ByVal sender As System.Object,ByVal e As _

2 System.EventArgs) Handles MyBase.Load

3 Dim newButton As New System.Windows.Forms.Button()

4 ' Задать свойства newButton

5 With newButton

6 .Visible =True

7 .Size =New Size(l00.l00)

8 ' .Text ="I'm a new button"

9 ' Обычно здесь задаются и другие свойства

10 End With

11 Me.Controls.Add(newButton)

12 AddHandler newButton.Click.AddressOf Me.newButton_Click

13 End Sub

14 Public Sub newButton_Click(ByVal sender As _

15 System.Object.ByVal e As System.EventArgs)

16 MsgBox("You clicked on my new button")

17 End Sub

В строке З создается новая кнопка, а в строках 5-10 удобная сокращенная запись With используется для задания ряда свойств объекта newButton. Только в строке 11 новая кнопка размещается на форме. Строка 12 снова демонстрирует замечательную гибкость механизма обработки событий .NET: код, содержащийся в строках 14-17, назначается обработчиком события для кнопки. Возможный результат выполнения программы показан на рис. 8.15.

Рис. 8.15. Создание кнопки во время выполнения программы

 

Наследование форм

Прежде всего следует сказать, что «визуальное наследование», часто упоминаемое в рекламных материалах по VB .NET, существует лишь в больном воображении специалистов по маркетингу. На самом деле речь идет о том, что формы, созданные в программе, могут использоваться как основа для определения новых форм посредством наследования. Конечно, это весьма удобно и полезно, но ничего принципиально нового в таком наследовании нет. Класс формы, производный от Windows. Forms. Form и дополненный специализированными свойствами, методами и событиями, в дальнейшем может использоваться в качестве базового для определения новых классов.[ История с «визуальным наследованием» как нельзя лучше демонстрирует тупость специалистов по рекламе. Возможно, эффектный термин поразит некомпетентноге менеджера, но у программистов он лишь вызывает раздражение. ]

Предположим, вы хотите создать для своей организации окно-заставку (splash screen), которое отдельные подразделения будут дополнять своими данными. Базовая форма создается следующим образом:

  1. Выполните команду File > New > Project.
  2. Выберите тип приложения Windows Application, введите в поле Name строку SplashScreeriBase и нажмите кнопку ОК.

Предположим, вы хотите преобразовать стандартное приложение Windows в библиотеку классов, чтобы откомпилировать его в DLL вместо ЕХЕ-файла. Проще всего это делается так:

  1. Щелкните правой кнопкой мыши в строке SplashScreenBase окна решения и выберите в контекстном меню команду Properties.
  2. Выберите в раскрывающемся списке Output Type строку Class Library (вместо Windows Application). Нажмите кнопку ОК.
  3. Сконструируйте форму, разместите на ней нужные элементы, реализуйте свойства, методы и события.
  4. Откомпилируйте программу.

После построения библиотеки DLL остается лишь включить ссылку на нее в решение, после чего классы DLL используются в программе наравне с остальными классами. При выполнении команды Project > Add Inherited Form можно поручить IDE включить в проект весь необходимый код, для чего достаточно ответить на несколько вопросов в диалоговых окнах. С другой стороны, возня с диалоговыми окнами выглядит немного глупо, поскольку после включения ссылки на DLL в проект остается лишь привести первую строку приложения к следующему виду:

Public Class Form1

Inherits SplashScreenBase. Form1

Все остальное за вас сделает механизм наследования! Этот способ особенно хорош тем, что работа дизайнера автоматически синхронизируется с унаследованной формой.

 

Построение нестандартных элементов на базе наследования

Наследование применяется при построении не только новых форм, но и новых элементов. Допустим, вы хотите создать текстовое поле, предназначенное для ввода только целых чисел. Как обычно, все начинается с объявления нового класса:

Public Class PositivelntegerTextBox

Inherits System . Windows . Forms . TextBox

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

Чтобы сократить объем этого примера, мы ограничимся упрощенной версией элемента. В частности, проблемы лицензирования и безопасности вообще не рассматриваются — за дополнительной информацией обращайтесь к более серьезным книгам, посвященным программированию элементов в .NET.

Итак, создайте новую библиотеку классов и включите в решение ссылку на сборку Windows.Forms.dll.


Мы начинаем работу с библиотеки классов, а не с проекта типа User Control, потому что он лучше подходит для элементов, написанных «на пустом месте». Если вы захотите построить элемент, содержащий несколько других элементов, выберите в диалоговом окне New Project тип Windows Controls Library — в вашем распоряжении окажется контейнер, предназначенный для построения сложного элемента посредством включения.

 

Переопределение события

Начнем с переопределения событий базового класса. Например, событие OnChange поможет предотвратить ввод в поле всего, что не является целым числом. Следующий обработчик разрешает вводить или вставлять из буфера только положительные целые числа:

1 Public Class PositivelntegerTextBox

2 Inherits System.Windows.Forms.TextBox

3 Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)

4 MyBase.OnTextChanged(e)

5 If Not (IsNumeric(Me.Text))Then

6 Me.Text - String.Empty

7 Else

8 Dim temp As Decimal

9 temp = CType(Me.Text.Decimal)

10 If temp - Math.Round(temp.0) <> 0 Then

11 Me.Text = String.Empty

12 End If

13 End If

14 End Sub

15 End Class

В строках 1 и 2 объявляется специализированная версия обычного текстового поля. Поскольку при специализации на базе наследования сохраняются все члены базового класса, которые не подверглись явным изменениям, вам не придется прибегать к услугам программы-мастера (как в VB6), чтобы решить вопрос с неизменными свойствами — например, с основным цветом. При переопределении событий в производном классе обычно вызывается обработчик базового класса, как в строке 4. Необходимость этой строки связана с тем, что мы не программируем обработку этого события от начала и до конца, а хотим воспользоваться унаследованными аспектами поведения базового класса. В строках 5-6 предотвращается ввод нечисловых данных типа 32Skiddoo. В строках 9-12 из текстового поля удаляются дробные числа; при помощи встроенной функции Round программа убеждается в том, что округленное число совпадает с исходным. Следует заметить, что простое уничтожение введенного текста выглядит несколько жестоко по отношению к пользователю. В более изощренной программе следовало бы сохранить предыдущий текст, чтобы восстановить его при необходимости. В этом случае одна ошибка ввода не будет приводить к полной потере введенных данных.

На этой стадии приведенный выше фрагмент можно откомпилировать в DLL и получить вполне работоспособный элемент. Чтобы протестировать элемент после компиляции, создайте новое приложение Windows и поместите элемент на панель элементов:

  1. Выполните команду Tools > Customize Toolbox (или нажмите Ctrl+T).
  2. Перейдите на вкладку .NET Framework Components.
  3. Нажмите кнопку Browse и выберите DLL нужнопа^лемента (библиотека находится в подкаталоге \bin основного каталога решения).

Элемент помещается на вкладку .NET Framework Components (рис. 8.16).

Рис. 8.16. Нестандартный элемент на вкладке .NET Framework Components

Рис. 8.17. Нестандартный элемент на панели элементов

Нестандартный элемент размещается в нижней части панели (рис. 8.17). Дважды щелкните в строке Poslti velntegerTextBox, и элемент появится на форме. Обратите внимание: наш простейший элемент обладает всеми свойствами обычных текстовых полей и особенностями поведения, присущими текстовым полям в режиме конструирования. Все это было автоматически унаследовано от класса текстовых полей Windows. Forms. TextBox без малейших усилий с вашей стороны.

Элемент, помещенный на панель элементов, остается на ней и может использоваться в будущих проектах. Чтобы удалить элемент с панели, щелкните на нем правой кнопкой мыши и выберите команду Delete.

 

Добавление новых событий

Добавить поддержку нового события в элемент ничуть не сложнее, чем включить обработчик события в класс (эта тема рассматривалась в главе 6). Предположим, каждый раз, когда пользователь вводит нечто отличное от положительного целого числа, элемент должен инициировать событие BadDataEntered. Новый код класса выделен жирным шрифтом:

Public Class PositivelntegerTextBox

Inherits System.Windows.Forms.TextBox

Public Event BadDataEntered(ByVal Sender As Object, _

ByVal e As EventArgs)

Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)

MyBase.OnTextChanged(e)

If Not (IsNumeric(Me.Text)) Then Me.Text = String.Empty

RaiseEvent BadDataEntered(Me. New System.EventArgs()) Else

Dim temp As Decimal temp = CType(Me.Text,Decimal)

If temp = Math.Round(temp.0) <> 0 Then

Me.Text = String.Empty

RaiseEvent BadDataEntered(Me, New System.EventArgs())

End If

End If

End Sub

End Class

В элементах VB существует понятие события по умолчанию (default event). Событие по умолчанию срабатывает автоматически при двойном щелчке на экземпляре элемента в дизайнере форм. Событие по умолчанию задается при помощи специального атрибута. Атрибуты соответствуют экземплярам класса System.Attribute; атрибут Def aul tEvent входит в пространство имен System. ComponentModel. В программе атрибуты заключаются в угловые скобки, а при установке атрибута Defaul tEvent указывается имя события в кавычках. Чтобы назначить событие BadDataEntered событием по умолчанию для данного элемента, приведите начало класса к следующему виду:

Imports System.ComponentModel

<DefaultEvent("BadDataEntered")> Public Class _

PositivelntegerTextBox

Inherits System.Windows.Forms.TextBox