为wpf DataGridColumn启用排序,其中source是转换后的值

时间:2018-01-16 13:22:03

标签: wpf sorting datagrid converter

在我的wpf / c#项目中,我有3个维度的数据类型:长度,宽度和深度。当用户在datagrid中输入这些项时,使用转换器在第4列中计算此项的体积。我想要的是为此列启用排序。我试图将SortMemberPath放到Converter返回值,但这没有用。我认为这样做的一种方法是使用一个属性扩展我的数据类型,但如果可能的话,我想避免这种情况,只使用一些xaml / converter技术。

数据类型定义:

zsh

视图模型

public partial class packs
{        
    public packs()
    {
    }

    public int id { get; set; }

    public Nullable<decimal> length { get; set; }
    public Nullable<decimal> width { get; set; }
    public Nullable<decimal> depth { get; set; }      
}

查看

public PacksVM
{
    public ObservableCollection<packs> Packs{ get; set; }
    ...
}

和VolumeConverter

...
<DataGrid 
          x:Name="furniturePackagesGrid"                                                       
          ItemsSource="{Binding Path=Packs}"
          >
    <DataGrid.Columns>                                                 
        <DataGridTextColumn Header="Length" 
            Binding="{Binding length}"/>
        <DataGridTextColumn Header="Width" 
            Binding="{Binding width}" />
        <DataGridTextColumn Header="Depth" 
            Binding="{Binding depth}"/>
        <DataGridTextColumn Header="Volume (m3)"  
            Binding="{Binding Mode=OneWay, Converter={StaticResource PackVolumeConverter}}"
            IsReadOnly="True"
            CanUserSort="True"
<!--I show no code for PackVolumeSortConverter because it is never called-->
            SortMemberPath="{Binding Converter={StaticResource PackVolumeSortConverter}}"
             />                                                          
    </DataGrid.Columns>
</DataGrid>
...

1 个答案:

答案 0 :(得分:0)

就我在文档中看到的那样,SortMemberPath在你的意义上是不可绑定的,但是应该包含一个字符串,其中包含要排序的属性的路径。

如果您不想使用卷属性对packs class进行规范,我可以想出的唯一方法是为该类创建一个视图模型包装器:

  public class VMPacks
  {
    public VMPacks(packs p)
    {
      Packs = p;
    }

    public packs Packs { get; private set; }

    public decimal Volume
    {
      get
      {
        decimal volume = (Packs.length ?? default(decimal)) *
                 (Packs.width ?? default(decimal)) *
                 (Packs.depth ?? default(decimal)) / 1000000000;

        return volume;
      }
    }

  }

然后相应地调整列绑定,或者选择适当的属性和可能的​​实现INotifyPropertyChanged等。

修改

实际上可以通过以下方式进行自定义排序:

向DataGrid添加排序事件处理程序:

<DataGrid 
  x:Name="furniturePackagesGrid"
  AutoGenerateColumns="False"
  Sorting="furniturePackagesGrid_Sorting"
  >

将SortMemberPath设置为虚拟值,如:

    <DataGridTextColumn Header="Volume (m3)"                            
                        Binding="{Binding Mode=OneWay, Converter={StaticResource PackVolumeConverter}}"
                        IsReadOnly="True"      
                        SortMemberPath="depth"
                        CanUserSort="True" />

这只是为了避免绑定表达式错误。

最后实现Sorting事件处理程序,如下所示:

private void furniturePackagesGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
  if (e.Column.DisplayIndex == 3)
  {
    DataGrid grid = sender as DataGrid;

    List<packs> packs = grid.ItemsSource as List<packs>;

    Func<packs, decimal> volume = (p) =>
    {
      decimal v = (p.length ?? default(decimal)) *
        (p.width ?? default(decimal)) *
        (p.depth ?? default(decimal)) / 1000000000;
      return v;
    };

    packs.Sort((p1, p2) =>
    {
      if (p1 == p2)
        return 0;

      if (e.Column.SortDirection == ListSortDirection.Descending)
        return Decimal.Compare(volume(p2), volume(p1));
      return Decimal.Compare(volume(p1), volume(p2));
    });

    grid.ItemsSource = packs;
  }
}

它要求将DataGrid.ItemsSource填充为List:

  furniturePackagesGrid.ItemsSource = Enumerable.Range(0, 10000).Select(i => new packs
  {
    depth = 2 + i,
    id = i,
    length = 3 + i,
    width = 4 + i,
  }).ToList();