Создание
диалоговых окон
Чтобы вывести
собственное диалоговое окно, создайте форму, задайте ее свойствам 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), которое
отдельные подразделения будут дополнять своими данными. Базовая форма создается
следующим образом:
- Выполните команду File
> New > Project.
- Выберите тип приложения
Windows Application, введите в поле Name строку SplashScreeriBase и нажмите
кнопку ОК.
Предположим,
вы хотите преобразовать стандартное приложение Windows в библиотеку классов,
чтобы откомпилировать его в DLL вместо ЕХЕ-файла. Проще всего это делается так:
- Щелкните правой кнопкой
мыши в строке SplashScreenBase окна решения и выберите в контекстном меню
команду Properties.
- Выберите в раскрывающемся
списке Output Type строку Class Library (вместо Windows Application). Нажмите
кнопку ОК.
- Сконструируйте форму,
разместите на ней нужные элементы, реализуйте свойства, методы и события.
- Откомпилируйте программу.
После построения
библиотеки 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 и поместите элемент на панель элементов:
- Выполните команду Tools
> Customize Toolbox (или нажмите Ctrl+T).
- Перейдите на вкладку
.NET Framework Components.
- Нажмите кнопку 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