1)PreviewMouseLeftButtonDown 是隧道事件,從根節點往下傳遞
2)MouseLeftButtonDown 是冒泡事件,從下往根節點傳遞
3)知道這兩點,再來看前面從 PreviewMouseLeftButtonDown 到 MouseUp 的整個過程及 Click 在當中所處的順序,就好理解不少
4)具體:
鼠標即將點下,從根節點往下傳遞
->控件接受到鼠標點下,從下往根節點冒泡
->鼠標即將彈起,從上往下傳遞
->控件接受到鼠標要鬆開,如果 ButtonBase 等有 Click 事件的控件則觸發 Click 事件
->控件從下往上冒泡鼠標彈起事件。code
<StackPanel x:Name="s0" Height="100" Width="200" Background="Red" PreviewMouseLeftButtonDown="PreviewMouseLeftButtonDownEventHandler" PreviewMouseDown="PreviewMouseDownEventHandler" MouseLeftButtonDown="MouseLeftButtonDownEventHandler" MouseDown="MouseDownEventHandler" PreviewMouseLeftButtonUp="PreviewMouseLeftButtonUpEventHandler" PreviewMouseUp="PreviewMouseUpEventHandler" MouseLeftButtonUp="MouseLeftButtonUpEventHandler" MouseUp="MouseUpEventHandler"> <StackPanel x:Name="s1" Height="90" Width="180" Background="Yellow" PreviewMouseLeftButtonDown="PreviewMouseLeftButtonDownEventHandler" PreviewMouseDown="PreviewMouseDownEventHandler" MouseLeftButtonDown="MouseLeftButtonDownEventHandler" MouseDown="MouseDownEventHandler" PreviewMouseLeftButtonUp="PreviewMouseLeftButtonUpEventHandler" PreviewMouseUp="PreviewMouseUpEventHandler" MouseLeftButtonUp="MouseLeftButtonUpEventHandler" MouseUp="MouseUpEventHandler"> <Button x:Name="btn" Height="40" Width="78" Content="click" Click="Button_ClickEventHandler" MouseLeftButtonDown="MouseLeftButtonDownEventHandler" PreviewMouseLeftButtonDown="PreviewMouseLeftButtonDownEventHandler" PreviewMouseDown="PreviewMouseDownEventHandler" MouseDown="MouseDownEventHandler" PreviewMouseLeftButtonUp="PreviewMouseLeftButtonUpEventHandler" PreviewMouseUp="PreviewMouseUpEventHandler" MouseLeftButtonUp="MouseLeftButtonUpEventHandler" MouseUp="MouseUpEventHandler"> </Button> </StackPanel> </StackPanel>
private void PrintControlAndEvent(string controlName, string routedEventName) { Console.WriteLine(string.Format("{0} : {1}", controlName, routedEventName)); } private void PreviewMouseLeftButtonDownEventHandler(object sender, MouseButtonEventArgs e) { PrintControlAndEvent((sender as FrameworkElement).Name, e.RoutedEvent.ToString()); } ... private void Button_ClickEventHandler(object sender, RoutedEventArgs e) { PrintControlAndEvent((sender as FrameworkElement).Name, e.RoutedEvent.ToString()); }
輸出:orm
s0 : UIElement.PreviewMouseLeftButtonDown s0 : Mouse.PreviewMouseDown s1 : UIElement.PreviewMouseLeftButtonDown s1 : Mouse.PreviewMouseDown btn : UIElement.PreviewMouseLeftButtonDown btn : Mouse.PreviewMouseDown s0 : UIElement.PreviewMouseLeftButtonUp s0 : Mouse.PreviewMouseUp s1 : UIElement.PreviewMouseLeftButtonUp s1 : Mouse.PreviewMouseUp btn : UIElement.PreviewMouseLeftButtonUp btn : Mouse.PreviewMouseUp btn : ButtonBase.Click
輸出:事件
s0 : UIElement.PreviewMouseLeftButtonDown s0 : Mouse.PreviewMouseDown s1 : UIElement.PreviewMouseLeftButtonDown s1 : Mouse.PreviewMouseDown s1 : UIElement.MouseLeftButtonDown s1 : Mouse.MouseDown s0 : UIElement.MouseLeftButtonDown s0 : Mouse.MouseDown s0 : UIElement.PreviewMouseLeftButtonUp s0 : Mouse.PreviewMouseUp s1 : UIElement.PreviewMouseLeftButtonUp s1 : Mouse.PreviewMouseUp s1 : UIElement.MouseLeftButtonUp s1 : Mouse.MouseUp s0 : UIElement.MouseLeftButtonUp s0 : Mouse.MouseUp
button 的 mousedown 等已經被內部處理了,Handled 已被標記爲 True。若是想強制執行,能夠路由
btn.AddHandler(Button.MouseDownEvent, new MouseButtonEventHandler(MouseDownEventHandler), true); btn.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(MouseLeftButtonDownEventHandler), true); btn.AddHandler(Button.MouseUpEvent, new MouseButtonEventHandler(MouseUpEventHandler), true); btn.AddHandler(Button.MouseLeftButtonUpEvent, new MouseButtonEventHandler(MouseLeftButtonUpEventHandler), true); 第三個入參: handledEventsToo: //若是爲 true,則將按如下方式註冊處理程序:即便路由事件在其事件數據中標記爲已處理,也會調用處理程序; //若是爲 false,則使用默認條件註冊處理程序,即當路由事件被標記爲已處理時,將不調用處理程序。
xaml 裏寫的 MouseLeftButtonDown="MouseLeftButtonDown" 的 handledEventsToo 值就是 false。
因此,在已經被內部處理的狀況下,沒法觸發。
而即便在後臺寫 true,也只能觸發 Button 的 MouseDownEvent,不會繼續往上傳遞。
由於 handled 標記爲 true,除非再把上層的控件也添加路由回調爲 true。string