Wpf 如何按显示的、转换的值而不是绑定的源属性值对DataGridTextColumn进行排序?
如何按显示的、转换的值、未绑定的源属性值对WPF DataGridTextColumn进行排序?现在它是按行viewmodel中的整数值排序的,而不是由转换器返回的显示文本。我使用MVVM 下面是一个请求示例。然而,这是一个普遍的问题。我可以将MmsClass.Name放入表示行的类中。但我需要在任何地方进行适当的分类,而不仅仅是在这里 一行的类:Wpf 如何按显示的、转换的值而不是绑定的源属性值对DataGridTextColumn进行排序?,wpf,mvvm,data-binding,datagrid,wpfdatagrid,Wpf,Mvvm,Data Binding,Datagrid,Wpfdatagrid,如何按显示的、转换的值、未绑定的源属性值对WPF DataGridTextColumn进行排序?现在它是按行viewmodel中的整数值排序的,而不是由转换器返回的显示文本。我使用MVVM 下面是一个请求示例。然而,这是一个普遍的问题。我可以将MmsClass.Name放入表示行的类中。但我需要在任何地方进行适当的分类,而不仅仅是在这里 一行的类: public class MaintenanceDataItem { public MaintenanceDataItem(int clas
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
}
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来说,使用转换器就没有多大意义。听起来您可能想查看CollectionViewSource.SortDescriptions 下面是一个可能的示例: XAML
其中MainWindowViewModel.Fruits简单定义为:public静态字符串[]Fruits{get;}={“苹果”、“香蕉”、“葡萄”、“橙子”、“猕猴桃”}代码>
结果
这将自动生成:
不幸的是,这种方法只适用于viewmodel值,如果您使用的是转换器,您反而希望将这些值公开为viewmodel属性,然后将它们提供给SortDescriptions。据我所知,DataGrid即使在用户排序模式下也不支持这种情况
如果您想讨论这个问题,请随时来我们的房间找任何一位房主,如果我不在那里,他们将能够提供帮助。不幸的是,这不是一项微不足道的任务。正如@Maverik正确指出的那样,DataGrid
对底层数据进行排序,而不是对转换器输出的数据进行排序。为此,您需要自己进行排序。首先创建一个类,该类具有一个属性以使用自定义排序器,另一个属性定义要在给定列上使用的排序器:
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));
icCustomSorter
是一个非常简单的界面:
public interface ICustomSorter : IComparer
{
ListSortDirection SortDirection { get; set; }
string SortMemberPath { get; set; }
}
现在需要从“AllowCustomSort”实现自定义排序:
这只是连接排序
事件,然后通过调用提供的iccustomsorter
对集合进行排序来处理它
在XAML中,您可以创建一个已实现的icCustomSorter
的实例,并使用以下附加属性:
<DataGridTextColumn Header="Column1" Binding="{Binding Column1, Converter={StaticResource Column1Converter}}" IsReadOnly="True"
util:CustomSortBehavior.CustomSorter="{StaticResource Column1Comparer}"/>
这很痛苦,您必须对所有转换的值进行自定义排序,但它确实允许您在DataGrid
超级简单的工作解决方案中执行此操作:
侦听DataGrid的排序事件
激发事件时,请验证列
按你喜欢的方式对列表排序
将已排序的新集合放回DataGrid的ItemsSource
已处理标记事件,因此不会应用基本排序
例如:
cs
//
///捕获DataGrid的排序事件和
///按员工而不是按计划顺序对所有行进行排序
///
私有void MainDataGrid_排序(对象发送方、DataGridSortingEventArgs e)
{
if(e.Column.Header是字符串Header&&Header.Equals(Properties.Resources.EmployeeName))
{
//AllRows是绑定到我的DataGrid的ItemsSource的属性
AllRows=programaItems.ToList().OrderBy(item=>item.SelectedWorkOrder.WorkOrderResource.EmployeeName),然后By(item=>item.SelectedWorkOrder.WorkOrderResource.PlanitSetupOrder);
//已处理的标志事件
e、 已处理=正确;
}
}
xaml
分享一些代码以更好地理解您的问题…感谢您的关注。我的问题是一般性的。这就是为什么我省略了代码。尽管如此,我还是添加了一段代码。您是否尝试将SortMemberPath
设置为列的Text
属性?我不确定是否可以设置像
这样的绑定。也许你需要设置一个RelativeSource(只是随便玩一下)。DataGridTextColumn没有文本。必须以其他方式找到它。查找文本块和文本的孩子。我尝试了这个,但没有成功:谢谢你的回答,但我不明白这些和我的问题有什么关系。这将使用属性,而不是转换的显示值,对吗?这还将在打开窗口时设置长度的升序排序。我只是想定义排序的工作方式(按显示值),而不是设置排序。重点是向您显示CollectionViewSource+SortDescriptions。并不是说你们像我在示例中展示的那个样硬编码。Re:你关于转换价值的问题,我已经回答了。简而言之,这是不可能的。我们的WPF会议室中提到了另一种方法。你很快就会看到另一个答案。如果没有,你可能想到我们的房间来推布拉德利(或者只是读一下我和他之间的文字记录)。。。至于为什么在SetMemberPath上使用SortDescriptions:我个人使用collectionviewsource作为一站式控件进行分组和排序,而不管显示控件是否支持SortMemberPath(您可能知道,它们通常不支持)。另外,SortDescriptions允许我执行我不知道您可以使用SortMemberPath执行的多重排序。@matti My viewmodel不需要知道显示的值。我不同意,因为模型包含我们的抽象,viewmodel需要实现它们并跟踪状态。而视图应尽可能保持沉默,仅表示viewmodel状态。这就是为什么可以从视图中进行排序,它只是表示。但是用于排序的值应该来自viewmodel。至于XAML转换器,我认为它们是boolToVis的意思,而不是从字典中获取数据
public interface ICustomSorter : IComparer
{
ListSortDirection SortDirection { get; set; }
string SortMemberPath { get; set; }
}
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;
}
}
}
}
<DataGridTextColumn Header="Column1" Binding="{Binding Column1, Converter={StaticResource Column1Converter}}" IsReadOnly="True"
util:CustomSortBehavior.CustomSorter="{StaticResource Column1Comparer}"/>
/// <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;
}
}
<DataGrid ... Sorting="MainDataGrid_Sorting">
<DataGrid.Columns...