在DataTemplate中使用TextSearch.Text

时间:2012-04-13 21:44:44

标签: .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

在表单上我有一个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>

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

Application's window

问题:

如果我尝试通过键入“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)也无济于事。

2 个答案:

答案 0 :(得分:12)

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

TextSearch的实现枚举ItemsSource属性的实际数据项,并直接查看那些 以读取Text依赖项属性。当您将ListBoxItem放入其中时,就像您在示例中所做的那样,因为实际项目是ListBoxItem个实例,并且Text依赖属性“附加”到它们。绑定到Dictionary<>后,它现在直接查看KeyValuePair<>DependencyObjectTextSearch.Text个实例,因此不能/不具有TextSearch.Text属性。这也是通过ListBoxItemItemContainerStyle上设置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)

如果没有设置ListBoxItemTextSearch.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; }
}