如何在DataGrid和CollectionViewSource之间同步排序标记?

时间:2012-07-16 08:33:39

标签: c# wpf xaml

如何实现(最好是纯粹在XAML中)WPF DataGrid的列标题中的排序标记与CollectionViewSource中的当前排序顺序同步?

例如,我有以下示例代码,它显示C:\中所有文件的属性,按长度排序:

<Window x:Class="DataGridSortTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase" 
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <CollectionViewSource x:Key="items" Source="{Binding Files}">
            <CollectionViewSource.SortDescriptions>
                <cm:SortDescription PropertyName="Length"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding Source={StaticResource items}}"/>
    </Grid>
</Window>

MainWindow.xaml.cs中的代码隐藏是:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Files = Directory.GetFiles(@"C:\").Select(f => new FileInfo(f)).ToList();

        DataContext = this;
    }

    public IEnumerable<FileInfo> Files { get; private set; } 
}

当我开始这个程序时,它看起来像这样:

Screenshot

即。文件正确排序,但标题中的标记丢失。使用“marker”,我的意思是:

Sort marker

注意:我正在寻找通用解决方案。仅设置DataGridColumn.SortDirection不是解决方案。我正在寻找一种方法来指示DataGrid从集合视图中自动检索排序顺序。

3 个答案:

答案 0 :(得分:1)

这似乎是一个古老的问题,但今天我遇到了同样的问题,并找到了一个通用的解决方案。因此,想法是SortDescriptions集合隐式实现INotifyCollectionChanged,因此我们有能力观察它并设置DataGrid&#34;排序标记&#34;适当。我在单独的行为中实现了这个:

public class DataGridSortDescriptionsSyncBehavior : Behavior<DataGrid>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        var view = CollectionViewSource.GetDefaultView(AssociatedObject.ItemsSource);
        var notifyCollection = view.SortDescriptions as INotifyCollectionChanged;
        if (notifyCollection != null)
            notifyCollection.CollectionChanged += SortDescriptions_CollectionChanged;
    }

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

        var view = CollectionViewSource.GetDefaultView(AssociatedObject.ItemsSource);
        var notifyCollection = view.SortDescriptions as INotifyCollectionChanged;
        if (notifyCollection != null)
            notifyCollection.CollectionChanged -= SortDescriptions_CollectionChanged;
    }

    private void SortDescriptions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Reset)
        {
            // clear all columns sort directions
            foreach (var column in AssociatedObject.Columns)
                column.SortDirection = null;
        }

        if (e.NewItems != null)
        {
            // set columns sort directions
            foreach (SortDescription descr in e.NewItems)
                SetSortDirection(descr.PropertyName, descr.Direction);
        }

        if (e.OldItems != null)
        {
            // reset columns sort directions
            foreach (SortDescription descr in e.OldItems)
                SetSortDirection(descr.PropertyName, null);
        }
    }

    private void SetSortDirection(string sortMemberPath, ListSortDirection? direction)
    {
        var column = AssociatedObject.Columns.FirstOrDefault(c => c.SortMemberPath == sortMemberPath);
        if (column != null)
        {
            column.SortDirection = direction;
        }
    }
}

对于那些不了解行为的人 - 您需要添加对System.Windows.Interactivity程序集的引用并将行为应用于DataGrid:

<DataGrid ItemsSource="{Binding Data}">
    <i:Interaction.Behaviors>
        <local:DataGridSortDescriptionsSyncBehavior />
    </i:Interaction.Behaviors>
</DataGrid>

现在,当您修改集合时,&#34;排序标记&#34;自动调整。此外,请注意,此行为仅适用于默认集合视图。如果您正在使用显式创建的集合视图 - 只需将其发送到行为(例如,通过行为&#39; s属性)并使用它而不是默认集合视图。

答案 1 :(得分:0)

对于您的通用解决方案,我有两个提案。

首先:

您可以创建新的DataGrid类并自动检查SortDescriptions。

 class ExDataGrid : DataGrid
    {
        bool isFirstRow = true;

        protected override void OnLoadingRow(DataGridRowEventArgs e)
        {
            base.OnLoadingRow(e);
            if (isFirstRow)
                SortDirectionHelper(this);
        }

        private void SortDirectionHelper(DataGrid dg)
        {
            var tmp = dg.Items.SortDescriptions;

            foreach (SortDescription sd in tmp)
            {
                var col = dg.Columns.Where(x => (((Binding)x.ClipboardContentBinding).Path.Path == sd.PropertyName)).FirstOrDefault();
                if (col != null)
                {
                    col.SortDirection = sd.Direction;
                }
            }

            isFirstRow = false;
        }
    }

Xaml文件:

<Window x:Class="DataGridSortTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase" 
        Title="MainWindow" Height="350" Width="525"
        xmlns:dg="clr-namespace:DataGridSortTest"
        >
    <Window.Resources>
        <CollectionViewSource x:Key="items" Source="{Binding Files}" >
            <CollectionViewSource.SortDescriptions>
                <cm:SortDescription PropertyName="Length"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <Grid>      
        <dg:ExDataGrid x:Name="grid" ItemsSource="{Binding Source={StaticResource items}}" />
    </Grid>
</Window>

<强>第二

您可以在每个网格中为Loaded事件创建EventHandler

 private void grid_Loaded(object sender, RoutedEventArgs e)
        {
            SortDirectionHelper(sender as DataGrid);
        }

        public void SortDirectionHelper(DataGrid dg)
        {
            var tmp = dg.Items.SortDescriptions;

            foreach (SortDescription sd in tmp)
            {
                var col = dg.Columns.Where(x => (((Binding)x.ClipboardContentBinding).Path.Path == sd.PropertyName)).FirstOrDefault();
                if (col != null)
                {
                    col.SortDirection = sd.Direction;
                }
            }
        }

答案 2 :(得分:0)

来自msdn论坛

  

您需要在DataGrid上显式指定SortDirection属性   用于使标记显示在列标题中的列,如   标记功能是DataGrid不绑定源。

所以也许你最好使用@kmatyaszek解决方案