【问题标题】:Bubbling Routed Commands up from users control to main window将路由命令从用户控件冒泡到主窗口
【发布时间】:2016-02-08 06:23:21
【问题描述】:

我有一个这样定义的 RoutedCommand:

public static class Commands
{
    /// <summary>
    /// Represents the Foo feature of the program.
    /// </summary>
    public static readonly RoutedCommand Foo = new RoutedCommand("Foo", typeof(Window1));
}

然后我有一个用户控件,其命令定义如下:

<UserControl.CommandBindings>
    <CommandBinding Command="{x:Static local:Commands.Foo}" Executed="CommandBinding_Executed"/>    
</UserControl.CommandBindings>
<UserControl.InputBindings>
    <KeyBinding Command="{x:Static local:Commands.Foo}" Modifiers="Control"  Key="Space"></KeyBinding>
</UserControl.InputBindings>

并像这样在代码中处理! (针对我的用户控件类)

private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    MessageBox.Show("Executed from sub");
}

我的自定义用户控件在我的主窗口中定义:

<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}"></local:UserControl1>

我的主窗口也有自己的方式来处理 Foo 路由命令:

CommandBindings.Add(new CommandBinding(Commands.Foo, new ExecutedRoutedEventHandler((x, y) => {

            MessageBox.Show("Something Happend from main window");

        })));

InputBindings.Add(new InputBinding(Commands.Foo, new KeyGesture(Key.P, ModifierKeys.Alt)));

现在,如果该命令是从我的用户控件触发的,如果 ExecutedRoutedEventArgs 的 Handled 属性设置为 false,我希望事件会冒泡到窗口,并且它是:

但只有来自用户控件的消息框会显示,我希望窗口上已处理事件的消息框会在之后显示!

谢谢

【问题讨论】:

  • 您在 UC 和 MainWindow 中使用不同的输入绑定。如果按 Alt+P 会发生什么?

标签: c# .net wpf command


【解决方案1】:

CommandBinding.Executed 事件的处理程序由CommandBinding.OnExecuted 方法调用,该方法在处理程序完成后立即将RoutedEventArgs.Handled 设置为true。该方法是内部的而不是虚拟的,因此您对此行为无能为力。

如果你真的想让父级处理命令,你可以从你的处理程序中调用它。这不是同一个命令,但会导致主窗口上的处理程序触发。

    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        MessageBox.Show("Executed from sub");
        var rc = e.Command as RoutedCommand;
        var parentInput = FindParentInput();
        if (parentInput != null && rc != null)
        {
            rc.Execute(null, parentInput);
        }
    }

    private IInputElement FindParentInput()
    {
        DependencyObject element = this;
        while (element != null)
        {
            DependencyObject parent = VisualTreeHelper.GetParent(element);
            var input = parent as IInputElement;
            if (input != null)
                return input;
            element = parent;
        }
        return null;
    }

请注意,如果您尝试将null 用于第二个参数,它将再次将新命令发送到this 相同的UserControl。这就是为什么我包含了 FindParentInput 方法,该方法查找实现了 `IInputElement' 接口的最近的父对象。

【讨论】:

【解决方案2】:

您可以更简单地执行此操作,似乎所有 UIElement 都实现了 IInputElement,因此您应该可以路由到直接父级(在我的简单应用程序上尝试过,它可以从我的自定义控件返回到主窗口):

  private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
  {
     RoutedCommand c = e.Command as RoutedCommand;
     IInputElement parent = this.Parent as IInputElement;
     c.Execute(e.Parameter, parent);
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-28
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 2010-09-26
    • 1970-01-01
    相关资源
    最近更新 更多