在DataTemplate中使用TextSearch.Text

Dim*_*ima 7 .net wpf binding datatemplate text-search

我有一个非常简单的例子: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
Run Code Online (Sandbox Code Playgroud)

在表单上我有一个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>
Run Code Online (Sandbox Code Playgroud)

我还有一个非绑定的ListBox,手动预先填充值:

<ListBox>
    <Label TextSearch.Text="One" Content="1" />
    <Label TextSearch.Text="Two" Content="2" />
    <Label TextSearch.Text="Three" Content="3" />
</ListBox>
Run Code Online (Sandbox Code Playgroud)

因此,当我启动应用程序时,它看起来像这样:

应用程序的窗口

问题:

如果我尝试通过键入"one","two"或"three"来使用键盘导航项目,我只能在非绑定列表框中成功.绑定列表框失败.

一些评论:1.)如果我在绑定列表框中按"[",焦点会以循环方式从一个项目更改为一个项目:它从1到2,从2到3,从3到1,再从1再到2 2.)我已经使用Snoop检查了应用程序.我在绑定和非绑定列表框之间找到了一个区别.两个列表框都在Label控件上设置了TextSearch.Text属性(在ItemsPresenter内).但对于非约束情况:TextSearch.Text属性的"值源"是"本地".对于约束情况:"value source"是"ParentTemplate".

PS(和NB) 我知道我可以在列表框中使用TextSearch.TextPath,但这不是我需要的:)另外,为ListViewItem设置TextSearch.Text属性(通过使用Style)也无济于事.

Dre*_*rsh 12

首先让我解释一下TextSearch如何与ItemsControl一起使用:

TextSearch的实现枚举ItemsSource属性的实际数据项,并直接查看它们以读取Text依赖项属性.当你ListBoxItem像在你的例子中那样放入s时它会起作用,因为实际的项是ListBoxItem具有Text"附加"依赖属性的实例.一旦绑定到Dictionary<>它,它现在直接查看KeyValuePair<>不是DependencyObjects的实例,因此不能/不具有TextSearch.Text它们的属性.这也是为什么TextSearch.TextListBoxItemvia 上设置属性ItemContainerStyle没有效果的原因:ItemContainerStyle描述了数据在可视树中的外观,但TextSearch引擎只考虑原始数据源.如何在UI中设置数据样式并不重要,这就是为什么修改a DataTemplate永远不会做任何事情TextSearch.

另一种方法是创建一个视图模型类,该类继承自DependencyObjectTextSearch.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" }
};
Run Code Online (Sandbox Code Playgroud)

ListBox定义如下所示:

<ListBox Name="listBox">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Value}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

任何其他选择都需要你使用TextSearch.TextPath,但你似乎已经死了.如果您接受修改DataTemplate将永远不会工作,我建议的解决方案是简单地创建一个POCO视图模型,其中包含您要用于搜索的属性并指定它TextSearch.TextPath.这是完成你正在做的事情中最轻的,非黑客的方式.


Phi*_*hil 5

对您而言,一种可能的解决方案是使用TextSearch的回退行为,即在ListBoxItemif no TextSearch.TextTextSearch.TextPathset 的数据项上使用.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; }
}
Run Code Online (Sandbox Code Playgroud)