Reputation: 215
I know this question has been asked and I have looked at many results but the results I find don't seem to completely work or they give me issues.
What I want is a combo box that I can type and it will start to auto complete and narrow down based on a single column. For example if I had first name and last name I would type and the last names would narrow down.
With my example below, when I select a value in the combo box I get "System.Data.DataRowView". I have tested using the selection changed event just to check and I can't even set the text for the combo but If I can return the correct value from the data table.
If there are any suggestions for a good comprehensive resource to look up like a website, tutorial, video, online course, book I would be grateful.
RESOURCE XAML:
<Style x:Key="txtStyle" TargetType="{x:Type TextBlock}">
<Setter Property="TextAlignment" Value="Left"></Setter>
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="HorizontalAlignment" Value="Left"></Setter>
</Style>
<DataTemplate x:Key="comboKEY">
<Grid Height="25" Width="300" ShowGridLines="false">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path='id'}"
Style="{StaticResource txtStyle}"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding Path='site_name'}"
Style="{StaticResource txtStyle}"
TextWrapping="Wrap"></TextBlock>
</Grid>
</DataTemplate>
XAML COMBO BOX
<WrapPanel Orientation="Horizontal" Canvas.Left="10" Canvas.Top="90">
<ComboBox IsEditable="True"
Width="200"
Height="25"
IsTextSearchEnabled="False"
x:Name="cboName"
ItemTemplate="{StaticResource comboKEY
ItemsSource="{Binding}" SelectionChanged="cboName_SelectionChanged">
</ComboBox>
</WrapPanel>
CODE-BEHIND
private void cboName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
cboName.Text = dt.Rows[cboName.SelectedIndex]["dt_field"].ToString();
test1.Content = dt[cboName.SelectedIndex]["dt_field"].ToString();
}
Upvotes: 1
Views: 1378
Reputation: 29028
When you want to filter or sort a DataTable
, you should create a DataView
and bind to it. Then use a filter expression assigned to DataView.RowFilter
to dynamically filter the table.
The following example shows how to filter based on text input by handling TextBox.TextChanged
raised by the editable TextBox
of the ComboBox
.
The column to filter is also made dynamic.
Since the ComboBox.IsEditable
is set to True
, the selection box's ContenPresenter
is replaced by a TextBox
. This means you only can display text. By default the ComboBox
will call object.ToString()
. If the item like a DataRowView
doesn't provide a usable override, you are left to set the ComboBox.DisplayMemberPath
. Setting this property disallows to set the ComboBox.ItemTemplate
. If you still want to layout the drop down items, you must override the ComboBox.ItemContainerStyle
.
MainWindow.xaml.cs
partial class MainWindow : Window
{
// This property should be a DependencyProperty
public DataView DataTableView { get; set; }
// This property should be a DependencyProperty and have a property changed callback to update the DataTableView filter registered
public string FilteredColumnName { get; set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
var dataTable = new DataTable();
// TODO::Populate DataTable.
// Assume table has a column 'LastName'
this.DataTableView = dataTable.DefaultView;
// Filter based on column 'LastName'
this.FilteredColumnName = "LastName";
}
private void FilterDataTable_OnTextInput(object sender, TextChangedEventArgs textChangedEventArgs)
{
var comboBox = sender as ComboBox;
var dataview = comboBox.ItemsSource as DataView;
// Filter based on column 'LastName',
// where the value starts with the entered text: '<columnName> LIKE '<textInput>*'
dataview.RowFilter = $"{this.FilteredColumnName} LIKE '{(textChangedEventArgs.OriginalSource as TextBox).Text}*'";
}
}
MainWindow.xaml
<Window>
<ComboBox ItemsSource="{Binding DataTableView}"
DisplayMemberPath="LastName"
SelectedValuePath="LastName"
IsEditable="True"
StaysOpenOnEdit="True"
TextBox.TextChanged="FilterDataTable_OnTextInput">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Window>
Upvotes: 1