Подтвердить что ты не робот

Определение ярлыков MenuItem

Мне нужен простой способ установить ярлык для пунктов меню.

Но это не работает с ярлыком, просто щелкнув:

<MenuItem Header="Editar">
    <MenuItem Header="Procurar" Name="MenuProcurar"
              InputGestureText="Ctrl+F"
              Click="MenuProcurar_Click">
        <MenuItem.ToolTip>
            <ToolTip>
                Procurar
            </ToolTip>
        </MenuItem.ToolTip>
    </MenuItem>
</MenuItem>

Я использую WPF 4.0

4b9b3361

Ответ 1

Вам нужно использовать KeyBindingsCommandBindings если вы (re) используете RoutedCommands, например, те, что найдены в ApplicationCommands class) для этого в элементах управления, где должны работать ярлыки.

например.

<Window.CommandBindings>
        <CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
        <KeyBinding Key="N" Modifiers="Control" Command="New"/>
</Window.InputBindings>

Для пользовательских RoutedCommands:

static class CustomCommands
{
    public static RoutedCommand DoStuff = new RoutedCommand();
}

использование:

<Window
    ...
    xmlns:local="clr-namespace:MyNamespace">
        <Window.CommandBindings>
                <CommandBinding Command="local:CustomCommands.DoStuff" Executed="DoStuff_Executed" />
        </Window.CommandBindings>
        <Window.InputBindings>
                <KeyBinding Key="D" Modifiers="Control" Command="local:CustomCommands.DoStuff"/>
        </Window.InputBindings>
    ...
</Window>

(Часто более удобно использовать ICommand interface вместо использования RoutedCommands. У вас может быть конструктор, который принимает делегаты для Execute и CanExecute, чтобы легко создавать команды, которые выполняют разные вещи, такие реализации часто называют DelegateCommand или RelayCommand. Таким образом вам не нужно CommandBindings.)

Ответ 2

H.B. был прав... Я просто хотел добавить дополнительные замечания.

Удалите событие Click на вас MenuItem и привяжите его вместо Command.

1 - добавьте/создайте свои команды:

 <Window.CommandBindings>
        <CommandBinding Command="Open" Executed="OpenCommandBinding_Executed"></CommandBinding>
        <CommandBinding Command="SaveAs" Executed="SaveAsCommandBinding_Executed"></CommandBinding>
    </Window.CommandBindings>

Команды ссылаются на следующий код

private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    Open();//Implementation of open file
}
private void SaveAsCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    SaveAs();//Implementation of saveAs
}

2 - Свяжите команды с необходимыми ключами:

<Window.InputBindings>
    <KeyBinding Key="O" Modifiers="Control" Command="Open"></KeyBinding>
    <KeyBinding Key="S" Modifiers="Control" Command="SaveAs"></KeyBinding>
</Window.InputBindings>

3 - Наконец, назначьте команды с помощью пункта меню (InpuGestureText - только текст для оформления):

<Menu Name="menu1" >
    <MenuItem Header="_File" >
        <MenuItem Name="menuOpen" Header="_Open..." Command="Open" InputGestureText="Ctrl+O"  />
        <MenuItem Name="menuSaveAs" Header="_Save as..." Command="SaveAs" InputGestureText="Ctrl+S"  />
     </MenuItem>
</Menu>

Таким образом, несколько входов могут быть связаны с одной и той же командой.

Ответ 3

По моему скромному мнению гораздо проще использовать _ в заголовке. Это автоматически создаст желаемый HotKey.

Например:

<MenuItem Header="_Editar">
<MenuItem Header="_Procurar" Name="MenuProcurar"
          InputGestureText="Ctrl+F"
          Click="MenuProcurar_Click">
    <MenuItem.ToolTip>
        <ToolTip>
            Procurar
        </ToolTip>
    </MenuItem.ToolTip>
</MenuItem>
</MenuItem>

Ответ 4

Я чересчур смещен Windows.Forms и gulp VB 6, поэтому я вроде согласен с Джонатаном и Jase, чтобы был более простой/процедурный метод статической проводки обработчиков событий, которые необязательно CommandBindings. И есть, я думаю.

Хороший учебник для использования обработчиков не CommandBinding, подобных этому, но с акцентом на кнопках можно найти в этом сообщении в блоге MSDN, я верю. Я перегоняю и нацеливаю MenuItem s...

Создание ICommand

Сначала создайте класс, реализующий ICommand. Вы можете поместить это где угодно, конечно, даже в свой файл MainWindow.xaml.cs, если хотите, чтобы ваш демо-код был безумно прост. Скорее всего, вы захотите сделать CanExecute более сложным, если хотите позже/позже добавить пункты меню, но на данный момент мы всегда будем иметь доступ к нашим элементам меню.

