我有一个非常简单的示例:具有单个表单的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.TextListBoxItem上设置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。这是完成工作的最轻便,简便的方法。

09-26 13:55