将用户控制的路由命令冒泡到主窗口

时间:2015-11-07 01:20:45

标签: c# .net wpf command

我有一个如此定义的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>

并在代码中处理! (针对我的usercontrol类)

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,它是:

enter image description here

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

谢谢

2 个答案:

答案 0 :(得分: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。这就是为什么我包含查找实现`IInputElement&#39;的最近父级的FindParentInput方法的原因。接口

答案 1 :(得分:0)

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

    var remove = document.getElementsByClassName("Done");

    for(var i=0;i<remove.length;i++){
        var button = remove[i];

        if(button){

          if(window.localStorage.getItem(remove[i].id)=='true'){

            document.getElementById(remove[i].id).parentNode.style.display = 'none';

          }
        }
    }

    for(var i=0;i<remove.length;i++){
      var button = remove[i];

        if(button){
          button.addEventListener('click', (event) => {
              var bclick = event.target;
              window.localStorage.setItem(bclick.id,'true');
              bclick.parentElement.remove();

          });
        }


      }