我可以在同一个控件上为同一个命令设置多个 CommandBindings 吗?

发布于 2024-08-22 10:11:08 字数 1799 浏览 2 评论 0原文

我有一个 UserControl,它将 CommandBinding 添加到它的 CommandBindings 集合中以处理特定的命令。后来我在窗口中使用此控件,并希望向该同一控件添加另一个绑定以添加其他行为。但问题是,当我这样做时,似乎当我将另一个 CommandBinding 添加到控件的 CommandBindings 集合中时,它会替换已经为同一命令创建的任何绑定。那么看起来一个控件只能有一个 CommandBinding,这是正确的吗?

请参阅下面的代码示例,该示例尝试为同一个保存命令设置两个 CommandBindings。

<Window x:Class="MultipleCommandBindings.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

最初,在编写此代码时,我预计会出现编译时或运行时异常,但令我惊讶的是它没有抱怨。接下来,我很失望,因为我的 CommandBinding_Executed 处理程序只被调用一次,而不是我希望的两次。

更新: 经过一些测试后,我的第二个 CommandBinding 似乎并没有覆盖第一个 CommandBinding,而是显示即使我没有在事件处理程序中将 Handled 设置为 true,第一个命令绑定也会吞没该命令。此时我非常确定,问题的解决方案是理解为什么即使 Handled 未设置为 true,路由命令也不会传播通过第一个处理程序。

更新: 我发现了这个很棒的小花絮,它只是证实了一些奇怪的事情WPF 中命令路由背后的行为。

更新: 关于如何解决每个命令似乎只能有一个有效 CommandBinding 这一事实的一个想法是,默认 CommandBinding 类将 Executed 和 CanExecute 公开为事件,当然,就像所有事件一样可以有多个处理程序。我们的想法是使用标准 CommandBindings.Add 方法之外的其他方法来向命令添加其他处理程序。也许这可以通过 Control 类上的扩展方法并与自定义 CompositeCommandBinding 类结合来完成,该类允许我们在一个主绑定中聚合多个绑定。

I have a UserControl that adds a CommandBinding to it's CommandBindings collection to handle a specific Command. Later I use this control in a window and want to add another binding to that same control to add additional behavior. The problem though, is that when I do this it seems that when I add another CommandBinding to the CommandBindings collection of a control that it replaces any binding that was already made for the same Command. So what it seems like is that a control can only have a single CommandBinding per control, is this correct?

Please see the code example below which attempts to set two CommandBindings for the same Save Command.

<Window x:Class="MultipleCommandBindings.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

Originally I was expecting either a compile-time or runtime exception when wrote this code but was surprised that it didn't complain. Next though I was disappointed since my CommandBinding_Executed handler only gets called once instead of twice as I was hoping.

Update:
After a bit of testing it appears that my second CommandBinding is not overwriting my first one but instead it appears that even though I'm not setting Handled to true in my event handler that the first command binding swallows up the Command. I'm pretty sure at this point that the solution to my problem is to understand why the routed command is not propagating past the first handler even when Handled is not set to true.

Update:
I've found this great little tidbit of information which just confirms some of the strange behavior behind Command routing in WPF.

Update:
One thought about how to work around the fact that it appears that there can only be a single effective CommandBinding per command is that it appears that the default CommandBinding class exposes Executed and CanExecute as events which of course like all events can have multiple handlers. The idea then is to have some other way than the standard CommandBindings.Add method to add additional handlers to a command. Maybe this could be done via an extension method on the Control class and conjunction with a custom CompositeCommandBinding class which allows us to aggregate multiple bindings within one main binding.

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

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

发布评论

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

评论(2

赢得她心 2024-08-29 10:11:08

到目前为止,我只能想出解决此问题的方法,即在逻辑树中的两个不同级别处理命令。在下面的示例中,我在网格中处理“保存”命令,然后在“窗口”元素中再次处理“保存”命令。

<Window x:Class="MultipleCommandBindings.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed2"/>
</Window.CommandBindings>
<Grid>
    <Grid.CommandBindings>
        <CommandBinding Command="Save"
                        Executed="CommandBinding_Executed1" />
    </Grid.CommandBindings>

    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

为了使其正常工作,我的后台代码还需要手动将命令执行传播到下一个级别。

    private void CommandBinding_Executed1(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 1!");
        var command = e.Command as RoutedUICommand;
        command.Execute(e.Parameter, this);
    }

    private void CommandBinding_Executed2(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 2!");
    }

如果有人对如何监视命令有更好的想法,但仍然让它自然地在树上传播,我很乐意看到它,否则我可能会采取这种解决方法。

So far I've only been able to come up with a workaround for this problem which is to handle the command at two different levels in the logical tree. In the example below I handle the Save command within my grid and then also again within the Window element.

<Window x:Class="MultipleCommandBindings.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.CommandBindings>
    <CommandBinding Command="Save"
                    Executed="CommandBinding_Executed2"/>
</Window.CommandBindings>
<Grid>
    <Grid.CommandBindings>
        <CommandBinding Command="Save"
                        Executed="CommandBinding_Executed1" />
    </Grid.CommandBindings>

    <Button Height="23"
            HorizontalAlignment="Right"
            Margin="0,0,25,88"
            Name="button1"
            VerticalAlignment="Bottom"
            Width="75"
            Command="Save">Button</Button>
</Grid>

In order to get this to work my code behind needs to also manually propagate the Command execution to the next level up.

    private void CommandBinding_Executed1(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 1!");
        var command = e.Command as RoutedUICommand;
        command.Execute(e.Parameter, this);
    }

    private void CommandBinding_Executed2(object sender, ExecutedRoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Executed 2!");
    }

If anybody has any better ideas on how I can monitor a command still let it propagate naturally up the tree I would love to see it otherwise I might just resort to this workaround.

甩你一脸翔 2024-08-29 10:11:08

我不知道你问题的答案,但使用 Reflector 对我来说听起来很合理。

我想知道你为什么要这样做?也许使用 Composite 模式来聚合行为更有意义,而不是尝试组合命令绑定?

I don't know the answer to your question, but using Reflector sounds reasonable to me.

I'm wondering why are you doing this? Maybe it makes more sense to use Composite pattern to aggregate behaviors, rather then trying to combine command bindings?

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