56

Is it possible to make a textbox autocomplete in WPF?

I found a sample where a combo box is used and the triangle is removed by editing the style template.

Is there a better solution?

Danny Beckett
  • 20,529
  • 24
  • 107
  • 134

7 Answers7

40

You can find one in the WPF Toolkit, which is also available via NuGet.

This article demos how to create a textbox which can auto-suggest items at runtime based on input, in this case, disk drive folders. WPF AutoComplete Folder TextBox

Also take a look at this nice Reusable WPF Autocomplete TextBox, it was for me very usable.

Alexander Zwitbaum
  • 4,776
  • 4
  • 48
  • 55
13

Nimgoble's is the version I used in 2015. Thought I'd put it here as this question was top of the list in google for "wpf autocomplete textbox"

  1. Install nuget package for project in Visual Studio

  2. Add a reference to the library in the xaml:
    xmlns:behaviors="clr-namespace:WPFTextBoxAutoComplete;assembly=WPFTextBoxAutoComplete"

  3. Create a textbox and bind the AutoCompleteBehaviour to List<String> (TestItems):
    <TextBox Text="{Binding TestText, UpdateSourceTrigger=PropertyChanged}" behaviors:AutoCompleteBehavior.AutoCompleteItemsSource="{Binding TestItems}" />

IMHO this is much easier to get started and manage than the other options listed above.

Mage Xy
  • 1,803
  • 30
  • 36
JumpingJezza
  • 5,498
  • 11
  • 67
  • 106
  • 6
    Works well for inline autocomplete, but doesn't provide a drop-down list with options.. – lambinator Mar 25 '16 at 20:47
  • 1
    @lambinator - yes no dropdown. From a design POV, if I have just a few items (say <20-50?) Then I just use a regular combobox because you can type ahead in it anyway: http://stackoverflow.com/a/8333801/345659. If I have too many items to display (who wants to scroll for ages?) then I use this autocomplete textbox. – JumpingJezza Mar 28 '16 at 05:37
4

or you can add the AutoCompleteBox into the toolbox by clicking on it and then Choose Items, go to WPF Components, type in the filter AutoCompleteBox, which is on the System.Windows.Controls namespace and the just drag into your xaml file. This is way much easier than doing these other stuff, since the AutoCompleteBox is a native control.

