2015-11-24 6 views
0

Я пытаюсь добавить shourcut к моему MenuItem:Добавить shorcut в MENUITEM

<Menu x:Name="menu" VerticalAlignment="Top"> 
     <Menu.InputBindings> 
      <KeyBinding Modifiers="Control" Key="N" Command="{Binding NewTerrainCommand}" CommandParameter="{Binding ElementName=Viewport3D, Path=Camera}" /> 
     </Menu.InputBindings> 

     <MenuItem Header="_File"> 
      <MenuItem Header="_New Terrain" Command="{Binding NewTerrainCommand}" CommandParameter="{Binding ElementName=Viewport3D, Path=Camera}" InputGestureText="Ctrl+N" /> 
     </MenuItem> 
     <MenuItem Header="_Edit" /> 
     <MenuItem Header="_Window" /> 
     <MenuItem Header="_Help" /> 
    </Menu> 

Я читал, что это может быть сделано путем определения, но что данное сочетание клавиш просто принес мне больше вопросов:

  • Где я могу установить команду в теге keybinding или теге menuitem или обоих?
  • Как связать привязку клавиш с элементом меню?

и все еще не работает, я уверен, что у меня что-то не хватает.

спасибо.

+1

Создайте 'KeyBinding' против вашего' Window'. WPF начнет с сосредоточенного элемента и поднимет визуальное дерево в поисках 'KeyBinding' – dkozl

+0

@dkozl, поэтому мне нужно определить привязку клавиш к моему окну (в обоих местах) ?, это не так, но что, если datacontext, который имеет ли команда не то же самое, что и datacontext окна? – elios264

+0

Он должен быть где-то вдоль визуального дерева от сосредоточенного элемента, где имеет смысл использовать этот короткий отрезок. Во всех других случаях, когда команда может быть найдена, но параметр неверен, 'CanExecute' должен возвращать false, чтобы отключить команду. – dkozl

ответ

1

Небольшое пояснение первое:

Think команды (в данном случае RoutedCommand, или в целом и реализациях ICommand) как сигнал, своего рода, который распространяется через дерево визуалов. В каждом элементе визуального дерева WPF проверяет, существует ли конкретное действие, зарегистрированное против этой команды, и если оно найдено, это действие выполняется.

В вашем примере, есть три различных ассоциаций, которые должны быть объявлены:

  1. MenuItem должна быть связана с командой
  2. Командование должно быть связано с соответствующими действиями (CanExecute, Executed)
  3. MenuItem требуется связь с Ctrl+N комбинация клавиш.

Выполнение (# 1) прост - вы просто указываете команду в качестве привязки в MenuItem.

(# 2) более интересен. Команды, как я упоминал ранее, предназначены для передачи сигнала для действия через визуальное дерево. Это означает, что разные части визуального дерева должны были бы объявить свою соответствующую способность обрабатывать эту команду. Это заявление сделано с помощью CommandBinding. A CommandBinding связывает команду с действиями (CanExecute, Executed) в контексте визуального объекта.

Предположив, что метод, чтобы выполнить нашу команду будет жить в главном Window класса (как правило, MainWindow), мы должны были бы указать CommandBinding на экземпляре MainWindow. (Если быть более точным, MainWindow был бы одним из типов, объявляющих его способность обрабатывать указанную команду. Возможно, другие типы объявляют интерес к тому же Command - наш следующий пример просто имеет только один тип, выражающий интерес к передавая команду).

После того, как эта ассоциация объявляются (между MainWindow и командованием в вопросе), в любое время командование срабатывает (например, с помощью MenuItem), WPF бы знать, чтобы вызвать зарегистрированные CanExecute и Executed методы в MainWindow, поскольку соответствующее CommandBinding существует, чтобы заявить, что MainWindow способен обрабатывать команду.

(# 3) относительно легко сделать. RoutedCommand имеет свойство InputGestures, и к нему можно добавить KeyGesture. После добавления MenuItem, связанный с этой командой, автоматически выдает KeyGesture.

В следующем примере (в основном получены из вашего собственного кода, с изменениями) показывает, как это все связаны друг с другом:

MainWindow.xaml:

<Window x:Class="CommandsSample.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:system_windows_input="clr-namespace:System.Windows.Input;assembly=PresentationCore" 
     xmlns:local="clr-namespace:CommandsSample" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <!-- The following DataContext declaration simply means that the current instance of MainWindow (i.e., 'this') 
     is the operative DataContext for all data bindings specified in the rest of this XAML --> 
    <Window.DataContext> 
     <Binding RelativeSource="{RelativeSource Self}"/> 
    </Window.DataContext> 
    <Window.Resources> 
     <!-- Declare a RoutedCommand with an associated KeyGesture --> 
     <RoutedCommand x:Key="NewFileCommand"> 
      <RoutedCommand.InputGestures> 
       <system_windows_input:KeyGesture> 
        Ctrl+N 
       </system_windows_input:KeyGesture> 
      </RoutedCommand.InputGestures> 
     </RoutedCommand> 
    </Window.Resources> 

    <!-- The following CommandBinding associates NewFileCommand with actions defined in the code behind --> 
    <Window.CommandBindings> 
     <CommandBinding Command="{StaticResource NewFileCommand}" CanExecute="CouldCreateNewFile" Executed="CreatenewFile"/> 
    </Window.CommandBindings> 

    <!-- Main UI consisting of a Menu and a TextBox --> 
    <DockPanel> 
     <Menu DockPanel.Dock="Top"> 
      <MenuItem Header="_File"> 
       <!-- The New MenuItem will automatically infer the KeyGesture Ctrl+N from NewFileCommand --> 
       <MenuItem Header="_New" Command="{StaticResource NewFileCommand}" /> 

       <MenuItem Header="_Open"/> 
       <MenuItem Header="_Save"/> 
       <Separator/> 
       <MenuItem Header="_Exit"/> 
      </MenuItem> 
     </Menu> 
     <TextBox AcceptsReturn="True" Text="{Binding FileText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
    </DockPanel> 
</Window> 

MainWindow.xaml.cs:

using System; 
using System.Windows; 
using System.Windows.Input; 

namespace CommandsSample 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     #region NewFileCommand Handlers 

     /// <summary> 
     /// CanExecute 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void CouldCreateNewFile(object sender, CanExecuteRoutedEventArgs e) 
     { 
      e.CanExecute = !string.IsNullOrEmpty(FileText); 
     } 

     /// <summary> 
     /// Executed 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void CreatenewFile(object sender, ExecutedRoutedEventArgs e) 
     { 
      FileText = string.Empty; 
     } 

     #endregion NewFileCommand Handlers 

     #region Dependency Properties 

     /// <summary> 
     /// The contents of the TextBox in the UI are backed by this property 
     /// </summary> 
     public String FileText 
     { 
      get { return (String)GetValue(FileTextProperty); } 
      set { SetValue(FileTextProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for FileText. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty FileTextProperty = 
      DependencyProperty.Register("FileText", typeof(String), typeof(MainWindow), new PropertyMetadata(string.Empty)); 


     #endregion Dependency Properties 
    } 
} 
+0

Спасибо за ваше объяснение, но в моем случае я не использовал код позади, я только установил datacontext (который имеет ICommand) для окна, поэтому я не думаю, что могу использовать ваш пример, потому что командование обязано связывать перенаправленная команда на 2 кодовых вызова – elios264