Passing Events Arguments of the Source Handler to a Routed Event in wpf

The following code shows the normal event and the routed event. Here I used the same event name to explain the goals, but in fact I only use a routed event.

//Normal Event public event SelectedHandler Selected; public delegate void SelectedHandler(Object Sender, RoutedEventArgs e); //Routed Event public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent( "Selected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyUserControl)); //add remove handlers public event RoutedEventHandler Selected { add { AddHandler(SelectedEvent, value); } remove { RemoveHandler(SelectedEvent, value); } } 

I raise these events from several event handlers as follows

 private void lstvMyView_SelectionChanged(object sender, SelectionChangedEventArgs e) { //Normal Event Raise if (Selected != null) Selected(this, e); //Routed Event Raise RoutedEventArgs args = new RoutedEventArgs(SelectedEvent); RaiseEvent(args); } private void lstvMyView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { //Normal Event Raise if (Selected != null) Selected(this, e); //Routed Event Raise RoutedEventArgs args = new RoutedEventArgs(SelectedEvent); RaiseEvent(args); } 

When I handle a regular event, I can send the arguments of both handlers to the event, but in the Routed event, the arguments will be new. I want to pass the arguments of both handlers to a routed event. Can this be achieved? If so, how?

+4
source share
2 answers

First of all, you do not need this (and should be deleted):

 //Normal Event public event SelectedHandler Selected; public delegate void SelectedHandler(Object Sender, RoutedEventArgs e); 

i.e. you don’t need to define a separate “normal” event because you have already done this with this declaration:

 public event RoutedEventHandler Selected { add { AddHandler(SelectedEvent, value); } remove { RemoveHandler(SelectedEvent, value); } } 

with the above code block, you "wrap" the routed event with "normal" (clr) so that users of your class can use it with the "normal" syntax (ie instanceOfMyUserControl.Selected += .... )

second, if you want the event arguments of your routed event to be the same as those in the SelectionChanged event for the ListView you are listening to, you must declare your routed event this way:

 public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent( "Selected", RoutingStrategy.Bubble, typeof(SelectionChangedEventHandler), typeof(MyUserControl)); //add remove handlers public event SelectionChangedEventHandler Selected { add { AddHandler(SelectedEvent, value); } remove { RemoveHandler(SelectedEvent, value); } } 

Note that I replaced RoutedEventHandler with SelectionChangedEventHandler , as it is a predefined one that can "carry" SelectionChangedEventArgs .

Now for the sunrise event. You do not need to raise either “normal” or routable (since “normal” is a wrapper for routing), so you should remove this:

 //Normal Event Raise if (Selected != null) Selected(this, e); 

and pick up only the routed version, which can be done as follows:

 SelectionChangedEventArgs args = new SelectionChangedEventArgs(SelectedEvent, e.RemovedItems, e.AddedItems); RaiseEvent(args); 

Note that I use the event arguments from the source event to set the AddedItems and RemovedItems one custom.

+11
source

To keep track of the last comment (can I give a link to a specific comment?) I will write another answer so that people can follow.

I think that you do not have enough event points. What do you want your event handler to know when it received it? This, as a rule, is the purpose of the event arguments - you pass some information to the handler, with which you give some idea of ​​what exactly happened.

So, the first time you raise your event, you will do it like this:

 private void lstvMyView_SelectionChanged(object sender, SelectionChangedEventArgs e) { SelectionChangedEventArgs args = new SelectionChangedEventArgs(SelectedEvent, e.RemovedItems, e.AddedItems); RaiseEvent(args); } 

First you need to build the arguments, and then use the RaiseEvent() function with these arguments, because you want to raise a special type of wpf routing. The arguments must be an instance of a class that inherits RoutedEventArgs. Note that you create SelectionChangedEventArgs , which are defined in wpf, to “transfer” additional information to the event handler - namely, which elements were removed from the selection and which were added, so when the handler receives the event, it can use this information. if he wants to. You think about it:

 //Normal Event Raise if (Selected != null) Selected(this, e); 

basically - (as I said in my first answer) delete it, you don't need it.

So, what bothers you, the second time you raise an event. This is a prototype of what you need to do:

 private void lstvMyView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { SelectionChangedEventArgs args = new SelectionChangedEventArgs(SelectedEvent, ?, ?); RaiseEvent(args); } 

as you see, again you need to build SelectionChangedEventArgs and use the RaiseEvent() function to raise the event. But this time, you cannot use e.RemovedItems and e.AddedItems , because you are handling the MouseLeftButtonUp event, which (through its args) carries information about the state of the mouse - not that the elements were added to the selection (in the end, its event mouse, not a selection event). You must decide what to replace the two question marks with - as I said in the comments to the first answer, you need to decide what information you want to convey to the user of your event. What does it mean that the mouse button is no longer on "lstvMyView"? The easiest way to do the following:

 SelectionChangedEventArgs args = new SelectionChangedEventArgs(SelectedEvent, Enumerable.Empty<object>(), Enumerable.Empty<object>()); RaiseEvent(args); 

with which you raise an event and tell your consumer that no items have been removed from the selection and no items have been added.

0
source

Source: https://habr.com/ru/post/1332875/


All Articles