Silverlight Datagrid:当该列被排序时突出显示整个列

问题描述:

我在我的Silverlight应用程序中有一个DataGrid,我想在该列进行排序时突出显示整列。Silverlight Datagrid:当该列被排序时突出显示整个列

它在概念上与前面的问题类似:Silverlight DataGrid: Highlight an entire column

任何想法?我想过可能将一个行为附加到LayoutUpdated事件并检查单元格以查看它是否在排序列中?

有几个问题需要解决,以便做你想做的事情。最大的问题是,找出列的排序时间应该会更困难。我发现唯一的方法是识别列被排序,使其DataGrid.ItemsSource为PagedCollectionView并在其SortDescriptions属性上侦听CollectionChanged事件。如果您的ItemsSource使用PagedCollectionView,并且可以排序的所有列都是DataGridBoundColumn(实际上是TemplateColumn以外的任何预构造),则此行为应该与您想要执行的操作相当接近。

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; 
    }   
} 
+0

那近乎完美的作品。非常感谢您的回答,我注意到的唯一一件事情是它有时会出现滚动问题,但它仍然是一个非常大的帮助! – GotDibbs 2010-10-19 18:49:29

+0

滚动问题是由'DataGrid'虚拟化行的方式引起的。它只是实例化屏幕上可见的行数加1并将其保存在内存中。要解决此问题,您可能需要修改代码以保留已排序的列的列表,并在加载行事件处理程序中突出显示这些列的单元格。 – Stephan 2010-10-19 19:02:10

+0

Yeap这是我采取的确切路线。再次感谢! – GotDibbs 2010-10-19 19:20:33