修复 DataGrid 中的第一行
Fix the first row in a DataGrid
我试图让 DataGrid 中的一行始终位于顶部,同时仍然能够按列(整数和字符串列)对所有其他行进行排序。
我的数据结构提供了一点帮助:第一列命名为 "Id",而我试图保持在顶部的行始终具有所有 ID 中最低的 ID。此行包含聚合值。
典型的 DataGrid 可能如下所示:
ID | Name | Result1 | Result2
5 | avg | 2 | 5
6 | opt1 | 1 | 3
7 | opt2 | 3 | 7
可能有n列,列数会在运行时发生变化。 DataGrid 绑定到 ListCollectionView,我还实现了一个基于 trilson86's answer:
的自定义排序器
<DataGrid result:CustomSortBehaviour.AllowCustomSort="True"
IsReadOnly="True"
ItemsSource="{Binding ResultDataView}">
</DataGrid>
到目前为止,使用 trilson86 的 soution,我设法在排序时将第一行保持在最前面。这是我的 CustomSortBehavior-class 中的处理程序,它为自定义排序器准备有用的数据块(例如当前 DataGrid 中的最小 ID):
private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null || !GetAllowCustomSort(dataGrid)) return;
var listColView = dataGrid.ItemsSource as ListCollectionView;
var min = listColView.Cast<DataRowView>().Min(x => x.Row[0]);
var sorter = new MyComparer();
e.Handled = true;
var direction = (e.Column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
e.Column.SortDirection = sorter.SortDirection = direction;
sorter.IdOfFirstRow = Convert.ToInt32(min);
listColView.CustomSort = sorter;
}
自定义排序器本身:
public int Compare(object x, object y)
{
var rowView1 = x as DataRowView;
var rowView2 = y as DataRowView;
var row1 = rowView1.Row;
var row2 = rowView2.Row;
var row1Id = Convert.ToInt32(row1[0]);
var row2Id = Convert.ToInt32(row2[0]);
if (row1IdValue == IdOfFirstRow)
return -1;
if (row2IdValue == IdOfFirstRow)
return 1;
if (SortDirection == ListSortDirection.Ascending) {
return row2Id.CompareTo(row1Id);
}
else
{
return row1Id.CompareTo(row2Id);
}
}
这只是解决方案的一半.. 原样硬编码,我只能按 Id 排序。因为列将在运行时添加,所以我无法在设计时定义所有列并根据列值类型(int 或 string)附加排序器。
如何按所有其他列排序,同时保持具有最小 ID 的行位于顶部的限制?
为什么不使用 DisplayIndex 属性 来获取您正在排序的列。
private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid == null || !GetAllowCustomSort(dataGrid)) return;
ListSortDirection direction = (e.Column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
ListCollectionView lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(dataGrid.ItemSource);
int min = lcv.Cast<DataRowView>().Min(x => x.Row[0]);
lcv.CustomSort = new CustomComparer(direction, e.Column.DisplayIndex, min); //DisplayIndex gets you your column
e.Handled = true;
}
然后此比较器应该执行您要查找的操作,而不是在对列中的整数和字符串进行排序时对最小 ID 行进行排序。
public class CustomComparer : IComparer
{
ListSortDirection _direction;
int colNum;
int _IdOfFirstRow;
public CustomComparer(ListSortDirection direction, int colNum, int IdOfFirstRow)
{
_direction = _direction;
_colNum = colNum;
_IdOfFirstRow = IdOfFirstRow;
}
public int Compare(object x, object y)
{
DataRowView rowView1 = x as DataRowView;
DataRowView rowView2 = y as DataRowView;
int valX, valY;
if (x == y)
return 0;
//Don't sort min Id
var row1Id = Convert.ToInt32(rowView1[0]);
var row2Id = Convert.ToInt32(rowView2[0]);
if (row1Id == _IdOfFirstRow)
return -1;
else if (row2Id == _IdOfFirstRow)
return 1;
string strX = rowView1[_colNum] as string;
string strY = rowView2[_colNum] as string;
bool ret1 = int.TryParse(strX, valX);
bool ret2 = int.TryParse(strY, valY);
if (ret1 == false && ret2 == false) //is a string
{
if (_direction == ListSortDirection.Ascending)
{
return strX.CompareTo(strY);
}
else
{
return strY.CompareTo(strX);
}
}
else
{
if (_direction == ListSortDirection.Ascending)
{
return valX.CompareTo(valY);
}
else
{
return valY.CompareTo(valX);
}
}
}
}
我试图让 DataGrid 中的一行始终位于顶部,同时仍然能够按列(整数和字符串列)对所有其他行进行排序。
我的数据结构提供了一点帮助:第一列命名为 "Id",而我试图保持在顶部的行始终具有所有 ID 中最低的 ID。此行包含聚合值。
典型的 DataGrid 可能如下所示:
ID | Name | Result1 | Result2
5 | avg | 2 | 5
6 | opt1 | 1 | 3
7 | opt2 | 3 | 7
可能有n列,列数会在运行时发生变化。 DataGrid 绑定到 ListCollectionView,我还实现了一个基于 trilson86's answer:
的自定义排序器 <DataGrid result:CustomSortBehaviour.AllowCustomSort="True"
IsReadOnly="True"
ItemsSource="{Binding ResultDataView}">
</DataGrid>
到目前为止,使用 trilson86 的 soution,我设法在排序时将第一行保持在最前面。这是我的 CustomSortBehavior-class 中的处理程序,它为自定义排序器准备有用的数据块(例如当前 DataGrid 中的最小 ID):
private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null || !GetAllowCustomSort(dataGrid)) return;
var listColView = dataGrid.ItemsSource as ListCollectionView;
var min = listColView.Cast<DataRowView>().Min(x => x.Row[0]);
var sorter = new MyComparer();
e.Handled = true;
var direction = (e.Column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
e.Column.SortDirection = sorter.SortDirection = direction;
sorter.IdOfFirstRow = Convert.ToInt32(min);
listColView.CustomSort = sorter;
}
自定义排序器本身:
public int Compare(object x, object y)
{
var rowView1 = x as DataRowView;
var rowView2 = y as DataRowView;
var row1 = rowView1.Row;
var row2 = rowView2.Row;
var row1Id = Convert.ToInt32(row1[0]);
var row2Id = Convert.ToInt32(row2[0]);
if (row1IdValue == IdOfFirstRow)
return -1;
if (row2IdValue == IdOfFirstRow)
return 1;
if (SortDirection == ListSortDirection.Ascending) {
return row2Id.CompareTo(row1Id);
}
else
{
return row1Id.CompareTo(row2Id);
}
}
这只是解决方案的一半.. 原样硬编码,我只能按 Id 排序。因为列将在运行时添加,所以我无法在设计时定义所有列并根据列值类型(int 或 string)附加排序器。
如何按所有其他列排序,同时保持具有最小 ID 的行位于顶部的限制?
为什么不使用 DisplayIndex 属性 来获取您正在排序的列。
private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid == null || !GetAllowCustomSort(dataGrid)) return;
ListSortDirection direction = (e.Column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
ListCollectionView lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(dataGrid.ItemSource);
int min = lcv.Cast<DataRowView>().Min(x => x.Row[0]);
lcv.CustomSort = new CustomComparer(direction, e.Column.DisplayIndex, min); //DisplayIndex gets you your column
e.Handled = true;
}
然后此比较器应该执行您要查找的操作,而不是在对列中的整数和字符串进行排序时对最小 ID 行进行排序。
public class CustomComparer : IComparer
{
ListSortDirection _direction;
int colNum;
int _IdOfFirstRow;
public CustomComparer(ListSortDirection direction, int colNum, int IdOfFirstRow)
{
_direction = _direction;
_colNum = colNum;
_IdOfFirstRow = IdOfFirstRow;
}
public int Compare(object x, object y)
{
DataRowView rowView1 = x as DataRowView;
DataRowView rowView2 = y as DataRowView;
int valX, valY;
if (x == y)
return 0;
//Don't sort min Id
var row1Id = Convert.ToInt32(rowView1[0]);
var row2Id = Convert.ToInt32(rowView2[0]);
if (row1Id == _IdOfFirstRow)
return -1;
else if (row2Id == _IdOfFirstRow)
return 1;
string strX = rowView1[_colNum] as string;
string strY = rowView2[_colNum] as string;
bool ret1 = int.TryParse(strX, valX);
bool ret2 = int.TryParse(strY, valY);
if (ret1 == false && ret2 == false) //is a string
{
if (_direction == ListSortDirection.Ascending)
{
return strX.CompareTo(strY);
}
else
{
return strY.CompareTo(strX);
}
}
else
{
if (_direction == ListSortDirection.Ascending)
{
return valX.CompareTo(valY);
}
else
{
return valY.CompareTo(valX);
}
}
}
}