datagrid 绑定动态列
如题, 许多时候我们渴望绑定一个不确定的列到datagrid,
如果你真想这样那么10分钟后你将实现,
缺点是你不可能在datagrid的一行中得到一个完整的类了.
她借助了一个国外的源码类,DataGridDataSource.cs
--------------------------------------------------------------------------
代码:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Controls;
using DataGridDataSource;
namespace GridTestSilverlight
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.TheGrid.ItemsSource = GenerateData("这里传入数据").ToDataSource();
}
public IEnumerable<IDictionary> GenerateData(string xml)
{
//注意此处的for循环,只是为了模拟数据格式,
//卑微的我只是提供了一种绑定多列的方式,
//伟大而牛B的您可以根据自己需求满足这种格式,
for (int j = 200; j < 215;j ++ )
{
var dict = new Dictionary<object, object>();
for (var i = 1; i <= 4; i++)
{
dict["当前列" + i] = "---" + j ;
}
yield return dict;
}
}
}
}
/*
我自己实际工程中用到的.
* 数据格式为
* <Temp>
* <时间>2011-3-14 10:21:52</时间>
* <时间>2011-3-16 10:21:52</时间>
* <时间>2011-3-17 10:21:52</时间>
* <时间>2011-3-18 10:21:52</时间>
* </Temp>
* <Temp>
* <时间>2011-3-19 10:21:52</时间>
* <时间>2011-3-21 10:21:52</时间>
* <时间>2011-3-31 10:21:52</时间>
* <时间>2011-3-22 10:21:52</时间>
* </Temp>
* private IEnumerable<IDictionary> GenerateData(XDocument xml)
{
var element = xml.Descendants("Temp");
foreach (XElement item in element)
{
var dict = new Dictionary<object, object>();
var nodes = item.Elements();
foreach (XElement node in nodes)
{
dict[node.Name] = node.Value;
}
yield return dict;
}
}
*
*/
DataGridDataSource.cs 类
对于此文件, 类中注释部分为源码,注释下方是我添加的,不难看出是为了能够让DataGrid的表头出现中文.
自此皆大欢喜. 我用到了我想用的.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Text.RegularExpressions;
namespace DataGridDataSource
{
public static class DataSourceCreator
{
//private static readonly Regex PropertNameRegex =
// new Regex(@"^[A-Za-z]+[A-Za-z0-9_]*$", RegexOptions.Singleline);
private static readonly Regex PropertNameRegex =
new Regex(@"^[\u4e00-\u9fa5]+$", RegexOptions.Singleline);
private static readonly Dictionary<string, Type> _typeBySigniture =
new Dictionary<string, Type>();
public static IEnumerable ToDataSource(this IEnumerable<IDictionary> list)
{
IDictionary firstDict = null;
bool hasData = false;
foreach (IDictionary currentDict in list)
{
hasData = true;
firstDict = currentDict;
break;
}
if (!hasData)
{
return new object[] { };
}
if (firstDict == null)
{
throw new ArgumentException("IDictionary entry cannot be null");
}
string typeSigniture = GetTypeSigniture(firstDict);
Type objectType = GetTypeByTypeSigniture(typeSigniture);
if (objectType == null)
{
TypeBuilder tb = GetTypeBuilder(typeSigniture);
ConstructorBuilder constructor =
tb.DefineDefaultConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName);
foreach (DictionaryEntry pair in firstDict)
{
//if (PropertNameRegex.IsMatch(Convert.ToString(pair.Key), 0))
if(true)
{
CreateProperty(tb,
Convert.ToString(pair.Key),
GetValueType(pair.Value));
}
else
{
throw new ArgumentException(
@"Each key of IDictionary must be
alphanumeric and start with character.");
}
}
objectType = tb.CreateType();
_typeBySigniture.Add(typeSigniture, objectType);
}
return GenerateEnumerable(objectType, list, firstDict);
}
private static Type GetTypeByTypeSigniture(string typeSigniture)
{
Type type;
return _typeBySigniture.TryGetValue(typeSigniture, out type) ? type : null;
}
private static Type GetValueType(object value)
{
return value == null ? typeof(object) : value.GetType();
}
private static string GetTypeSigniture(IDictionary firstDict)
{
StringBuilder sb = new StringBuilder();
foreach (DictionaryEntry pair in firstDict)
{
sb.AppendFormat("_{0}_{1}", pair.Key, GetValueType(pair.Value));
}
return sb.ToString().GetHashCode().ToString().Replace("-", "Minus");
}
private static IEnumerable GenerateEnumerable(
Type objectType, IEnumerable<IDictionary> list, IDictionary firstDict)
{
var listType = typeof(List<>).MakeGenericType(new[] { objectType });
var listOfCustom = Activator.CreateInstance(listType);
foreach (var currentDict in list)
{
if (currentDict == null)
{
throw new ArgumentException("IDictionary entry cannot be null");
}
var row = Activator.CreateInstance(objectType);
foreach (DictionaryEntry pair in firstDict)
{
if (currentDict.Contains(pair.Key))
{
PropertyInfo property =
objectType.GetProperty(Convert.ToString(pair.Key));
var value = currentDict[pair.Key];
try
{
if (value != null && value.GetType() != property.PropertyType && !property.PropertyType.IsGenericType)
value = Convert.ChangeType(
currentDict[pair.Key],
property.PropertyType,
null);
}catch
{
}
property.SetValue(
row,
value,
null);
}
}
listType.GetMethod("Add").Invoke(listOfCustom, new[] { row });
}
return listOfCustom as IEnumerable;
}
private static TypeBuilder GetTypeBuilder(string typeSigniture)
{
AssemblyName an = new AssemblyName("TempAssembly" + typeSigniture);
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType("TempType" + typeSigniture
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, typeof(object));
return tb;
}
private static void CreateProperty(
TypeBuilder tb, string propertyName, Type propertyType)
{
if(propertyType.IsValueType && !propertyType.IsGenericType)
{
propertyType = typeof(Nullable<>).MakeGenericType(new[] { propertyType });
}
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName,
propertyType,
FieldAttributes.Private);
PropertyBuilder propertyBuilder =
tb.DefineProperty(
propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr =
tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
propertyType, Type.EmptyTypes);
ILGenerator getIL = getPropMthdBldr.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new Type[] { propertyType });
ILGenerator setIL = setPropMthdBldr.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, fieldBuilder);
setIL.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}