Использование TextSearch.Текст в шаблон данных DataTemplate

у меня есть очень простой пример: приложение формы 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>

поэтому, когда я запускаю приложение, оно выглядит так:

Application's window

ВОПРОС:

Если я попытаюсь перемещаться по элементам с помощью клавиатура, набрав "один", "два" или "три", мне удается только в списке без привязки. Ошибка связанного списка.

некоторые замечания: 1.) Если я нажимаю " ["в поле связанного списка, фокус изменяется от элемента к элементу циклически: он переходит от 1 к 2, от 2 к 3, от 3 к 1, от 1 снова к 2 и т. д. 2.) Я проверил приложение со Snoop. Одно различие я нашел между связанными и не связанными списками. Оба списка имеют TextSearch.Свойство Text, установленное в элементах управления Label (внутри ItemsPresenter). Но для не связанный случай: "источник значения" TextSearch.Свойство Text является "локальным". Для связанного случая: "источник значения" - "ParentTemplate".

С. П. (Б. Н.) Я знаю, что могу использовать TextSearch.TextPath в списке, но это не то, что мне нужно :) Кроме того, установка TextSearch.Свойство Text для ListViewItem (с помощью Style) не помогает.

2 ответов


позвольте мне начать с объяснения того, как TextSearch работает с ItemsControl:

реализация TextSearch перечисляет фактические элементы данных ItemsSource собственность и смотрит на те напрямую читать Text свойства зависимостей. Когда вы ставите ListBoxItems в нем, как и в вашем примере, он работает, потому что фактические элементы ListBoxItem экземпляров с Text свойство зависимостей "прикреплено" к ним. Как только вы привязываетесь к своему Dictionary<> это сейчас глядя прямо на KeyValuePair<> экземпляров, которые не являются DependencyObjects и, следовательно, не может / не имеет TextSearch.Text собственность на них. Это также Почему установка TextSearch.Text собственности на ListBoxItem через ItemContainerStyle нет эффект:ItemContainerStyle описывает, как ваши данные должны выглядеть в визуальном дереве, но TextSearch engine рассматривает только исходный источник данных. Не имеет значения, как вы стилизовали эти данные в пользовательском интерфейсе, и поэтому изменение 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 Name="listBox">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Value}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

любая другая альтернатива потребует от вас, чтобы использовать TextSearch.TextPath, но вы, кажется, категорически против этого. Если вы примете это изменение, DataTemplate никогда не будет работать, решение, которое я бы рекомендовал, - это просто создать модель представления POCO, которая имеет свойство, которое вы хотите использовать для поиска, и указать, что TextSearch.TextPath. Это самый легкий и простой способ сделать то, что вы делаете.


возможным решением для вас является использование Резервного поведения TextSearch .ToString () на элементе данных ListBoxItem, если не TextSearch.Text или TextSearch.TextPath задаются.

так, например, это позволит вам искать без указания TextSearch.Текст или. 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; }
}