Search code examples
c#wpfxamllistviewgridviewcolumn

WPF DataGridColumn DisplayMemeberBinding


I have this ListView sort procedure:

    /// <summary>
    /// Handle the event of clicking on a column header to sort
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void GridViewColumnHeaderClicked(object sender, RoutedEventArgs e)
    {
        GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;

        if (headerClicked == null)
            return;

        if (headerClicked.Role == GridViewColumnHeaderRole.Padding)
            return;

>>>     var sortingColumn = (headerClicked.Column.DisplayMemberBinding as Binding)?.Path?.Path;
        if (sortingColumn == null)
            return;

        var direction = ApplySort(Items, sortingColumn);

        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 && _lastHeaderClicked != headerClicked)
        {
            _lastHeaderClicked.Column.HeaderTemplate =
                Resources["HeaderTemplateDefault"] as DataTemplate;
        }

        _lastHeaderClicked = headerClicked;
    }

And it works well when the ListView.View is defined using DisplayMemberBinding like so:

    <!-- Name -->
    <GridViewColumn Width="200" 
                    DisplayMemberBinding="{Binding FullName}">
        <GridViewColumn.Header>
        <GridViewColumnHeader Content=" Name"
                              HorizontalContentAlignment="Left" />
        </GridViewColumn.Header>
    </GridViewColumn>

I now have a requirement of making some columns right aligned so I have to use something like this:

<!-- Name -->
<GridViewColumn Width="200">
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding FullName}"
                       TextAlignment="Right" />
            </DataTemplate>
    </GridViewColumn.CellTemplate>
    <GridViewColumn.Header>
    <GridViewColumnHeader Content=" Name"
                          HorizontalContentAlignment="Left" />
    </GridViewColumn.Header>
</GridViewColumn>

However, I now no longer have a DisplayMemberBinding to reference for the sort procedure (line marked with >>>). Is there a way to find the binding from the CellTemplate -> TextBlock? I have been digging thru both the C# code and XAML code using Snoop but am unable to find the binding.


Solution

  • I would personally write an attached property:

    public static class GridViewExt
    {
        #region GridViewExt.SortColumnPath Attached Property
        public static String GetSortColumnPath(GridViewColumn obj)
        {
            return (String)obj.GetValue(SortColumnPathProperty);
        }
    
        public static void SetSortColumnPath(GridViewColumn obj, String value)
        {
            obj.SetValue(SortColumnPathProperty, value);
        }
    
        public static readonly DependencyProperty SortColumnPathProperty =
            DependencyProperty.RegisterAttached("SortColumnPath", typeof(String), typeof(GridViewExt),
                new PropertyMetadata(null, SortColumnPath_PropertyChanged));
    
        private static void SortColumnPath_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = d as GridViewColumn;
        }
        #endregion GridViewExt.SortColumnPath Attached Property
    }
    

    Usage:

    private void GridViewColumnHeaderClicked(object sender, RoutedEventArgs e)
    {
        GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
    
        if (headerClicked == null)
            return;
    
        if (headerClicked.Role == GridViewColumnHeaderRole.Padding)
            return;
    
        //  ...if DisplayMemberPath is null...
        var sortingColumn = GridViewExt.GetSortColumnPath(headerClicked.Column);
    
        if (sortingColumn == null)
            return;
    

    XAML:

    <GridViewColumn 
        Width="200"
        local:GridViewExt.SortColumnPath="FullName"
        >
        <GridViewColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding FullName}"
                           TextAlignment="Right" />
                </DataTemplate>
        </GridViewColumn.CellTemplate>
    

    I had a notion that you could use both DisplayMemberBinding and CellTemplate, but CellTemplate is disregarded if DisplayMemberBinding is used.