今天在开发工作中遇到了一个问题:
我的很多DataGridView,因为数据源(DataSource)使用的是数组,导致在点击每列列头的时候无法就指定列进行排序
因此我需要写一个将数组转换为DataTable的函数。
在网上查了一下,找到了这篇Blog,总结得比较全面:
不过这篇Blog中,从数组转换成DataTable的函数(函数ToDataTable<T>)有一个BUG,在创建每个数据行的时候,没有对list的元素进行判空操作。这样做在数组中有元素为空时,会导致TargetException,更有甚者如果把这段代码运用到Load函数的时候,有可能函数直接中断执行且不弹出任何异常。
下面是我改造之后的代码(需要引用System.Reflection):
public static class DataHelper{ public static DataTable GetDataTable(this IEnumerable list) { DataTable dtResult = new DataTable(); List propertiyInfos = new List (); //生成各列 Array.ForEach (typeof(T).GetProperties(), p => { propertiyInfos.Add(p); dtResult.Columns.Add(p.Name, p.PropertyType); }); //生成各行 foreach (var item in list) { if (item == null) { continue; } DataRow dataRow = dtResult.NewRow(); propertiyInfos.ForEach(p => dataRow[p.Name] = p.GetValue(item, null)); dtResult.Rows.Add(dataRow); } return dtResult; }}
我写了个例子,做了以下测试。
建立一个Windows窗体应用程序,工程名为Array2DataTable
建立一个类Hero,里面有五个属性:
public class Hero{ public Hero(int id, string name, int strength, int dexterity, int intelligence) { this.idField = id; this.nameField = name; this.strengthField = strength; this.dexterityField = dexterity; this.intelligenceField = intelligence; } private int idField; public int id { get { return idField; } set { idField = value; } } private string nameField; public string name { get { return nameField; } set { nameField = value; } } private int strengthField; public int strength { get { return strengthField; } set { strengthField = value; } } private int dexterityField; public int dexterity { get { return dexterityField; } set { dexterityField = value; } } private int intelligenceField; public int intelligence { get { return intelligenceField; } set { intelligenceField = value; } }}
在FormMain中的Load函数中加入下面代码:
private void FormMain_Load(object sender, EventArgs e){ Hero[] heros = new Hero[10]; heros[0] = new Hero(1, "秃驴", 59, 64, 78); heros[1] = new Hero(2, "独眼龙", 96, 99, 94); heros[2] = new Hero(3, "三脚猫", 50, 88, 73); heros[3] = new Hero(4, "绿帽王八", 79, 77, 61); heros[4] = new Hero(5, "四眼田鸡", 89, 93, 63); heros[5] = new Hero(6, "地头蛇", 71, 70, 58); heros[6] = new Hero(7, "单身狗", 95, 82, 89); heros[7] = new Hero(8, "替罪羊", 90, 81, 93); heros[8] = new Hero(9, "黄牛", 81, 52, 67); dgvArray.DataSource = heros; dgvDataTable.DataSource = DataHelper.GetDataTable(heros);}
程序运行后的效果如下,可以看到,以DataTable为数据源的DataGridView(dgvDataTable),已经可以点击列首进行排序了:
如果希望某几列可以排序,某几列不可以排序,可以手动将这些列的信息添加到DataGridView的列中,并配置好DataPropertyName,最后在“编辑列”中设置“SortMode”属性,该属性的值为System.Windows.Forms.DataGridViewColumnSortMode 类型枚举。这个枚举下有三个值,现将三者列在下面,其中的说明信息摘自VS中反射到的元数据:
1)DataGridViewColumnSortMode.NotSortable
-此列仅能以编程方式进行排序,但由于它原本并不打算排序,所以列标头将不包含排序标志符号的空间
2)DataGridViewColumnSortMode.Automatic
-除非列标头用于进行选择,否则用户可以通过单击列标头对列进行排序。 排序标志符号将自动显示出来
3)DataGridViewColumnSortMode.Programmatic
-此列仅能以编程方式进行排序,并且列标头将包含排序标志符号的空间
这个设置的默认值都是DataGridViewColumnSortMode.Automatic
END