2012-05-12 4 views
2

Есть две разных идей о том элементе, который играет роль цели команды по умолчанию в книге «WPF развития управления»:Какова целевая команда по умолчанию?

Page 258 » Мишень команды объекта, на котором команда поднятый , Интерфейс ICommandSource содержит свойство CommandTarget , которое может быть установлено для определенного объекта. По умолчанию исходный код команды считается целью команды.

Page 262 »По умолчанию, когда CommandTarget не установлен, то элемент с фокусом клавиатуры используется.

Кроме того, в этом tutorial, мы можем оставить пункты меню и командные кнопки цели неопределенной в то время как пункты меню только (то есть, а не кнопки) могут обнаружить цель команды действительно. Итак, какова целевая команда по умолчанию ?!

ответ

1

Я думаю, я просто понял, что это означает:

Если элемент фокусирования, он не может обнаружить неопределенную маршрутизируемую команда цели автоматически.

Если элемент сфокусирован, это означает, что он всегда будет иметь фокус клавиатуры, когда он активирован, чтобы поднять команду. Таким образом, если у него есть CommandBinding для Command, он всегда будет обрабатывать его сам, и если он не будет, он всегда будет отключен.

Однако вы можете обойти это, установив FocusManager.IsFocusScope на true в контейнере управления, как в этом XAML:

<Window x:Class="MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:my="clr-namespace:CommandRouting" 
    Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="auto"/> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Menu IsMainMenu="True"> 
      <MenuItem x:Name="TestMenuItem" Command="{x:Static my:MainWindow.TestCommand}"/> 
     </Menu> 
     <GroupBox x:Name="CommandBindingOnControlsGroupBox" Header="CommandBinding on Controls" Grid.Row="1"> 
      <StackPanel> 
      <Button x:Name="CommandBindingOnButtonButton" Command="{x:Static my:MainWindow.TestCommand}" Content="CommandBinding on Button"> 
       <Button.CommandBindings> 
        <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed" PreviewExecuted="CommandBinding_Executed"/> 
       </Button.CommandBindings> 
      </Button> 
       <TextBox x:Name="CommandBindingOnTextBoxTextBox"> 
        <TextBox.CommandBindings> 
         <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/> 
        </TextBox.CommandBindings> 
        <TextBox.InputBindings> 
         <!-- provide alternate keyboard shortcut --> 
         <KeyBinding Key="{x:Static Key.P}" Modifiers="{x:Static ModifierKeys.Control}" Command="{x:Static my:MainWindow.TestCommand}"/> 
        </TextBox.InputBindings> 
       </TextBox> 
       <Button x:Name="CommandTargetOnButtonButton" Command="{x:Static my:MainWindow.TestCommand}" Content="CommandTarget on Button" CommandTarget="{Binding ElementName=CommandBindingOnControlsGroupBox}"> 
        <Button.CommandBindings> 
         <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/> 
        </Button.CommandBindings> 
       </Button> 
      </StackPanel> 
     </GroupBox> 
     <GroupBox x:Name="CommandBindingOnContainerGroupBox" Header="CommandBinding on Container" Grid.Row="2"> 
      <GroupBox.CommandBindings> 
       <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" PreviewExecuted="CommandBinding_Executed"/> 
      </GroupBox.CommandBindings> 
      <StackPanel x:Name="CommandBindingOnInnerContainerStackPanel"> 
       <StackPanel.CommandBindings> 
        <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/> 
       </StackPanel.CommandBindings> 
       <Button x:Name="CommandBindingOnContainerButton" Command="{x:Static my:MainWindow.TestCommand}" Content="CommandBinding on Two Containers"> 
       </Button> 
       <TextBox x:Name="CommandBindingOnContainerTextBox"> 
        <TextBox.InputBindings> 
         <!-- provide alternate keyboard shortcut --> 
         <KeyBinding Key="{x:Static Key.P}" Modifiers="{x:Static ModifierKeys.Control}" Command="{x:Static my:MainWindow.TestCommand}"/> 
        </TextBox.InputBindings> 
       </TextBox> 
      </StackPanel> 
     </GroupBox> 
     <GroupBox x:Name="OtherFocusScopeGroupBox" FocusManager.IsFocusScope="True" Header="Other FocusScope, No CommandBindings" Grid.Row="3"> 
      <StackPanel > 
       <Button x:Name="OtherFocusScopeButton" Command="{x:Static my:MainWindow.TestCommand}" Content="Other FocusScope"> 
       </Button> 
       <TextBox x:Name="OtherFocusScopeTextBox"> 
        <TextBox.CommandBindings> 
         <CommandBinding Command="{x:Static my:MainWindow.TestCommand}" Executed="CommandBinding_Executed"/> 
        </TextBox.CommandBindings> 
        <TextBox.InputBindings> 
         <!-- provide alternate keyboard shortcut --> 
         <KeyBinding Key="{x:Static Key.P}" Modifiers="{x:Static ModifierKeys.Control}" Command="{x:Static my:MainWindow.TestCommand}"/> 
        </TextBox.InputBindings> 
       </TextBox> 
      </StackPanel> 
     </GroupBox> 
    </Grid> 
