我正在使用 Windows窗体DataGridView 来显示MyObject
个对象的通用列表。
首先,我将此集合包装到BindingSource
集合中,然后:
dataGridView.DataSource = myBindingSource;
我想要做的是允许用户通过单击表示MyObject中具体属性的列标题对列进行排序。
我读过一些文章,我应该在绑定之前进行排序。但是,如果我想实时对列进行排序,并且在已经绑定的情况下进行排序,它对我没有帮助。
问题是,我到底需要做什么,所以我可以在DataGridView中看到排序箭头,我可以对每列进行排序?
答案 0 :(得分:30)
完整的代码,用于对datagridview列进行排序,其数据源是通用List
//-----------------------------------------------------------------------------------------
//In the form - In constructor or form load, populate the grid.
//--------------------------------------------------------------------------------------------
List<student> students;
private void PopulateList()
{
student std1 = new student("sss", 15, "Female");
student std2 = new student("ddd", 12, "Male");
student std3 = new student("zzz", 16, "Male");
student std4 = new student("qqq", 14, "Female");
student std5 = new student("aaa", 11, "Male");
student std6 = new student("lll", 13, "Female");
students = new List<student>();
students.Add(std1);
students.Add(std2);
students.Add(std3);
students.Add(std4);
students.Add(std5);
students.Add(std6);
dataGridView1.DataSource = students;
}
//---------------------------------------------------------------------------------------------
//Comparer class to perform sorting based on column name and sort order
//---------------------------------------------------------------------------------------------
class StudentComparer : IComparer<Student>
{
string memberName = string.Empty; // specifies the member name to be sorted
SortOrder sortOrder = SortOrder.None; // Specifies the SortOrder.
/// <summary>
/// constructor to set the sort column and sort order.
/// </summary>
/// <param name="strMemberName"></param>
/// <param name="sortingOrder"></param>
public StudentComparer(string strMemberName, SortOrder sortingOrder)
{
memberName = strMemberName;
sortOrder = sortingOrder;
}
/// <summary>
/// Compares two Students based on member name and sort order
/// and return the result.
/// </summary>
/// <param name="Student1"></param>
/// <param name="Student2"></param>
/// <returns></returns>
public int Compare(Student Student1, Student Student2)
{
int returnValue = 1;
switch (memberName)
{
case "Name" :
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Name.CompareTo(Student2.Name);
}
else
{
returnValue = Student2.Name.CompareTo(Student1.Name);
}
break;
case "Sex":
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Sex.CompareTo(Student2.Sex);
}
else
{
returnValue = Student2.Sex.CompareTo(Student1.Sex);
}
break;
default:
if (sortOrder == SortOrder.Ascending)
{
returnValue = Student1.Name.CompareTo(Student2.Name);
}
else
{
returnValue = Student2.Name.CompareTo(Student1.StudentId);
}
break;
}
return returnValue;
}
}
//---------------------------------------------------------------------------------------------
// Performing sort on click on Column Header
//---------------------------------------------------------------------------------------------
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
//get the current column details
string strColumnName = dataGridView1.Columns[e.ColumnIndex].Name;
SortOrder strSortOrder = getSortOrder(e.ColumnIndex);
students.Sort(new StudentComparer(strColumnName, strSortOrder));
dataGridView1.DataSource = null;
dataGridView1.DataSource = students;
customizeDataGridView();
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder;
}
/// <summary>
/// Get the current sort order of the column and return it
/// set the new SortOrder to the columns.
/// </summary>
/// <param name="columnIndex"></param>
/// <returns>SortOrder of the current column</returns>
private SortOrder getSortOrder(int columnIndex)
{
if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None ||
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending)
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
return SortOrder.Ascending;
}
else
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending;
return SortOrder.Descending;
}
}
答案 1 :(得分:9)
我发现很难相信网格不提供开箱即用的基本排序,不需要代码。毕竟,必须处理标题点击事件并调用DataGridView.Sort指示列(由点击的内容,由网格跟踪确定)和排序方向(由当前排序状态确定,由网格跟踪)是非常愚蠢的)。
为什么没有简单的SortMode或AllowUserToSort属性默认执行完全相同的操作?
我已将网格绑定到List,并且我将列映射到的属性都是基本类型,如string,int,DateTime等。所有这些都是IC Comparable。那么为什么我还需要写一行代码呢?特别是考虑到文档的内容如下:
默认情况下,用户可以对数据进行排序 单击一个DataGridView控件 文本框列的标题。
这是Framework 3.0文档,我的目标是3.5,但“其他版本”都是指Visual Studio的版本,而不是Framework的版本。微软究竟发生了什么?!?
答案 2 :(得分:5)
本文中的一个很好的解决方案“呈现SortableBindingList”: http://www.timvw.be/2007/02/22/presenting-the-sortablebindinglistt/
答案 3 :(得分:2)
这是一个使用Reflection和Linq按列排序的更简单的解决方案。 dataGridView1的DataSource设置为compareList,声明为:
private List<CompareInfo> compareList;
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
string strColumnName = dataGridView1.Columns[e.ColumnIndex].Name;
SortOrder strSortOrder = getSortOrder(e.ColumnIndex);
if (strSortOrder == SortOrder.Ascending)
{
compareList = compareList.OrderBy(x => typeof(CompareInfo).GetProperty(strColumnName).GetValue(x, null)).ToList();
}
else
{
compareList = compareList.OrderByDescending(x => typeof(CompareInfo).GetProperty(strColumnName).GetValue(x, null)).ToList();
}
dataGridView1.DataSource = compareList;
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder;
}
private SortOrder getSortOrder(int columnIndex)
{
if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None ||
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending)
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
return SortOrder.Ascending;
}
else
{
dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending;
return SortOrder.Descending;
}
}
public class CompareInfo
{
public string FileName { get; set; }
public string UAT_Folder { get; set; }
public string UAT_Path
{
get { return UAT_Folder + FileName; }
}
public string PROD_Folder { get; set; }
public string PROD_Path
{
get { return PROD_Folder + FileName; }
}
}
答案 4 :(得分:1)
我的解决方案是:
我自己使用myBindingSource,我进行排序,分组..无论是在一个单独的线程中。 然后我只需将结果绑定到DataGridView 。
myDataGridView.DataSource = bindingSource;
为此,我设置了要排序的所有列'Programatically'
(在设计器中)
然后我手动添加箭头(ASCENDING / DESCENDING)
通过设置
cell.SortGlyphDirection = ... ;
代码背后。
答案 5 :(得分:0)
看这个artice
http://msdn.microsoft.com/en-us/library/0868ft3z.aspx
通过阅读它我看到了这个“此方法通过比较指定列中的值来对DataGridView的内容进行排序。默认情况下,排序操作将使用Compare方法使用DataGridViewCell比较列中的单元格对。 ::。Value property。“
最诚挚的问候, 约尔丹
答案 6 :(得分:0)
您可能还想看看这篇文章,您可以获得两个有趣的链接来实现自定义的SortableBindingList:
Sort Datagridview columns when datasource binded to List(Of T)
答案 7 :(得分:0)
当绑定到List时,使用DataGridView解决排序问题的另一个选项是,如果您没有处理大量数据集,那么可能您可以尝试将List转换为DataTable,然后将生成的DataTable绑定到BindingSource / DataGridView 。
这需要IComparer的自定义实现。在我的情况下,我正在处理一个较小的列表,但还有更多的字段要显示。因此实施IComparer意味着编写太多锅炉板代码。
选中此项以便将List转换为DataTable的简洁方法:https://stackoverflow.com/a/34062898/4534493
答案 8 :(得分:0)
如果最好创建自己的用户控件,则可以使用以下代码创建自定义排序方法:
private string _lastSortColumn;
private ListSortDirection _lastSortDirection;
public void Sort(DataGridViewColumn column)
{
// Flip sort direction, if the column chosen was the same as last time
if (column.Name == _lastSortColumn)
_lastSortDirection = 1 - _lastSortDirection;
// Otherwise, reset the sort direction to its default, ascending
else
{
_lastSortColumn = column.Name;
_lastSortDirection = ListSortDirection.Ascending;
}
// Prep data for sorting
var data = (IEnumerable<dynamic>)DataSource;
var orderProperty = column.DataPropertyName;
// Sort data
if (_lastSortDirection == ListSortDirection.Ascending)
DataSource = data.OrderBy(x => x.GetType().GetProperty(orderProperty).GetValue(x, null)).ToList();
else
DataSource = data.OrderByDescending(x => x.GetType().GetProperty(orderProperty).GetValue(x, null)).ToList();
// Set direction of the glyph
Columns[column.Index].HeaderCell.SortGlyphDirection
= _lastSortDirection == ListSortDirection.Ascending
? SortOrder.Ascending : SortOrder.Descending;
}
然后您可以覆盖标题click方法来调用您的排序函数:
protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)
{
base.OnColumnHeaderMouseClick(e);
var column = Columns[e.ColumnIndex];
if (column.SortMode == DataGridViewColumnSortMode.Automatic
|| column.SortMode == DataGridViewColumnSortMode.NotSortable)
Sort(column);
}
答案 9 :(得分:0)
首先我使用了 System.Reflection; 然后:写这个方法
public DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public |
BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
然后调用方法: DataTable dt = ToDataTable(lst.ToList());