0

I'm trying to sort a ListView by it's headers.

I'm following this MSDN example, with the alternation given here - where this line works if I were to use direct binding:

GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
string sortString = ((Binding)headerClicked.Column.DisplayMemberBinding).Path.Path

But problem is I'm not binding the columns directly using DisplayMemberBinding="{Binding PVNum}" but rather I am using CellTemplate:

<ListView.Resources>
    <DataTemplate x:Key="NumberTemplate">
        <TextBlock Text="{Binding PVNum}" TextAlignment="Center"  />
    </DataTemplate>
</ListView.Resources>

<ListView.View>
  <GridView AllowsColumnReorder="False">
     <GridView.Columns>
        <GridViewColumn Header=" " CellTemplate="{StaticResource NumberTemplate}"/>
      </GridView.Columns>
   </GridView>
</ListView.View>

So my question is - how do I get this "PVNum" string in the code behind?

I did try this, though s is null - so I guess I'm off:

 var t = headerClicked.Column.CellTemplate.LoadContent() as TextBlock;
 var s = t.GetBindingExpression(TextBox.TextProperty);

Any suggestions?

Maverick Meerkat
  • 5,737
  • 3
  • 47
  • 66

2 Answers2

2

A possible solution is to define an attached property for GridViewColumn:

public class GridViewColumnAttachedProperties
{
    public static readonly DependencyProperty SortPropertyNameProperty = DependencyProperty.RegisterAttached(
        "SortPropertyName", typeof(string), typeof(GridViewColumnAttachedProperties), new PropertyMetadata(default(string)));

    public static void SetSortPropertyName(DependencyObject element, string value)
    {
        element.SetValue(SortPropertyNameProperty, value);
    }

    public static string GetSortPropertyName(DependencyObject element)
    {
        return (string) element.GetValue(SortPropertyNameProperty);
    }
}

In XAML you set the attached properties to the Path used in the Binding inside the templates. Based on the example from the MSDN site:

<ListView x:Name='lv' Height="150" HorizontalAlignment="Center" VerticalAlignment="Center" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
    <ListView.Resources>
        <DataTemplate x:Key="YearTemplate">
            <TextBlock Text="{Binding Year}" TextAlignment="Center"  />
        </DataTemplate>
        <DataTemplate x:Key="MonthTemplate">
            <TextBlock Text="{Binding Month}" TextAlignment="Center"  />
        </DataTemplate>
        <DataTemplate x:Key="DayTemplate">
            <TextBlock Text="{Binding Day}" TextAlignment="Center"  />
        </DataTemplate>
    </ListView.Resources>

    <ListView.ItemsSource>
        <collections:ArrayList>
            <system:DateTime>1993/1/1 12:22:02</system:DateTime>
            <system:DateTime>1993/1/2 13:2:01</system:DateTime>
            <system:DateTime>1997/1/3 2:1:6</system:DateTime>
            <system:DateTime>1997/1/4 13:6:55</system:DateTime>
            <system:DateTime>1999/2/1 12:22:02</system:DateTime>
            <system:DateTime>1998/2/2 13:2:01</system:DateTime>
            <system:DateTime>2000/2/3 2:1:6</system:DateTime>
            <system:DateTime>2002/2/4 13:6:55</system:DateTime>
            <system:DateTime>2001/3/1 12:22:02</system:DateTime>
            <system:DateTime>2006/3/2 13:2:01</system:DateTime>
            <system:DateTime>2004/3/3 2:1:6</system:DateTime>
            <system:DateTime>2004/3/4 13:6:55</system:DateTime>
        </collections:ArrayList>
    </ListView.ItemsSource>

    <ListView.View>
        <GridView>
            <GridViewColumn CellTemplate="{StaticResource YearTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Year" />
            <GridViewColumn CellTemplate="{StaticResource MonthTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Month" />
            <GridViewColumn CellTemplate="{StaticResource DayTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Day" />
        </GridView>
    </ListView.View>
</ListView>

And in the Click event handler you can just retrieve the value of the attached property with string bindingName = headerClicked.Column.GetValue(GridViewColumnAttachedProperties.SortPropertyNameProperty) as string;. Based on the MSDN example:

GridViewColumnHeader _lastHeaderClicked;
ListSortDirection _lastDirection = ListSortDirection.Ascending;

private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;

    if (headerClicked != null)
    {
        if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
        {
            ListSortDirection direction;
            if (!ReferenceEquals(headerClicked, _lastHeaderClicked))
            {
                direction = ListSortDirection.Ascending;
            }
            else
            {
                if (_lastDirection == ListSortDirection.Ascending)
                {
                    direction = ListSortDirection.Descending;
                }
                else
                {
                    direction = ListSortDirection.Ascending;
                }
            }

            string bindingName = headerClicked.Column.GetValue(GridViewColumnAttachedProperties.SortPropertyNameProperty) as string;
            Sort(bindingName, direction);

            if (direction == ListSortDirection.Ascending)
            {
                headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate;
            }
            else
            {
                headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate;
            }

            // Remove arrow from previously sorted header  
            if (_lastHeaderClicked != null && !ReferenceEquals(_lastHeaderClicked, headerClicked))
            {
                _lastHeaderClicked.Column.HeaderTemplate = null;
            }

            _lastHeaderClicked = headerClicked;
            _lastDirection = direction;
        }
    }
}

private void Sort(string sortBy, ListSortDirection direction)
{
    ICollectionView dataView = CollectionViewSource.GetDefaultView(lv.ItemsSource);

    dataView.SortDescriptions.Clear();
    SortDescription sd = new SortDescription(sortBy, direction);
    dataView.SortDescriptions.Add(sd);
    dataView.Refresh();
}
Szabolcs Dézsi
  • 8,743
  • 21
  • 29
2

It should be TextBlock.Text property:

var t = headerClicked.Column.CellTemplate.LoadContent() as TextBlock;
var s = t.GetBindingExpression(TextBlock.TextProperty);
string sourcePropertyName = s.ParentBinding.Path.Path;
mm8
  • 163,881
  • 10
  • 57
  • 88