1

I have a WPF MenuItem, returned from a function with no other information, and I want to set another (new) MenuItem's click event to be the same function as the first MenuItem.

I have seen code to do this in Windows forms (e.g. Is it possible to "steal" an event handler from one control and give it to another?), but I can't find a solution for WPF routed events.

Community
  • 1
  • 1
Darren
  • 4,408
  • 4
  • 39
  • 57

1 Answers1

0

When I need to copy menu items in WPF I use the command pattern as suggested, but with some clever trickery you can still support event handlers as well (see more below). The code I use to copy items looks something like this, where "item" is the old MenuItem I am copying:

MenuItem copy = new MenuItem();
copy.Header = item.Header;
copy.Icon = item.Icon;
copy.Command = item.Command;
copy.CommandParameter = item.CommandParameter;
foreach( CommandBinding binding in item.CommandBindings ) {
    copy.CommandBindings.Add( binding );
}
newCollection.Add( copy );

Obviously you might need to tweak which properties you copy depending on which features of the MenuItem you tend to use. I pretty much stick to Header, Icon, and Command so that's all I implemented.

Now, if you need to support event handler-style, you will need some sort of construction abstraction because you can only "play" with it before assigning to the event. Once you've added the event handler to the menu item it's pretty un-retrievable. If you have an actual RoutedEventHandler object though (pre-subscription), you can do this little work-around (where "handler" is the RoutedEventHandler instance I am wrapping):

ExecutedRoutedEventHandler executed = (sender, args) =>
{
    RoutedEventArgs innerArgs = new RoutedEventArgs();
    // The consumer probably shouldn't rely on these, but we'll copy them for completeness sake
    innerArgs.RoutedEvent = args.RoutedEvent;
    innerArgs.Handled = args.Handled;
    innerArgs.Source = args.Source;
    handler.Invoke( sender, innerArgs );
};
RoutedUICommand cmd = new RoutedUICommand( "Temp", "Temp", this.GetType() );
newItem.CommandBindings.Add( new CommandBinding(cmd, executed) );
newItem.Command = cmd;

You might need to replace

this.GetType()

with something else depending on the context in which you are constructing the menu items. I think it needs to be the type of the object that is going to be the ultimate parent of the MenuItem in the visual tree (in my case the object whose context menu items I am copying).

Dana Cartwright
  • 1,566
  • 17
  • 26