我有一个非常简单的示例:具有单个表单的WPF表单应用程序,其中包含带有数据的字典:
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
在表单上,我有一个ListBox(名为“ lst1”),它使用“ dict”作为项源:
<ListBox x:Name="lst1">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Value}"
TextSearch.Text="{Binding Path=Key, Mode=OneWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我还有一个非绑定列表框,手动填充了值:
<ListBox>
<Label TextSearch.Text="One" Content="1" />
<Label TextSearch.Text="Two" Content="2" />
<Label TextSearch.Text="Three" Content="3" />
</ListBox>
因此,当我启动应用程序时,它看起来像这样:
问题:
如果我尝试通过输入“一个”,“两个”或“三个”来使用键盘导航项目,则只能在非绑定列表框中成功。绑定列表框失败。
一些说明:
1.)如果在绑定列表框中按“ [”,则焦点以循环方式从一个项目更改为另一个项目:焦点从1变到2,从2变到3,从3变到1,再从1变到2,依此类推。
2.)我已经用Snoop检查了应用程序。我发现绑定列表框和非绑定列表框之间的差异。这两个列表框的Label控件(在ItemsPresenter内部)都设置了TextSearch.Text属性。但是对于非绑定情况:TextSearch.Text属性的“值源”是“本地”。对于绑定情况:“值源”是“ ParentTemplate”。
附言(和N.B.)
我知道我可以在列表框中使用TextSearch.TextPath,但这不是我所需要的:)
此外,设置ListViewItem的TextSearch.Text属性(通过使用样式)也无济于事。
最佳答案
让我首先解释一下TextSearch如何与ItemsControl一起工作:
TextSearch的实现枚举了ItemsSource
属性的实际数据项,并直接查看这些数据项以读取Text
依赖项属性。当像您在示例中一样在其中放置ListBoxItem
时,它可以工作,因为实际项是带有ListBoxItem
依赖项属性的Text
实例。绑定到Dictionary<>
后,它现在直接查看不是KeyValuePair<>
的DependencyObject
实例,因此不能/不具有TextSearch.Text
属性。这也是为什么通过TextSearch.Text
在ListBoxItem
上设置ItemContainerStyle
属性无效的原因:ItemContainerStyle
描述的是数据在可视树中的外观,但是TextSearch
引擎仅考虑原始数据源。在UI中设置数据样式的方式无关紧要,这就是为什么修改DataTemplate
永远不会为TextSearch
做任何事情的原因。
一种替代方法是创建一个继承自DependencyObject
的视图模型类,在该类中,您根据要搜索的值在该属性上设置TextSearch.Text
附加属性。这是一些示例代码,显示了它如何工作:
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定义看起来像这样:
<ListBox Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
其他任何替代方法都将要求您使用
TextSearch.TextPath
,但您似乎对此深信不疑。如果您接受修改DataTemplate
永远行不通的做法,我建议的解决方案是简单地创建一个POCO视图模型,该模型具有要用于搜索的属性,并将其指定为TextSearch.TextPath
。这是完成工作的最轻便,简便的方法。