3.2 Custom Routed Events
In order to facilitate communication between objects in the program, we usually need to define some routed events ourselves. So how do you create custom routed events? The following example illustrates the creation of a custom routed event.
Creating a custom routed event is generally divided into three steps:
- Declaring and registering routed events
First, defining a routed event is very similar to the definition of a dependency property--Declaring a field of type RoutedEvent modified by public static ReadOnly, You then use the Registerroutedevent method of the EventManager class to register. The code for the complete registered routed event is as follows:
Declares and registers a routed event public static readonly RoutedEvent clickevent = eventmanger.registerroutedevent ("click", Routingstrategy.bubble,typeof (Routedeventhandler), typeof (ButtonBase));
Let's analyze the four parameters of the Eventmanger.registerroutedevent method.
The first argument is of type string, which is called the name of the routed event. According to Microsoft's recommendation, the prefix of the string routedevent variable is consistent with the name of the CLR event wrapper. In this case, the name of the route variable is clickevent, and the string is click.
The second parameter is a policy for routed events, in WPF, there are three strategies for routed events:
- Bubble, bubbling: A routed event starts at the container that fires it, passing up the layer up to the outermost container (window or page).
- Tunnel, tunnel: Routed events are passed in the same direction as bubble, which is moved by the root of the UI tree to the control that fires the event
- Direct, Direct: simulates a CLR direct event, delivering the message directly to the event handler
The third parameter is used to specify the type of the event handler. The event handler's return value type and parameter list must be consistent with the delegate specified by this parameter, or it will cause the compile-time exception to be thrown.
The fourth parameter is used to indicate which type of host the routed event is.
- To create a CLR event wrapper for routed events
Adding a CLR event wrapper for routed events is to expose routed events much like a traditional direct event, and without paying attention to the underlying implementation, the programmer will not feel the difference between it and the traditional direct event. In programming, you can still add event handlers for events using the + = number and use-= To remove event handlers that are no longer used.
- Create a method that can fire routed events
The way to fire a routed event is simple, first create a message that needs to be carried by the event and associate it with the routed event, and then call the element's RaiseEvent method to send the event.
Let's do it ourselves. A routed event is created that is used to report when an event occurs. This is an example of how custom routed events are created.
As mentioned above, there are three steps to creating a custom routed event, namely declaring and registering routed events, adding a wrapper for the CLR to routed events, and firing routed events. In this case, we want to fire the routed event, first to create a message that needs to be carried by the event. The so-called "no movement, fodder first", we start by creating an event parameter that is used to host the message.
1 //event arguments for hosting time messages2 classReporttimeeventargs:routedeventargs3 {4 PublicDateTime Clicktime {Get;Set; }5 6 PublicReporttimeeventargs (RoutedEvent routedevrent,ObjectSOURCE):Base(Routedevrent,source)7 {8 9 }Ten}
Then, create a derived class of the button class and add routed events for it as described in the previous steps:
1 classTimebutton:button2 {3 //declaring, registering routed events4 Public Static ReadOnlyRoutedEvent reporttimeevent = eventmanager.registerroutedevent ("Reporttime", Routingstrategy.bubble,typeof(eventhandler<reporttimeeventargs>),typeof(Timebutton));5 6 //CLR Event wrapper7 Public EventRoutedeventhandler Reporttime8 {9Add { This. AddHandler (reporttimeevent, value); }TenRemove { This. RemoveHandler (Reporttimeevent,value); } One } A - //fires a routed event, borrowing the Click event's firing method - the protected Override voidOnClick () - { - Base. OnClick (); - +Reporttimeeventargs args =NewReporttimeeventargs (Reporttimeevent, This); -Args. Clicktime =DateTime.Now; + This. RaiseEvent (args); A } at}
Here is the interface XAML code for the program:
1 <Windowx:class= "_02_ a custom routed event. MainWindow "2 xmlns= "Http://schemas.microsoft.com/winfx/2006/xaml/presentation"3 xmlns:x= "Http://schemas.microsoft.com/winfx/2006/xaml"4 xmlns:d= "http://schemas.microsoft.com/expression/blend/2008"5 XMLNS:MC= "http://schemas.openxmlformats.org/markup-compatibility/2006"6 xmlns:local= "Clr-namespace:_02_ Custom routed event"7 mc:ignorable= "D"8 Title= "Routed Event"Height= "+"Width= "+"Name= "Window_1"9 Local:TimeButton.ReportTime= "Reporttimehandle">Ten <GridName= "Grid_1"Local:TimeButton.ReportTime= "Reporttimehandle"> One <GridName= "Grid_2"Local:TimeButton.ReportTime= "Reporttimehandle"> A <GridName= "Grid_3"Local:TimeButton.ReportTime= "Reporttimehandle"> - <StackPanelName= "Stackpanel_1"Local:TimeButton.ReportTime= "Reporttimehandle"> - <ListBoxName= "ListBox"Margin= "Ten"></ListBox> the <Local:timebuttonx:name= "Timebutton"Width= "a"Height= "a" - Content= "Chime"Local:TimeButton.ReportTime= "Reporttimehandle"> - </Local:timebutton> - </StackPanel> + </Grid> - </Grid> + </Grid> A </Window>
On the UI Interface, window is the root, with a three-layer grid and a layer of StackPanel (the Name property is set inside), Inside the innermost StackPanel is a listbox and Timebutton (the derived class of the button class just created above). We can see that from the outermost window to the most inner Timebutton, the listener reporttimeevent the routed event and responds to the event with the Reporttimehandle method. The code for Reporttimehandle is as follows:
1 //Reporttimeevent routed event handler2 Private voidReporttimehandle (Objectsender, Reporttimeeventargs e)3 {4FrameworkElement element = Sender asFrameworkElement;5 stringTimestr =e.clicktime.tolongtimestring ();6 stringContent =string. Format ("{0} reached {1}", timestr, element. Name);7 This. LISTBOX.ITEMS.ADD (content);9}
To run the program, the effect is as follows:
In this example, we use the policy of the routed event as bubbling (bubble), we make a simple modification to the program, when declaring and registering a routed event, change the policy of its event to tunnel (tunnel):
// declaring, registering routed events Public Static ReadOnly RoutedEvent reporttimeevent = eventmanager.registerroutedevent ("reporttime"typeof typeof(Timebutton));
The effect is as follows:
By comparing the two, we can clearly see that the two different strategies are different, so we can better understand what we said before.
At this point, you have a question, if you let a routed event be processed in a certain place, then no longer pass backwards? Very simply, in an instance of the RoutedEventArgs class or its derived class, it has a property of type bool handeled, and once this property is set to True, the routed event is no longer passed down. For our example, we need to make the following modifications:
1 //Reporttimeevent routed event handler2 Private voidReporttimehandle (Objectsender, Reporttimeeventargs e)3 {4FrameworkElement element = Sender asFrameworkElement;5 stringTimestr =e.clicktime.tolongtimestring ();6 stringContent =string. Format ("{0} reached {1}", timestr, element. Name);7 This. LISTBOX.ITEMS.ADD (content);8 9 if(element = = This. Grid_2)Ten { Onee.handled =true; A } -}
This is modified as follows:
To be continue!
Learning from WPF learning Events (II.)