- 浏览: 401050 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (309)
- xaml C# wpf (0)
- scala java inner clas (1)
- Tools UML Eclipse UML2 (1)
- Timer .NET Framework (1)
- perl (6)
- python function paramter (1)
- Python Docstring (1)
- Python how to compare types (1)
- Python (8)
- java (5)
- C# (76)
- C# WPF (0)
- p4 (0)
- WPF (46)
- .net (6)
- xaml (1)
- javascript (40)
- windows (10)
- scala (4)
- winform (1)
- c++ (48)
- tools (12)
- cmd (1)
- os (0)
- CI (0)
- shell (0)
- C (2)
- haskell (49)
- functional (1)
- tool (1)
- gnu (1)
- linux (1)
- kaskell (0)
- svn (0)
- wcf (3)
- android (1)
最新评论
Updated: there was a mistake in my impl, I referenced the code in PresentationCore and modified my code based on the findings.
Routed Event is a special Event in WPF and Silverlight where the Event can traval up/down the tree, and you can have a handler to the parent on the visual tree to handle the event coming from this chidlren.
There are two phases of the Event, they are called the RoutingStrategy
- Tunnel Phase / Or you can call it the capturing phase
- Bubble Phase
For more information about phase, please see the information RoutingStrategy.
First let's see the How to Register Routing Event and How we use use them
Routing Event
Register and Setup the Event
To Register the routing event, you may call the EventManager.RegisterRoutedEvent; Below shows the examle.
By convention, you should give the RoutedEvent static readonly field a name ended with the suffix Event.
public class MyButtonSimple : Button { // namespace of RoutedEvent is System.Windows. public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple)); }
You may provide add-and-remove common language runtiem (CLR() event accessor; so that in CODE you can add/remove event handlers
// CLR accessors // this is necessary if you want to manipulate the Event from the code public event RoutedEventHandler Tap { add { AddHandler(TapEvent, value); } remove { RemoveHandler(TapEvent, value); } }
You may add a method to raise the event, this can be used for example, exposing to the client...
// and methods that raises teh TapEvent // this is to allow cilent to raise the events void RaiseTapEvent() { RaiseEvent(new RoutedEventArgs(MyButtonSimple.TapEvent)); // you can try the overload to provide a default Sender //RaiseEvent(new RoutedEventArgs(MyButtonSimple.TapEvent, this)); }
We may raise the event through, e.g. OnClick event (ihow to raise the event and how the event responds to the changes to depends on your needs)
protected override void OnClick() { RaiseTapEvent(); // suppress the base's Click Event //base.OnClik(); }
Then comes how you use it ;
Use the RoutedEvent
Instance listeners are particular class instances/elements where one or more handlers have been attached for that routed event by a call to AddHandler. Existing WPF routed events make calls to AddHandler as part of the common language runtime (CLR) event wrapper add{} and remove{} implementations of the event, which is also how the simple XAML mechanism of attaching event handlers via an attribute syntax is enabled. Therefore even the simple XAML usage ultimately equates to an AddHandler call.
Instance Handlers
You can use the event handler by providing an handler to the instance of MyButtonSimple in Xaml, or in CLR. Or you can register an handler to the event in the parent node, which is capable of handling any events that is coming from MyButtonSimple instance, also in Xaml or in CLR.
To register an handler through an instance method/object is called the Routed Event's Instance Handlers.
Below shows you how to use Instance Handlers to reponse to the custom Routed Event.
<Window x:Class="RoutedEventsTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:custom="clr-namespace:RoutedEventsTest" > <Window.Resources> <Style TargetType="{x:Type custom:MyButtonSimple}"> <Setter Property="Height" Value="20"/> <Setter Property="Width" Value="250"/> <Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="Background" Value="#808080"/> </Style> </Window.Resources> <StackPanel Background="LightGray" custom:MyButtonSimple.Tap="MainWindowTapHandler" > <custom:MyButtonSimple x:Name="mybtnSimple" Tap="TapHandler">Click to Tap Custom event</custom:MyButtonSimple> <custom:MyButtonSimpleDerived x:Name="mybtnSimpleDerived">Click to tap Custom Event on Derived Class</custom:MyButtonSimpleDerived> </StackPanel> </Window>
and below is the code behind code, where the TapHandler and MainWindowTapHandler are defined.
namespace RoutedEventsTest { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void TapHandler(object sender, RoutedEventArgs e) { Console.WriteLine("Instance Handler at child node"); // if you set the Handler to true, then the Bubbling will stop //e.Handled = true; } private void MainWindowTapHandler(object sender, RoutedEventArgs e) { Console.WriteLine("Instance Handler at the parent node"); } } }
Class Handlers
Class listeners exist because types have called a particular EventManager API ,RegisterClassHandler, in their static constructor, or have overridden a class handler virtual method from an element base class
Class Handlers respond before instance handlers
On each given element node in an event route, class listeners have the opportunity to respond to the routed event before any instance listener on the element can.
class handlers are sometimes used to suppress routed events that a particular control class implementation does not wish to propagate further, or to provide special handling of that routed event that is a feature of the class. For instance, a class might raise its own class-specific event that contains more specifics about what some user input condition means in the context of that particular class. ...
To register a Class Handler, you can do is to call EventManager.RegisterClassHandler in its static constructor.
static MyButtonSimple() { EventManager.RegisterClassHandler(typeof(MyButtonSimple), TapEvent, new RoutedEventHandler(ClassOnTapEvent)); } internal static void ClassOnTapEvent(object sender, RoutedEventArgs e) { Console.WriteLine("Class handler fire ealier than any instance handler"); }
Class Handler Virtuals
Let's first see what is the class handler virtuals...
Some elements, particularly the base elements such as UIElement, expose empty "On*Event" and "OnPreview*Event" virtual methods that correspond to their list of public routed events. These virtual methods can be overridden to implement a class handler for that routed event. The base element classes register these virtual methods as their class handler for each such routed event using RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) as described earlier. The On*Event virtual methods make it much simpler to implement class handling for the relevant routed events, without requiring special initialization in static constructors for each type.
Below I will show you to implement the Class Handler Virtuals
First you might call EventManager.ReisterClassHandler on the Constructor; and you may provide an empty OnXXX handler with protected virtua lpattern
public MyButtonSimple() { EventManager.RegisterClassHandler(typeof(MyButtonSimple), TapEvent, new RoutedEventHandler(OnTapEvent)); } protected virtual void OnTapEvent(object sender, RoutedEventArgs e) { // this is empty to allow dervied class to override it Console.WriteLine("Class Handler Virtuals makes it much simpler to implement class handling for the relevant routed events, without requiring special initialization in static constructor for each type"); }
Then you can create a derived class, which override the OnTap methods.
public class MyButtonSimpleDerived : MyButtonSimple { protected override void OnTap(object sender, RoutedEventArgs e) { Console.WriteLine("You can override the base's OnXXXEvent"); // Calling the base implementation is strongly recommended because the virtual method is on the base class. //base.OnTapEvent(sender, e); } }
And last you add the Derived class to xam or in CLR.
One tip on how to implement the Class Handlers Virtuals:
Calling the base implementation is strongly recommended because the virtual method is on the base class. The standard protected virtual pattern of calling the base implementations from each virtual essentially replaces and parallels a similar mechanism that is native to routed event class handling, whereby class handlers for all classes in a class hierarchy are called on any given instance, starting with the most-derived class' handler and continuing to the base class handler. You should only omit the base implementation call if your class has a deliberate requirement to change the base class handling logic. Whether you call the base implementation before or after your overriding code will depend on the nature of your implementation.
Order of the Class Handlers and Instance Handlers.
the order would be (giving that the routing event strategy is Bubbling)
- Class Handler
- Class handlers virtual
- Instance Handler where the Tap event is used (Child)
- Instance handler at the parent node (parent)
Give the code in this example, you will see the following output if you click on the mybuttonSimple
Class handler fire ealier than any instance handler
Class Handler Virtuals makes it much simpler to implement class handling for the relevant routed events, without requiring special initialization in static constructor for each type
You can override the base's OnXXXEvent
Instance Handler at child node
Instance Handler at the parent node
Do you see the problem?
The System.Window.UIElement impl on Class handler virtuals
the problem is that both the derived OnTap and the Base's OnTap are called.
The reason is when mybuttonSimple create, MyButtonSimple.OnTap is added as a class handler. and when myButtonSimpleDerived is created, the MyButtonSimpleDerived is added as a class handler, and you end up have both the base and derived classes OnXXX method called.
Below is the revised code after reading the Presenation's code.
static MyButtonSimple() { EventManager.RegisterClassHandler(typeof(MyButtonSimple), TapEvent, new RoutedEventHandler(OnTapThunk)); } internal static void OnTapThunk(object sender, RoutedEventArgs e) { Console.WriteLine("Class handler fire ealier than any instance handler"); MyButtonSimple buttonSimple = sender as MyButtonSimple; if (buttonSimple != null) { buttonSimple.OnTap(sender, e); } }
Now, the full code of MyButtonSimple and MyButtonSimpleDerived is as follow.
namespace RoutedEventsTest { public class MyButtonSimple : Button { // namespace of RoutedEvent is System.Windows. public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple)); // CLR accessors // this is necessary if you want to manipulate the Event from the code public event RoutedEventHandler Tap { add { AddHandler(TapEvent, value); } remove { RemoveHandler(TapEvent, value); } } // and methods that raises teh TapEvent // this is to allow cilent to raise the events void RaiseTapEvent() { RaiseEvent(new RoutedEventArgs(MyButtonSimple.TapEvent)); // you can try the overload to provide a default Sender //RaiseEvent(new RoutedEventArgs(MyButtonSimple.TapEvent, this)); } protected override void OnClick() { RaiseTapEvent(); // suppress the base's Click Event //base.OnClik(); } static MyButtonSimple() { EventManager.RegisterClassHandler(typeof(MyButtonSimple), TapEvent, new RoutedEventHandler(OnTapThunk)); } internal static void OnTapThunk(object sender, RoutedEventArgs e) { Console.WriteLine("Class handler fire ealier than any instance handler"); MyButtonSimple buttonSimple = sender as MyButtonSimple; if (buttonSimple != null) { buttonSimple.OnTap(sender, e); } } protected virtual void OnTap(object sender, RoutedEventArgs e) { // this is empty to allow dervied class to override it Console.WriteLine("Class Handler Virtuals makes it much simpler to implement class handling for the relevant routed events, without requiring special initialization in static constructor for each type"); } } public class MyButtonSimpleDerived : MyButtonSimple { protected override void OnTap(object sender, RoutedEventArgs e) { Console.WriteLine("You can override the base's OnXXXEvent"); // Calling the base implementation is strongly recommended because the virtual method is on the base class. //base.OnTapEvent(sender, e); } } }
References:
You may find this Karl's blog very intereseting. - WPF Samples Series - EventManger RegisterClassHandler
发表评论
-
wpf - example to enhance ComboBox for AutoComplete
2014-09-19 15:56 1979first let’s see an example ... -
WPF – Virtualization – VirutalizationStackPanel and ItemsPanelTemplate
2013-08-05 21:55 1421Topic: WPF – Virtualization – ... -
wpf - BehaviorBase and one use examples
2013-06-18 18:41 1318Behavior is something that we ... -
WPF - Setting foreground color of Entire window
2013-06-13 16:00 1925You might as well as I would s ... -
WPF - Enhanced TabControl - TabControlEx aka Prerendering TabControl
2013-06-13 13:12 5337As an opening word, let's che ... -
wpf - ControlTemplate and AddLogicChild/RemoveLogicalChild
2013-06-10 15:42 1191Recently I was trying to debug ... -
wpf - default implicit style
2013-05-10 10:24 796We know that if you left out ... -
wpf - Style setter on the attached property
2013-05-08 14:54 2857I believe that you are familia ... -
wpf - specify enum values in xaml
2013-05-08 11:31 3592Many a situation you find tha ... -
wpf - IG xamDataGrid bind to XmlDataProvider with Xml Island
2012-12-18 14:28 1289Sometimes you may bind to some ... -
wpf - translate winform button/mouse event to wpf events
2012-12-12 17:37 2166It is common that we sometimes ... -
wpf - Freezable and its meaning
2012-09-27 12:38 0This article is based on the di ... -
wpf - Customize the grid lines for original wpf Grid control
2012-09-27 12:01 1461The System.WIndows.Controls.Gri ... -
c# - Convert from System.Drawing.Image to System.WIndows.Media.ImageSource
2012-09-25 14:27 7421In Previous discussion, we have ... -
wpf - Get Effective DependencyProperty value on a DependencyObject
2012-08-28 19:05 1048As discussed in my previous pos ... -
wpf - Default(Theme) style and its DefaultStyleKey
2012-08-28 17:54 1392As dicsused in the subsection o ... -
wpf - Dependency Property Value Precedence
2012-08-28 18:56 886A dependency property to an Dep ... -
wpf - WPF TemplateBinding vs RelativeSource TemplatedParent
2012-08-28 14:20 3719This is a post that summarizes ... -
wpf - ICutomTypeDescriptor , PropertyDescriptor and its use in PropertyGrid
2012-08-28 14:04 3589The type ICustomTypeDe ... -
wpf - tips to convert UI controls in WPF/Silverlight/Winforms into a Bitmap
2012-08-27 17:44 986In previous discussion, we have ...
相关推荐
【标题】"WPF-JJDown-v1.234.0" 提示我们这是一个基于Windows Presentation Foundation(WPF)的应用程序,名为JJDown。版本号v1.234.0表明这是该软件的第1次重大更新,第234次次要更新或修复。这通常意味着它经历了...
gong-wpf-dragdrop, GongSolutions.WPF.DragDrop 库是WPF的拖动'n'拖放框架 简介GongSolutions.WPF.DragDrop 库是一个易于使用的拖拉'n'拖放框架。特性使用 MVVM: 拖放逻辑可以放在ViewModel中。 代码不需要放在in中...
【WPF】是一种Windows Presentation Foundation的简称,是微软.NET Framework的一部分,用于构建Windows桌面应用程序的UI框架。WPF提供了一套完整的图形呈现系统,包括2D和3D图形、动画、布局、文本渲染等,同时也...
在本项目"WPF-MaterialDesign-master.zip"中,重点在于利用**Material Design**这一设计语言来增强WPF应用的视觉效果。Material Design是Google推出的一种设计规范,其灵感来源于现实世界中的纸张和墨水,强调层次感...
Prism-Samples-Wpf-master11-15的VS2017版本实现,下载手动重新安装一下nuget包即可,方便大家学习
**WPF-Blockly** 是一个基于Windows Presentation Foundation (WPF) 的图形化编程工具,它为用户提供了构建和设计程序的直观界面。WPF作为Microsoft .NET Framework的一部分,主要用于构建桌面应用程序,它提供了...
【标题】"wpf-4_SourceCode.zip" 提供的是 WPF 4 技术的实战源代码,对应书籍 "WPF 4 Unleashed" 的配套资源。这本书由业界专家编写,深入探讨了Windows Presentation Foundation (WPF) 4 的各个方面,旨在帮助读者...
gong-wpf-dragdrop-develop.rar
《Pro WPF 4.5 in C# 4th Edition》是关于Windows Presentation Foundation(WPF)技术的一部权威著作,由资深.NET开发者撰写。这个压缩包包含的是书中的第21章到第30章的源代码示例,旨在帮助读者深入理解和实践WPF...
GongSolutions.WPF.DragDrop 一种易于使用的WPF拖放框架。 支持.NET Framework 4.5+和.NET Core 3(3.0和3.1) 产品特点 与MVVM一起使用:拖放的逻辑可以放在ViewModel中。 无需在代码背后放置任何代码,而是将...
WPF-进阶视频教程(共113集)-028样式选择器.mp4
WPF-进阶视频教程(共113集)-059隔离存储区.mp4
WPF-进阶视频教程(共113集)-031模板选择器.mp4
WPF-进阶视频教程(共113集)-036使用范围分组.mp4
WPF-进阶视频教程(共113集)-050组合到一起.mp4
WPF-进阶视频教程(共113集)-085块元素1.mp4
WPF-进阶视频教程(共113集)-086块元素2.mp4
WPF-进阶视频教程(共113集)-113ClickOnce部署.mp4
WPF-进阶视频教程(共113集)-068媒体播放器窗口.mp4
WPF-进阶视频教程(共113集)-047非矩形窗口.mp4