Usage of TextSearch.Text in DataTemplate
.net, binding, datatemplate, text-search, wpf
Solution
Let me start by explaining exactly how TextSearch works with the ItemsControl:
TextSearch's implementation enumerates the actual data items of the `ItemsSource` property and looks at those directly to read the `Text` dependency property. When you put `ListBoxItem`s in it like you do in your example it works because the actual items are `ListBoxItem` instances with the `Text` dependency property "attached" to them. Once you bind to your `Dictionary<>` it's now looking directly at `KeyValuePair<>` instances which are not `DependencyObject`s and thus can't/don't have the `TextSearch.Text` property on them. This is also why setting the `TextSearch.Text` property on the `ListBoxItem` via the `ItemContainerStyle` has no effect: the `ItemContainerStyle` is describing how your data should look in the visual tree, but the `TextSearch` engine only considers the raw data source. It does not matter how you've styled that data in the UI and that is why modifying a `DataTemplate` will never do anything for `TextSearch`.
One alternative is creating a view model class that inherits from `DependencyObject` where you set the `TextSearch.Text` attached property on that based on the value you want to be searchable. Here's some sample code that shows how this would work:
private sealed class MyListBoxItem : DependencyObject
{
public static readonly DependencyProperty KeyProperty = DependencyProperty.Register("Key", typeof(string), typeof(MyListBoxItem), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(MyListBoxItem), new FrameworkPropertyMetadata(string.Empty));
public string Key
{
get
{
return (string)GetValue(KeyProperty);
}
set
{
SetValue(KeyProperty, value);
SetValue(TextSearch.TextProperty, value);
}
}
public string Value
{
get
{
return (string)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
}
// Assign a list of these as the list box's ItemsSource
this.listBox.ItemsSource = new List<MyListBoxItem>
{
new MyListBoxItem { Key = "One", Value = "1" },
new MyListBoxItem { Key = "Two", Value = "2" },
new MyListBoxItem { Key = "Three", Value = "3" }
};
ListBox definition looks something like this:
<ListBox Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Any other alternative will require you to use `TextSearch.TextPath`, but you seem dead set against that. If you come to accept that modifying the `DataTemplate` will never work, the solution I would recommend is to simply create a POCO view-model that has the property on it that you want to use for searching and specify that to `TextSearch.TextPath`. It is the lightest weight, non-hacky way to accomplish what you're doing.
Problem
I have a very simple example: WPF form application with single form which contains a dictionary with data: ``` Dim dict As New Collections.Generic.Dictionary(Of String, String) Private Sub MainWindow_Loaded() Handles Me.Loaded dict.Add("One", "1") dict.Add("Two", "2") dict.Add("Three", "3") lst1.ItemsSource = dict End Sub ``` On form I have a ListBox (named "lst1"), which uses "dict" as items source: ``` <ListBox x:Name="lst1"> <ListBox.ItemTemplate> <DataTemplate> <Label Content="{Binding Value}" TextSearch.Text="{Binding Path=Key, Mode=OneWay}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> ``` Also I have one non-bound ListBox, prefilled with values manually: ``` <ListBox> <Label TextSearch.Text="One" Content="1" /> <Label TextSearch.Text="Two" Content="2" /> <Label TextSearch.Text="Three" Content="3" /> </ListBox> ``` So when I launch app, it looks like this: THE QUESTION: If I try to navigate items with keyboard by typing "one", "two" or "three", I succeed only in non-bound list box. Bound list box fails. Some remarks: 1.) If I press "[" while in bound list box, focus changes from item to item in cyclic manner: it goes from 1 to 2, from 2 to 3, from 3 to 1, from 1 again to 2 etc. 2.) I have checked app with Snoop. One difference I found between bound and non-bound list boxes. Both list boxes have TextSearch.Text property set on Label controls (inside ItemsPresenter). But for non-bound case: "value source" of TextSearch.Text property is "Local". For bound case: "value source" is "ParentTemplate". P.S. (and N.B.) I know that I can use TextSearch.TextPath on the list box, but this is not what I need :) Also, setting TextSearch.Text property for ListViewItem (by using Style) does not help.