Первый способ создания и обработки событий: WithEvents
Задача. Давайте смоделируем такую ситуацию: На вашем счете в банке лежит какая-то сумма. Вы приходите в магазин и хотите расплатиться за покупку кредитной карточкой, открытой на этот счет в банке. Вы отдаете карточку кассиру, тот направляет в банк приказ снять с вашего счета нужную сумму, приказ выполняется, кассир вам карточку возвращает. Все, покупка сделана. Задача программиста состоит в том, чтобы предусмотреть запрет на выполнение этой операции, если вы накупили товаров на сумму, превышающую ту, что у вас на счете. При этом у кассира должно возникнуть сообщение «На счете не хватает денег».
Приступим к решению. Магазин и банк относятся к тем фирмам, которые предпочитают хранить свою финансовую информацию в секрете друг от друга. Поэтому пусть магазин будет у нас формой, а для банка создадим свой класс. Класс будет очень простой, он ограничится вашим счетом и его обработкой.
Создайте проект. Разместите на форме текстовое поле, кнопку и метку. Создайте в проекте класс clsСчет. В этом классе будет присутствовать переменная Сумма_на_счете, объявленная Private, чтобы в магазине случайно не раскрыли тайну вклада клиента. Кроме этого в классе будет присутствовать метод Снятие_со_счета, смысл которого ясен из названия. Кассир вводит в текстовое поле сумму покупок, затем нажатием на кнопку формы запускает упомянутый метод, метод проверяет, хватает ли денег на счете, и если да, то уменьшает эти деньги на сумму покупок, а если нет, то порождает некое событие («передает сигнал» – RaiseEvent). На форме уже ждет наготове обработчик этого события. Он его воспринимает («принимает сигнал») и начинает выполняться, в результате чего метка на форме покажет текст «На счете не хватает денег».
С учетом сказанного разберитесь в приведенном ниже коде, а новинки я поясню:
Форма:
Private WithEvents
Счет As New clsСчет
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Счет.Снятие_со_счета(Val(TextBox1.Text))
End Sub
Private Sub Счет_Не_хватает_денег() Handles Счет.Не_хватает_денег
Label1.Text = "На счете не хватает денег"
End Sub
Класс:
Public Class clsСчет
Private Сумма_на_счете As Decimal = 1000
Public Event
Не_хватает_денег()
Public Sub Снятие_со_счета(ByVal Сумма_к_снятию As Decimal)
If Сумма_на_счете - Сумма_к_снятию >= 0 Then
Сумма_на_счете = Сумма_на_счете - Сумма_к_снятию
Else
RaiseEvent
Не_хватает_денег()
End If
End Sub
End Class
Пояснения: Вот последовательность действий банковского программиста, пишущего код класса и решившего использовать события:
Сначала он должен придумать событиям подходящие имена и объявить их при помощи слова Event (событие):
Public Event
Не_хватает_денег()
Затем он должен крепко подумать, в какие моменты выполнения кода его класса должны возникать эти события и во все места кода класса, где оно должно возникать, вставить оператор, порождающий это событие:
RaiseEvent
Не_хватает_денег()
В нашем случае событием является любая попытка сделать значение переменной Сумма_на_счете отрицательным. Такая попытка предпринята только в одном месте программы, поэтому оператор RaiseEvent встречается только один раз. В больших программах мест в коде, где встречаются соответствующие попытки, может быть несколько. В каждое место нужно будет вставить RaiseEvent.
Затем наш банковский программист должен позвонить магазинному программисту, пишущему код формы, и предупредить его, что класс теперь использует события, а значит порождать из него объекты нужно с использованием слова WithEvents:
Private WithEvents
Счет As New clsСчет
Когда программист, пишущий код формы, вставит эту строку в код формы, у него в поле, расположенном в верхней левой части окна кода, появится элемент Счет. Для создания обработчика останется только выбрать в поле, расположенном в верхней правой части окна кода, событие Не_хватает_денег этого элемента. Получится заготовка:
Private Sub Счет_Не_хватает_денег() Handles Счет.Не_хватает_денег
Важно понять следующую вещь: Событие не несет в себе никакой информации о том, что именно произошло. В нем ничего нет, кроме его названия. Как тогда программист, пишущий код формы, может быть уверен, что событие Не_хватает_денег возникает именно в тот момент, когда со счета пытаются снять больше, чем там есть? Уверенность может возникнуть только в том случае, если программист, пишущий код класса, пообещает, что так оно и есть на самом деле. Конечно, если код формы и класса пишет один и тот же программист (как в нашем случае), тогда другое дело.
Рассеиваем сомнения. Вы скажете: Того же эффекта можно добиться безо всяких событий, просто написав в коде класса вместо RaiseEvent Не_хватает_денег() оператор, меняющий текст на метке. Но я думаю, магазин не очень будет доволен, что банк протягивает свои длинные руки и так грубо вмешивается во внутренние дела фирмы (то есть формы). Конечно, есть и другие способы решить задачу, но все они хуже. Механизм событий очень гибок и не сует нос в чужие дела. Программисту класса в нашем случае не нужно даже ничего знать о том, как именно на форме будут обрабатывать его событие и будут ли обрабатывать вообще. Его дело – породить событие, а там хоть трава не расти.