[Summary] some minor problems encountered when using WPF to route events

Source: Internet
Author: User


In this document, an example of using the WPF routing event is provided at the beginning, because all the expressions in this article are based on this instance. The examples provided in this article are from the "WPF custom routing event" article. In the "WPF custom routing event" article, the instance code is described in detail. Therefore, if you have any questions while reading the instance code in this article, you can first read the article "WPF custom routing events" to see if you can get the answers you want.


1. Create the detailreporteventargs class, which is derived from the routedeventargs class. The routedeventargs class contains status information and event data related to the routing event. The detailreporteventargs class defines the eventtime and eventpublishr attributes, the occurrence time of the eventtime attribute record, and the publisher of The eventpublishr attribute record the event. The complete code of the detailreporteventargs class is as follows.

//************************************** ********************** // WPF routing event sample code // Author: may 3, May /// Date: // http://blog.csdn.net/yl2isoft ////****************************** * ***************************** using system; using system. windows; namespace detail {public class detailreporteventargs: routedeventargs {public detailreporteventargs (routedevent, object source): Base (routedevent, source) {} public datetime eventtime {Get; set ;} public String eventpublisher {Get; Set ;}}}

2. Create a New detailreportbutton class, which is derived from the button class and adds a route event detailreportevent for this class. The complete code of the detailreportbutton class is as follows.

//************************************** ********************** // WPF routing event sample code // Author: may 3, May /// Date: // http://blog.csdn.net/yl2isoft ////****************************** * ***************************** using system; using system. windows; using system. windows. controls; namespace wpfroutedeventexp {public class detailreportbutton: button {public static readonly routedevent detailreportevent = eventmanager. registerroutedevent ("detailreport", routingstrategy. bubble, typeof (eventhandler <detailreporteventargs>), typeof (detailreportbutton); public event routedeventhandler detailreport {Add {This. addhandler (detailreportevent, value);} remove {This. removehandler (detailreportevent, value) ;}} protected override void onclick () {base. onclick (); detailreporteventargs ARGs = new detailreporteventargs (detailreportevent, this); args. eventpublisher = This. tostring (); args. eventtime = datetime. now; this. raiseevent (ARGs );}}}

3. The complete code for using the detailreportbutton class is provided below, including the image code and the image backend code.

Program Screen code:

<Window x:Class="WpfRoutedEventExp.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:WpfRoutedEventExp"        Title="MainWindow" Height="350" Width="525">    <Grid x:Name="Grid_FirstLayer" >        <Grid x:Name="Grid_SecondLayer" >            <Grid x:Name="Grid_ThirdLayer" >                <local:DetailReportButton x:Name="Button_Confirm" Width="100" Height="100" Content="Click Me" Margin="142,111,250,100" />            </Grid>        </Grid>    </Grid></Window>

Backend code of the program screen:

//************************************** ********************** // WPF routing event sample code // Author: may 3, May /// Date: // http://blog.csdn.net/yl2isoft ////****************************** * ***************************** using system. windows; namespace wpfroutedeventexp {// <summary> // mainwindow. interaction logic of XAML // </Summary> Public partial class mainwindow: window {public mainwindow () {initializecomponent (); this. grid_thirdlayer.addhandler (detailreportbutton. detailreportevent, new routedeventhandler (button_clicked1); this. grid_secondlayer.addhandler (detailreportbutton. detailreportevent, new routedeventhandler (button_clicked1); this. grid_firstlayer.addhandler (detailreportbutton. detailreportevent, new routedeventhandler (button_clicked1); this. button_confirm.addhandler (detailreportbutton. principal, new routedeventhandler (button_clicked1);} private void button_clicked1 (Object sender, routedeventargs e) {frameworkelement ele = sender as frameworkelement; Include = e as entity; MessageBox. show (DH. eventpublisher + "-->" + ELE. name + ";" + DH. eventtime );}}}
4. Execute the program and obtain the result.


Figure 1 program running

The result is displayed: Click the screen button to trigger the routing event. The message of the routing event starts from the trigger of the event and passes it to the external container control layer by layer, until the Container Control at the outermost layer.


Your and my agreements

Because the instance code is modified repeatedly in the following description, the following conventions are provided:

Each modification will be rolled back to the previous status after the relevant knowledge points are described.


My press conference

The following is a question-and-answer Summary of several small issues that I encountered or thought of when using WPF to route events.

Q1: In addition to using the addhandler method, is there any way to associate the event you want to listen to with the event processor?

You can associate the listening event with the event processor in The XAML code. You can also use custom routing events to modify the instance Code as follows.

(1) comment out the following four lines of code.

this.Grid_ThirdLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));       this.Grid_SecondLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));            this.Grid_FirstLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));           this.Button_Confirm.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));

(2) associate the monitored event with the event processor in The XAML Code. For detailed operations, see the description.

Figure 2 associate the monitored event with the event processor in XAML

(3) Figure 2 shows that the event processor used is not button_clicked1, but button_clicked2. The Code of button_clicked2 is given below.

private void Button_Clicked2(object sender, DetailReportEventArgs e){    FrameworkElement ele = sender as FrameworkElement;    MessageBox.Show(e.EventPublisher + "-->" + ele.Name + ";" + e.EventTime);}

Comparing button_clicked2 with button_clicked1, we find that the essential difference between the two is that the type of the second parameter is different.

The second parameter type of button_clicked2 is detailreporteventargs, and the second parameter type of button_clicked1 is routedeventargs.

Continue Q: Why is the difference?

