如何重写WPF路由命令调度机制

发布于 2024-07-23 09:43:43 字数 2721 浏览 7 评论 0原文

我可以以某种方式扩展 WPF 命令路由,以便它首先检查命令是否可以在聚焦字段中调用,如果不能在其他字段中调用(永远不会改变)? 有什么钩子吗? 也许您不知道这是否可行,但在网络上的某个地方看到了类似的内容并且可以保留链接吗?

抽象示例

例如,如果我要编写一个带有侧面板的文本编辑器,并且面板将具有焦点。 如果我按 Ctrl+G,某些命令将被调用,因为面板具有命令绑定和焦点(正常的 WPF 行为)。 另外,如果我按 Ctrl+H 但这次面板没有调用命令的命令绑定。 在这种情况下,我希望路由引擎切换到文本编辑器,并在那里冒泡相同的命令。

真实示例

我有一个菜单项,上面写着“粘贴”,但焦点位于侧面板上。 如果我按绑定到面板的菜单命令将被执行。 假设没有适当的命令绑定到面板。 在这种情况下,我想粘贴到文本编辑器中。

代码

该代码或多或少代表了这种情况。 我想按 Ctrl+H 并执行 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");
        }
    }
}

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");
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

-小熊_ 2024-07-30 09:43:44

我解决这个问题的方法是使用 Window.AddHandler 方法捕获所有路由命令事件,然后像这样从 textBlock1 重新引发它们。

textBlock1.RaiseEvent(e);

我还没有这方面的代码,但想法是,如果未处理,路由事件将冒泡到窗口范围,我们在其中捕获所有未处理的事件并从主窗口区域重新引发它们

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文