The following code shows a normal event and a routed event. Here I have used the same event name for explaining purposes but in reality I am using just the 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 am raising these events from a couple of event handlers as follows
pr开发者_如何转开发ivate 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 am handling the normal Event I am able to send the args of both the handlers to the event but in Routed Event the args will be a new instance. I want to pass the args of both the handlers to the Routed Event. Is it possible to achieve this? If yes then how?
first of all you do not need this (and should remove it):
//Normal Event
public event SelectedHandler Selected;
public delegate void SelectedHandler(Object Sender, RoutedEventArgs e);
i.e. you do not need to define a separate "normal" event, because you have already done it with this declaration:
public event RoutedEventHandler Selected
{
add { AddHandler(SelectedEvent, value); }
remove { RemoveHandler(SelectedEvent, value); }
}
with the above code block you are "wrapping" the routed event with a "normal" (clr) one so the users of your class can use it with the "normal" syntax (i.e. instanceOfMyUserControl.Selected += ....
)
second, if you want the event arguments of your routed event to be the same as the ones of the SelectionChanged
event of the the ListView
you are listening to, you should 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); }
}
Notice that I have substituted the RoutedEventHandler
with SelectionChangedEventHandler
, as it is the predefined one that can "carry" SelectionChangedEventArgs
.
Now for the rising of the event. You do not need to rise both the "normal" and the routed one (as the "normal" is a wrapper for the routed), so you should delete this:
//Normal Event Raise
if (Selected != null)
Selected(this, e);
and rise only the routed version, which can be done this way:
SelectionChangedEventArgs args =
new SelectionChangedEventArgs(SelectedEvent, e.RemovedItems, e.AddedItems);
RaiseEvent(args);
Notice that I am using the event arguments from the original event to set the AddedItems
and RemovedItems
of the one custom one.
To follow on your last comment (can one give a link to a particular comment ?) I will write another answer so people can follow.
I think you are missing the point of events altogether. What do you want the handler of your event to know when it receives it? That is generally the purpose of the event arguments - you pass some info to the handler with which you give some background on what exactly happened.
So the first time you are raising your event, you will do it this way:
private void lstvMyView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectionChangedEventArgs args =
new SelectionChangedEventArgs(SelectedEvent, e.RemovedItems, e.AddedItems);
RaiseEvent(args);
}
You first have to construct the arguments and then use the RaiseEvent()
function with that arguments, because you want to raise a wpf's special routed type of event. The arguments have to be an instance of a class that inherits RoutedEventArgs. Notice that you are constructing SelectionChangedEventArgs
which are defined in wpf to "carry" additional information to the handler of the event - namely which items have been removed from the selection and which have been added, so when the handler receives the event it can use that info if he wants.
About this think you are doing:
//Normal Event Raise
if (Selected != null)
Selected(this, e);
basically - (as I said in my first answer) remove it, you do not need it.
So what is bothering you is the second time you are raising the event. This is a prototype of what you have to do:
private void lstvMyView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
SelectionChangedEventArgs args =
new SelectionChangedEventArgs(SelectedEvent, ?, ?);
RaiseEvent(args);
}
as you see, again you have to construct the SelectionChangedEventArgs
and use the RaiseEvent()
function to raise the event. But this time you can not use e.RemovedItems
and e.AddedItems
, because you are handling a MouseLeftButtonUp
event, that (via its args) carries information about the mouse state - not what items have been added to the selection (after all its a mouse event, not a selection event).
You have to decide with what to replace the two question marks - as I said in the comments to the first answer, you have to decide what information you want to convey to the user of your event. What means that the a mouse button is no longer down on the "lstvMyView"? The simplest thing to do is this:
SelectionChangedEventArgs args =
new SelectionChangedEventArgs(SelectedEvent, Enumerable.Empty<object>(), Enumerable.Empty<object>());
RaiseEvent(args);
with which you are raising the event and telling its consumer that no items have been removed from the selection and no items have been added.
精彩评论