This is because when the addhandler method is used, the imported event processor must meet the routedeventhandler definition, and the routedeventhandler definition is as follows:

public delegate void RoutedEventHandler(object sender, RoutedEventArgs e)

Obviously, routedeventhandler is essentially a delegate, and the method that matches the delegate must meet the following requirements:

The first parameter is of the object type, the second parameter is of the routedeventargs type, and does not return values.

Therefore, the instance uses button_clicked1 that meets the requirements of the delegate.

The following describes the causes of the existence of button_clicked2.

View the custom routing Event code:

public static readonly RoutedEvent DetailReportEvent = EventManager.RegisterRoutedEvent("DetailReport",RoutingStrategy.Bubble,typeof(EventHandler<DetailReportEventArgs>),typeof(DetailReportButton));

You can find the type of the event processor required by the routing event from the definition, which is eventhandler <detailreporteventargs>.

You can also view the definition of eventhandler <detailreporteventargs> as follows:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

Replace teventargs with detailreporteventargs and get the following definition code:

public delegate void EventHandler<DetailReportEventArgs>(object sender, DetailReportEventArgs e);

Now that we can see this definition, we can see why button_clicked2 exists.


Q2: Since CLR event packaging is added for routing events, can we operate routing events through the "+ =" and "-=" symbols?

Of course.

The following describes how to modify the sample code.

Comment out all code in the instance that associates the event with the event processor (this is required in the screen code and the back-end code of the screen ).

Add the following code to the image backend code:

this.Button_Confirm.DetailReport += Button_Clicked1;

Run the program and click the button to get the following message box:


Figure 3 run After subscribing to an event using "+ ="

The event processor is correctly executed. In this case, the routing event is the same as a common CLR event, and the message is directly transmitted to the Bound event processor.

Then, add the following code:

this.Button_Confirm.DetailReport -= Button_Clicked1;

Run the program again, click the button, and then click "Haha". I think you understand.


Q3: Can controls in the same container listen to messages that route events to each other?

Modify the sample code as described below.

(1) Add a button named button_samelayer before the detailreportbutton.

<Grid x:Name="Grid_ThirdLayer" >    <Button x:Name="Button_SameLayer"/>    <local:DetailReportButton x:Name="Button_Confirm"  Width="100" Height="100" Content="Click Me" Margin="142,111,250,100" /></Grid>

(2) Enable button_samelayer to listen to the detailreportevent event of detailreportbutton.

 this.Button_SameLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));

(3) run the program and find that button_samelayer does not listen to the arrival of the routing event.

It can be seen that controls in the same container cannot listen to messages of Event Routing.


Q4: How can I transfer a routing event to a node instead of transmitting it?

In the event handling method button_clicked1, add the following code:

if (ele == this.Grid_SecondLayer){    e.Handled = true;}
In this way, the message will not be transmitted when it is passed to the grid_secondlayer control.

Because "E. Handled = true" means that the routing event has been processed and does not need to be passed on.


Q5: What is the difference between routedeventargs source and originalsource?

To elaborate on this topic, you need to make a relatively large change to the instance.

(1) create a user control myusercontrol. myusercontrol does not complete any meaningful work. The XAML code of myusercontrol is as follows:

<UserControl x:Class="WpfRoutedEventExp.MyUserControl"             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="300" d:DesignWidth="300">    <Grid x:Name="Grid_FirstLayerInUserControl">        <Grid x:Name="Grid_SecondLayerInUserControl">            <Button x:Name="Button_ThirdLayerInUserControl" Width="100" Height="100" Content="Hello,Kitty!"/>        </Grid>    </Grid></UserControl>

Shows the design view corresponding to the Code:


Figure 4 custom control design diagram

(2) Use our Custom User Control in the instance code and specify the name myusercontrol for it.

<Grid x:Name="Grid_ThirdLayer" >     <local:DetailReportButton x:Name="Button_Confirm" Width="100" Height="100" Content="Click Me" Margin="142,111,250,100" />                 <local:MyUserControl x:Name="myUserControl" Width="100" Height="100" HorizontalAlignment="Left" Margin="285,110,0,100"/>  </Grid>
The custom control myusercontrol is located in the container grid_thirdlayer, after the button_confirm button.


Figure 5 use custom controls

(2) Remove all event listening.

(3) Enable grid_firstlayer to listen to the Click Event of the button.

this.Grid_FirstLayer.AddHandler(Button.ClickEvent, new RoutedEventHandler(Button_Clicked1));

(4) modify the event processor method button_clicked1 and output the source and originalsource attribute values of the event in the method.

private void Button_Clicked1(object sender, RoutedEventArgs e){   MessageBox.Show(e.Source + ";" + e.OriginalSource );}
(5) Click "Hello, Kitty !" Button ("Hello, Kitty !" Button in the custom control myusercontrol). The following result is displayed:


Figure 6 Differences between source and originalsource

The result shows that the value of E. Source is myusercontrol (custom control), and the value of E. originalsource is button ("Hello, Kitty !" Button ).

Both source and originalsource are event sources. Only source indicates the message source on the logicaltree, while originalsource indicates the source on the visualtree.

Button. click routing events are generated from the button control named button_thirdlayerinusercontrol in the custom control. In the main window, myusercontrol is the end node of logicaltree, so E. source is myusercontrol, while the form's visualtree contains the internal structure of myusercontrol, so E. originalsource returns the button_thirdlayerinusercontrol button.


This article is not complete and will be continued later...

[Summary] some minor problems encountered when using WPF to route events

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.