views:

95

answers:

2

I have a DataGrid in my Silverlight application that I would like to highlight an entire column when that column is sorted.

It's similar in concept to this previous question: Silverlight DataGrid: Highlight an entire column.

Any ideas? I've thought maybe attaching a behavior to the LayoutUpdated event and checking a cell to see if it's in a sorted column?

+2  A: 

There are several issues that you have to get around to do what you want to do. The biggest issue is that finding out when a column is sorted is a lot harder then it should be. The only way I have ever found to identify that a column was sorted to make DataGrid.ItemsSource a PagedCollectionView and listen to the CollectionChanged event on its SortDescriptions property. If you use a PagedCollectionView for your ItemsSource and all columns that can be sorted on are DataGridBoundColumn (really any of the premades other than TemplateColumn) then this behavior should be fairly close to what you want to do.

public class DataGridSortedColumnHighlightBehavior : Behavior<DataGrid>
{

    private List<DataGridRow> rows = new List<DataGridRow>();

    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.LoadingRow += AssociatedObject_LoadingRow;
        AssociatedObject.UnloadingRow += AssociatedObject_UnloadingRow;

        if (AssociatedObject.ItemsSource == null)
        {
            AssociatedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
        }
        else
        {
            var collection =
                ((AssociatedObject.ItemsSource as PagedCollectionView).SortDescriptions as INotifyCollectionChanged);
            collection.CollectionChanged += DataGridSortedColumnHighlightBehavior_CollectionChanged;
        }
    }

    void AssociatedObject_UnloadingRow(object sender, DataGridRowEventArgs e)
    {
        rows.Remove(e.Row);
    }

    void AssociatedObject_LoadingRow(object sender, DataGridRowEventArgs e)
    {
        rows.Add(e.Row);
    }

    private void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
    {
        if (AssociatedObject.ItemsSource != null)
        {
            AssociatedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;
            var collection =
                ((AssociatedObject.ItemsSource as PagedCollectionView).SortDescriptions as INotifyCollectionChanged);
            collection.CollectionChanged += DataGridSortedColumnHighlightBehavior_CollectionChanged;
        }
    }

    void DataGridSortedColumnHighlightBehavior_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if(e.NewItems != null)
        {
            foreach(SortDescription sortDesc in e.NewItems)
            {
                foreach(var column in AssociatedObject.Columns)
                {
                    var boundColumn = column as DataGridBoundColumn;
                    if (boundColumn == null)
                        continue;
                    if (boundColumn.Binding.Path.Path == sortDesc.PropertyName)
                    {
                        foreach (var row in rows)
                            ColorCell(column,row,Colors.Red);
                    }
                }
            }
        }
        if(e.OldItems != null)
        {
            foreach(SortDescription sortDesc in e.OldItems)
            {
                foreach(var column in AssociatedObject.Columns)
                {
                    var boundColumn = column as DataGridBoundColumn;
                    if (boundColumn == null)
                        continue;
                    if (boundColumn.Binding.Path.Path == sortDesc.PropertyName)
                    {
                        foreach (var row in rows)
                            ColorCell(column,row,Colors.White);
                    }
                }
            }
        }
    }

    private void ColorCell(DataGridColumn column, DataGridRow item, Color color )
    {
        var content = column.GetCellContent(item);
        if (content == null)
            return;

        var parent = GetParent<DataGridCell>(content);

        if (parent != null)
            parent.Background = new SolidColorBrush(color);

    }

    public static T GetParent<T>(DependencyObject source)
        where T : DependencyObject
    {
        DependencyObject parent = VisualTreeHelper.GetParent(source);
        while (parent != null && !typeof(T).IsAssignableFrom(parent.GetType()))
        {
            parent = VisualTreeHelper.GetParent(parent);
        }
        return (T)parent;
    }        
}
Stephan
That works almost perfectly. Thanks much for your answer, the only one thing I've noticed is that it sometimes has a problem with scrolling, but its still a very big help!
GotDibbs
The scrolling issue is caused by the way the `DataGrid` virtualizes rows. It only keeps instantiates the number of rows visible on the screen plus 1 and keeps those in memory. To fix the issue you probably need to modify the code to keep a list of the columns that are sorted and in the LoadingRow event handler highlight the cells for those columns.
Stephan
Yeap thats the exact route that I took. Thanks again!
GotDibbs