【问题标题】:Filtering a listview in Windows Phone 8.1 app在 Windows Phone 8.1 应用程序中筛选列表视图
【发布时间】:2014-08-28 18:35:34
【问题描述】:

我正在使用 XAML/C# 开发 Windows Phone 8.1 应用程序。

我有一个列表视图,其项目源设置为 CollectionViewSource,称为 MusicSource。在 C# 的后端,我有一个名为 sourceObservableCollection,下面的代码通过获取手机上的所有音乐文件来填充它,按艺术家分组,然后将它们放在 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>

所以我在列表视图中得到如下内容:

迈克尔杰克逊

  • 不好
  • 危险
  • 惊悚
  • 怪物

阿姆

  • 不怕
  • 怪物

当用户在搜索文本框中键入时,列表视图应该被过滤,并且只显示与搜索文本框中的文本匹配的项目。例如,如果我在搜索框中输入“Monster”,列表视图会立即被过滤,并且仅在“Michael Jackson”组标题中显示“Monster”,在“Eminem”组标题中显示“The Monster”。

我将如何实现这一目标?

【问题讨论】:

  • 类似于“itemSource = AlphaKeyGroup.CreateGroups(source, CultureInfo.CurrentUICulture, s => s.Artist, true).Where(s => s.Artist.Contains( "searchedtext") || s.Album.Contains("searchedtext");
  • 问题是当您更改项目来源时,所有选定的项目都会被取消选择
  • 嗯。我不确定您要达到什么目的,所以我不知道为什么您在输入搜索框时会选择项目。但是,您可以有两个列表框并将 Visibility 设置为绑定到一个属性,例如“bool isSearching”。如果 isSearching == true,隐藏列表框 1 并显示列表框 2。但不确定这会如何影响性能。

标签: c# xaml listview windows-phone


【解决方案1】:

我对 Windows 8 应用商店应用程序有类似的任务 - 当用户键入示例文本时对分组列表视图进行实时过滤。我制作了一个包含 FilterText 和 Groups 的视图模型。 Group 有两个可观察的集合 - AllItems(项目的完整列表)和 Items(在屏幕上可见)。当 FilterText 更改时,我将检查每个组中的每个项目并确定是否将其保留在 Items 中。这是一些代码:

...

var rule = x => GetTextToFilter(x).IndexOf(filterText,
                StringComparison.CurrentCultureIgnoreCase) >= 0;

foreach (var group in Groups)
{
    group.UpdateVisibleItems(rule);
}

...

void UpdateVisibleItems(Func<ItemViewModel, bool> rule)
{
    for (int i = 0, j = 0; i < AllItems.Count; i++)
    {
        var item = AllItems[i];
        if (rule(item))
        {
            if (j == _Items.Count || (j < _Items.Count && _Items[j] != item))
            {
                _Items.Insert(j, item);
            }

            j++;
        }
        else
        {
            if (j < _Items.Count && _Items[j] == item)
            {
                _Items.RemoveAt(j);
            }
        }
    }
}

如果项目在过滤后仍然可见,这种方式选择保持不变。动画看起来是正确的,因为系统将其视为可观察集合上的一系列插入/删除(完整的列表刷新将使整个列表被删除和恢复,这将是错误的动画)。

效果很好(前提是 AllItems 不是数百万行),但在特定情况下我遇到了奇怪的异常 - 当 ListView.GroupStyle.HidesIfEmpty=True 和一些(或全部?)组在更新过程中被清除时 - 进程崩溃在 Windows.UI.Xaml.dll 中。 C# 代码中没有捕获异常(UnhandledException 和 TaskScheduler.UnobservedTaskException 是静默的)。事件日志中没有可用的内容。调试器无法显示详细信息,甚至无法附加到失败的进程。如果我添加await Task.Delay(),它将更加稳定,但仍可能不时失败。如果我设置ListView.GroupStyle.HidesIfEmpty=False - 一切正常!

【讨论】:

    【解决方案2】:

    嗯,这似乎并不难,你所要做的就是首先制作你的歌曲列表,然后在其中搜索它的项目并将不需要的项目折叠起来! 为了便于工作,使用 listview 控件并在其项目中进行搜索。 请注意,首先您必须在母控件中缓存所有列表视图控件以供将来搜索,以避免再次获取所有音乐并禁用搜索模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多