使用事件
要在应用程序中使用事件,您必须提供一个事件处理程序(事件处理方法),该处理程序执行程序逻辑以响应事件并向事件源注册事件处理程序。 我们将该过程叫做事件连结。 Windows 窗体和 Web 窗体的可视设计器所提供的应用程序快速开发 (RAD) 工具简化(或者说隐藏)了事件连结的详细信息。
本主题介绍处理事件的常规模式。 有关 .NET Framework 中事件模型的概述,请参见事件和委托。 有关 Windows 窗体中事件模型的更多信息,请参见如何:在 Windows 窗体应用程序中使用事件。 有关 Web 窗体中事件模型的更多信息,请参见如何:在 Web 窗体应用程序中使用事件。
事件模式
由于不同 RAD 工具提供不同级别的支持,所以 Windows 窗体和 Web 窗体中的事件连接详细信息是不同的。 不过,两个方案遵循同一事件模式,该模式具有下列特征:
- 引发名为 EventName 事件的类具有以下成员:
Public Event EventName As EventNameEventHandler
public event EventNameEventHandler EventName;
public:
event EventNameEventHandler^ EventName;
- EventName 事件的事件委托是 EventNameEventHandler,它具有以下签名:
Public Delegate Sub EventNameEventHandler(sender As Object, e As EventNameEventArgs)
public delegate void EventNameEventHandler(object sender, EventNameEventArgs e);
delegate void EventNameEventHandler(Object^ sender, EventNameEventArgs^ e);
要使用 EventName 事件,您的事件处理程序必须与事件委托具有相同签名:
Sub EventHandler(sender As Object, e As EventNameEventArgs)
End Sub
void EventHandler(object sender, EventNameEventArgs e) {}
void EventHandler(Object^ sender, EventNameEventArgs^ e) {}
备注
.NET Framework 中的事件委托命名为 EventNameEventHandler,而文档中的术语“事件处理程序”指的是事件处理方法。命名方案后的逻辑是 EventNameEventHandler 委托指向实际处理事件的事件处理程序(方法)。
如果事件没有任何关联数据,则引发事件的类使用 System.EventHandler 作为委托,并将 System.EventArgs 作为事件数据。 具有关联数据的事件使用从事件数据类型的 EventArgs 派生的类以及相应的事件委托类型。 例如,如果您要处理 Windows 窗体应用程序中的 MouseUp 事件,则事件数据类是 MouseEventArgs,而事件委托是 MouseEventHandler。 请注意,某些鼠标事件使用事件数据的公共类和公共事件委托,因此命名方案与上面所述的约定不完全匹配。 对于鼠标事件,事件处理程序必须具有以下签名:
Sub Mouse_Moved(sender As Object, e As MouseEventArgs)
End Sub
void Mouse_Moved(object sender, MouseEventArgs e){}
void Mouse_Moved(Object^ sender, MouseEventArgs^ e){}
发送方和事件变量参数向事件处理程序提供有关鼠标事件的详细信息。 发送方对象指示引发事件的对象。 MouseEventArgs 参数提供有关引发事件的鼠标移动的详细信息。 许多事件源提供有关事件的其他数据,且许多事件处理程序在处理事件时使用事件特定的数据。 有关阐释如何引发和处理具有事件特定数据的事件的示例,请参见如何:引发和使用事件。
备注
事件也会发生在用户界面 (UI) 上下文之外,事实上,.NET Framework 包括许多引发事件的非 UI 类。但是,所有事件都遵循此处所述的模式。
有关从类引发事件的信息,请参见引发事件。
静态事件和动态事件
.NET Framework 允许订户为获得事件通知而进行静态或动态注册。 静态事件处理程序在其所处理的事件所属类的整个生存期内有效。 这是处理事件的最常用方法。 动态事件处理程序在程序执行期间显式激活和停用,通常是为了响应某些条件程序逻辑。 例如,如果只在特定条件下才需要事件通知,或者如果应用程序提供了多个事件处理程序,并由运行时条件来确定要使用哪个事件处理程序,则可以使用动态事件处理程序。
EventInfo.AddEventHandler 方法添加动态事件处理程序,而 EventInfo.RemoveEventHandler 方法停用这些事件处理程序。 各种语言还提供各自的用于动态处理事件的功能。 下面的示例定义一个 TemperatureMonitor 类,每当温度达到预定义的阈值时该类将引发 TemperatureTheshold 事件。 随后,在程序执行期间将激活和停用订阅此事件的事件处理程序。
public class TemperatureEventArgs : Inherits EventArgs
Private oldTemp As Decimal
Private newTemp As Decimal
Public ReadOnly Property OldTemperature As Decimal
Get
Return Me.oldTemp
End Get
End Property
Public ReadOnly Property NewTemperature As Decimal
Get
Return Me.newTemp
End Get
End Property
Public Sub New(oldTemp As Decimal, newTemp As Decimal)
Me.oldTemp = oldTemp
Me.newTemp = newTemp
End Sub
End Class
Public Delegate Sub TemperatureEventHandler(sender As Object, _
ev As TemperatureEventArgs)
Public Class TemperatureMonitor
Private currentTemperature As Decimal
Private threshholdTemperature As Decimal
Public Event TemperatureThreshold As TemperatureEventHandler
Public Sub New(threshHold As Decimal)
Me.threshholdTemperature = threshHold
End Sub
Public Sub SetTemperature(newTemperature As Decimal)
If (Me.currentTemperature > threshholdTemperature And _
newTemperature <= Me.threshholdTemperature) Or _
(Me.CurrentTemperature < Me.threshholdTemperature And _
newTemperature >= Me.threshholdTemperature) Then
OnRaiseTemperatureEvent(newTemperature)
End If
Me.currentTemperature = newTemperature
End Sub
Public Function GetTemperature() As Decimal
Return Me.currentTemperature
End Function
Protected Overridable Sub OnRaiseTemperatureEvent(newTemperature As Decimal)
RaiseEvent TemperatureThreshold(Me, New TemperatureEventArgs(Me.currentTemperature, _
newTemperature))
End Sub
End Class
Public Module Example
Public Sub Main()
Dim tempMon As New TemperatureMonitor(32d)
tempMon.SetTemperature(33)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
tempMon.SetTemperature(32)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
' Add event handler dynamically using Visual Basic syntax.
AddHandler tempMon.TemperatureThreshold, AddressOf TempMonitor
tempMon.SetTemperature(33)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
tempMon.SetTemperature(34)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
tempMon.SetTemperature(32)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
' Remove event handler dynamically using Visual Basic syntax.
RemoveHandler tempMon.TemperatureThreshold, AddressOf TempMonitor
tempMon.SetTemperature(31)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
tempMon.SetTemperature(35)
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.", _
tempMon.GetTemperature())
End Sub
Private Sub TempMonitor(sender As Object, e As TemperatureEventArgs)
Console.WriteLine(" ***Warning: Temperature is changing from {0} to {1}.", _
e.OldTemperature, e.NewTemperature)
End Sub
End Module
' The example displays the following output:
' Current temperature is 33 degrees Fahrenheit.
' Current temperature is 32 degrees Fahrenheit.
' Current temperature is 33 degrees Fahrenheit.
' Current temperature is 34 degrees Fahrenheit.
' ***Warning: Temperature is changing from 34 to 32.
' Current temperature is 32 degrees Fahrenheit.
' Current temperature is 31 degrees Fahrenheit.
' Current temperature is 35 degrees Fahrenheit.
using System;
public class TemperatureEventArgs : EventArgs
{
private decimal oldTemp;
private decimal newTemp;
public decimal OldTemperature
{
get { return this.oldTemp; }
}
public decimal NewTemperature
{
get { return this.newTemp; }
}
public TemperatureEventArgs(decimal oldTemp, decimal newTemp)
{
this.oldTemp = oldTemp;
this.newTemp = newTemp;
}
}
public delegate void TemperatureEventHandler(object sender, TemperatureEventArgs ev);
public class TemperatureMonitor
{
private decimal currentTemperature;
private decimal threshholdTemperature;
public event TemperatureEventHandler TemperatureThreshold;
public TemperatureMonitor(decimal threshhold)
{
this.threshholdTemperature = threshhold;
}
public void SetTemperature(decimal newTemperature)
{
if ( (this.currentTemperature > this.threshholdTemperature &&
newTemperature <= this.threshholdTemperature) ||
(this.currentTemperature < this.threshholdTemperature &&
newTemperature >= this.threshholdTemperature) )
OnRaiseTemperatureEvent(newTemperature);
this.currentTemperature = newTemperature;
}
public decimal GetTemperature()
{
return this.currentTemperature;
}
protected virtual void OnRaiseTemperatureEvent(decimal newTemperature)
{
// Raise the event if it has subscribers.
if (TemperatureThreshold != null)
TemperatureThreshold(this, new TemperatureEventArgs(this.currentTemperature,
newTemperature));
}
}
public class Example
{
public static void Main()
{
Example ex = new Example();
ex.MonitorTemperatures();
}
public void MonitorTemperatures()
{
TemperatureMonitor tempMon = new TemperatureMonitor(32);
tempMon.SetTemperature(33);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
tempMon.SetTemperature(32);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
// Add event handler dynamically using C# syntax.
tempMon.TemperatureThreshold += this.TempMonitor;
tempMon.SetTemperature(33);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
tempMon.SetTemperature(34);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
tempMon.SetTemperature(32);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
// Remove event handler dynamically using C# syntax.
tempMon.TemperatureThreshold -= this.TempMonitor;
tempMon.SetTemperature(31);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
tempMon.SetTemperature(35);
Console.WriteLine("Current temperature is {0} degrees Fahrenheit.",
tempMon.GetTemperature());
}
private void TempMonitor(object sender, TemperatureEventArgs e)
{
Console.WriteLine(" ***Warning: Temperature is changing from {0} to {1}.",
e.OldTemperature, e.NewTemperature);
}
}
// The example displays the following output:
// Current temperature is 33 degrees Fahrenheit.
// Current temperature is 32 degrees Fahrenheit.
// Current temperature is 33 degrees Fahrenheit.
// Current temperature is 34 degrees Fahrenheit.
// ***Warning: Temperature is changing from 34 to 32.
// Current temperature is 32 degrees Fahrenheit.
// Current temperature is 31 degrees Fahrenheit.
// Current temperature is 35 degrees Fahrenheit.