In the original company, writing custom controls is a common task. However, these controls often have a bad characteristic: No routing event is used either internally or externally. Then how should we slaughter custom controls and use routing events in development? We will discuss this issue in this short article.
Introduction to routing events
When talking about routing events, we need to ask ourselves a question first. When. Net already supports events, why does WPF provide additional support for routing events? This is because in the WPF development model, the original CLR events cannot meet the development requirements, and thus the handling of the events is cumbersome:
The first is the control encapsulation. In WPF, we can use one control as a sub-control of another control to present rich effects. For example, we can include an image in a button. In this case, the image is actually clicked on the button. Because of this, we expect that the control that actually triggers the click event is a button, not an image embedded in it. This requires that the click event be transmitted along the visual tree in sequence, that is, the routing function of the routing event. It can be said that this is the most intuitive reason for WPF to add routing events.
Also, since WPF provides a rich combination modelProgramThe interface may contain multiple identical interface elements. In order to listen to specific events in one place, rather than adding event processing functions to these interfaces in sequence. Routing events provide a simple way to handle this situation: Add event processing functions to their common parent elements. The event processing function is called only when the routing event is routed to this element. For example, when providing support for the dragdrop function in Treeview, you cannot mark the response to the mouse operation in sequence in each entry. Instead, you should listen to the mouse operation event in the Treeview element.
In addition to these obvious advantages, routing events also provide richer functions. First, the routing event allows software developers to use static handlers defined by classes through the eventmanager. registerclasshandler () function. The static handler defined in this class is similar to the type of static constructor: When a routing event arrives at an element instance in the route, WPF will first call this type of handler, then execute the listener function registered by the instance. This control is often used in the internal implementation of WPF. In addition, by using eventmanager, which manages route events, we can call the getroutedevents () function to obtain corresponding route events, instead of using reflection and other time-consuming methods.
Routing events generally use the following three routing policies: 1) Bubble: from the event source to the root element. 2) Direct: only the event source has the opportunity to respond to the event. 3) tunnel: Call the event handler from the root of the element tree and drill down until the event source. In general, all input events provided by WPF are implemented using Tunnel/bubble pairs. Tunnel events are often called preview events.
You may wonder how the direct routing of routing events is different from that of common CLR events? In fact, there is no difference. However, routing events provide better support for WPF. For example, a trigger or other functions require that an event is a routing event. At the same time, the routing event also provides a class processing mechanism, which provides a more flexible execution mode for WPF. In the subsequent sections, you will see how WPF completes some common WPF functions through class processing functions.
Route event Programming
Similar to the Dependency Property, WPF also provides a WPF Event System for routing events. Adding a route event for a type is similar to adding a dependency attribute for the type: software developers need to register a route event with the Event System through the registerroutedevent () function of eventmanager. The function signature is as follows:
1 Public StaticRoutedevent registerroutedevent (StringName, routingstrategy,2Type handlertype, type ownertype );
This function has four parameters: the first parameter name indicates the name of the event in the WPF Event System, and the second parameter routingstrategy indicates the routing principle of the routing event. The third parameter handlertype is used to indicate the type of the event handler function, while the last parameter ownertype is used to indicate the type of the event that owns the route. For example, the following is the control class that registers the mousedoubleclick event.Code:
1 Public Static ReadonlyRoutedevent mousedoubleclickevent =2Eventmanager. registerroutedevent ("Mousedoubleclick", Routingstrategy. Direct,3Typeof(Mousebuttoneventhandler ),Typeof(Control ));
This function returns a routedevent instance. Generally, this instance is saved by a public static readonly field and can be simulated as a CLR event through the add and remove accessors. Let's take the mousedoubleclick event as an example. The implementation of the mousedoubleclick event in the control class is as follows:
1 Public Event Mousebuttoneventhandler mousedoubleclick 2 { 3 Add 4 { 5 Base . Addhandler (mousedoubleclickevent, value ); 6 } 7 Remove 8 { 9 Base . Removehandler (mousedoubleclickevent, value ); 10 } 11 }
As we mentioned earlier, the eventmanager class also provides a registerclasshandler () function to register a handler for a specific routing event. The function is prototype as follows:
1 Public Static VoidRegisterclasshandler (type classtype, routedevent,2Delegate handler,BoolHandledeventstoo );
The first parameter of the function is used to specify the type of the registration class handler, while the second parameter is used to specify the event that the class handler needs to listen. The third parameter specifies the class handler, and setting the last parameter to true allows the class handler to process the route events marked as handled.
The class handler registered by the registerclasshandler () function can run before the event handlers of each instance run. In this type of processing program, software developers can choose to mark the event as handled, or convert the current event to another event. Take the DoubleClick event of the control class as an example. The static constructor of the control class first registers a class Handler through the registerclasshandler () function:
Eventmanager. registerclasshandler (Typeof(Control), uielement. mouseleftbuttondownevent,NewMousebuttoneventhandler (control. handledoubleclick ),True);
Next, in the class handler handledoubleclick (), it will convert the mouseleftbuttondown event to a double-click event when you double-click it:
1 Private Static Void Handledoubleclick (Object Sender, mousebuttoneventargs E) 2 { 3 If (E. clickcount = 2 ) // Process double-click 4 { 5 Control control = (Control) sender; 6 Mousebuttoneventargs ARGs = New Mousebuttoneventargs (E. mousedevice, 7 E. timestamp, E. changedbutton, E. stylusdevice ); 8 If (E. routedevent = Uielement. previewmouseleftbuttondownevent) 9 | (E. routedevent = Uielement. previewmouserightbuttondownevent )) 10 { 11 Args. routedevent = Previewmousedoubleclickevent; 12 Args. Source = E. originalsource; 13 Args. overridesource (E. source ); // Note the processing of Source 14 Control. onpreviewmousedoubleclick (ARGs ); // Send a double-click preview message 15 } 16 Else 17 { 18 Args. routedevent = Mousedoubleclickevent; 19 Args. Source = E. originalsource; 20 Args. overridesource (E. source ); 21 Control. onmousedoubleclick (ARGs ); // Send double-click message 22 } 23 If (ARGs. Handled) 24 E. Handled = True ; // Set handled to true to hide the message. 25 } 26 }
Note that the class handler function registered by the registerclasshandler () function must be a static member function. Therefore, you need to obtain the type instance of the route event from the parameter. For example, in the above function, the class handler function obtains the type instance that actually sends the routing event through the sender parameter.
The code above also shows you how to hide messages and how to implement custom input events during component programming. In the above Code, the response function of the routing event will manually send a double-click message, so that the control's previewdoubleclick and doublec lick events are triggered. Next, the response function of the routing event sets the handled attribute of the original event to true to hide the original low-level input event. This method of hiding a low-level event and converting it into a high-level event is very common in WPF. Take the commonly used button class as an example. When you press the mouse, we receive the previewmousedown event, but cannot receive the mousedown event. On the one hand, you need to understand and master this method, on the other hand, you should be able to estimate the cause of this situation when encountering this situation, and use the corresponding solution: preview-event.
In addition to the registerroutedevent () function, software developers can also use routedevent's addowner () function to take routing events of other types as their own routing events. The prototype of the routedevent member function addowner () is as follows:
1 PublicRoutedevent addowner (type ownertype)
This function also returns a routedevent instance and can be used in CLR packaging. Take the mousemove event provided by the uielement class as an example. WPF first adds an event reference through the addowner () function:
1 Public Static ReadonlyRoutedevent mousemoveevent =2Mouse. mousemoveevent. addowner (Typeof(Uielement ));
Next, you still need to add a CLR event packaging for the additional event as usual:
1 Public Event Mouseeventhandler mousemove 2 { 3 Add 4 { 5 This . Addhandler (mouse. mousemoveevent, value, False ); 6 } 7 Remove 8 { 9 This . Removehandler (mouse. mousemoveevent, value ); 10 } 11 }
The last thing to talk about is how to handle the routing event that handled has been set to true. When you need to handle this type of event, you must first consider whether your current solution is inappropriate. If you have strong enough reasons to prove that it is necessary to handle the routing event with the handled attribute set to true, you must use the addhandler function to add a listener for the routing event, set the value of the handledeventstoo attribute to true in this function call. In addition, software developers can use the handledeventstoo attribute in eventsetter to implement the same functions.
Additional event
And the relationship between the additional property and the dependency property. The Event System of WPF also supports common routing events and additional events. Different from the syntax implementation of additional attributes, the syntax used for additional events is no different from that used for common routing events. For example, in the following code, the use of the image. mousedown event is the use of common routing events:
1 <StackpanelImage. mousedown=...>
The use of the mouse. mousedown event is the use of the additional routing event:
1 <StackpanelMouse. mousedown=...>
In the above two sections of code, we use the limited event Syntax of "type name. event name. However, they are a common routing event and an additional event. So how can we identify what are routing events and what are additional events. In fact, additional events are more important to their semantic features. Similar to the service features of additional properties, additional events often correspond to a global service, such as the mouse input service corresponding to the mouse class. These services may not exist as child elements of the current element in XAML.
As we have seen before, many types of WPF integrate the routing events provided by some services into the type definition through a series of methods such as addowner () function call, for example, the uielement class integrates the routing events provided by the mouse class. This is often a control writing policy adopted by the control writer. After all, system services are often relatively low-level APIs. This event can be directly used when it is integrated into the type, rather than the limited form of the routing event. On the other hand, it makes the expression of the event in XAML more intuitive.
Of course, you do not need to create a service only for the input and other underlying components. In fact, in the control development process, the use of such a service is also common. Take selector as an example. When you view the implementation of treeviewitem and listboxitem, you will find that they have added the selector through the addowner () function. the use of the selected event, while the selector itself adds a listener for the event, and finally converts it to the routing event selectionchanged. This is a very obvious use of additional routing events. The reason why the selected event is implemented as a service is that the selected operations for each project often occur inside each project, such as clicking the mouse, therefore, it is a good solution to process selected events in these entries and route the events to selector.
How to Create a routing event? The answer is to addYoureventHandler () and removeYoureventHandler () two functions. The first parameter of both functions must indicate the event to be operated, and the event name must matchYoureventThe name is matched. The second parameter is the handler that needs to be specified for the additional event. Take the addmousedownhandler () and removemousedownhandler () functions provided by the mouse class as an example:
1 Public Static Void Addmousedownhandler (dependencyobject element, 2 Mousebuttoneventhandler handler) 3 { 4 Uielement. addhandler (element, mousedownevent, Handler ); 5 } 6 7 Public Static Void Removemousedownhandler (dependencyobject element, 8 Mousebuttoneventhandler handler) 9 { 10 Uielement. removehandler (element, mousedownevent, Handler ); 11 }
In this way, you can reference the mousedown additional event provided by the mouse. mousedown class in XAML.
Reprinted please indicate the original address: http://www.cnblogs.com/loveis715/archive/2012/04/09/2439803.html
Business reprint please contact me in advance: silverfox715@sina.com
More highlightsArticle, Please see blog home: http://www.cnblogs.com/loveis715/