WPF Listbox выделяет часть элемента ListBoxItem - PullRequest
3 голосов
/ 28 апреля 2009

У меня есть TextBox и ListBox. Пользователь может искать элементы ListBox из TextBox.

ListBox привязан к CollectionViewSource.

CollectionViewSource имеет обработчик события Filter, который фильтрует элементы на основе текста, который пользователь вводит в TextBox.

Мое требование - выделить введенный пользователем текст в TextBlock элементов ListBoxItem.

Я думал разбить TextBlock на несколько объектов Run и изменить свойство Background объектов Run, которые нужно выделить.

Я думаю, что это невозможно сделать с DataTemplates.

Есть ли простой способ сделать это?

Спасибо!

Ответы [ 2 ]

9 голосов
/ 28 апреля 2009

ОБНОВЛЕНИЕ: я подробно остановился на этой теме в этом сообщении в блоге .

Не думаю, что есть простой способ сделать это, но вот как я бы решил эту проблему:

  1. Определить модель представления для элементов в списке. Он должен включать свойства, позволяющие отобразить текст и определить, какая часть текста должна быть выделена (в основном, начальный и конечный индексы).
  2. Когда пользователь вводит текст в поле поиска, просматривайте модели просмотра и проверяйте совпадения в тексте. Если совпадение найдено, установите индексы соответствующим образом. Если совпадение не найдено, установите индексы обратно на -1 или что-то еще, что не соответствует.
  3. По вашему мнению, установите Background из TextBlock s на индексы. Используйте конвертер для преобразования индексов в ярко-желтый (или любой другой) GradientBrush между двумя индексами.

Вот как Я думаю Вы можете вычислить размеры выделенных частей TextBlock:

  1. Получите TextPointer через свойство TextBlock.ContentStart.
  2. Перейдите к началу выбора, набрав TextPointer.GetPositionAtOffset(indexOfStart), используя LogicalDirection.Forwards.
  3. Переместитесь в конец выделения, набрав TextPointer.GetPositionAtOffset(indexOfStart), используя LogicalDirection.Backwards.
  4. Позвоните TextPointer.GetCharacterRect, чтобы получить ограничение Rectangle выделенного содержимого.

Если честно, я не уверен, что последний бит сработает. Я должен попробовать это для себя, и я могу сделать это для сообщения в блоге.

РЕДАКТИРОВАТЬ : Просто было время, чтобы попробовать это для себя. Это определенно работает, хотя с небольшими изменениями в моей логике выше. Ниже приведен код, который демонстрирует. Вот скриншот:

Скриншот http://img219.imageshack.us/img219/2969/searchx.png

Window1.xaml

<Window x:Class="TextSearch.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1">
    <StackPanel>
        <TextBox x:Name="_searchTextBox"/>
        <Grid>
            <Path Fill="Yellow" Stroke="Black" StrokeThickness="0">
                <Path.Data>
                    <RectangleGeometry x:Name="_rectangleGeometry"/>
                </Path.Data>
            </Path>
            <TextBlock x:Name="_textBlock">Some sample text that you can search through by typing in the above TextBox.</TextBlock>
        </Grid>
    </StackPanel>
</Window>

Window1.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace TextSearch
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            _searchTextBox.TextChanged += _searchTextBox_TextChanged;
        }

        void _searchTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            var searchText = _searchTextBox.Text;
            var index = _textBlock.Text.IndexOf(searchText);

            if (index == -1)
            {
                _rectangleGeometry.Rect = Rect.Empty;
            }
            else
            {
                var textPointer = _textBlock.ContentStart;
                textPointer = textPointer.GetPositionAtOffset(index + 1, LogicalDirection.Forward);
                var leftRectangle = textPointer.GetCharacterRect(LogicalDirection.Forward);
                textPointer = textPointer.GetPositionAtOffset(searchText.Length, LogicalDirection.Backward);
                var rightRectangle = textPointer.GetCharacterRect(LogicalDirection.Forward);
                _rectangleGeometry.Rect = new Rect(leftRectangle.TopLeft, rightRectangle.BottomRight);
            }
        }
    }
}

Я думаю, что код довольно понятен. Очевидно, вам нужно будет расширить концепцию до вашего конкретного сценария. Вы можете предпочесть использовать свойство Background TextBlock в сочетании с DrawingBrush или GradientBrush вместо использования отдельного Path.

0 голосов
/ 21 июня 2012

Фильтрация в окне списка WPF. Следующий пример кода хорошо работает для меня.

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <TextBox Name="txtSearch" Height="21" Margin="63,12,12,0" VerticalAlignment="Top"></TextBox>
    <ListBox Name="listItems" ItemsSource="{Binding}" Margin="22,0,0,44" Height="179" VerticalAlignment="Bottom" />
</Grid>

Код Vb.net

привязка данных в вашем списке

Dim _dtable As New DataTable("tblItems") _dtable.Columns.Add("Id", GetType(Integer))
    _dtable.Columns.Add("Name", GetType(String))
    _dtable.Columns.Add("Price", GetType(Double))
    ' Add any initialization after the InitializeComponent() call.
    For i = 100 To 110
        _dtable.Rows.Add(i, "Item " & i, 15.0)
    Next







  Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    listItems.DataContext = _dtable.DefaultView
End Sub
Private Sub txtSearch_TextChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.TextChangedEventArgs) Handles txtSearch.TextChanged

_dtable.DefaultView.RowFilter = "Имя как '" & txtSearch.Text & "%'"

End Sub

приведенный выше пример кода работает для меня

...