MelloG
  • 1,044
  • 1
  • 11
  • 11
  • 16
    `System.Windows.Controls.AutoCompleteBox` is not part of WPF. You will have to add a reference to the [WPF Toolkit](http://wpf.codeplex.com/) to use that control. – Martin Liversage Jan 29 '13 at 10:13
  • 1
    @MartinLiversage I added the wpf tool kit for visual studio 2013. But still the auto complete box cannot be seen in the tool box. why is that? – vigamage Feb 08 '16 at 06:39
4

I know this is a very old question but I want to add an answer I have come up with.

First you need a handler for your normal TextChanged event handler for the TextBox:

private bool InProg;
internal void TBTextChanged(object sender, TextChangedEventArgs e)
            {
            var change = e.Changes.FirstOrDefault();
            if ( !InProg )
                {
                InProg = true;
                var culture = new CultureInfo(CultureInfo.CurrentCulture.Name);
                var source = ( (TextBox)sender );
                    if ( ( ( change.AddedLength - change.RemovedLength ) > 0 || source.Text.Length > 0 ) && !DelKeyPressed )
                        {
                         if ( Files.Where(x => x.IndexOf(source.Text, StringComparison.CurrentCultureIgnoreCase) == 0 ).Count() > 0 )
                            {
                            var _appendtxt = Files.FirstOrDefault(ap => ( culture.CompareInfo.IndexOf(ap, source.Text, CompareOptions.IgnoreCase) == 0 ));
                            _appendtxt = _appendtxt.Remove(0, change.Offset + 1);
                            source.Text += _appendtxt;
                            source.SelectionStart = change.Offset + 1;
                            source.SelectionLength = source.Text.Length;
                            }
                        }
                InProg = false;
                }
            }

Then make a simple PreviewKeyDown handler:

    private static bool DelKeyPressed;
    internal static void DelPressed(object sender, KeyEventArgs e)
    { if ( e.Key == Key.Back ) { DelKeyPressed = true; } else { DelKeyPressed = false; } }

In this example "Files" is a list of directory names created on application startup.

Then just attach the handlers:

public class YourClass
  {
  public YourClass()
    {
    YourTextbox.PreviewKeyDown += DelPressed;
    YourTextbox.TextChanged += TBTextChanged;
    }
  }

With this whatever you choose to put in the List will be used for the autocomplete box. This may not be a great option if you expect to have an enormous list for the autocomplete but in my app it only ever sees 20-50 items so it cycles through very quick.

ARidder101
  • 315
  • 2
  • 6
  • 16
2

If you have a small number of values to auto complete, you can simply add them in xaml. Typing will invoke auto-complete, plus you have dropdowns too.

<ComboBox Text="{Binding CheckSeconds, UpdateSourceTrigger=PropertyChanged}"
          IsEditable="True">
    <ComboBoxItem Content="60"/>
    <ComboBoxItem Content="120"/>
    <ComboBoxItem Content="180"/>
    <ComboBoxItem Content="300"/>
    <ComboBoxItem Content="900"/>
</ComboBox>
Jeson Martajaya
  • 6,996
  • 7
  • 54
  • 56
1

I'm surprised why no one suggested to use the WinForms Textbox.

XAML:

     <WindowsFormsHost  Margin="10" Width="70">
        <wf:TextBox x:Name="textbox1"/>
     </WindowsFormsHost>

Also don't forget the Winforms Namespace:

xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

C#:

     AutoCompleteStringCollection stringCollection = new AutoCompleteStringCollection(){"String 1", "String 2", "etc..."};
   
     textbox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
     textbox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
     textbox1.AutoCompleteCustomSource = stringCollection;

With Autocomplete, you need to do it in the Code behind, because for some reasons, others might can explain, it throws an exception.

JP-Hundhausen
  • 70
  • 1
  • 7
1

Here a way by using WPF PopUp element with a textBox :

XAML file

<TextBox x:Name="DocumentType"
    Margin="20"
    KeyUp="DocumentType_KeyUp"
    LostFocus="DocumentType_LostFocus"/>

<Popup x:Name="autoCompletorListPopup"
        Visibility="Collapsed"
        StaysOpen="False"
        AllowsTransparency="True"
        PlacementTarget="{Binding ElementName=DocumentType}"
        Width="150"
        Placement="Bottom">
    <ListBox x:Name="autoCompletorList"
                Background="WhiteSmoke"
                MaxHeight="200"
                Margin="20 0"
                SelectionChanged="autoCompletorList_SelectionChanged"/>
</Popup>

CS file

List<string> listDocumentType = new List<string>() {"Pdf File","AVI File","JPEG file","MP3 sound","MP4 Video"} //...

private void autoCompletorList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    try
    {
        if (autoCompletorList.SelectedItem != null)
        {
            DocumentType.Text = autoCompletorList.SelectedValue.ToString();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private void DocumentType_KeyUp(object sender, KeyEventArgs e)
{
    try
    {
        if(e.Key == Key.Enter)
        {
            // change focus or remove focus on this element
            NextElementBox.Focus();
        }
        else
        {
            if (DocumentType.Text.Trim() != "")
            {
                autoCompletorListPopup.IsOpen = true;
                autoCompletorListPopup.Visibility = Visibility.Visible;
                autoCompletorList.ItemsSource = listDocumentType.Where(td => td.Trim().ToLower().Contains(DocumentType.Text.Trim().ToLower()));
            }
            else
            {
                autoCompletorListPopup.IsOpen = false;
                autoCompletorListPopup.Visibility = Visibility.Collapsed;
                autoCompletorList.ItemsSource = null;
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private void DocumentType_LostFocus(object sender, RoutedEventArgs e)
{
    try
    {
        if (autoCompletorList.SelectedItem != null)
        {
            DocumentType.Text = autoCompletorList.SelectedValue.ToString();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
Romylussone
  • 773
  • 1
  • 8
  • 19