</Window> 
+0

+1 Спасибо. Как я уже говорил, в случае ** Unspecified CommandTarget ** сфокусированный элемент будет считаться «CommandTarget», и механизм начнет перемещаться от него, чтобы найти ближайшее командное связующее. Следовательно, я думаю, что лучше сказать: ** «Таким образом, если у него есть CommandBinding для Command', он поднимет событие * Executed * routed (как его e.sender), и поэтому' он всегда будет обрабатывать его сам , и если это не будет, механизм продолжит поиск, пока не достигнет корня. Таким образом, это может быть включено, если на этом пути найдено другое связующее. ** Согласен со мной? – Mimi

+0

Да, это технически более полно. Тем не менее, дело здесь в том, что настраиваемый элемент управления всегда будет его собственным CommandTarget, поскольку он всегда будет тянуть фокус клавиатуры к себе, в то время как идея не указывать CommandTarget заключается в том, что команда может обрабатываться любым элементом, который в настоящее время сфокусирован. Как я уже сказал, это ограничение можно обойти, установив FocusManager.IsFocusScope. Вероятно, нужно иметь значение между CommandTarget, элементом, который вызывает Executed RoutedEvent, и CommandHandler, элементом с CommandBinding, который обрабатывает событие. – hbarck

2

Из контекста я не понимаю, что означает первое выделенное предложение, но я думаю, что это неправильно. Второе предложение с другой стороны, это право

MSDN:

Если целевая команда не определена, то элемент с фокусом клавиатуры будет использоваться в качестве цели команды.

Это полезно, если вы хотите, чтобы команды работали над чем-то, например, команда вставки в текстовом поле, сфокусированное в данный момент. Вы хотите, чтобы команда paste всегда работала, независимо от того, в каком текстовом поле или, возможно, какой другой элемент управления имеет фокус, и это делает это возможным. Стоит отметить, что в отношении меню есть еще одна концепция, которая называется FocusScope. Командование в WPF иногда может быть сложным, подумайте о кнопке сохранения, которая не занимает фокус текстового поля, поэтому не обновляет свойство Text (потому что оно только обновляет привязку цели на focuslost). Но помните, CommandTarget работает только на RoutedCommands, а не на «простых» ICommands.

Что касается вашего учебного видео, он не видел его: эта концепция работает для всех CommandSources, которая не принимает сам Focus Keyboard.

Таким образом, CommandTarget до тех пор, пока Command является RoutedCommand, текущий элемент сфокусирован на клавиатуре, иначе он игнорируется.

+0

+1 Спасибо @dowhilefor. Я сомневаюсь, понять это; 'Если элемент сфокусирован, он не может автоматически обнаружить неопределенную маршрутизированную команду.' Это правильно? – Mimi

+0

@ Мими честно, я тоже этого не понимаю. Фокусное управление не имеет ничего общего с командами и не заботится о целевой команде. Командная цель - это просто элемент управления, в котором маршрутизация начинается вверх до окна, пока не найдет CommandBinding, которое обрабатывает фактическую командную логику. – dowhilefor

0

Здесь не хватает одного пункта: CommandTarget для данной команды может быть только объектом, который определяет CommandBinding для этой команды.

Редактировать: уточнить и исправить следующие абзацы, чтобы не оставлять вводящую в заблуждение информацию в системе.

