RoutedCommands, связанные с подэлементами, никогда не срабатывают

Я пытаюсь разобраться с RoutedCommands в WPF. Мне нравится, как они уменьшают связь между различными элементами пользовательского интерфейса и моделями, но я не могу заставить привязки работать для пользовательских элементов управления, которые являются дочерними для окна. Я думаю, что это будет легкой добычей для любого из вас, волшебников WPF! :-)

Вот пример кода, который можно попробовать:

Маршрутизируемая команда:

using System.Windows.Input;

namespace Wpf.RoutedCommands
{
    public static class Commands
    {
        public static readonly RoutedCommand SayHi = new RoutedCommand();
    }
}

XAML главного окна:

<Window x:Class="Wpf.RoutedCommands.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Wpf.RoutedCommands"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<!-- uncommenting the below makes it work but introduces coupling -->
<!--<Window.CommandBindings>
    <CommandBinding Command="{x:Static local:Commands.SayHi}" Executed="cmdSayHi" CanExecute="cmdCanSayHi"></CommandBinding>
</Window.CommandBindings>-->
<DockPanel LastChildFill="True">
    <Button DockPanel.Dock="Bottom" Content="Say Hi!" Command="{x:Static local:Commands.SayHi}" />
    <local:Greeter x:Name="Greeter" />
</DockPanel>    

Main window code:

using System.Windows.Input;

namespace Wpf.RoutedCommands
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // these two will be used if you uncomment the command bindings in XAML
        private void cmdCanSayHi(object sender, CanExecuteRoutedEventArgs e) => e.CanExecute = true;

        private void cmdSayHi(object sender, ExecutedRoutedEventArgs e) => Greeter.SayHi();
    }
}

Пользовательский элемент управления ("Greeter") XAML:

<UserControl x:Class="Wpf.RoutedCommands.Greeter"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Wpf.RoutedCommands"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<UserControl.CommandBindings>
    <CommandBinding Command="{x:Static local:Commands.SayHi}" Executed="cmdSayHi"  CanExecute="cmdCanSayHi"/>
</UserControl.CommandBindings>
<Grid>
    <Label x:Name="Label" />
</Grid>

Greeter code:

using System.Windows.Input;

namespace Wpf.RoutedCommands
{
    public partial class Greeter
    {
        public Greeter()
        {
            InitializeComponent();
        }

        private void cmdSayHi(object sender, ExecutedRoutedEventArgs e) => SayHi();

        private void cmdCanSayHi(object sender, CanExecuteRoutedEventArgs e) => e.CanExecute = true;

        public void SayHi() => Label.Content = "Hi!";
    }
}

Если вы создадите проект WPF и воспользуетесь вышеуказанным, вы увидите, что кнопка в главном окне отключена. Отладка показывает, что метод Greeter.cmdCanSayHi никогда не вызывается.

Если вы раскомментируете неактивный XAML в главном окне, все будет работать. Итак: почему я могу привязываться к командам из окна, но не к его дочерним элементам управления? Это связано со временем рендеринга или что-то в этом роде?


person Jonas Rembratt    schedule 04.10.2017    source источник


Ответы (1)


RoutedCommand ищет в визуальном дереве элемент, находящийся в фокусе, и вверх для элемента, который имеет соответствующий CommandBinding, а затем выполняет делегат Execute для этого конкретного CommandBinding.

Ваш UserControl расположен под Button в дереве элементов.

person mm8    schedule 04.10.2017
comment
Что ж, это, конечно, объясняет. Вы также знаете, почему маршрутизируемые команды были разработаны таким образом? - person Jonas Rembratt; 04.10.2017