views:

994

answers:

4

I am working an a sortable WPF ListView and I made a lot of progress already. It's not so hard since there is a lot of stuff on the internet already. But there is a little bit of information I am still missing.

With a Colum like that:

<GridViewColumn Width="200" Header="Fahrzeugname" DisplayMemberBinding="{Binding Name}">

I can sort it like this:

Binding columnBinding = column.DisplayMemberBinding as Binding;

if (columnBinding != null)
{
    sorts.Clear();
    sorts.Add(new SortDescription(columnBinding.Path.Path, direction));
    lastColumnSorted = column;
}

But my problem is I don't have a DisplayMemberBinding since I use a DataTemplate:

<DataTemplate>
    <TextBlock Text="{Binding Name}" TextAlignment="Left"/>
</DataTemplate>

How do I get the Binding property for this column in the C# Code?

A: 

Why would you attempt to do this automatically? Why not provide an attached property that users can set to dictate the property by which the column should be sorted?

<GridViewColumn s:SortableColumn.SortBy="{Binding Name}" ...>

That way you offer more freedom of implementation, and the code will be faster and more robust.

HTH, Kent

Kent Boogaart
+2  A: 

I wrote a set of attached properties to do exactly what Kent suggested, you can check it out here


EDIT : as requested, here's a sample of a command for GridViewSort.Command :

    private ICommand _sortCommand;
    public ICommand SortCommand
    {
        get
        {
            if (_sortCommand == null)
            {
                _sortCommand = new RelayCommand(SortPersonsBy);
            }
            return _sortCommand;
        }
        set { _sortCommand = value; }
    }

    private void SortPersonsBy(object param)
    {
        string propertyName = param as string;
        ICollectionView view = CollectionViewSource.GetDefaultView(_persons);
        ListSortDirection direction = ListSortDirection.Ascending;
        if (view.SortDescriptions.Count > 0)
        {
            SortDescription currentSort = view.SortDescriptions[0];
            if (currentSort.PropertyName == propertyName)
            {
                if (currentSort.Direction == ListSortDirection.Ascending)
                    direction = ListSortDirection.Descending;
                else
                    direction = ListSortDirection.Ascending;
            }
            view.SortDescriptions.Clear();
        }
        if (!string.IsNullOrEmpty(propertyName))
        {
            view.SortDescriptions.Add(new SortDescription(propertyName, direction));
        }
    }

(it actually implements the same behavior as when GridViewSort.AutoSort is set to true...)

Thomas Levesque
Great article! A sample for the GridViewSort.Command would be fine. Since I am not so experienced with this topic.
Holli
I updated my answer to add the sample
Thomas Levesque
Thanks, I will look into that.
Holli
A: 

the WPF built-in way would be to use the ICollectionView.

ICollectionView view = CollectionViewSource.GetDefaultView(yourItemsSourceList);
if(view.CanSort)
{
   view.SortDescriptions.Add(...)
}
Martin Moser
A: 

I am facing a similar WPF Listview/Gridview sorting issue and I have some contraints which makes it difficult to implement the CSharp solutions provided. Essentially I have an existing ASP.NET application with thousands of lines of debugged VB code as well as working SQL for a database with over 100 tables and some very complex joins. I have to write a Windows .exe based upon the same application but I want to use WPF to implement a similar graphical look & feel.

Having finished with the disclaimer I encountered the sorting issue and searched the internet for all the great shared concepts like those above and tried converting them from CS into VB. I am an experienced programmer but I discovered that this was simply beyond my reach so I turned elsewhwere and developed my own sort instead. It will probably horrify the purists but I am a pragmatist and producing a commercial application takes precedence.

In order to sort the grid I decided to just use the Mouse events on the column headers. DoubleClick for Ascending sorts and MouseRightButtonUp for descending.

Private Sub ListViewGrid_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles ListingDG.MouseDoubleClick

    Try

        Dim mouseHdrClick As String = DirectCast(DirectCast(e.OriginalSource, System.Object), System.Windows.Controls.TextBlock).Text

        Dim SqlOrderBy As String = ""

        Select Case UCase(mouseHdrClick.Trim)

            Case UCase("Product Name")
                SqlOrderBy = " ORDER BY Product_Name"

Then I just reload the ListViewGrid using the SqlOrderBy string variable. The only problem I encountered was that I was forced to click on the Header text in the column header for it to work. I solved that by just appending the XML space character ( ) to fill the column width. The .Trim command clears them off again for the Select Case to work. I still haven't figured out how to add the little Up and Down arrows but the functionality is what counts here since those are just cosmetic touches right now.

Finally let me add that I am fully aware that if I change the Gridview structure it will cause the Header text to move elsewhere in the OriginalSource but that is an issue I can live with for now. I know that this is a quick & dirty workaround and there are probably much better alternatives so any recommendations will be appreciated.

Rich