Sharath
Sharath

Reputation:

AutoComplete TextBox in WPF

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?

Upvotes: 57

Views: 131453

Answers (7)

Romylussone
Romylussone

Reputation: 815

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);
    }
}

Upvotes: 1

JP-Hundhausen
JP-Hundhausen

Reputation: 80

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.

Upvotes: 1

Jeson Martajaya
Jeson Martajaya

Reputation: 7352

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>

Upvotes: 3

ARidder101
ARidder101

Reputation: 315

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.

Upvotes: 4

JumpingJezza
JumpingJezza

Reputation: 5665

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.

Upvotes: 13

Alexander Zwitbaum
Alexander Zwitbaum

Reputation: 4846

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.

Upvotes: 41

MelloG
MelloG

Reputation: 1064

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.

Upvotes: 4

Related Questions