我有一个非常简单的例子: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,手动预填充值:
<ListBox>
<Label TextSearch.Text="One" Content="1" />
<Label TextSearch.Text="Two" Content="2" />
<Label TextSearch.Text="Three" Content="3" />
</ListBox>
因此,当我启动应用时,它看起来像这样:
如果我尝试通过键入“one”,“two”或“three”来使用键盘导航项目,我只能在非绑定列表框中成功。绑定列表框失败。
一些评论: 1.)如果我在绑定列表框中按“[”,则焦点会以循环方式从一个项目更改为另一个项目:它从1到2,从2到3,从3到1,再从1再到2等。 2.)我已经使用Snoop检查了应用程序。我在绑定和非绑定列表框之间找到了一个区别。两个列表框都在Label控件上设置了TextSearch.Text属性(在ItemsPresenter内)。但对于非约束情况:TextSearch.Text属性的“值源”是“本地”。对于约束情况:“value source”是“ParentTemplate”。
P.S。 (和N.B。) 我知道我可以在列表框中使用TextSearch.TextPath,但这不是我需要的:) 另外,为ListViewItem设置TextSearch.Text属性(使用Style)也无济于事。
答案 0 :(得分:12)
首先让我解释一下TextSearch如何与ItemsControl一起使用:
TextSearch的实现枚举ItemsSource
属性的实际数据项,并直接查看那些 以读取Text
依赖项属性。当您将ListBoxItem
放入其中时,就像您在示例中所做的那样,因为实际项目是ListBoxItem
个实例,并且Text
依赖属性“附加”到它们。绑定到Dictionary<>
后,它现在直接查看KeyValuePair<>
个DependencyObject
个TextSearch.Text
个实例,因此不能/不具有TextSearch.Text
属性。这也是通过ListBoxItem
在ItemContainerStyle
上设置ItemContainerStyle
属性无效的原因:TextSearch
描述了您的数据在可视树中的外观,但是DataTemplate
引擎仅考虑原始数据源。如何在UI中设置数据样式并不重要,这就是为什么修改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 Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ListBox定义如下所示:
TextSearch.TextPath
任何其他替代方案都需要您使用DataTemplate
,但您似乎已经死了。如果您接受修改TextSearch.TextPath
将永远不会起作用,我建议的解决方案就是简单地创建一个POCO视图模型,该模型具有您要用于搜索的属性并将其指定为{{ 1}}。这是完成你正在做的事情中最轻的,非黑客的方式。
答案 1 :(得分:5)
如果没有设置ListBoxItem
或TextSearch.Text
,可能的解决方案是使用TextSearch在TextSearch.TextPath
的数据项上使用.ToString()的后备行为
因此,例如,这将允许您在不指定TextSearch.Text或.TextPath的情况下进行搜索。
<Page.DataContext>
<Samples:TextSearchViewModel/>
</Page.DataContext>
<Grid>
<ListBox ItemsSource="{Binding Items}"
IsTextSearchCaseSensitive="False"
IsTextSearchEnabled="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
public class TextSearchItem
{
public int Value { get; set; }
public string SearchText { get; set; }
public override string ToString()
{
return SearchText;
}
}
public class TextSearchViewModel
{
public TextSearchViewModel()
{
Items = new List<TextSearchItem>
{
new TextSearchItem{ Value = 1, SearchText = "One"},
new TextSearchItem{ Value = 2, SearchText = "Two"},
new TextSearchItem{ Value = 3, SearchText = "Three"},
new TextSearchItem{ Value = 4, SearchText = "Four"},
};
}
public IEnumerable<TextSearchItem> Items { get; set; }
}