3
votes

Can I extend WPF commands routing in a way so it would first check whether command can be invoked in the focused field and if not in some other (never changing)? Is there any hooks for that? Maybe you don't know whether that would work but saw something similar somewhere on the net and can spare the link?

Abstract example

For example if I would be writing a text editor with a side panel and panel would have the focus. If I would press Ctrl+G some command will be invoked because panel has command binding and focus (that normal WPF behavior). Also if I press Ctrl+H but this time panel have no command binding for invoked command. In this case I would want routing engine to switch to text editor and bubble same command there to.

Real example

I have a menu item which says Paste but focus is on the side panel. If I press menu command binded to panel will be executed. Suppose there is no appropriate command binded to panel. In this case I would like to paste into text editor.

Code

This code more or less represents this scenario. I would like to press Ctrl+H and execute CommandBinding_Executed_1

Window1.xaml

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1">
    <StackPanel>        
        <TextBox x:Name="textBlock1">
            <TextBox.CommandBindings>
                <CommandBinding Command="local:Window1.TestCommand" Executed="CommandBinding_Executed_1" />
                <CommandBinding Command="local:Window1.ForwardedTestCommand" Executed="CommandBinding_Executed_1" />
            </TextBox.CommandBindings>
        </TextBox>
        <TextBox x:Name="textBlock2">
            <TextBox.CommandBindings>
                <CommandBinding Command="local:Window1.TestCommand" Executed="CommandBinding_Executed_2" />
            </TextBox.CommandBindings>
            <TextBox.InputBindings>
                <KeyBinding Command="local:Window1.TestCommand" Gesture="Ctrl+G" />
                <KeyBinding Command="local:Window1.ForwardedTestCommand" Gesture="Ctrl+H" />
            </TextBox.InputBindings>
        </TextBox>
    </StackPanel>
</Window>

Window1.xaml.cs

using System.Windows;
using System.Windows.Input;

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        public static RoutedUICommand TestCommand = new RoutedUICommand("TestCommand", "TestCommand", typeof(Window1));
        public static RoutedUICommand ForwardedTestCommand = new RoutedUICommand("ForwardedTestCommand", "ForwardedTestCommand", typeof(Window1));

        public Window1()
        {
            InitializeComponent();
        }

        private void CommandBinding_Executed_1(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("CommandBinding_Executed_1");
        }

        private void CommandBinding_Executed_2(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("CommandBinding_Executed_2");
        }
    }
}
1

1 Answers

0
votes

The way I was able to solve this is using Window.AddHandler method to catch all routed command events and then re-raise them from textBlock1 like so.

textBlock1.RaiseEvent(e);

I don't have a code for that yet, but the idea is that routed event if not handled is bubbled up to window scope where we catch all unhandled events and re-raise them from main window area