Use AutoCompleteBox in WPF

Michele Cirella 1 Reputation point
2020-11-01T15:58:10.403+00:00

I am using Visual Studio 2019 with a WPF project with .NET Framework 4.8.
I need to use a AutoCompleteBox, but i'm not figure how to add to Visual Studio. All previous answers are old and refer to a WFPToolkit that seems ha been removed. Using NuGet command Install-Package WPFToolkit, return a package not found error.
I have installed Extended.Wpf.Toolkit and added the related dll .\MyProject\packages\Extended.Wpf.Toolkit.4.0.1\lib\net40\Xceed.Wpf.Toolkit.dll with all components. But in the list there isn't the AutoCompleteBox item.

How to solve? Are there some updated information?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,772 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Emon Haque 3,176 Reputation points
    2020-11-28T17:57:20.447+00:00

    I also had wanted to have this feature once but never attempted to create one. This time I've taken a shot and it's obviously a goal. Here's what I've in my Themes\Generic.xaml for the AutoCompleteBox:

    <Style TargetType="{x:Type local:AutoCompleteBox}">  
        <Setter Property="Template">  
            <Setter.Value>  
                <ControlTemplate TargetType="{x:Type local:AutoCompleteBox}">  
                    <Grid>  
                        <TextBox x:Name="inputText" Text="{TemplateBinding Text}"/>  
                        <Popup IsOpen="{Binding IsSuggestionVisible, RelativeSource={RelativeSource TemplatedParent}}"  
                               Width="{Binding ElementName=inputText, Path=ActualWidth}"  
                               MaxHeight="100"  
                               Placement="Bottom">  
                            <ListBox x:Name="suggestionBox"  
                                     BorderThickness="1"  
                                     BorderBrush="DodgerBlue"  
                                     IsSynchronizedWithCurrentItem="True"  
                                     ItemsSource="{TemplateBinding ItemsSource}">  
                                <ListBox.Resources>  
                                    <Style TargetType="ListBox">  
                                        <Style.Triggers>  
                                            <DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="False">  
                                                <Setter Property="Visibility" Value="Collapsed"/>  
                                            </DataTrigger>  
                                        </Style.Triggers>  
                                    </Style>  
                                </ListBox.Resources>  
                                <ListBox.InputBindings>  
                                    <KeyBinding Key="Return"   
                                                Command="{Binding SelectItem, RelativeSource={RelativeSource TemplatedParent}}"  
                                                CommandParameter="{Binding ElementName=suggestionBox, Path=SelectedItem}"/>  
                                </ListBox.InputBindings>  
                            </ListBox>  
                        </Popup>  
                    </Grid>  
                </ControlTemplate>  
            </Setter.Value>  
        </Setter>  
    </Style>  
    

    and in AutoCompleteBox.cs I've these:

    public class AutoCompleteBox : Control  
    {  
        TextBox inputText;  
        ListBox suggestionBox;  
        ICollectionView suggestionView;  
    
        static AutoCompleteBox()  
        {  
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoCompleteBox), new FrameworkPropertyMetadata(typeof(AutoCompleteBox)));  
        }  
        public override void OnApplyTemplate()  
        {  
            base.OnApplyTemplate();  
            inputText = (TextBox)GetTemplateChild("inputText");  
            suggestionBox = (ListBox)GetTemplateChild("suggestionBox");  
            suggestionView = CollectionViewSource.GetDefaultView(ItemsSource);  
            suggestionView.Filter = filterSuggestion;  
            inputText.TextChanged += updateSuggestion;  
            inputText.KeyUp += onKeyUp;  
            SelectItem = new Command(selectItem, (o) => IsSuggestionVisible);  
        }  
    
        void onKeyUp(object sender, KeyEventArgs e)  
        {  
            if (e.Key == Key.Down)  
            {  
                if (IsSuggestionVisible)  
                {  
                    suggestionView.MoveCurrentToFirst();  
                    suggestionBox.Focus();  
                    //((ListBoxItem)suggestionBox.SelectedItem).Focus();  
                }  
            }  
        }  
    
        bool filterSuggestion(object o) => (((string)o).ToLower()).Contains(inputText.Text.ToLower());  
        void updateSuggestion(object sender, TextChangedEventArgs e)  
        {  
            suggestionView.Refresh();  
            IsSuggestionVisible = string.IsNullOrWhiteSpace(inputText.Text) ? false : true;  
        }  
        void selectItem(object o)  
        {  
            var text = (string)o;  
            inputText.Text = text;  
            inputText.CaretIndex = text.Length + 1;  
            inputText.Focus();  
            IsSuggestionVisible = false;  
        }  
    
        public string Text  
        {  
            get { return (string)GetValue(TextProperty); }  
            set { SetValue(TextProperty, value); }  
        }  
    
        // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...  
        public static readonly DependencyProperty TextProperty =  
            DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteBox), new PropertyMetadata(null));  
    
    
        public IEnumerable ItemsSource  
        {  
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }  
            set { SetValue(ItemsSourceProperty, value); }  
        }  
    
        // Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...  
        public static readonly DependencyProperty ItemsSourceProperty =  
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(AutoCompleteBox), new PropertyMetadata(null));  
    
        public bool IsSuggestionVisible  
        {  
            get { return (bool)GetValue(IsSuggestionVisibleProperty); }  
            set { SetValue(IsSuggestionVisibleProperty, value); }  
        }  
    
        // Using a DependencyProperty as the backing store for IsSuggestionVisible.  This enables animation, styling, binding, etc...  
        public static readonly DependencyProperty IsSuggestionVisibleProperty =  
            DependencyProperty.Register("IsSuggestionVisible", typeof(bool), typeof(AutoCompleteBox), new PropertyMetadata(false));  
    
    
        public ICommand SelectItem  
        {  
            get { return (ICommand)GetValue(SelectItemProperty); }  
            set { SetValue(SelectItemProperty, value); }  
        }  
    
        // Using a DependencyProperty as the backing store for SelectItem.  This enables animation, styling, binding, etc...  
        public static readonly DependencyProperty SelectItemProperty =  
            DependencyProperty.Register("SelectItem", typeof(ICommand), typeof(AutoCompleteBox), new PropertyMetadata(null));       
    }  
    

    The problem I'm having with this is Focus. When I press the DownArrow, it first selects the ListBox and then the focus moves to the SelectedItem so basically I've to press DownArrow twice to get to the SelectedItem:

    43502-test1.gif

    in onKeyUp I've tried ((ListBoxItem)suggestionBox.SelectedItem).Focus(); to take focus to the SelectedItem directly BUT that crashes the App. How to get to the SelectedItem directly?

    ----
    EDIT

    this in onKeyUp:

    if (IsSuggestionVisible)  
    {  
        suggestionView.MoveCurrentToFirst();  
        ((ListBoxItem)suggestionBox.ItemContainerGenerator.ContainerFromItem(suggestionView.CurrentItem)).Focus();                    
    }  
    

    solves the Focus issue.

    1 person found this answer helpful.
    0 comments No comments

  2. DaisyTian-1203 11,621 Reputation points
    2020-11-02T08:13:47.607+00:00

    A Fork of the MS Wpf Toolkit, supporting NetCore3, splited in 4 Nugets,you can refer to DotNetProjects.Wpf.Toolkit for more details. The control AutoCompleteBox is under DotNetProjects.WpfToolkit.Input now.
    Here is my step to use it:
    Step one :Search and install DotNetProjects.Input.Toolkit in your project Nuget Package
    Step two: Add xmlns:input="clr-namespace:System.Windows.Controls;assembly=DotNetProjects.Input.Toolkit" to import the dll

    By the way, the control in table Extended WPF Toolkit Controls may give you some help to use the new WPFToolKit


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.