WPF中在冒泡事件或者隧道事件會隨其層間關係在visual tree上層層傳遞,可是,某些事件傳遞到某些控件是即會」終止「(再也不響應相應的註冊事件),給人一種事件終結者的印象。例如:textbox對mousdown事件。html
產生緣由:事件處理到達該控件後,其事件對象屬性Handled被標記爲True。WPF事件引擎在處理控件對應事件時,若檢測到該屬性爲True,就不會調用相應的處理程序。即 WPF路由事件被標記爲handled之後, 並非不在visual tree上傳遞了;而是,事件引擎再也不去調用這個事件的handler了。express
若仍想再其上層元素中(上層是相對事件的傳遞方向而言)仍然處理響應的事件,解決方式:windows
一、若上層控件能夠註冊相應事件。即沒有重寫對應控件的Template屬性。直接上代碼:api
<Grid MouseDown="Grid_MouseDown" > <TextBox Name="txt1" Text="{Binding Path=txt1 ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" MouseDown="Txt_MouseDown" /> </Grid>
1 private void txt_MouseDown(object sender, MouseEventArgs e) 2 { 3 MessageBox.Show("TextMouseDown事件"); 4 e.Handled = false;//使冒泡繼續上傳 5 } 6 7 private void Grid_MouseDown(object sender, MouseEventArgs e) 8 { 9 MessageBox.Show("GridMouseDown事件"); 10 }
二、當自定義控件模板時,綁定模版事件不起效,此時用上面的方法再也不生效。例如:自定義列表控件模版樣式app
<UserControl x:Class="Test" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="290" d:DesignWidth="180"> <Grid name="gridMain"> <ItemsControl Focusable="False" Background="Transparent" ItemsSource="{Binding InfoModel, Mode=OneWay}"> <ItemsControl.Template> <ControlTemplate TargetType="ItemsControl"> <Border x:Name="scrBorder"> <ScrollViewer x:Name="scrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Padding="{TemplateBinding Padding}" MouseLeftButtonDown="MouseLeftButtonDown"> <ItemsPresenter /> </ScrollViewer> </Border> </ControlTemplate> </ItemsControl.Template> <ItemsControl.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Desc}" Grid.Column="0"/> <TextBlock Text="{Binding Value}" Margin="0" Grid.Column="1"/> <TextBlock Text="{Binding Unit}" Grid.Column="2" Margin="3,0,15,0"/> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel></StackPanel> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style> <Setter Property="Control.Margin" Value="1"/> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl> </Grid> </UserControl>
ScrollViewer在控件模版中,ScrollViewer的MouseButtonDown事件處理事件以下:斷點設置會發現鼠標點擊時並不會觸發。函數
1 private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 2 { 3 //e.Handled = false ; 4 }
解決辦法:UIElement.AddHandler 方法:爲指定的路由事件添加路由事件處理程序,並將該處理程序添加到當前元素的處理程序集合中。具體解釋詳見:https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.uielement.addhandler?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DZH-CN%26k%3Dk(System.Windows.UIElement.AddHandler);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)%26rd%3Dtrue&view=netframework-4.8ui
大致意思:因爲WPF事件visual tree上傳遞過程當中,某個元素將該事件標記爲已處理,致使事件在傳遞時再也不繼續有響應,(緣由:Handled被標記爲True)若是但願後續元素也能響應此方法,可使用此方法。url
所以咱們能夠在上面UserControl的構造函數中添加下面代碼:表示gridMain處理相應鼠標點擊事件spa
1 public UserControl() 2 { 3 InitializeComponent(); 4 5 gridMain.AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(MouseLeftButtonDown), true); 6 }
再次斷點調試MouseLeftButtonDown,會發現斷點命中。調試
AddHandler這個代碼的關鍵點是最後那個true,它告訴WPF引擎相應元素call這個handle,即便它被標記爲Handled=true。可是元素處理後其上層元素也照樣不會相應,由於handle仍被標記已處理。因而可知,WPF路由事件被標記爲handled之後,並非不在visual tree上傳遞了;而是,不去call這個handler了。
上例中若是想要UserControl繼續響應,處境就與1同樣了,只需將handle標記爲false便可。
引用博文:
https://www.cnblogs.com/DebugLZQ/archive/2013/05/07/3062733.html