Friday, August 13, 2010

WPF - Editable ComboBox with DataTemplate

In this post, we will discuss with issue when we define data template for a combo box and make it editable. When we select the item from combo box, it shows class name. Let's create a view with editable combo box. We are defining the DataTemplate of items in the ComboBox and displaying them in a TextBlock. We can also define several style formatting with item data template.
<Window x:Class="WPFComboBoxEditable.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFComboBoxEditable"
Title="Window1" Height="300" Width="300"
DataContext="{DynamicResource ViewModel}" >
<Window.Resources>
<local:Window1ViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid>
<Label HorizontalAlignment="Left" Margin="12,13,0,0" Name="label1" Width="62" Height="24" VerticalAlignment="Top">Student</Label>
<ComboBox Height="25" Margin="80,12,12,0" Name="comboBox1" VerticalAlignment="Top"
ItemsSource="{Binding StudentList}" IsEditable="True">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding StudentName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>

This view is expecting a DataContext (Window1ViewModel) with list StudentList. This is a list of Student objects.
public class Window1ViewModel : DependencyObject
{
public static DependencyProperty StudentListProperty =
DependencyProperty.Register("StudentList", typeof(List), typeof(Window1ViewModel));

public List StudentList
{
get { return (List)GetValue(StudentListProperty); }
set { SetValue(StudentListProperty, value); }
}

public Window1ViewModel()
{
StudentList = new List();
StudentList.Add(new Student() { StudentName = "Amir" });
StudentList.Add(new Student() { StudentName = "Asif" });
StudentList.Add(new Student() { StudentName = "Catherine" });
StudentList.Add(new Student() { StudentName = "Cindrella" });
StudentList.Add(new Student() { StudentName = "David" });
StudentList.Add(new Student() { StudentName = "Ellis" });
StudentList.Add(new Student() { StudentName = "Farooq" });
StudentList.Add(new Student() { StudentName = "Muhammad" });
StudentList.Add(new Student() { StudentName = "Saleem" });
StudentList.Add(new Student() { StudentName = "Usman" });
}
}

The Student class used above can be defined as follows:
public class Student
{
public string StudentName { get; set; }
}

When we run this, it is shown like this:


Everything is fine up until now. As soon as we select any item from the list, the unexpected happens.


This can be fixed by setting TextPath of TextSearch to the property you want to use for searching.
TextSearch.TextPath="StudentName"

This is updated in the combox box declaration as follows:

<ComboBox Height="25" Margin="80,12,12,0" Name="comboBox1" VerticalAlignment="Top"
ItemsSource="{Binding StudentList}" IsEditable="True" TextSearch.TextPath="StudentName">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding StudentName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

After the application of above update, running the application and selecting the combobox item, the correct item seems selected.



Note:
After finding the fix, it seems an obvious solution because it makes sense that WPF runtime would not know what property to use for selection because it is based on a data template.

5 comments:

Amal said...

Thanks for this post :) Could not find the correct combination of xaml tags to use to get this done until now ... WPF has its own way of confusing us :P

Anonymous said...

Great post!! Just what i was looking for.
thanks.

AGajdy said...

Thank you very much for this post :)

AGajdy said...

Thanks for this post. Really helpful.

Muhammad Shujaat Siddiqi said...

Thanks Guys for liking this!