如何按显示的、转换的值、未绑定的源属性值对 WPF DataGridTextColumn 进行排序?现在它按行视图模型中的整数值排序,而不是显示转换器返回的文本。我使用 MVVM。
这是根据要求提供的示例。然而,这是一般性问题。我可以将 MmsClass.Name 放在代表行的类中。但我需要在任何地方进行适当的排序,而不仅仅是这里。
连续班级:
public class MaintenanceDataItem
{
public MaintenanceDataItem(int classId, Type objectType, object value, IEnumerable<MmsData> rows)
{
ClassId = classId;
TypeOfObject = objectType;
Value = value;
ObjectIds = new List<int>();
MmsDataRows = rows;
}
public int ClassId { get; private set; }
// rest of the properrties omitted
}
转换器:
public class MmsClassToNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
MmsClass mmsClass;
if (MmsClasses.Instance.TryGetValue((int) value, out mmsClass))
{
return mmsClass.Name;
}
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
xaml 中的列:
<DataGridTextColumn Header="{StaticResource ResourceKey=MmsStrCondClass}"
Binding="{Binding ClassId,
Converter={StaticResource mmsclasstonameconverter}}"
Width="*">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="TextWrapping" Value="NoWrap" />
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
我真的以为默认排序会显示值。如果这个问题不容易解决,那么使用转换器对于 datagridcolumn 就没多大意义。
不幸的是,这不是一项微不足道的任务。正如 @Maverik 正确指出的那样,
DataGrid
对基础数据进行排序,而不是转换器吐出的内容。为此,您需要自己Sort
。首先创建一个类,其中一个属性用于使用自定义排序器,另一个用于定义要在给定列上使用的排序器:
public static ICustomSorter GetCustomSorter(DependencyObject obj)
{
return (ICustomSorter)obj.GetValue(CustomSorterProperty);
}
public static void SetCustomSorter(DependencyObject obj, ICustomSorter value)
{
obj.SetValue(CustomSorterProperty, value);
}
// Using a DependencyProperty as the backing store for CustomSorter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomSorterProperty =
DependencyProperty.RegisterAttached("CustomSorter", typeof(ICustomSorter), typeof(CustomSortBehavior), new PropertyMetadata(null));
public static bool GetAllowCustomSort(DependencyObject obj)
{
return (bool)obj.GetValue(AllowCustomSortProperty);
}
public static void SetAllowCustomSort(DependencyObject obj, bool value)
{
obj.SetValue(AllowCustomSortProperty, value);
}
// Using a DependencyProperty as the backing store for AllowCustomSort. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AllowCustomSortProperty =
DependencyProperty.RegisterAttached("AllowCustomSort", typeof(bool), typeof(CustomSortBehavior), new PropertyMetadata(false, AllowCustomSortChanged));
ICustomSorter
是一个非常简单的界面:
public interface ICustomSorter : IComparer
{
ListSortDirection SortDirection { get; set; }
string SortMemberPath { get; set; }
}
现在您需要从“AllowCustomSort”实现自定义排序:
private static void AllowCustomSortChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGrid control = d as DataGrid;
{
var oldAllow = (bool)e.OldValue;
var newAllow = (bool)e.NewValue;
if (!oldAllow && newAllow)
{
control.Sorting += HandleCustomSorting;
}
else
{
control.Sorting -= HandleCustomSorting;
}
}
}
private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
{
//Check if we should even be using custom sorting
DataGrid dataGrid = sender as DataGrid;
if (dataGrid != null && GetAllowCustomSort(dataGrid))
{
//Make sure we have a source we can sort
ListCollectionView itemsSource = dataGrid.ItemsSource as ListCollectionView;
if (itemsSource != null)
{
ICustomSorter columnSorter = GetCustomSorter(e.Column);
//Only do our own sort if a sorter was defined
if (columnSorter != null)
{
ListSortDirection nextSortDirection = e.Column.SortDirection == ListSortDirection.Ascending ?
ListSortDirection.Descending :
ListSortDirection.Ascending;
e.Column.SortDirection = columnSorter.SortDirection = nextSortDirection;
columnSorter.SortMemberPath = e.Column.SortMemberPath;
itemsSource.CustomSort = columnSorter;
//We've handled the sort, don't let the DataGrid mess with us
e.Handled = true;
}
}
}
}
这只是连接
Sorting
事件,然后通过调用提供的 ICustomSorter
对集合进行排序来处理它。
在 XAML 中,您创建一个已实现的
ICustomSorter
的实例并使用附加属性,如下所示:
<DataGridTextColumn Header="Column1" Binding="{Binding Column1, Converter={StaticResource Column1Converter}}" IsReadOnly="True"
util:CustomSortBehavior.CustomSorter="{StaticResource Column1Comparer}"/>
这很痛苦,您必须对所有转换后的值进行自定义排序,但它确实允许您在
DataGrid
中执行此操作。
听起来您想研究一下 CollectionViewSource.SortDescriptions。
这是一个示例:
<Window.Resources>
<CollectionViewSource x:Key="Fruits" Source="{Binding Source={x:Static local:MainWindowViewModel.Fruits}}">
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription Direction="Ascending" PropertyName="Length"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Source={StaticResource Fruits}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Fruit Name" Binding="{Binding}" />
<DataGridTextColumn Header="Name Length" Binding="{Binding Length}" />
</DataGrid.Columns>
</DataGrid>
其中 MainWindowViewModel.Fruits 简单定义为:
public static string[] Fruits { get; } = {"Apples", "Bananas", "Grapes", "Oranges", "Kiwis"};
这会自动生成:
不幸的是,此方法仅适用于视图模型值,如果您使用转换器,您可能希望将这些值公开为视图模型属性,然后将它们输入到 SortDescriptions 中。据我所知,即使在用户排序模式下,DataGrid 也不支持这种情况。
如果您想讨论这个问题,请随时来到我们的#wpf 房间,并联系任何房间主人,如果我不在的话,他们将能够提供帮助。
超级简单的工作解决方案:
示例:
CS
/// <summary>
/// catch DataGrid's sorting event and
/// sort AllRows by employee, than by planit order
/// </summary>
private void MainDataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
if (e.Column.Header is string header && header.Equals(Properties.Resources.EmployeeName))
{
// AllRows is a property binded to my DataGrid's ItemsSource
AllRows = programaItems.ToList().OrderBy(item => item.SelectedWorkOrder.WorkOrderResource.EmployeeName).ThenBy(item => item.SelectedWorkOrder.WorkOrderResource.PlanitSetupOrder);
// flag event handled
e.Handled = true;
}
}
xaml
<DataGrid ... Sorting="MainDataGrid_Sorting">
<DataGrid.Columns...