public class HelloWorldCommand : ICommand
{
    public void Execute(object parameter)
    {
        MessageBox.Show(@"""Hello, world!"" from " 
            + (parameter ?? "somewhere secret").ToString());
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
} 

Как говорится в учебном пособии, вы могли бы вызывать эту команду где-нибудь уже, с кодом вроде...

var hwc = new HelloWorldCommand();
if (hwc.CanExecute(this))
    hwc.Execute(this);

Объявление вашей команды в окне

Итак, добавьте свое "объявление" для HelloWorldCommand в наше окно, чтобы мы могли использовать его позже. Внутри тэгов Window зарегистрируйте команду как ресурс:

<Window.Resources>
    <local:HelloWorldCommand x:Key="hwc"/>
</Window.Resources>

Теперь у нас есть аккуратный ярлык для ссылки на эту команду "local namespaced", "hwc", хотя вы, очевидно, можете использовать любую нужную строку. Мы будем использовать это в нашем xaml.

Проводка (и повторное использование!) команды

Добавьте наш MenuItem к нашему xaml. Я заменил запас Grid на DockPanel, потому что самый простой способ (для меня) иметь эквидированные виджеты, которые заполняют Window, хотя я оставил весь остальной пользовательский интерфейс.

Обратите внимание на Command="{StaticResource hwc}", разбрызгиваемую в каждое объявление MenuItem. Ключ здесь hwc - помните, что наш ярлык для HelloWorldCommand, который мы установили на уровне Window. И, конечно же, StaticResource говорит, что просто ищет ресурсы Window. Мы ничего не обязываем; мы просто используем наш ярлык.

<DockPanel LastChildFill="True">
    <Menu DockPanel.Dock="Top">
        <MenuItem Header="_File">
            <MenuItem 
                Header="_Open" 
                Command="{StaticResource hwc}" 
            >
                <MenuItem.CommandParameter>
                    <!-- so you could make this object as complex as you wanted, 
                        like, say, your entire Window. See magic incantation, below. -->
                    <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}" />
                </MenuItem.CommandParameter>

            </MenuItem>

            <MenuItem 
                Header="_Close" 
                Command="{StaticResource hwc}" 
                CommandParameter="Close"
                InputGestureText="Ctrl+G" />

            <MenuItem 
                Header="_Save" 
                Command="{StaticResource hwc}" 
                CommandParameter="Save" />

            <Separator />

            <MenuItem 
                Header="_Quit" 
                Command="{StaticResource hwc}" 
                CommandParameter="Quit" />
        </MenuItem>
</DockPanel>

CommandParameters для выделения источников событий

Обратите внимание, что мы используем одну и ту же команду для всего! Но как мы можем определить, какой виджет отобразил событие? Для этого вам нужно использовать CommandParameter - запомнить нашу подпись метода Execute: Execute(object parameter). Этот параметр CommandParameter - это то, что мы можем использовать, чтобы знать, как обрабатывать событие. Попробуйте запустить это и обратите внимание, что MessageBox будет использовать все, что в CommandParameter, чтобы вы знали источник события. Мы делаем все это вручную, но это не так уж плохо.

Также обратите внимание, что вы можете сделать эти объекты такими сложными, насколько хотите. Вы можете использовать свойство в теге MenuItem для определения параметра или использовать теги "real" <MenuItem.CommandParameter>, например, в пункте меню Open, чтобы определить что-то сложное. В этом случае мы передаем весь родительский объект Window, что было самым простым (хотя и не самым чистым) способом бросить наш контекст VB6-ish в код обработчика событий.

Добавление сочетаний клавиш в MenuItem (aka, "Ответ на OP" )

И теперь мы можем наконец ответить на исходный вопрос! Позвольте, наконец, подключить сочетание клавиш для пункта меню Close. Вы заметите, что мы уже объявили InputGestureText. Сам по себе InputGestureText является только косметическим. Если бы мы были слишком придирчивы, мы могли бы утверждать, что механизм создания сочетания клавиш не имеет прямого, неотъемлемого отношения с MenuItem вообще!

Нам нужно вместо этого (или дополнительно) зарегистрировать прослушиватель для Ctrl-G на уровне Window, чтобы поймать нажатие клавиши. Итак, на верхнем уровне ваших тегов Window вставьте это (взятое в основном здесь):

<Window.InputBindings>
    <KeyBinding Modifiers="Control"
                Key="G"
                Command="{StaticResource hwc}" 
                CommandParameter="window input binding"
    />
</Window.InputBindings>

Обратите внимание, что вы можете поместить теги CommandParameter в свой KeyBinding, переместив его из самозакрывающейся части XML в "реальные" открытые и закрытые теги KeyBinding.

И все готово. Запустите приложение и нажмите Ctrl-G. Whaddup.

Довольно просто, как только у вас есть игроки прямо, и гораздо меньше магического привязки-y, чем большинство команд для команд и MenuItems, я думаю.


Возможный совет:

Вся вещь CommandBinding немного смутила меня. Я полагаю, это просто для определенных типов команд. То есть вы не можете просто подключить любой Command, который вам нравится. Такие вещи, как то, что хвастается здесь (в том, что, по общему признанию, достойное учебное пособие!)...

Это может быть не совсем очевидно, но с помощью команд мы просто получили целую кучу вещей бесплатно: ярлыки клавиш, текст и InputGestureText на элементах, а WPF автоматически включает/отключает элементы в зависимости от активного элемента управления и его государство. В этом случае Cut и Copy отключены, потому что не выбран текст, но вставка включена, потому что мой буфер не пуст!

... является видом магии-y и не обязательно хорош, и может быть запутанным, когда вы новичок в меню WPF.

Ответ 5

Вы также можете объявить RoutedUICommand в XAML:

<Window.Resources>
    <RoutedUICommand x:Key="BuildCmd" Text="Build">
        <RoutedUICommand.InputGestures>
            <KeyGesture>CTRL+SHIFT+B</KeyGesture>
        </RoutedUICommand.InputGestures>
    </RoutedUICommand>      
</Window.Resources>

Сделайте привязку

<Window.CommandBindings>
    <CommandBinding Command="{StaticResource BuildCmd}" Executed="BuildCmdExecuted"/>
</Window.CommandBindings>

И в MenuItem

<MenuItem Command="{StaticResource BuildCmd}"/>

Обсуждается другое решение здесь.