Определение ярлыков MenuItem - PullRequest
44 голосов
/ 13 января 2011

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

Но это не работает с ярлыком, просто нажатием:

<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

Ответы [ 5 ]

57 голосов
/ 04 июня 2013

HB был прав ... Я просто хотел добавить больше точности.

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

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

<Window.CommandBindings>
     <CommandBinding Command="Open" Executed="OpenCommandBinding_Executed"/>
     <CommandBinding Command="SaveAs" Executed="SaveAsCommandBinding_Executed"/>
</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 Key="S" Modifiers="Control" Command="SaveAs"/>
</Window.InputBindings>

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

<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>

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

56 голосов
/ 13 января 2011

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

, например

<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 , чем использовать RoutedCommands. Вы можете иметь конструктор, который принимает делегаты для Execute и CanExecute, чтобы легко создавать команды, которые делать разные вещи, такие реализации часто называют DelegateCommand или RelayCommand. Таким образом, вам не нужно CommandBindings.)

10 голосов
/ 02 декабря 2011

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

Например:

<MenuItem Header="_Editar">
<MenuItem Header="_Procurar" Name="MenuProcurar"
          InputGestureText="Ctrl+F"
          Click="MenuProcurar_Click">
    <MenuItem.ToolTip>
        <ToolTip>
            Procurar
        </ToolTip>
    </MenuItem.ToolTip>
</MenuItem>
</MenuItem>
7 голосов
/ 18 ноября 2015

Я слишком склонен к 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>

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

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

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

Обратите внимание на Command="{StaticResource hwc}" s, добавленные в каждую 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 для определения параметра или использовать «настоящие» теги <MenuItem.CommandParameter>, как в пункте меню Open выше, для определения чего-то сложного.В этом случае мы передаем весь родительский Window объект , что было самым простым (хотя и не самым чистым) способом бросить наш контекст VB6-ish в обработчик событийcode.

Добавление сочетаний клавиш к MenuItem s (он же «Ответ на 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.

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


Возможный профессиональный совет:

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

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

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

7 голосов
/ 15 марта 2015

Вы также можете объявить 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}"/>

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

...