Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF ComboBox TextSearch using Contains instead of StartsWith

Tags:

c#

combobox

wpf

I got a ComboBox with alot of "Customers" using MultiBinding as Text (for instance "644 Pizza Place") and this works great searching from start (CustomerNumber). But how do I make it match and select by just enter "Pizza Place"?

<MultiBinding StringFormat="{}{0} {1}">
    <Binding Path="CustomerNumber" />
    <Binding Path="CustomerName" />
</MultiBinding>
like image 499
Johan Olsson Avatar asked Mar 07 '13 15:03

Johan Olsson


2 Answers

ComboBox uses TextSearch class for item lookup. You can set TextSearch.TextPath dependency property on the ComboBox:

    <ComboBox Name="cbCustomers" TextSearch.TextPath="CustomerName">...</ComboBox>

This will allow you to match by CustomerName, but you will loose matching by CustomerNumber.

The lookup, without much details, is done in the following way: ComboBox.TextUpdated method is invoked as you type. This method invokes TextSearch.FindMatchingPrefix to find the matching item. TextSearch.FindMatchingPrefix is the method where string.StartsWith(..) calls are used.

There is no way to replace string.StartsWith() calls or TextSearch.FindMatchingPrefix calls for something else. So it looks like you have to write your custom ComboBox class if you want to swap string.StartsWith() with your custom logic (like string.Contains)

like image 199
anikiforov Avatar answered Sep 28 '22 20:09

anikiforov


Here I have an alternatives in MVVM framework.

my xaml file:

<ComboBox Name="cmbContains" IsEditable="True" IsTextSearchEnabled="false" ItemsSource="{Binding pData}"  DisplayMemberPath="wTitle" Text="{Binding SearchText ,Mode=TwoWay}"  >
  <ComboBox.Triggers>
      <EventTrigger RoutedEvent="TextBoxBase.TextChanged">
          <BeginStoryboard>
              <Storyboard>
                  <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsDropDownOpen">
                      <DiscreteBooleanKeyFrame Value="True" KeyTime="0:0:0"/>
                  </BooleanAnimationUsingKeyFrames>
              </Storyboard>
          </BeginStoryboard>
      </EventTrigger>
  </ComboBox.Triggers>
</ComboBox>

my cs file:

//ItemsSource - pData
//There is a string attribute - wTitle included in the fooClass (DisplayMemberPath)
private ObservableCollection<fooClass> __pData;
public ObservableCollection<fooClass> pData {
    get { return __pData; }
    set { Set(() => pData, ref __pData, value);
        RaisePropertyChanged("pData");
    }
}

private string _SearchText;
public string SearchText {
    get { return this._SearchText; }
    set {
        this._SearchText = value;
        RaisePropertyChanged("SearchText");

        //Update your ItemsSource here with Linq
        pData = new ObservableCollection<fooClass>{pData.ToList().Where(.....)};
    }
}

You can see the editable comboBox is binding to the string (SearchText) Once there is a TextChanged event the drop down is shown and the Two way binding update the value. The ItemsSource changed in the cs file while it goes into the set{}; syntax.

A gist with the code above

like image 38
Tony Wu Avatar answered Sep 28 '22 20:09

Tony Wu