WPF: Changing a ComboBox's ItemTemplate removes the ability to jump down the list as you type. Any way to fix this?

20.1k views Asked by At

PersonVM.cs

public class MainWindowVM
{
    public MainWindowVM()
    {
        PersonList = new ObservableCollection<Person>(Employees);
    }

    private Person[] Employees = new Person[]
    {
        new Person { ID = 1, Name = "Adam" },
        new Person { ID = 2, Name = "Bill" },
        new Person { ID = 10, Name = "Charlie" },
        new Person { ID = 15, Name = "Donna" },
        new Person { ID = 20, Name = "Edward" }
    };

    public ObservableCollection<Person> PersonList { get; set; }
}

Person.cs

public class Person
{
    public string Name { get; set; }
    public int ID { get; set; }
}

MainWindow.xaml (Functionally working version -- Not what I want to display)

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ComboBox Height="23" Width="300"
                  ItemsSource="{Binding Path=Objects}"
                  DisplayMemberPath="Name"
                  >
        </ComboBox>
    </Grid>
</Window>

MainWindow.xaml (Displays correctly -- Doesn't function properly)

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ComboBox Height="23" Width="300"
                  ItemsSource="{Binding Path=Objects}"
                  >
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock DataContext="{Binding}">
                        <TextBlock.Text>
                            <MultiBinding StringFormat="{} {0} | {1}">
                                <Binding Path="ID" />
                                <Binding Path="Name" />
                            </MultiBinding>
                        </TextBlock.Text>
                    </TextBlock>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</Window>

The second code displays what I want the ComboBox to display {ID} | {Name}, but it takes away a common function of the ComboBox. In the first example, when the ComboBox is selected the user can start typing into it and have it jump down the list. For example, if you press the letter A it jumps to "Adam", B jumps to "Bill", etc. This is how a ComboBox is supposed to function. But, when I override the ComboBox ItemTemplate it loses that functionality. Is there another way to Bind what I need and keep that functionality or to reenable it? Perhaps the ItemTemplate is setup wrong?

1

There are 1 answers

0
Fredrik Hedblad On BEST ANSWER

See my answer to this question: Can I do Text search with multibinding

Unfortunately TextSearch.Text doesn't work in a DataTemplate. I think you have two options here

Option 1. Set IsTextSearchEnabled to True for the ComboBox, override ToString in your source class and change the MultiBinding in the TextBlock to a Binding

<ComboBox ...
          IsTextSearchEnabled="True">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox> 

public class Person
{
    public override string ToString()
    {
        return String.Format("{0} | {1}", Name, ID);
    }

    public string Name { get; set; }
    public int ID { get; set; }
}

Option 2. Make a new Property in your source class where you combine Name and ID for the TextSearch.TextPath. Also, you should call OnPropertyChanged for NameAndId whenever you do it for Name or ID

<ComboBox ...
          TextSearch.TextPath="NameAndId"
          IsTextSearchEnabled="True">


public string NameAndId
{
    return String.Format("{0} | {1}", Name, ID);
}