什么是路由事件?
我們從兩個維度來理解路由事件:
功能的角度來看,路由事件是一種事件類型,不僅僅可以在事件源上處理事件響應,還可以在元素樹的多個偵聽器上處理事件響應(事件偵聽器是附加和調用事件處理程序的元素。事件源是最初引發事件的元素或對象)
實現的角度來看,路由事件是使用 CLR 事件“包裝器”實現的,由 RoutedEvent 類的實例支持,并由 WPF 事件系統處理。
根據路由事件的定義方式,當事件在源元素上引發時:
從源元素到根元素(通常是頁面或窗口)通過元素樹冒泡
從根元素到源元素通過元素樹向下隧道
不遍歷元素樹,只出現在源元素上
<Border Height="30" Width="200" BorderBrush="Gray" BorderThickness="1"><StackPanel?Background="LightBlue"?Orientation="Horizontal"?Button.Click="StackPanel_Click"><Button Name="YesButton">YES</Button><Button Name="NoButton">No</Button><Button Name="CancelButton">Cancel</Button></StackPanel>
</Border>
示例中的這三個Button都有自己Click事件,當觸發一個button的Click事件時,Button元素的Click事件沿著樹傳播到根節點,Button和Border沒有響應時間處理程序,但是StackPanel會響應。在這個例子中事件傳播:Button -> StackPanel -> Border -> 父元素
如何實現路由事件?
我們可以通過WPF框架提供的接口來注冊路由事件,由 RoutedEvent 類的實例支持。從注冊中獲得的 RoutedEvent 實例通常存儲為注冊它的類的公共靜態只讀成員。該類稱為事件“所有者”類。通常,路由事件是對同名 CLR 事件的“包裝器”。CLR 事件包裝器包含添加和刪除訪問器,以便通過特定于語言的事件語法在 XAML 和代碼隱藏中附加處理程序。add 和 remove 訪問器覆蓋其 CLR 實現并調用路由事件 AddHandler 和 RemoveHandler 方法。路由事件機制類似于依賴屬性的機制。
以下示例注冊 Tap 路由事件,存儲返回的 RoutedEvent 實例,并實現 CLR 事件包裝器。
// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(name: "Tap",routingStrategy: RoutingStrategy.Bubble,handlerType: typeof(RoutedEventHandler),ownerType:?typeof(CustomButton));// Provide CLR accessors for adding and removing an event handler.
public event RoutedEventHandler Tap
{add { AddHandler(TapEvent, value); }remove { RemoveHandler(TapEvent, value); }
}
路由策略
路由事件使用以下三種路由策略之一:
冒泡:最初,事件源上的事件處理程序被調用。路由事件然后路由到連續的父元素,依次調用它們的事件處理程序,直到它到達元素樹根。大多數路由事件使用冒泡路由策略。冒泡路由事件通常用于報告來自復合控件或其他 UI 元素的輸入或狀態更改。
隧道:最初,調用元素樹根處的事件處理程序。路由事件然后路由到連續的子元素,依次調用它們的事件處理程序,直到它到達事件源。遵循隧道路由的事件也稱為預覽事件。WPF 輸入事件通常實現為預覽和冒泡對。
直接:僅調用事件源上的事件處理程序。這種非路由策略類似于標準 CLR 事件的 Windows 窗體 UI 框架事件。與 CLR 事件不同,直接路由事件支持類處理并且可由 EventSetters 和 EventTriggers 使用。
為什么用路由事件?
軟件開發人員并需要知道你正在處理的事件是路由事件,路由事件本身具有自己的特性,如果你正在處理元素自身引發的事件,則該行為是不可用的。但是,如果你將事件附加到父元素或者子元素 ,這時路由事件就體現了它自己的特性。
路由事件支持沿事件路由的元素之間的事件信息交換,因為每個偵聽器都可以訪問相同的事件數據實例。如果一個元素更改了事件數據中的某些內容,則該更改對事件路由中的后續元素可見。?WPF 樣式和模板功能(例如 EventSetters 和 EventTriggers)要求引用的事件是路由事件。