Our application is based on a stack of pages, which are just subclasses of a FrameworkElement
. The main window maintains that stack and uses the built-in Close
command to close them by simply popping them off the stack.
Now in some cases, the element being closed (or popped-off the stack) needs to do some cleanup first. Having that page also listen to the Close
event seemed like the right thing to do.
Now, since that page would actually get the event before the window (the Close
command is implemented via a 'bubbling event') we thought all we had to do was to set the command binding on the page, then in the handler, set e.Handled
to false and it would continue up to the window.
Here's the code in the page (InitializeCommands
is called from the constructor)...
private void InitializeCommands(){
CommandBindings.Add(
new CommandBinding(ApplicationCommands.Close, Close_Execute, Close_CanExecute)
);
}
private void Close_CanExecute(object sender, CanExecuteRoutedEventArgs e){
// True executes this handler, but blocks the one in the window
// False executes the one in the window, but ignores this one
e.CanExecute = true;
// Doesn't seem to have any effect
e.Handled = false;
}
private void Close_Execute(object sender, ExecutedRoutedEventArgs e){
Console.WriteLine("I want to respond passively!");
// Doesn't seem to have any effect
e.Handled = false;
}
However, regardless of what we set that property to, the command never makes it to the main window. If we remove the command binding in the page, it works again, proving the page is swallowing the command regardless of that property.
So what do you have to do to make the page listen to the Close
event passively?
Yes, CommandBinding eats commands. Here's an excerpt of its implementation:
internal void OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (!e.Handled)
{
if (e.RoutedEvent == CommandManager.ExecutedEvent)
{
if (this.Executed != null && CheckCanExecute(sender, e))
{
this.Executed(sender, e);
e.Handled = true;
}
}
else if (this.PreviewExecuted != null && CheckCanExecute(sender, e))
{
this.PreviewExecuted(sender, e);
e.Handled = true;
}
}
}
As you can see, if you return true for CanExecute, the commands get eaten.
You might want to take a look at CompositeCommand. That'd be more up your alley. You create a global CompositeCommand that is bound to the frame and then different views can attach to it. Different implementations can have different cool ways of determining how multiple subscribers to the commands behave. I.e. all must return canExecute, any must return, only goes to the active view, etc.
EDIT: CompositeCommand was originally part of Prism, but you can either find a standalone implementation or just yank the one from Prism itself:
https://github.com/PrismLibrary/Prism/blob/master/Source/Prism/Commands/CompositeCommand.cs