今天在开发工作中遇到了一个问题:
我的很多DataGridView,因为数据源(DataSource)使用的是数组,导致在点击每列列头的时候无法就指定列进行排序
因此我需要写一个将数组转换为DataTable的函数。
在网上查了一下,找到了这篇Blog,总结得比较全面:
http://blog.youkuaiyun.com/emoonight/article/details/6617683
不过这篇Blog中,从数组转换成DataTable的函数(函数ToDataTable<T>)有一个BUG,在创建每个数据行的时候,没有对list的元素进行判空操作。这样做在数组中有元素为空时,会导致TargetException,更有甚者如果把这段代码运用到Load函数的时候,有可能函数直接中断执行且不弹出任何异常。
下面是我改造之后的代码(需要引用System.Reflection):
public static class DataHelper
{
public static DataTable GetDataTable<T>(this IEnumerable<T> list)
{
DataTable dtResult = new DataTable();
List<PropertyInfo> propertiyInfos = new List<PropertyInfo>();
//生成各列
Array.ForEach<PropertyInfo>(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<Hero>(heros);
}
程序运行后的效果如下,可以看到,以DataTable为数据源的DataGridView(dgvDataTable),已经可以点击列首进行排序了:
如果希望某几列可以排序,某几列不可以排序,可以手动将这些列的信息添加到DataGridView的列中,并配置好DataPropertyName,最后在“编辑列”中设置“SortMode”属性,该属性的值为System.Windows.Forms.DataGridViewColumnSortMode 类型枚举。这个枚举下有三个值,现将三者列在下面,其中的说明信息摘自VS中反射到的元数据:
1)DataGridViewColumnSortMode.NotSortable
-此列仅能以编程方式进行排序,但由于它原本并不打算排序,所以列标头将不包含排序标志符号的空间
2)DataGridViewColumnSortMode.Automatic
-除非列标头用于进行选择,否则用户可以通过单击列标头对列进行排序。 排序标志符号将自动显示出来
3)DataGridViewColumnSortMode.Programmatic
-此列仅能以编程方式进行排序,并且列标头将包含排序标志符号的空间
这个设置的默认值都是DataGridViewColumnSortMode.Automatic
END