我需要使用自然排序(在资源管理器中)对DataGridView进行排序,以便数字和文本(在同一列中)自然排序,而不是按字母顺序排序(以便“位置3”位于“位置20”之前,等等)。我有一个DataGridView,我将DataView设置为DataSource。 DataView包含一个DataTable,它是使用数据库中的某些值创建的。列类型是字符串。我有一个IComparer,它做了它应该做的,但我无法弄清楚如何使用它,因为我无法找到如何进行排序。 DataGridView.SortCompare事件(完美)不起作用,因为它是数据绑定的。 DataView.Sort只接受具有列名和排序顺序的字符串。
非常讨厌。试图在StackOverflow上阅读相关问题,并搜索谷歌的很多和很多,但我真的找不到这个。只有我真正找到的东西是使用数据视图的Sort(字符串)方法,因为它按字母顺序排序,因此无法正常工作。
有没有人知道怎么做而没有太多麻烦?它应该是别人而不是我这个?我真的不想重新实现整个datagridview或dataview类,只是为了获得自定义排序......
更新:如果有人想知道,我仍然在寻找这个问题的好答案。虽然与此同时,我最终创建了自己的简单表类,然后手动将其提供给datagridview。覆盖SortCompare方法。有点烦人,但并不太难,因为我只需要显示值(没有编辑或任何东西),因此可以将所有内容转换为字符串。
答案 0 :(得分:5)
查看this MSDN page和this blog post。原则上,您需要在GridView上配置数据源的排序(无论是ObjectDataSource还是SqlDataSource)。
据我所知,DataView类除了简单的升序/降序排序外不支持任何其他内容。如果没有看到加载和绑定数据的代码,很难提出具体的建议,但你可以:
答案 1 :(得分:2)
此代码应该有效。它类似于ListView的ListViewItemSorter。使用IComparer。
使用:
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
MyDataGridHelper.DataGridSort(dgv, e.ColumnIndex);
}
MyDataGridHelper.cs:
public class MyDataGridHelper
{
public static void DataGridSort(DataGridView dgv, int column)
{
DataGridViewCustomSorter dgvSorter = null;
if (dgv.Tag == null || !(dgv.Tag is IComparer))
{
dgvSorter = new DataGridViewCustomSorter(dgv);
dgv.Tag = dgvSorter;
}
else
{
dgvSorter = (DataGridViewCustomSorter)dgv.Tag;
}
dgvSorter.SortColumn = column;
dgv.Sort(dgvSorter);
}
private class DataGridViewCustomSorter : IComparer
{
private int ColumnIndex;
private SortOrder OrderOfSort;
private DataGridView myDataGridView;
private TypeCode mySortTypeCode;
public DataGridViewCustomSorter(DataGridView dgv)
{
myDataGridView = dgv;
mySortTypeCode = Type.GetTypeCode(Type.GetType("System.String"));
ColumnIndex = 0;
OrderOfSort = SortOrder.None;
}
public int Compare(object x, object y)
{
int result;
DataGridViewRow dgvX, dgvY;
dgvX = (DataGridViewRow)x;
dgvY = (DataGridViewRow)y;
string sx = dgvX.Cells[ColumnIndex].Value.ToString();
string sy = dgvY.Cells[ColumnIndex].Value.ToString();
//null handling
if (sx == String.Empty && sy == String.Empty)
result = 0;
else if (sx == String.Empty && sy != String.Empty)
result = -1;
else if (sx != String.Empty && sy == String.Empty)
result = 1;
else
{
switch (mySortTypeCode)
{
case TypeCode.Decimal:
Decimal nx = Convert.ToDecimal(sx);
Decimal ny = Convert.ToDecimal(sy);
result = nx.CompareTo(ny);
break;
case TypeCode.DateTime:
DateTime dx = Convert.ToDateTime(sx);
DateTime dy = Convert.ToDateTime(sy);
result = dx.CompareTo(dy);
break;
case TypeCode.String:
result = (new CaseInsensitiveComparer()).Compare(sx, sy);
break;
default:
result = (new CaseInsensitiveComparer()).Compare(sx, sy);
break;
}
}
if (OrderOfSort == SortOrder.Descending)
result = (-result);
return result;
}
public int SortColumn
{
set
{
if (ColumnIndex == value)
{
OrderOfSort = (OrderOfSort == SortOrder.Descending ? SortOrder.Ascending : SortOrder.Descending);
}
ColumnIndex = value;
try
{
mySortTypeCode = Type.GetTypeCode(Type.GetType((myDataGridView.Columns[ColumnIndex]).Tag.ToString()));
}
catch
{
mySortTypeCode = TypeCode.String;
}
}
get { return ColumnIndex; }
}
public SortOrder Order
{
set { OrderOfSort = value; }
get { return OrderOfSort; }
}
} //end class DataGridViewCustomSorter
} //end class MyDataGridHelper
答案 2 :(得分:0)
您可以创建2个隐藏列。将文本部分分配给第一个隐藏列,将数字部分分配给第二个隐藏列。现在按这些隐藏列排序(第一列的alpha排序和第二列的数字排序)。
通过这种方式,您可以保留原始列以用于显示目的&有2个隐藏的列用于排序。
答案 3 :(得分:0)
这里有一些解决方案“使用SortCompare事件自定义排序 “和”使用IComparer接口自定义排序“:
答案 4 :(得分:0)
您可以将排序逻辑移动到数据库查询中,并让它返回一个具有正确排序顺序的附加列。
然后(沿着@True C Sharp的回答)你可以有一个包含这个值的隐藏列,并按此而不是显示列进行排序。
这假定用于确定排序顺序的逻辑可以在SQL中执行。如果用于确定排序顺序的算法很复杂,则这可能不起作用。