如何按显示的,转换后的值,而不是绑定的源属性值对WPF DataGridTextColumn进行排序?现在它在行视图模型中按整数值排序,而不是由Converter返回的显示文本。我使用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的意义不大。
答案 0 :(得分:4)
听起来你想要查看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"};
这会自动生成:
不幸的是,此方法仅适用于viewmodel值,如果您使用转换器,则您希望将这些值公开为viewmodel属性,然后将它们提供给SortDescriptions。据我所知,即使在用户排序模式下,DataGrid也不支持这种情况。
如果您想讨论这个问题,请随时放入我们的#wpf room并抓住任何房主,如果我不能帮助他们,他们将能够提供帮助已经。
答案 1 :(得分:4)
不幸的是,这不是一项微不足道的任务。正如@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
中执行此操作。
答案 2 :(得分:0)
超级简单的工作解决方案:
示例:
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...