Andrew Truckle
Andrew Truckle

Reputation: 19097

Menu Key Bindings are not working

None of my menu shortcuts are working.

I have read a bit up on this issue and according to the answer here it implies that I need to use commands instead of clicks.

Here is the menu structure:

<MenuItem x:Uid="MenuItem_10" Header="Zoom In" InputGestureText="CTRL +" Click="menuViewZoomInOutScaleFactor" Tag="25">
    <MenuItem.InputBindings>
        <KeyBinding x:Uid="KeyBinding_7" Key="OemPlus" Modifiers="Ctrl" />
    </MenuItem.InputBindings>
</MenuItem>
<MenuItem x:Uid="MenuItem_11" Header="Zoom Out" InputGestureText="CTRL -" Click="menuViewZoomInOutScaleFactor" Tag="-25">
    <MenuItem.InputBindings>
        <KeyBinding x:Uid="KeyBinding_8" Key="OemMinus" Modifiers="Ctrl"/>
    </MenuItem.InputBindings>
</MenuItem>
<Separator x:Uid="Separator_7"/>
<MenuItem x:Uid="MenuItem_12" Header="400%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=400}, Mode=OneWay}" Tag="400" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_13" Header="300%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=300}, Mode=OneWay}" Tag="300" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_14" Header="250%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=250}, Mode=OneWay}" Tag="250" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_15" Header="200%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=200}, Mode=OneWay}" Tag="200" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_16" Header="175%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=175}, Mode=OneWay}" Tag="175" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_17" Header="150%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=150}, Mode=OneWay}" Tag="150" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_18" Header="125%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=125}, Mode=OneWay}" Tag="125" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_19" Header="100%" IsCheckable="True" InputGestureText="CTRL + 0"  IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=100}, Mode=OneWay}" Tag="100" Click="menuViewZoomScaleFactor">
    <MenuItem.InputBindings>
        <KeyBinding x:Uid="KeyBinding_9" Key="D0"  Modifiers="Ctrl"/>
    </MenuItem.InputBindings>
</MenuItem>
<MenuItem x:Uid="MenuItem_20" Header="75%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=75}, Mode=OneWay}" Tag="75" Click="menuViewZoomScaleFactor"/>
<MenuItem x:Uid="MenuItem_21" Header="50%" IsCheckable="True" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ZoomFactor, Converter={ValueConverters:IsIntegerEqual To=50}, Mode=OneWay}" Tag="50" Click="menuViewZoomScaleFactor"/>
<Separator x:Uid="Separator_8"/>
<MenuItem x:Uid="MenuItem_22" Header="Custom..."/>

As you can see, three of the menu items shoudl be associated with:

  1. Ctrl + 0
  2. Ctrl +
  3. Ctrl -

I couldn't find those specific letters in the Keys list and settled for D0, OemPlus and OemMinus. Eitherway, none of my key bindings are actually getting processed. Why?

I can't see how I can convert from using clicks to commands. Up until now, all of my commands have been tied in with the view model. But in this instance I need the command to be associated with the code behind.

Here are my current click handlers:

private void menuViewZoomScaleFactor(object sender, RoutedEventArgs e)
{
    SetZoomFactor(Int32.Parse((String)((MenuItem)sender).Tag));
}

private void menuViewZoomInOutScaleFactor(object sender, RoutedEventArgs e)
{
    int iStep = Int32.Parse((String)((MenuItem)sender).Tag);

    if ((iStep == 25 && Settings.Default.ZoomFactor <= 375) ||
        (iStep == -25 && Settings.Default.ZoomFactor >= 75))
    {
        SetZoomFactor(Settings.Default.ZoomFactor + iStep);
    }
}

private void SetZoomFactor(int iZoomFactor)
{
    Settings.Default.ZoomFactor = iZoomFactor;

    IServiceProvider serviceProvider = myWorkbookView.Document as IServiceProvider;

    Guid SID_SWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
    Guid serviceGuid = SID_SWebBrowserApp;

    Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;

    SHDocVw.IWebBrowser2 WebBrowser = (SHDocVw.IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid);
    WebBrowser.ExecWB(SHDocVw.OLECMDID.OLECMDID_OPTICAL_ZOOM, SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, Settings.Default.ZoomFactor);
}

So I have to get my menu key bindings functional.

Upvotes: 0

Views: 855

Answers (1)

Eli Arbel
Eli Arbel

Reputation: 22739

If you want to use InputBindings in WPF you have to use commands. You'll need to assign commands to menu items as well as add command bindings and input gestures. You can use CommandParameters to pass arguments to the command binding handlers.

Think of the routed command object as a key that defines the link between the command source (the menu item or an input binding) and the command binding. The command bindings define the scopes of the visual tree where the command can run.

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow">
    <Window.CommandBindings>
        <CommandBinding Command="IncreaseZoom"
                        Executed="IncreaseZoom_OnExecuted" />
        <CommandBinding Command="Zoom"
                        Executed="Zoom_OnExecuted" />
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Gesture="Ctrl+Plus"
                    Command="IncreaseZoom" />
    </Window.InputBindings>
    <Grid>
        <Menu>
            <MenuItem Header="View">
                <MenuItem x:Uid="MenuItem_10"
                          Header="Zoom In"
                          InputGestureText="CTRL +"
                          Command="IncreaseZoom" />
                <MenuItem x:Uid="MenuItem_12"
                          Header="400%"
                          IsCheckable="True"
                          IsChecked="{Binding Whatever}"
                          Command="Zoom">
                    <MenuItem.CommandParameter>
                        <system:Int32>400</system:Int32>
                    </MenuItem.CommandParameter>
                </MenuItem>
            </MenuItem>
        </Menu>
    </Grid>
</Window>

Code behind:

private void IncreaseZoom_OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
    IncrementZoom(25);
}

private void Zoom_OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
    var zoom = (int)e.Parameter;
    SetZoom(zoom);
}

If you don't find a suitable command in the built-in commands, you can define your own in a static class:

public static class MyCommands
{
    public static readonly RoutedCommand SampleCommand = new RoutedCommand(
        nameof(SampleCommand), typeof(MyCommands), 
        new InputGestureCollection { new KeyGesture(Key.B, ModifierKeys.Alt) });
}

As you can see, you can even define a default input gesture so you won't need to specify an additional input binding in XAML (just the command binding). To use this class in XAML:

<MenuItem Command="{x:Static m:MyCommands.SampleCommand}" />

Upvotes: 2

Related Questions