1.路由事件的作用
路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。通俗地说,路由事件会在可视树(逻辑树是其子集)上,上下routed,如果哪个节点上订阅了事件,就会被触发。
路由事件的规则有三种:
(1)冒泡;由事件源向上沿视觉树传递一直到根元素。如 MouseDown
(2)直接;只有事件源才有机会响应事件,某个元素引发事件后,不传递到其他元素
(3)隧道;从元素树的根部调用事件处理程序并依次向下深入直到事件源。 一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的。隧道事件常常被称为Preview事件。如 PreviewMouseDown
可以通过 e.handled = true 来停止路由。
class="brush:csharp;collapse:true;;gutter:true;">using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Documents; namespace LY.ExamineRoutedEvents { public class ExamineRoutedEvents : Application { static readonly FontFamily fontfam = new FontFamily("宋体"); const string strformat = "{0,-30},{1,-15},{2,-15},{3,-15}"; StackPanel stackOutput; DateTime dtLast; [STAThread] public static void Main() { ExamineRoutedEvents app = new ExamineRoutedEvents(); app.Run(); } protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); Window win = new Window(); win.Title = "Examine Routed Events"; //建立Grid Grid grid = new Grid(); win.Content = grid; //建立三行 RowDefinition rowdef = new RowDefinition(); rowdef.Height = GridLength.Auto; grid.RowDefinitions.Add(rowdef); rowdef = new RowDefinition(); rowdef.Height = GridLength.Auto; grid.RowDefinitions.Add(rowdef); rowdef = new RowDefinition(); rowdef.Height = new GridLength(100, GridUnitType.Star); grid.RowDefinitions.Add(rowdef); //建立button,加入到grid Button btn = new Button(); btn.HorizontalAlignment = HorizontalAlignment.Center; btn.Padding = new Thickness(24); btn.Margin = new Thickness(24); grid.Children.Add(btn); //建立textblock,加入button TextBlock text = new TextBlock(); text.FontSize = 24; text.Text = win.Title; btn.Content = text; //建立标题,显示在ScrollViewer TextBlock textHeadings = new TextBlock(); textHeadings.FontFamily = fontfam; textHeadings.Inlines.Add(new Underline(new Run(string.Format(strformat, "Routed Events", "Sender", "Source", "OriginalSource")))); grid.Children.Add(textHeadings); Grid.SetRow(textHeadings, 1); //加入Scorllviewer ScrollViewer scroll = new ScrollViewer(); grid.Children.Add(scroll); Grid.SetRow(scroll, 2); //建立Stackpanel,放入Scorllviewer stackOutput = new StackPanel(); scroll.Content = stackOutput; //新增事件处理器 UIElement[] els = { win, grid, btn, text }; foreach (UIElement el in els) { // Keyboard el.PreviewKeyDown += AllPurposeEventHandler; el.PreviewKeyUp += AllPurposeEventHandler; el.PreviewTextInput += AllPurposeEventHandler; el.KeyDown += AllPurposeEventHandler; el.KeyUp += AllPurposeEventHandler; el.TextInput += AllPurposeEventHandler; // Mouse el.MouseDown += AllPurposeEventHandler; el.MouseUp += AllPurposeEventHandler; el.PreviewMouseDown += AllPurposeEventHandler; el.PreviewMouseUp += AllPurposeEventHandler; // Stylus el.StylusDown += AllPurposeEventHandler; el.StylusUp += AllPurposeEventHandler; el.PreviewStylusDown += AllPurposeEventHandler; el.PreviewStylusUp += AllPurposeEventHandler; //Window,Grid,Textblock类没有click事件,所以用在ButtonBase类中定义的AddHandler方法 el.AddHandler(Button.ClickEvent, new RoutedEventHandler(AllPurposeEventHandler)); } win.Show(); } void AllPurposeEventHandler(object sender, RoutedEventArgs e) { //如果有时间空隙,加入空格 DateTime dtNow = DateTime.Now; if (dtNow - dtLast > TimeSpan.FromMilliseconds(100)) stackOutput.Children.Add(new TextBlock(new Run())); dtLast = dtNow; //显示事件信息 TextBlock text = new TextBlock(); text.FontFamily = fontfam; text.Text = string.Format(strformat, e.RoutedEvent.Name, TypeWithoutNamespace(sender), TypeWithoutNamespace(e.Source), TypeWithoutNamespace(e.OriginalSource)); stackOutput.Children.Add(text); (stackOutput.Parent as ScrollViewer).ScrollToBottom(); } string TypeWithoutNamespace(object obj) { string[] str = obj.GetType().ToString().Split('.'); return str[str.Length-1]; } } }
2.自定义路由事件