Правильное задание области применения в обработчиках событий
Распространенной ошибкой при программировании обработчиков событий является подключение обработчика события к объекту, который был объявлен с областью применения, слишком ограниченной для целей обработки этого события. Время жизни объекта не должно ограничиваться только функцией, подключающей метод обратного вызова в качестве обработчика события для объекта, но распространяться и на сам метод обратного вызова, в котором фактически обрабатывается событие. В противном случае, если объект оказывается вне области применения и больше не определен в методе обратного вызова, метод обратного вызова не вызывается и событие не обрабатывается нужным образом.
В следующем примере предпринимается попытка подключить метод обратного вызова MyNewInspector к событию NewInspector. Но метод обратного вызова в примере кода подключается к событию NewInspector объекта Inspectors, область применения которого ограничена функцией Connect. В результате, когда вызывается метод обратного вызова, программа уже вышла из функции Connect, объект Inspectors уже уничтожен сборщиком мусора, и поэтому MyNewInspector никогда не вызывается.
using Outlook = Microsoft.Office.Interop.Outlook;
class MyClass
{
private Outlook.Application MyApp;
public MyClass(Outlook.Application appOutlook)
{
MyApp = appOutlook;
}
// Connects the NewInspector event to my callback method
public void Connect()
{
MyApp.Inspectors.NewInspector += new Outlook.
InspectorsEvents_NewInspectorEventHandler(
MyNewInspector);
}
public void MyNewInspector(Outlook.Inspector inspector)
{
MessageBox.Show("
My event handler caught a NewInspector event");
}
}
. В следующем примере MyInspectors имеет область всего Класса MyClass и гарантирует, что метод обратного вызова подключен в течение времени существования класса.
using Outlook = Microsoft.Office.Interop.Outlook;
class MyClass
{
private Outlook.Application MyApp;
private Outlook.Inspectors MyInspectors;
public MyClass(Outlook.Application appOutlook)
{
MyApp = appOutlook;
}
// Connects the NewInspector event to my callback method
public void Connect()
{
MyInspectors = MyApp.Inspectors;
MyInspectors.NewInspector += new Outlook.
InspectorsEvents_NewInspectorEventHandler(
MyNewInspector);
}
public void MyNewInspector(Outlook.Inspector inspector)
{
MessageBox.Show("
My event handler caught a NewInspector event");
}
}
Благодаря синтаксическим различиям подключений обработчиков событий в различных языках эта проблема менее распространена в таких языках, как Visual Basic, где можно подключить событие, задавая экземпляр родительского объекта, и одновременно определить метод обратного вызова. В следующем примере в Visual Basic используется ключевое слово Handles для подключения метода обратного вызова Region_Expanded к событию Expanded. Экземпляр родительского объекта Region имеет область, охватывающий MyClass, включая метод обратного вызова Region_Expanded.
Imports Outlook = Microsoft.Office.Interop.Outlook
Public Class MyClass
' The Region object has a lifetime spanning the class
' including the callback method Region_Expanded
Private WithEvents Region As Outlook.FormRegion
...
Private Sub Region_Expanded() Handles Region.Expanded
MsgBox("My EventHandler caught an Expanded event.")
End Sub
End Class
В этом примере, так как метод обратного вызова Region_Expanded подключен к событию Expanded в течение времени существования класса, метод обратного вызова вызывается соответствующим образом.