WPF 基礎 - 點擊事件的執行順序及 Button 點擊事件的特殊性

1. 點擊事件的執行順序

  1. PreviewMouseLeftButtonDown
  2. PreviewMouseDown
  3. MouseLeftButtonDown
  4. MouseDown
  5. PreviewMouseLeftButtonUp
  6. PreviewMouseUp
  7. Click
  8. MouseLeftButtonUp
  9. MouseUp

1)PreviewMouseLeftButtonDown 是隧道事件,從根節點往下傳遞
2)MouseLeftButtonDown 是冒泡事件,從下往根節點傳遞
3)知道這兩點,再來看前面從 PreviewMouseLeftButtonDown 到 MouseUp 的整個過程及 Click 在當中所處的順序,就好理解不少
4)具體:
鼠標即將點下,從根節點往下傳遞
->控件接受到鼠標點下,從下往根節點冒泡
->鼠標即將彈起,從上往下傳遞
->控件接受到鼠標要鬆開,如果 ButtonBase 等有 Click 事件的控件則觸發 Click 事件
->控件從下往上冒泡鼠標彈起事件。code

2. 例子

<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());
}

2.1 點擊 Button

輸出: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

2.2 點擊 s1

輸出:事件

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

2.3 點擊 Button 後未能觸發 MouseLeftButtonDown、MouseLeftButtonUp、MouseDown、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

相關文章
相關標籤/搜索