Иллюстрированный самоучитель по VB.NET

         

Динамическая обработка событий


Основной проблемой синтаксиса 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


    Содержание раздела