我有一个非常基本的DataGrid
包含一些测试数据。数据以ObservableCollection<T>
Client
的{{1}}提供,其中包含objects
,Organization
和FirstName
属性。我按LastName
对项目进行分组,并希望能够按特定群组中的Organization
和FirstName
进行排序(此部分正常运行),并按{{1}对群组进行排序}。最后一部分是我遇到问题的部分。
如果我没有指定任何排序属性,或者我在LastName
中指定了一个属性(见下文),例如Organization
或CollectionViewSource.SortDescriptions
,{{1除外它会让我做一个初步的排序。如果您查看下面的图像,公司名称将不按顺序显示,因为这是集合的初始化方式。如果我点击PropertyName="Name"
标题,它会按升序对其进行排序,但不会让我在此之后再进行排序。如果我再次单击标题,它将更改箭头,这表示排序方向,但不会发生实际排序。无论我指定什么排序属性,这都是相同的...即使是完全任意的属性,除非它PropertyName="CompleteNonsense"
,或者没有指定属性。
如果我在PropertyName="Organization"
上指定排序,它将按升序开始排序,但如果单击标题则不会排序。因此,似乎该属性名称确实触发排序,但仅限于第一次。
截图:
这里是Organization
的{{1}}:
PropertyName="Organization"
这里是PropertyName="Organization"
和XAML
的{{1}}:
DataGrid
有没有人知道如何在<DataGrid ItemsSource="{Binding Source={StaticResource GroupedData}}"
AutoGenerateColumns="False" IsReadOnly="True"
GridLinesVisibility="None" HeadersVisibility="Column"
CanUserAddRows="False" CanUserDeleteRows="False"
CanUserResizeRows="False" Background="White">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Margin" Value="10,0,0,0"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel Background="LightBlue" DataContext="{Binding Items}">
<TextBlock Text="{Binding Path=Organization}"
Foreground="Blue" Margin="5,0,0,0" Width="100"/>
<TextBlock Text="Employee Count:" Foreground="Blue" Margin="40,0,0,0"/>
<TextBlock Text="{Binding Path=Count}" Foreground="Blue"
Margin="5,0,0,0"/>
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Organization" Binding="{Binding Organization}"/>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
<DataGridTextColumn Width="*"/>
</DataGrid.Columns>
</DataGrid>
超出初始排序后对组进行排序?
修改
我一直在搞乱这个问题(真的需要弄明白这一点)并为标题创建了一个快速的代码隐藏事件处理程序。 XAML
事件:
Grouping
Sorting
每次点击<CollectionViewSource Source="{Binding Data}" x:Key="GroupedData">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Organization"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Organization"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
后,弹出Organization
,向下排序箭头点,点击Click
后,它会立即恢复向上指向。组的实际排序永远不会在视觉上发生。有些东西让它卡在<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="ColumnHeader_Click"/>
</Style>
</DataGrid.ColumnHeaderStyle>
订单中。
答案 0 :(得分:4)
注意:有关最新代码,请参阅修改。
这有点棘手,但我能够找到答案。下面的代码适用于Sorting
事件的代码隐藏处理程序,但可以轻松调整以放置在ViewModel
或View
中(取决于您的操作方式)。< / p>
<强>代码:强>
<DataGrid Sorting="DataGrid_Sorting" ... > ... </DataGrid>
private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
var headerName = "Organization";
var column = e.Column;
if (!column.Header.ToString().Equals(headerName))
{
return;
}
var source = (sender as System.Windows.Controls.DataGrid).ItemsSource as ListCollectionView;
if (source == null)
{
return;
}
e.Handled = true;
var sortDirection = column.SortDirection == ListSortDirection.Ascending ?
ListSortDirection.Descending : ListSortDirection.Ascending;
using (source.DeferRefresh())
{
source.SortDescriptions.Clear();
source.SortDescriptions.Add(new SortDescription(headerName, sortDirection));
}
source.Refresh();
column.SortDirection = sortDirection;
}
使用上面的代码,群组本身按Organization
排序,每个群组中的项目按FirstName
和LastName
排序。希望这段代码可以帮助别人。我一整天都在搜索,这似乎是人们在DataGrid
处理群组时遇到的常见问题。
唯一的缺点是当组项目按分组属性以外的任何其他方式排序时,它会将组的顺序重置为默认值。在尝试了很多代码后,我无法找到解决方案。如果有人找到该部分的解决方案,我很乐意给他们“正确答案”。
帮助我的一些资源:
How to force DataGrid group order in WPF?
WPF Datagrid group and sort
修改强>
找出关于通过组内排序重置的组间排序的最后部分。这有点乱,因为我没有时间来清理它,但我想我会分享我的代码:
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Organization"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Organization" Direction="Ascending"/>
<scm:SortDescription PropertyName="FirstName" Direction="Ascending"/>
<scm:SortDescription PropertyName="LastName" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
SortGroupedDataGrid("Organization", sender, e);
}
private void SortGroupedDataGrid(string groupHeader, object sender, DataGridSortingEventArgs e)
{
// Get the main ListCollectionView and make sure it's not null.
var source = (sender as System.Windows.Controls.DataGrid).ItemsSource as ListCollectionView;
if (source == null)
{
return;
}
// Mark event as handled, so that automated sorting would not take place.
e.Handled = true;
// Main header which was used for the grouping. I'm only using one, but more can be added.
var headerName = groupHeader;
// Get the column that was being sorted on.
var column = e.Column;
// Check if the column was the same as the one being used for the grouping.
// I remove spaces so that any properties I use match the headers. Regex would probably
// work just as well, but it's an overkill for me at this time.
var isMainHeader = column.Header.ToString().Replace(" ", "").Equals(headerName);
// Because I set the initial sorting for all the properties in the XAML to be
// be sorted in Ascending order, I set these ones to Descending. One is for
// the main column and the other is for the secondary column. This does not account
// for a case where user Shift + Clicks multiple columns to chain sort.
var mainSortDirection = ListSortDirection.Descending;
var secondarySortDirection = ListSortDirection.Descending;
// If this is a main column sort event...
if (isMainHeader)
{
// Check its sorting direction and set it as opposite.
mainSortDirection = column.SortDirection == ListSortDirection.Descending ?
ListSortDirection.Ascending : mainSortDirection;
}
else
{
// ...else, get the sorting direction of the main column, because we want
// it to stay the same, and get the opposite sorting direction for the
// secondary column.
mainSortDirection = source.SortDescriptions[0].Direction;
secondarySortDirection = column.SortDirection == ListSortDirection.Descending ?
ListSortDirection.Ascending : secondarySortDirection;
}
// Defer refreshing of the DataGrid.
using (source.DeferRefresh())
{
// Clear any existing sorts. I've had some issues trying to alter existing ones.
source.SortDescriptions.Clear();
// Since we want main column to either alter if its sort event was called, or
// stay the same if secondary column event was called, we always set it first.
source.SortDescriptions.Add(new SortDescription(headerName, mainSortDirection));
// If this was not a main column event...
if (!isMainHeader)
{
// ...then set sorting for that other column. Since it'll be at index 1,
// after the main one, it'll only sort within each group, as I wanted.
source.SortDescriptions.Add(new SortDescription(column.Header.ToString().Replace(" ", ""), secondarySortDirection));
// Set the header direction as well.
column.SortDirection = secondarySortDirection;
}
else
{
// Otherwise, it's a main event and we want to show the error for its header.
// If you want primary sorting direction to always display, then simply take
// it outside of else scope, so that it's always assigned.
column.SortDirection = mainSortDirection;
}
}
// Now we can refresh and post changes.
source.Refresh();
}