9

我有一个 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 似乎没有覆盖我的第一个,而是似乎即使我没有在我的事件处理程序中将 Handled 设置为 true,第一个命令绑定也会吞噬命令。在这一点上,我很确定我的问题的解决方案是了解为什么即使 Handled 未设置为 true,路由命令也不会传播到第一个处理程序。

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

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

4

2 回答 2

3

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

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

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

于 2010-02-18T21:03:17.740 回答
1

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

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

于 2010-02-18T17:15:01.013 回答