开发者

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 e开发者_如何学Pythonverything 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
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