ListView 中的 ICollectionView 排序问题

发布于 2024-09-15 19:58:28 字数 2988 浏览 8 评论 0原文

我看到 WPF 中引入了 ICollectionView 来处理需要启用排序和过滤的情况。我什至看到了几篇对项目进行排序的文章,但我主要关心的是为什么我的方法失败了。让我们看看我的代码:

 <ListView ItemsSource="{Binding}" x:Name="lvItems" GridViewColumnHeader.Click="ListView_Click">
            <ListView.View>
                <GridView AllowsColumnReorder="True">
                    <GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}" />
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Developer">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=Developer}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Salary">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=Salary}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>

                </GridView>
            </ListView.View>
        </ListView>

在代码隐藏中,当单击该项目时,我会这样做:

  ICollectionView Source { get; set; }


        private void ListView_Click(object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
            if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
            {
                //using (this.Source.DeferRefresh())
                //{
                    SortDescription currentPropertySort = this.Source.SortDescriptions.FirstOrDefault<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));
                    if (currentPropertySort != null)
                    {
                        if (currentPropertySort.Direction == ListSortDirection.Ascending)
                            currentPropertySort.Direction = ListSortDirection.Descending;
                        else
                            currentPropertySort.Direction = ListSortDirection.Ascending;

                    }
                    else
                        this.Source.SortDescriptions.Add(new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));


                //}
                    this.Source.Refresh();
                    this.lvItems.DataContext = this.Source;
                    this.lvItems.UpdateLayout();
            }


        }

因此,每当单击 ListBox 的标题时,都需要对该项目进行排序。我使用名为 Source 的属性保存该集合,然后通过调用 lvItems.DataContext = this.Source 来使用它。但是代码似乎不起作用。

I saw ICollectionView being introduced with WPF to handle situations when you need sorting and filtering enabled. I even saw few articles which sort items, but my main concern is why my approach is failing. Lets see my code :

 <ListView ItemsSource="{Binding}" x:Name="lvItems" GridViewColumnHeader.Click="ListView_Click">
            <ListView.View>
                <GridView AllowsColumnReorder="True">
                    <GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}" />
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Developer">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=Developer}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Salary">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=Salary}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>

                </GridView>
            </ListView.View>
        </ListView>

In codebehind, when the Item is clicked I am doing like this :

  ICollectionView Source { get; set; }


        private void ListView_Click(object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
            if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
            {
                //using (this.Source.DeferRefresh())
                //{
                    SortDescription currentPropertySort = this.Source.SortDescriptions.FirstOrDefault<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));
                    if (currentPropertySort != null)
                    {
                        if (currentPropertySort.Direction == ListSortDirection.Ascending)
                            currentPropertySort.Direction = ListSortDirection.Descending;
                        else
                            currentPropertySort.Direction = ListSortDirection.Ascending;

                    }
                    else
                        this.Source.SortDescriptions.Add(new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));


                //}
                    this.Source.Refresh();
                    this.lvItems.DataContext = this.Source;
                    this.lvItems.UpdateLayout();
            }


        }

So whenever the header for the ListBox is clicked, the item need to be sorted. I am holding the collection using a property called Source and then using it by calling lvItems.DataContext = this.Source. But the code does not seem to be working.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

極樂鬼 2024-09-22 19:58:28

这是 ListView_Click 方法的更新版本,有些效果。我不确定您到底在寻找什么排序行为,但下面的版本“堆叠”了一组排序描述,使最后单击的列作为“主要排序描述”。我希望这是有道理的,我希望下面的代码有所帮助。 =)

private void ListView_Click(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
    if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
    {
        if (this.Source.SortDescriptions
            .Count((item) => item.PropertyName.Equals(currentHeader.Column.Header.ToString())) > 0)                
        {
            SortDescription currentPropertySort = this.Source
                .SortDescriptions
                .First<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));

            //Toggle sort direction.
            ListSortDirection direction = 
                (currentPropertySort.Direction == ListSortDirection.Ascending)?
                ListSortDirection.Descending : ListSortDirection.Ascending;

            //Remove existing sort
            this.Source.SortDescriptions.Remove(currentPropertySort);
            this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), direction));
        }
        else
        {
            this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));
        }

        this.Source.Refresh();
    }
}

编辑:

顺便说一句,上面代码中的问题之一是调用“FirstOrDefault”来查询现有的 SortDescription。请注意,SortDescription 是一个不可为 null 的结构体,因此对 FirstOrDefault 的调用永远不会为 null 并且始终返回一个实例。因此,上面代码中的“else-statement”永远不会被调用。

Here's an updated version of your ListView_Click method that somewhat works. I'm not sure exactly what sorting behavior you were looking for but the version below "stacks up" a set of sort descriptions, making the last clicked column as the "primary sort description". I hope this makes sense and I hope the code below helps. =)

private void ListView_Click(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
    if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
    {
        if (this.Source.SortDescriptions
            .Count((item) => item.PropertyName.Equals(currentHeader.Column.Header.ToString())) > 0)                
        {
            SortDescription currentPropertySort = this.Source
                .SortDescriptions
                .First<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));

            //Toggle sort direction.
            ListSortDirection direction = 
                (currentPropertySort.Direction == ListSortDirection.Ascending)?
                ListSortDirection.Descending : ListSortDirection.Ascending;

            //Remove existing sort
            this.Source.SortDescriptions.Remove(currentPropertySort);
            this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), direction));
        }
        else
        {
            this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));
        }

        this.Source.Refresh();
    }
}

EDIT:

By the way, one of the problems in your code above is your call to "FirstOrDefault" to query an existing SortDescription. See, SortDescription is a struct, which is non-nullable so the call to FirstOrDefault will never be null and will always return an instance. Therefore, the "else-statement" in your code above will never get called.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文