Командная маршрутизация - это особый случай маршрутизации событий, то есть события, движущиеся вверх и вниз по логическому дереву: элементы управления, реализующие интерфейс ICommandSource, такие как InputBindings, Buttons или MenuItems, являются CommandSources. Если они поднимут команду, это приведет к запуску RoutedEvent в CommandTarget. Обычно это элемент, который имеет фокус клавиатуры. Событие перемещается вверх по логическому дереву, пока оно не достигнет корня.Все элементы с CommandBindings для команды по этому пути получают возможность обрабатывать команду, хотя обычно первый элемент, который обрабатывает команду, выигрывает и останавливает процесс маршрутизации. Это может быть даже сам CommandSource, если у него есть CommandBinding для этой команды, и это, вероятно, то, о чем ваша первая цитата. Если элемент обрабатывает событие, параметр отправителя будет элементом, который определяет CommandBinding, тогда как свойство Source RouteEventArgs события будет элементом, в котором маршрутизация пула событий, то есть CommandTarget.

Чтобы завершить путаницу, интерфейс ICommandSource определяет свойство CommandTarget. Это свойство предназначено для случаев, когда вы хотите выполнить короткую замыкание команды, и хотите, чтобы специальный элемент управления обрабатывал эту команду независимо от того, где находится фокус клавиатуры. В этом случае вы должны написать что-то вроде CommandTarget = "{Binding ElementName = MyCommandTargetControl}" на Button или MenuItem, о котором идет речь. Опять же, вы должны убедиться, что этот элемент управления имеет CommandBinding для команды, иначе команда будет постоянно отключена.

+0

Я не уверен, правильно ли понимаю ваше первое предложение. Но цель команды может быть чем угодно, а не тем, что имеет командную привязку к этой конкретной команде. Например, команда «Вставить», скажем, имеет окно CommandBinding, теперь кнопка получает команду «Вставить», а цель была установлена ​​на это конкретное текстовое поле. Это отлично работает, без текстового поля, имеющего команду для вставки. – dowhilefor

+0

В случае явного указания «CommandTarget» я обнаружил, что ближайший элемент в CommandTarget (между ним - корень визуального дерева), который имеет «CommandBinding», выполняет команду. Здесь 'e.Source' будет целевым элементом, и уникальным способом определения реального источника invoker является использование' CommandParameter' как самосвязывающего источника привязки. (через e.Parameter). С другой стороны, в случае неизвестного «CommandTarget» механизм команд начинает перемещаться из источника команды (который устанавливает свойство 'Command') до корня и не возвращается назад к сфокусированному элементу – Mimi

+0

@dowhilefor: TextBoxes иметь командные команды класса (см. CommandManager.RegisterClassCommandBinding для получения подробной информации) для большого количества команд редактирования. Вот почему они могут обрабатывать такие вещи, как копирование и вставка без явного CommandBindings. Чтобы проверить маршрутизацию команд, я бы использовал пользовательский RoutedCommand, так что я уверен, что никакое встроенное поведение не мешает мне ... – hbarck

4

Основываясь на нескольких других тестовых примерах и в отношении ответов @dowhilefor и @ hbarck, я пришел к выводу, что для каждого случая существует конкретная дорожка для путешествий.

указано CommandTarget: Она начинается от CommandTarget к корневому элементу визуального дерева, чтобы найти первый элемент (ближайший), который связал команду. (Это выглядит для этого элемента только на этом пути.) Вывод:

  1. Отправитель:CommandTarget элемент контейнера, который связал команду (с CommandBinding).
  2. e.source: Элемент, указанный в качестве CommandTarget.

Не выбрано CommandTarget: Он начинается от элемента, который получил фокус (при CommandSource объеме) к корневому элементу визуального дерева, чтобы найти первый элемент (ближайший), который связал команду. При этом условии сфокусированный элемент будет определяться как CommandTarget. Вывод:

  1. Отправитель: Контейнер сфокусированного элемента, который связан команда (с CommandBinding тегом).
  2. e.Source: Сфокусированный элемент.
+0

Да, я думаю, вы получили его здесь. Фактически, элемент, который инициирует команду (Button или MenuItem, который называется источником Command в документах WPF) полностью отсутствует, здесь я ошибся в своем первоначальном ответе, поэтому я собираюсь изменить или удалить это ... – hbarck

+0

Спасибо @hbarck. Ваш ответ был полезен. – Mimi

Смежные вопросы