0

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.

1
  • To all the viewers of this post, I have implemented this already. If you want to see take a look : abhisheksur.com/2010/08/… Thanks Commented Aug 29, 2010 at 23:55

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow thats great. I just overlooked the type of SortDescription and hence more credits to you for pointing me with that. Thank you so much for your code.
In my case the ListView only has been sorted at the first time, and Refresh() does not work at all! so what is the problem?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.