【问题标题】:Can I have multiple CommandBindings for the same Command on the same control?我可以在同一个控件上为同一个命令有多个 CommandBindings 吗?
【发布时间】:2010-02-18 16:18:44
【问题描述】:

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

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

<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,路由命令也不会传播到第一个处理程序。

更新: 我发现 this great little tidbit 的信息只是证实了 WPF 中命令路由背后的一些奇怪行为。

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

【问题讨论】:

  • 我能想到的唯一解决方案是订阅 Button 的 Click 事件,然后将 View 的 DataContext 转换为其 ViewModel 并使用该 var 手动执行 2 个命令。

标签: wpf command commandbinding


【解决方案1】:

到目前为止,我只能想出解决此问题的方法,即在逻辑树中的两个不同级别处理命令。在下面的示例中,我在网格中处理 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!");
    }

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • +1 表示您应该在视图中只有 1 个绑定,并允许在堆栈的下方调用多个行为。
    • 好吧,在我的例子中,我有一个用户控件,它可以是来自内部控件的几种不同类型的命令的来源。在用户控件中,我想知道何时发出任何这些命令,以便我可以让我的 ViewModel 启动一些其他进程,最终结果将通过我的 UserControl (View) 公开。我可以绑定到我要公开的属性,并查看它何时更改以了解何时可以使用,但我会查看有关启动整个过程的实际命令类型的信息。
    猜你喜欢
    • 2011-10-12
    • 2014-01-16
    • 1970-01-01
    • 2012-02-11
    • 2022-11-26
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    相关资源
    最近更新 更多