Page 1 of 1

Global keybindings in Noesis

Posted: 12 Apr 2016, 11:48
by peterh
I am creating a Unity application using NoesisGUI. My NoesisGUIPanel uses a UserControl named LayoutRoot as root for the GUI.

Inside this app, I have a button, let's call it ActionButton, which is a UserControl that is used in various views (but not all) in the app. Whenever ActionButton is used in a view, I'd like the Enter key to trigger the command tied to ActionButton.

At first I tried adding a KeyBinding to the InputBindings of ActionButton like this (hiding a bunch of irrelevant stuff for brevity):
<UserControl
        x:Name="ActionButtonControl"
        x:Class="MyNamespace.ActionButton">

    <UserControl.InputBindings>
      <!-- The ActionButton code behind defines a DependencyProperty named CommandProperty -->
      <KeyBinding Command="{Binding Command,ElementName=ActionButtonControl}" Gesture="Enter" /> 
    </UserControl.InputBindings>

    <Grid>
        <Button Content="" Command="{Binding Command,ElementName=ActionButtonControl}" />
    </Grid>
</UserControl>
This did not work. I figured it was because the ActionButton did not have application focus, so I tried defining a KeyBinding in LayoutRoot (the XAML root of the project) to see if focus was the problem:
<UserControl
        x:Class="MyNamespace.LayoutRoot"
        x:Name="Root">

  <UserControl.InputBindings>
    <KeyBinding Command="{Binding SomeCommand}" Gesture="Enter" />
  </UserControl.InputBindings>

  <Grid>
    <!-- Application contents here>
  </Grid>
</UserControl>
My theory was that if defined at the root, the InputBinding would always have focus, but the command won't trigger anyways. What am I doing wrong here?

Re: Global keybindings in Noesis

Posted: 12 Apr 2016, 13:44
by sfernandez
I confirmed there is a bug with the UserControl, that is not populating its InputBindings when defined in its associated xaml. Could you please report it in our bugtracker?

Meanwhile I found a way to workaround this problem. Instead of setting the InputBinding in the UserControl itself, do it in a root ContentControl that will wrap UserControl contents:
<UserControl
        x:Name="ActionButtonControl"
        x:Class="MyNamespace.ActionButton">

    <ContentControl>
        <ContentControl.InputBindings>
            <!-- The ActionButton code behind defines a DependencyProperty named CommandProperty -->
            <KeyBinding Command="{Binding Command,ElementName=ActionButtonControl}" Gesture="Enter" /> 
        </ContentControl.InputBindings>

        <Button x:Name="btn" Content="" Command="{Binding Command,ElementName=ActionButtonControl}" />

    </ContentControl>

</UserControl>
Other thing you have to keep in mind is that application focus must be contained under the control that defines the input bindings, otherwise the KeyDown event route won't go through it and binding won't be fired. So you probably want to set the focus to the Button when you load the ActionButtonControl:
public class ActionButton
{
    public ActionButton()
    {
        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        var btn = (Button)FindName("btn");
        btn.Focus();
    }

    // ...
}

Re: Global keybindings in Noesis

Posted: 15 Apr 2016, 08:51
by peterh
I can't get your workaround to work. I tried moving the keybinding out to the root element:
<UserControl
        x:Class="MyNamespace.LayoutRoot"
        x:Name="Root">

  <Grid>
    <Grid.InputBindings>
      <KeyBinding Command="{Binding SomeCommand}" Gesture="Enter" />
    </Grid.InputBindings>
    <!-- Application contents here>
  </Grid>
</UserControl>
But no luck there, either. Due to additional requirements on my GUI discovered (the button simply cannot be kept in focus at all times), I think I will go with rolling my own solution using Unity's built in key event handling instead.

Re: Global keybindings in Noesis

Posted: 29 Apr 2016, 15:08
by jsantos
Fixed in 1.2.6