简体   繁体   中英

WPF autocompletebox and the enter key

I am trying to get the WPF AutoCompleteBox to raise the KeyDown event when I press the enter key. I am using the normal KeyDown hook, which works for everything but the enter key it seems. Does anyone know how I can fix this?

You could inherit the AutoCompleteBox , adding an event for Enter .

public class MyAutoCompleteBox : AutoCompleteBox
{
    public override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        if(e.Key == Key.Enter) RaiseEnterKeyDownEvent();
    }

    public event Action<object> EnterKeyDown;
    private void RaiseEnterKeyDownEvent()
    {
        var handler = EnterKeyDown;
        if(handler != null) handler(this);
    }
}

In your consuming class, you can subscribe:

public void Subscribe()
{
    autoCompleteBox.EnterKeyDown += DoSomethingWhenEnterPressed;
}

public void DoSomethingWhenEnterPressed(object sender)
{

}

Very late answer, but I faced this same problem that brought me to this question and finally solved it using PreviewKeyDown

<wpftoolkit:AutoCompleteBox Name="AutoCompleteBoxCardName"  
     Populating="LoadAutocomplete"  
     PreviewKeyDown="AutoCompleteBoxName_PreviewKeyDown"/>

and

private void AutoCompleteBoxName_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter)
    {
        //...
    }
}

There is a slightly easier (and in my opinion more MVVM) way:

// This still goes in your code behind (yuck!)
protected override void OnKeyDown(KeyEventArgs e)
        {
            if (!IsDropDownOpen && SelectedItem != null && (e.Key == Key.Enter || e.Key == Key.Return))
            {
               // Drop down is closed so the item in the textbox should be submitted with a press of the Enter key
                base.OnKeyDown(e); // This has to happen before we mark Handled = false
                e.Handled = false; // Set Handled = false so the event bubbles up to your inputbindings
                return;
            }

            // Drop down is open so user must be selecting an AutoComplete list item
            base.OnKeyDown(e);
        }

This minimizes the blasphemous code-behind and allows your key event to continue to bubble up to something like an input binding:

<UserControl.InputBindings>
    <KeyBinding Key="Tab" Command="{Binding NextCommand}"/>
    <KeyBinding Key="Tab" Modifiers="Shift" Command="{Binding LastCommand}"/>
    <KeyBinding Key="Escape" Command="{Binding ClearCommand}"/>
    <KeyBinding Key="Enter" Command="{Binding EnterCommand}"/>
</UserControl.InputBindings>

(I know this is a late answer, but I still think it's usefull for people who want to solve this issue, without code behind )

A good way to do this in MVVM

First add the reference:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

and from the NuGet package (MVVMLight):

xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"

Than in your View :

<wpftoolkit:AutoCompleteBox Name="AutoCompleteBoxName">
    <i:Interaction.Triggers>
                    <i:EventTrigger EventName="PreviewKeyDown">
                        <cmd:EventToCommand Command="{Binding AutoCompleteEnter}" PassEventArgsToCommand="True"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
</wpftoolkit:AutoCompleteBox>

and than in your ViewModel :

public ICommand AutoCompleteEnter { get { return new RelayCommand<System.Windows.Input.KeyEventArgs>(Auto_Complete_Enter); } }

public void Auto_Complete_Enter(System.Windows.Input.KeyEventArgs e)
{
    //Detect if key is 'Enter/Return' key
    if ((e.Key == Key.Enter) || (e.Key == Key.Return))
    {
        Console.WriteLine("U have pressed the enter key");
    }
}

Hope this will still help some people out.

So, I've spend a lot of time trying to get this thing to work. Other responses are certainly helpful and will get you to destination, but i have following issues with implementation:

  1. I needed MVVM solution with an ability to bind Enter to Command within ViewModel, which means that Event Handlers was undesirable option.
  2. I was trying to avoid adding additional dependencies to fix single event in a single control, so no MVVMLight.

Solution:

  1. Pull copy of DonNetProjects.Input.Toolkit from github
  2. Navigate to AutoCompleteBox/System/Windows/Controls/AutoCompleteBox.cs
  3. Change overload of OnKeyDown method to following:

      if (IsDropDownOpen) { if (SelectionAdapter != null) { SelectionAdapter.HandleKeyDown(e); if (e.Handled) { return; } } if (e.Key == Key.Escape) { OnAdapterSelectionCanceled(this, new RoutedEventArgs()); //e.Handled = true; } } else { // The drop down is not open, the Down key will toggle it open. if (e.Key == Key.Down) { IsDropDownOpen = true; //e.Handled = true; } } // Standard drop down navigation switch (e.Key) { case Key.F4: IsDropDownOpen = !IsDropDownOpen; e.Handled = true; break; case Key.Enter: if (IsDropDownOpen) { OnAdapterSelectionComplete(this, new RoutedEventArgs()); e.Handled = true; } break; default: break; } base.OnKeyDown(e); 
  4. Recompile to new DLL and reference it instead of original WPFToolkit.

Result: If new version used as following:

   xmlns:tk="clr-namespace:System.Windows.Controls;assembly=DotNetProjects.Input.Toolkit"
   <tk:AutoCompleteBox ItemsSource="{Binding AvailableValues}" SelectedItem="{Binding SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <tk:AutoCompleteBox.InputBindings>
                <KeyBinding Key="Enter" Command="{Binding AddValue}"/>
            </tk:AutoCompleteBox.InputBindings>
    </tk:AutoCompleteBox>

Resulting behavior is: if dropdown is open, Enter would be rerouted to it to complete selection, if dropdown is closed it will fire command in KeyBinding.

Alternatively, when using Caliburn Micro , you can simply use:

<Controls:AutoCompleteBox ItemsSource="{Binding Keywords}"
                          ValueMemberPath="Name"                   
                          Text="{Binding EnteredText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                          IsTextCompletionEnabled="True"
                          cal:Message.Attach="[Event PreviewKeyDown] = [Action AddTagOnEnter($eventArgs)]" />

Specifically, note the last line to attach your event. For some other method parameter options, see here .

Finally, define a public method in your ViewModel:

public void AddTagOnEnter(KeyEventArgs e)
{
    if (e.Key != Key.Enter) return;
    // Do something useful
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM