不写Converter,在 Silverlight 中给 DataGrid 绑定数据

作者:互联网   出处:控件中国网   2014-11-05 19:18:33   阅读:1

给 DataGrid 绑定数据的通常做法是:

1、服务器端将数据集合 序列化 成 XML,或者其它格式。
2、在Silverlight 中获取到数据,并反序列化成实体集合。
3、绑定到 DataGrid ,搞定。


象RIA Service 也是类似的做法。只是 VS 将实体自动帮创建好了。


并且,DataGrid 不支持匿名类集合,使用匿名集合,需要自己写 Converter 才能绑定。否则只能绑定出 Title 和 数量。 :D


然后,我的想法是:
获取集合数据,在内存中动态构造出实体,赋值,然后绑定。

 

 

有一个类:
DataSourceCreator 可以干这件事情。上面的那个网址可以下载到这个类。


源代码如下: 


    
public static class DataSourceCreator
    {
        
private static readonly Regex PropertNameRegex =
                
new Regex(@"^[A-Za-z]+[A-Za-z0-9_]*$", 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))
                    {
                        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));
                        property.SetValue(
                            row,
                            Convert.ChangeType(
                                    currentDict[pair.Key],
                                    property.PropertyType,
                                    
null),
                            
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)
        {
            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,
                  
nullnew 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);
        }
    }

直接拷贝这code,需要加入以下引用:

using System.Text.RegularExpressions;
using System.Collections;
using System.Reflection;
using System.Text;
using System.Reflection.Emit;

 


这个类的静态方法 ToDataSource 扩展了 IEnumerable 接口,将普通的 IDictionary 集合 转化成了实体集合。


好。现在来看 json。


将 json 转化为 IDictionary 应该不是一件难事,通过试验,代码如下:


    
public partial class MainPage : UserControl
    {
        
private ProductContext _pro = new ProductContext();
        
public MainPage()
        {
            InitializeComponent();

            
string jsonData = @"
[
   {
      ""TitleID"":1,
      ""Title"":""CEO""
   }, 
   {
      ""TitleID"":2,
      ""Title"":""CTO""
   }, 
   {
      ""TitleID"":3,
      ""Title"":""CXO""
   }, 
   {
      ""TitleID"":4,
      ""Title"":""数据库管理员1221""
   }
]
";



            System.Json.JsonArray data 
= System.Json.JsonArray.Parse(jsonData) as System.Json.JsonArray;

            grid.ItemsSource 
= GenerateData(data).ToDataSource();

            
        }


        
public IEnumerable<System.Collections.IDictionary> GenerateData(System.Json.JsonArray data)
        { 
            
foreach (System.Json.JsonObject jo in data)
            {
                var dict 
= new Dictionary<stringobject>();
                
foreach (string key in jo.Keys)
                {
                    dict.Add(key, jo[key]);
                }

                
yield return dict;
            }

        }

    }



现在,我们可以使用同一个 Controller 驱动 silverlight 或者 ext 啦。

btw: 使用 System.Web.Script.Serialization.JavaScriptSerializer 可以序列化出 json, 这个类在 System.Web.Extensions 包里。

Copyright© 2006-2015 ComponentCN.com all rights reserved.重庆磐岩科技有限公司(控件中国网) 版权所有 渝ICP备12000264号 法律顾问:元炳律师事务所
客服软件
live chat