您如何被动地响应RoutedCommand?

时间:2018-12-27 00:25:36

标签: wpf routed-events

我们的应用程序基于一堆页面,这些页面只是FrameworkElement的子类。主窗口维护该堆栈,并使用内置的Close命令通过简单地将它们从堆栈中弹出来关闭它们。

现在,在某些情况下,被关闭(或弹出堆栈)的元素需要首先进行一些清理。让该页面同时收听Close事件似乎是正确的选择。

现在,由于该页面实际上会在窗口之前获取事件(Close命令是通过“冒泡事件”实现的),因此我们认为我们要做的就是在页面上设置命令绑定,然后在处理程序中,将e.Handled设置为false,它将继续到窗口。

这是页面中的代码({InitializeCommands从构造函数中调用)...

private void InitializeCommands(){

    CommandBindings.Add(
        new CommandBinding(ApplicationCommands.Close, Close_Execute, Close_CanExecute)
    );
}

private void Close_CanExecute(object sender, CanExecuteRoutedEventArgs e){
    // True executes this handler, but blocks the one in the window
    // False executes the one in the window, but ignores this one
    e.CanExecute = true;

    // Doesn't seem to have any effect
    e.Handled = false;
}
private void Close_Execute(object sender, ExecutedRoutedEventArgs e){
    Console.WriteLine("I want to respond passively!");
    // Doesn't seem to have any effect
    e.Handled = false;
}

但是,无论我们将该属性设置为什么,该命令都不会将其置于主窗口中。如果我们删除页面中的命令绑定,它将再次起作用,证明该页面正在吞噬命令,而与该属性无关。

那么,您要怎么做才能使页面被动地监听Close事件?

2 个答案:

答案 0 :(得分:0)

是的,CommandBinding吃命令。这是其实现的摘录:

internal void OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
    if (!e.Handled)
    {
        if (e.RoutedEvent == CommandManager.ExecutedEvent)
        {
            if (this.Executed != null && CheckCanExecute(sender, e))
            {
                this.Executed(sender, e);
                e.Handled = true;
            }
        }
        else if (this.PreviewExecuted != null && CheckCanExecute(sender, e))
        {
            this.PreviewExecuted(sender, e);
            e.Handled = true;
        }
    }
}

如您所见,如果为CanExecute返回true,则命令将被吃掉。

您可能想看看CompositeCommand。那将是你的小巷。您创建一个绑定到框架的全局CompositeCommand,然后可以将不同的视图附加到该框架。不同的实现可以采用不同的酷方法来确定命令的多个订阅者的行为。即所有必须返回canExecute,任何必须返回,仅进入活动视图,等等。

编辑:CompositeCommand最初是Prism的一部分,但是您可以找到一个独立的实现,也可以从Prism本身中提取一个实现:

https://github.com/PrismLibrary/Prism/blob/master/Source/Prism/Commands/CompositeCommand.cs

答案 1 :(得分:0)

另一个想法是看看AddHandler()方法。让我们为所有子事件添加一个事件处理程序。即为了控制面包屑,我可以这样做:

AddHandler(BreadcrumbSplitButton.ClickEvent,新的RoutedEventHandler(OnBreadcrumbSplitButtonClick));

在BreadCrumb类中,以侦听所有子级BreadcrumbSplitButtons中的ClickEvent。