|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Побудова
класів подій
У
попередньому прикладі ми скористалися готовим класом System.EventArgs. Можливості
цього класу вельми обмежені, оскільки його конструктор викликається без
аргументів. При професіональнішому підході в програмі визначається новий клас події,
доповнюючий цей базовий клас. Наприклад, в нього можна включити ReadOnly-свойство,
що повертає інформацію про передбачуване підвищення зарплати, і іншу
властивість для тексту повідомлення. Приклад подібного класу приведений нижче (вирішення
Customeventargexample в архіві). Запрошуване зростання зарплати і повідомлення інкапсулюються в
конструкторі події. Надалі для отримання цих даних використовуються дві властивості, доступних
тільки для читання: Public Class Impropersalaryraiseevent Inherits System.EventArgs Private m_message As String Private m_theraise As Decimal Sub New(Byval
theraise As Decimal. Byval thereason As String) Mybase.New() m_message = thereason m_theraise = theraise End Sub Readonly Property
Message() As String Get Return
m_message End Get End
Property Readonly Property theraise() As Decimal Get Return
m_theraise End Get End Property End Class Після того,
як цей клас буде включений в рішення, слід внести невеликі зміни до
оголошення події в класі Empl oyee: Public Event Salarysecurityevent(Byval Sender As Customeventargexample.EmployeeWithEvents. Byvale As Impropersalaryraiseevent) Тепер в
другому аргументі передається змінна класу Impropersalaryrai seevent. Наступні
зміни вносяться до фрагмента, в якому безпосередньо викликається подія: Public Overloads Sub Raisesalary(Byval Percent As Decimal) If Percent >
LIMIT Then ' Операція заборонена - необхідний пароль Raiseevent Salarysecurityevent(Me New Impropersalaryraiseevent(Percent, "INCORRECT PASSWORD!")) Else m_salary =(1 + Percent) * m_salary End If End Sub Залишається
лише злегка виправити код обробника події (зміни виділені жирним шрифтом). Module
Modulel Private Withevents
anemployee As Employeewitheventsii Sub Maine) Dim tom As New Employeewitheventsii("Tom". 100000) anemployee = tom Console.Wntel_ine(tom.TheName &"has salary " & tom.Salary) anemployee.RaiseSalary(0.2d)'Суфікс D - ознака типу Decimal Console.WriteLine(tom.TheName & "still has salary " & tom.Salary) Console.Writeline("Please press the Enter key") Console.ReadLine() End
Sub Public Sub anemployee_salarysecuhtyevent(Byval Sender _ As Customeventargexample.EmployeeWithEvents. Byval e As Customeventargexample.ImproperSalaryRaiseEvent) Handles anemployee.SalarySecurityEvent Msgbox(Sender.TheName & "had an improper salary raise of " & _ Formatpercent(e.theRaise)& "with INCORRECT PASSWORD!") End Sub End Module Результат показаний на наступному малюнку. Як видно з малюнка, дані про запитане зростання заробітної плати доступні в обробнику події.
Основною проблемою
синтаксису Withevents є його недостатня гнучкість. Обробники подій
не можна динамічно встановлювати і відключати на програмному рівні —
фактично вся схема обробки подій жорстко фіксується в програмі. Проте
в VB .NET підтримується інший спосіб динамічної обробки подій, значно
гнучкіший. Він заснований на можливості вказівки процедури класу-приймача, що
викликається при виникненні події (виключення доданих обробників також
відбувається динамічно). Звичайно,
для установки обробника події необхідно зареєструвати не тільки клас-приймач,
але і метод, який повинен викликатися при виникненні події. Для цієї мети
застосовується команда Addhandler, якою при виклику передаються два параметри:
Код Addhandl ег
включається в клас-приймач, а не в клас-джерело. Адреса методу, що викликається
при виникненні події, визначається оператором Addressof. При виклику Addressof
передається ім'я методу об'єкту класу-приймача. Наприклад, наступна команда
встановлює динамічний обробник події для об'єкту tom: Addhandler tom.SalarySecurityEvent.AddressOf
anemp1oyee_salarysecurityevent В
результаті тестова програма виявлятиме подію Sal arysecuri tyevent об'єкту
tom і у разі його виникнення — викликати процедуру anemployee_salarysecurityevent
поточного модуля (зрозуміло, процедура anemployee_salarysecurityevent повинна
володіти правильною сигнатурою!). Нижче приведений
фрагмент вирішення Addhandlerexamplel (ключові рядки виділені жирним шрифтом): Module
Modulel Private Withevents
anemployee As Employeewithevents Sub Main() Dim torn As New Employeewithevents("Tom". 100000) Console.WriteLine(tom.TheName & "has salary " & tom.Salary) Addhandler tom.SalarySecurityEvent, Addressof anemployee_salarysecurityevent tom.RaiseSalary(0.2d) ' Суфікс D - ознака типу Decimal Console.WriteLine(tom.TheName & "still has salary " & tom.Salary) Console.WriteLine("Please press the Enter key") Console. Readline() End
Sub Public Sub anemployee_salarysecurity?vent(Byval Sender _ As Addhandlerexamplel.EmployeeWi thevents,_ Byval e As Addhandlerexamplel.ImproperSalaryRaiseEvent)_ Handles anemployee.SalarySecurityEvent Msgbox(Sender.TheName
& "had an improper salary raise of " & _ Formatpercent(e.theRaise)& "with INCORRECT PASSWORD!") End Sub End Module Команда Addhandler
володіє просто неймовірною гнучкістю. Наприклад, установка обробників подій
може залежати від імені типу: If Typename(tom)="Manager"
Then Addhandler tom.SalarySecurityEvent.AddressOf _ anemployee_salarysecurityevent e End If Крім того,
один обробник подій можна пов'язати з декількома різними подіями, що
відбуваються в різних класах. Це дозволяє виконувати в VB .NET централізовану
обробку подій з динамічним призначенням обробників — в VB така можливість
зустрічається вперше. У приведеному нижче лістингу ініціюються різні події залежно
від переданих параметрів командного рядка. Головне місце в нім займають фрагменти
вигляду Case
"first" Addhandler m_eventgenerator.TestEvent,_ Addressof m_eventgenerator_testeventl При передачі
в командному рядку аргументу first встановлюється відповідний обробник
події. У програмі
використовується корисний метод Getcommandlineargs класу System.Environment. Як
згадувалося в розділі 3, цей метод повертає масив аргументів командного рядка.
Початковий елемент масиву містить ім'я виконуваного файлу; оскільки індексація
масиву починається з 0, для отримання першого аргументу використовується виклик System.Environment.GetComman3LineArgs(l),
проте передварітельно
необхідно переконатися в існуванні аргументів командного рядка, для чого перевіряється
довжина масиву System.Environment.GetCommandLineArgs. Перед запуском програми
перейдіть на сторінку Configuration Properties діалогового вікна Project Properties
і вкажіть аргументи командного рядка для тестування. Нижче приведений
повний початковий текст програми: Option
Strict On Module Modulel Private m_eventgenerator As Eventgenerator Sub Main() m_eventgenerator=
New Eventgenerator() Dim commandlinesoas
String = System.Environment.GetCommandLineArgs If commandlines.Length
= 1 Then Msgbox("No command argument.program ending!") Environment.Exit(-l)
Else Dim thecommand As String = commandlines(l) Console.WriteLine("Thecommand lineoption is" Sthecommand) ' Перевірити параметр командного рядка і призначити ' відповідний обробник події. Select
Case thecommand Case "first" Addhandler m_eventgenerator.TestEvent. Addressof m_eventgenerator_testevent1 Case
"second" Addhandler m_eventgenerator.TestEvent,_ Addressof m_eventgenerator_testevent2 Case
Else Addhandler m_eventgenerator.TestEvent. Addressof m_eventgenerator_testeventdefault End
Select ' Ініціювати події m_eventgenerator.TriggerEvents() End
If Console.WriteLine("Press enter to end.") Console. Readline() End
Sub 'Обробник за умовчанням для непорожнього командного рядка Public Sub m_eventgenerator_testeventdefault(_ Byval sender
As Object.ByVal evt As Eventargs) System.Console.WriteLine("Default choice
" & _ m_eventgenerator.GetDescri
pti on()) End Sub ' Обробник 12 для рядка "first" Public Sub m_eventgenerator_testevent1(_ Byval sender As Object.ByVal evt As Eventargs) System.Console.WriteLineC'lst
choice " & _ m_eventgenerator.GetDescription())
End Sub 'Обробник 13 для рядка "second" Public Sub m_eventgenerator_testevent2( Byval sender As Object.ByVal evt As Eventargs) System.Console.WriteLinet"2nd choice " & _ m_eventgenerator.GetDescri
pti on ()) End Sub End Module Public
Class Eventgenerator ' У
класі визначається тільки одне подія Public Event
Testevent(Byval sender As Object, Byvalevt As Eventargs) ' Також
можна було використовувати конструктор за умовчанням Public Sub New() '
Порожній конструктор End
Sub .Public Function
Getdescription() As String Return "Eventgenerator class" End
Function ' Процедура викликається для ініціації подій Public Sub Triggerevents() Dim e As System.EventArgs = New System.EventArgs() Raiseevent Testevent(Me.e) End Sub End
Class
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||