Прокрутка ListView CollectionViewSource в группу элементов на основе текста текстового поля поиска в C#

Я работаю над приложением Windows Phone 8.1 в XAML и C#.

У меня есть список, чей источник элемента установлен в CollectionViewSource называется MusicSource, На бэкэнде в C# у меня есть ObservableCollection называется source и следующий код заполняет его, получая все музыкальные файлы на телефоне, группирует их по исполнителям и затем помещает их в CollectionViewSource, который показывает их в виде списка:

var folders = await folder.GetFoldersAsync();
    if (folders != null)
        foreach (var fol in folders)
            await getMusic(fol);

var files = await folder.GetFilesAsync();
foreach (var file in files)
{
    MusicProperties musicProperties = await file.Properties.GetMusicPropertiesAsync();
    this.source.Add(new Music((musicProperties.Artist.Length > 0) ? musicProperties.Artist : "Custom", (musicProperties.Title.Length > 0) ? musicProperties.Title : file.Name, (musicProperties.Album.Length > 0) ? musicProperties.Album : "Custom Album", file.Path));
}
itemSource = AlphaKeyGroup<Music>.CreateGroups(source, CultureInfo.CurrentUICulture, s => s.Artist, true);
this.MusicSource.Source = itemSource;

Ниже приведена сторона XAML:

<Page.Resources>
    <DataTemplate x:Key="GroupTemplate">
        <Grid Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Column="1">
                <TextBlock x:Name="SongTitle" Text="{Binding Title}"
                           Style="{ThemeResource ListViewItemTextBlockStyle}"/>
                <TextBlock x:Name="ArtistName" Text="{Binding Album}"
                           Style="{ThemeResource ListViewItemContentTextBlockStyle}"/>
            </StackPanel>
        </Grid>
    </DataTemplate>

    <CollectionViewSource x:Name="MusicSource" IsSourceGrouped="true" />

    <DataTemplate x:Key="headerTemplate">
        <StackPanel HorizontalAlignment="Stretch" Width="{Binding ActualWidth, ElementName=contentList}">
            <TextBlock Text="{Binding Key}" />
        </StackPanel>
    </DataTemplate>
</Page.Resources>

<Grid>
    <SemanticZoom>
        <SemanticZoom.ZoomedInView>
            <ListView
                x:Name="contentList"
                SelectionMode="Multiple"
                ItemsSource="{Binding Source={StaticResource MusicSource}}"
                ItemTemplate="{StaticResource GroupTemplate}">
                <ListView.GroupStyle>
                    <GroupStyle HidesIfEmpty="True" HeaderTemplate="{StaticResource headerTemplate}"/>
                </ListView.GroupStyle>
            </ListView>
        </SemanticZoom.ZoomedInView>
    </SemanticZoom>
    <Border
        x:Name="SearchBorder"
        Background="White">
        <TextBox
                x:Name="Search" TextChanged="TextBox_TextChanged" />
    </Border>
</Grid>

Таким образом, я получаю что-то вроде следующего в списке:

Майкл Джексон

  • Плохой
  • опасно
  • Триллер

Eminem

  • Не бояться
  • Монстр

У меня есть текстовое поле с именем search это предназначено для поиска по списку.

Что должно произойти, так это то, что, когда я набираю текстовое поле, просмотр списка прокручивается до ближайшей группы, заголовок группы которой соответствует тексту в текстовом поле. Поэтому, если я наберу "Em", просмотр списка должен сразу прокрутиться вниз до категории "Eminem".

Как бы я этого достиг?

Кроме того, возможно ли сделать то же самое, кроме прокрутки до элемента, songTitle атрибут совпадает с текстом в текстовом поле?

2 ответа

Вау, это одна сложная проблема. Я сделал что-то очень похожее в прошлом. По сути, вы хотите AJAX-решение для набора ObservableCollection. Вы можете достичь этого, написав функцию поиска через AlphaKeyGroup с помощью сопоставления регулярных выражений. Это должно вернуть ваш элемент, к которому нужно перейти.

Что касается поиска каждого изменения текста, вам нужно прикрепить событие TextChanged к текстовому полю следующим образом:

<TextBox x:Name="my_search" TextChanged="my_search_TextChanged" Grid.Row="0" />

Когда он находит совпадение, вы хотите перейти к этому элементу с помощью

contentList.ScrollIntoView(matching_element);



Хорошо, опубликовано решение для Windows Phone 8.1: ListView Searching Project

Основные моменты включали в себя процедуру поиска, добавленную в класс GroupKey.

public T FindMatch(string pattern, GetKeyDelegate getKey)
{
    Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);

    foreach (T item in this.Items)
    {
        string key = getKey(item);
        Match match = rgx.Match(key);
        if (match.Success)
            return item;
    }

    return default(T);
}

Снимок экрана поиска что что

Задавать ICollectionView.Filter обратный вызов для фильтрации вашего списка каждый раз, когда TextChanged Событие возникает так:

private void TextBox_TextChanged(object sender, TextChangedEven)
    {
        ICollectionView view = lvTest.ItemsSource as ICollectionView;
        string txtToSearch = searchTextBox.Text;
        view.Filter = (p) => { return ((Music)p).ArtistName.Contains(txtToSearch); };
        view.Refresh();
    } 

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

Другие вопросы по тегам