开发者

Set focus on another control when a key pressed without code-behind

开发者 https://www.devze.com 2023-03-29 14:16 出处:网络
I\'m implementing something like an autosuggestion control: I have a user control that contains a TextBox and a ListBox. When the user enters text I\'m handing it with System.Windows.Interactivity beh

I'm implementing something like an autosuggestion control: I have a user control that contains a TextBox and a ListBox. When the user enters text I'm handing it with System.Windows.Interactivity behaviors and filling the ListBox with some values...

Everything works fine... but I want to enable the user to select items in the ListBox (i.e. to set Focus on the ListBox) when the down arrow key is pressed.

I know that it is possible to handle the KeyPressDown event of the 开发者_Python百科TextBox in the code-behind .cs file but how can I avoid this?


If you already use Interactivity that should not be much of an issue, just implement your own TriggerAction that has the properties Key & TargetName to indentify when and what to focus. Set it in an EventTrigger for PreviewKeyDown.

Sample implementation & use:

<TextBox>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PreviewKeyDown">
            <t:KeyDownFocusAction Key="Down"
                                  Target="{Binding ElementName=lbx}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>
<ListBox Name="lbx" ItemsSource="{Binding Data}" />
class KeyDownFocusAction : TriggerAction<UIElement>
{
    public static readonly DependencyProperty KeyProperty =
        DependencyProperty.Register("Key", typeof(Key), typeof(KeyDownFocusAction));
    public Key Key
    {
        get { return (Key)GetValue(KeyProperty); }
        set { SetValue(KeyProperty, value); }
    }

    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.Register("Target", typeof(UIElement), typeof(KeyDownFocusAction), new UIPropertyMetadata(null));
    public UIElement Target
    {
        get { return (UIElement)GetValue(TargetProperty); }
        set { SetValue(TargetProperty, value); }
    }

    protected override void Invoke(object parameter)
    {
        if (Keyboard.IsKeyDown(Key))
        {
            Target.Focus();
        }
    }
}

Tested it and it works, note that KeyDown does not because the arrow keys are intercepted and marked as handled by the TextBox.


I don't think you can avoid it

What's wrong with capturing the KeyDown event of the TextBox and if it's an Up or Down arrow key, just trigger the ListBox.KeyDown event in the code behind?

I see no reason not to use code-behind in MVVM if it is to provide view-specific functionality such as focus


This answer is based on the one from H.B., and adds support for checking to see if the Ctrl key is pressed. This means it can handle keycombinations such as Ctrl-F for find.

XAML

<TextBox>
<i:Interaction.Triggers>
    <i:EventTrigger EventName="PreviewKeyDown">
        <t:KeyDownFocusAction Key="Down" Ctrl="True"
                              Target="{Binding ElementName=lbx}" />
    </i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<ListBox Name="lbx" ItemsSource="{Binding Data}" />

Namespaces

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

See help on adding System.Windows.Interactivity.

DependencyProperty

public class KeyDownFocusAction : TriggerAction<UIElement>
{
    public static readonly DependencyProperty KeyProperty =
        DependencyProperty.Register("Key", typeof(Key), typeof(KeyDownFocusAction));
    public Key Key
    {
        get { return (Key)GetValue(KeyProperty); }
        set { SetValue(KeyProperty, value); }
    }

    public static readonly DependencyProperty CtrlProperty =
        DependencyProperty.Register("Ctrl", typeof(bool), typeof(KeyDownFocusAction));
    public bool Ctrl
    {
        get { return (bool)GetValue(CtrlProperty); }
        set { SetValue(CtrlProperty, value); }
    }

    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.Register("Target", typeof(UIElement), typeof(KeyDownFocusAction), new UIPropertyMetadata(null));
    public UIElement Target
    {
        get { return (UIElement)GetValue(TargetProperty); }
        set { SetValue(TargetProperty, value); }
    }

    protected override void Invoke(object parameter)
    {
        if (Keyboard.IsKeyDown(Key))
        {
            if (Ctrl == true)
            {
                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    Target.Focus();
                }
            }
        }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消