Question

I would like to have a ComboBox control on a form which will be used to search a list of investments as the user types. I can do this easily if I cache the entire collection of investments from the database on startup (currently 3,000 or so items), but I would prefer to not do that if it isn't necessary.

The behavior that I am trying to implement is:

  • The user types text into the editable ComboBox.
  • As the user enters each character, the database search function is triggered, narrowing down the search results with each successive keystroke.
  • As the search results are updated, the dropdown panel opens and displays the relevant matches

I have tried binding the Text property of the ComboBox to the InvestmentName (string) property on my ViewModel, and the ItemsSource property of the ComboBox to the InvestmentList (generic List) property on my ViewModel. When I do this, the Text property auto-completes from the ItemsSource, however the dropdown appears empty.

I have been able to achieve these results using a TextBox stacked on top of a ListBox, but it isn't very elegant and it takes up more screen real estate. I've also been able to get it to work with a TextBox stacked on top of a ComboBox, although the ComboBox steals the focus when the IsDropDownOpen property is set to "true" when there are valid search items. It also isn't very visually pleasing to use two controls for this.

I feel like I'm really close to getting it to work the way I want it to, but there is something which eludes me.

The XAML for this control is:

<ComboBox Height="23" Width="260" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left"
          ItemsSource="{Binding InvestmentList}" DisplayMemberPath="FullName"
          IsDropDownOpen="{Binding DoShowInvestmentList}"
          ItemsPanel="{DynamicResource ItemsTemplate}" IsEditable="True" 
          Text="{Binding Path=InvestmentName, Mode=TwoWay,
                 UpdateSourceTrigger=PropertyChanged}" />

The relevant ViewModel properties are:

    private bool _doShowInvestmentList;
    public bool DoShowInvestmentList
    {
        get { return _doShowInvestmentList; }
        set { if (_doShowInvestmentList != value) { _doShowInvestmentList = value; RaisePropertyChanged("DoShowInvestmentList"); } }
    }

    private List<PFInvestment> _investmentList;
    public List<PFInvestment> InvestmentList
    {
        get { return _investmentList; }
        set { if (_investmentList != value) { _investmentList = value; RaisePropertyChanged("InvestmentList"); } }
    }

    private string _investmentName;
    public string InvestmentName
    {
        get { return _investmentName; }
        set
        {
            if (_investmentName != value)
            {
                _investmentName = value;
                this.InvestmentList = DataAccess.SearchInvestmentsByName(value).ToList();

                if (this.InvestmentList != null && this.InvestmentList.Count > 0)
                    this.DoShowInvestmentList = true;
                else
                    this.DoShowInvestmentList = false;

                RaisePropertyChanged("InvestmentName");
            }
        }
    }

I've done a fair bit of research on this, but I haven't quite found the answer yet.

Was it helpful?

Solution

Check out this great article on CodeProject by... me :)

A Reusable WPF Autocomplete TextBox

Look towards the end for the Google suggest example, it is similar to what you need, where every keypress triggers another query to the server.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top