zoukankan      html  css  js  c++  java
  • 把object转换成DataSet,进行数据绑定

    概述:

        当我们遇到把对象的属性及值显示在GridView的时候,我们需要把ojbect转化为DataTable来进行绑定.

    代码如下:  

    /// <summary>
        
    /// Fills the DataSet with data from an object or collection.
        
    /// </summary>
        
    /// <remarks>
        
    /// The name of the DataTable being filled is will be the class name of
        
    /// the object acting as the data source. The
        
    /// DataTable will be inserted if it doesn't already exist in the DataSet.
        
    /// </remarks>
        
    /// <param name="ds">A reference to the DataSet to be filled.</param>
        
    /// <param name="source">A reference to the object or collection acting as a data source.</param>
        public void Fill(DataSet ds, object source)
        {
            
    string className = source.GetType().Name;
            Fill(ds, className, source);
        }
    /// <summary>
        
    /// Fills the DataSet with data from an object or collection.
        
    /// </summary>
        
    /// <remarks>
        
    /// The name of the DataTable being filled is specified as a parameter. The
        
    /// DataTable will be inserted if it doesn't already exist in the DataSet.
        
    /// </remarks>
        
    /// <param name="ds">A reference to the DataSet to be filled.</param>
        
    /// <param name="TableName"></param>
        
    /// <param name="source">A reference to the object or collection acting as a data source.</param>
        public void Fill(DataSet ds, string tableName, object source)
        {
            DataTable dt;
            
    bool exists;

            dt 
    = ds.Tables[tableName];
            exists 
    = (dt != null);

            
    if (!exists)
                dt 
    = new DataTable(tableName);

            Fill(dt, source);

            
    if (!exists)
                ds.Tables.Add(dt);
    }

    通过重载,使ojbect转化DataSet过渡到转化DataTable.

    /// <summary>
        
    /// Fills a DataTable with data values from an object or collection.
        
    /// </summary>
        
    /// <param name="dt">A reference to the DataTable to be filled.</param>
        
    /// <param name="source">A reference to the object or collection acting as a data source.</param>
        public void Fill(DataTable dt, object source)
        {
            
    if (source == null)
                
    throw new ArgumentException("NothingNotValid");

            
    // get the list of columns from the source
            List<string> columns = GetColumns(source);
            
    if (columns.Count < 1return;

            
    // create columns in DataTable if needed
            foreach (string column in columns)
                
    if (!dt.Columns.Contains(column))
                    dt.Columns.Add(column);

            
    // get an IList and copy the data
            CopyData(dt, GetIList(source), columns);
        }

     

    这个方法所做的第一件事情就是从数据源中获得一个字段名字(通常是公共的属性域)的列表.是通过GetColumns()方法完成的.

    接下来,代码对目标DataTable进行检查,确保它含有与从GetColumns()方法提取出来的每个字段名字相对应的字段.如果有任何字段没有找到,就将这些字段添加到DataTable中.最后就是源对象到DataTable的数据拷贝了。

     

    GetColumns方法:

    GetColumns()方法对源对象的类型进行判断,然后将具体工作分派给具体特定类型的工具方法:     

      private List<string> GetColumns(object source)
        {
            List
    <string> result;
            
    // first handle DataSet/DataTable
            object innerSource;
            IListSource iListSource 
    = source as IListSource;
            
    if (iListSource != null)
                innerSource 
    = iListSource.GetList();
            
    else
                innerSource 
    = source;

            DataView dataView 
    = innerSource as DataView;
            
    if (dataView != null)
                result 
    = ScanDataView(dataView);
            
    else
            {
                
    // now handle lists/arrays/collections
                IEnumerable iEnumerable = innerSource as IEnumerable;
                
    if (iEnumerable != null)
                {
                    Type childType 
    = GetChildItemType(
                      innerSource.GetType());
                    result 
    = ScanObject(childType);
                }
                
    else
                {
                    
    // the source is a regular object
                    result = ScanObject(innerSource.GetType());
                }
            }
            
    return result;
        }

      

    接下来,代码会对该对象进行检查,看看它是不是一个DataView.如果是一个DataView,代码就会调用一个ScanDataView()方法来将字段的名字从DataView对象中剥离出来.

    ScanDataView方法:   

      private List<string> ScanDataView(DataView ds)
        {
            List
    <string> result = new List<string>();
            
    for (int field = 0; field < ds.Table.Columns.Count; field++)
                result.Add(ds.Table.Columns[field].ColumnName);
            
    return result;
        }
     

    如果源对象不是DataView,但是却直接实现了IEnumerable接口的话,那么其子对象的类型将会被GetChildItemType()的方法提取出来.

    GetChildItemType方法:

    GetChildItemType()方法对子对象的类型进行检查,看看它是不是一个数组.如果是的话,它就会返回这个数组的元素类型---否则的话,它就会对listType的属性进行扫描来找到那个索引器:

    /// <summary>
        
    /// Returns the type of child object
        
    /// contained in a collection or list.
        
    /// </summary>
        public static Type GetChildItemType(Type listType)
        {
            Type result 
    = null;
            
    if (listType.IsArray)
                result 
    = listType.GetElementType();
            
    else
            {
                DefaultMemberAttribute indexer 
    =
                  (DefaultMemberAttribute)Attribute.GetCustomAttribute(
                  listType, 
    typeof(DefaultMemberAttribute));
                
    if (indexer != null)
                    
    foreach (PropertyInfo prop in listType.GetProperties(
                      BindingFlags.Public 
    |
                      BindingFlags.Instance 
    |
                      BindingFlags.FlattenHierarchy))
                    {
                        
    if (prop.Name == indexer.MemberName)
                            result 
    = GetPropertyType(prop.PropertyType);
                    }
            }
            
    return result;
        }

     

    索引器属性是可以被识别出来的,因为它有一个由编译器添加的[DefaultMember()]特性.如果代码找到了一个索引器,那么由这个索引器属性所返回的类型就被作为结果返回.如果数组和索引器的方法都失败了,那么就说明无法对子对象的类型进行判断,所以代码就返回null.

    GetPropertyType方法:

      /// <summary>
        
    /// Returns a property's type, dealing with
        
    /// Nullable<T> if necessary.
        
    /// </summary>
        public static Type GetPropertyType(Type propertyType)
        {
            Type type 
    = propertyType;
            
    if (type.IsGenericType &&
              (type.GetGenericTypeDefinition() 
    == typeof(Nullable)))
                
    return type.GetGenericArguments()[0];
            
    return type;
        }
     

    让我们再回到GetColumns()方法,代码调用了一个ScanObject()方法,用子对象的类型作为参数.ScanObject()用反射来处理类型.如果你能回忆起来的话,GetColumns()方法本身如果检测到源对象不是一个集合,而是一个单一复杂的Struct或对象的话也会调用ScanObject():

    ScanObject()方法:

      private List<string> ScanObject(Type sourceType)
        {
            List
    <string> result = new List<string>();

            
    if (sourceType != null)
            {
                
    // retrieve a list of all public properties
                PropertyInfo[] props = sourceType.GetProperties();
                
    if (props.Length >= 0)
                    
    for (int column = 0; column < props.Length; column++)
                        
    if (props[column].CanRead)
                            result.Add(props[column].Name);

                
    // retrieve a list of all public fields
                FieldInfo[] fields = sourceType.GetFields();
                
    if (fields.Length >= 0)
                    
    for (int column = 0; column < fields.Length; column++)
                        result.Add(fields[column].Name);
            }
            
    return result;
        }

     

    在Fill()方法中的最后一步是通过对一个CopyData()方法的调用来将数据从源列表拷贝到DataTable中.从GetColumns()中返回的字段名字列表被作为参数传进这个方法,用来从源列表的每个条目中提出数据.

     private void CopyData(
          DataTable dt, IList ds, List
    <string> columns)
        {
            
    // load the data into the DataTable
            dt.BeginLoadData();
            
    for (int index = 0; index < ds.Count; index++)
            {
                DataRow dr 
    = dt.NewRow();
                
    foreach (string column in columns)
                {
                    
    try
                    {
                        dr[column] 
    = GetField(ds[index], column);
                    }
                    
    catch (Exception ex)
                    {
                        dr[column] 
    = ex.Message;
                    }
                }
                dt.Rows.Add(dr);
            }
            dt.EndLoadData();
        }
     

    在对DataTable对象作任何修改之前,代码调用了它的BeginLoadData()方法,这就告诉了DataTable对象将要对它进行一批修改,以便于工作它可以暂时抑制一下它的正常的事件处理机制.这样做不仅仅使修改的过程更有效率,而且避免了UI因为DataTable的变化而进行刷新的问题.

    随后,这个方法对源列表中的所有条目进行了遍历.代码会为每一个条目都创建一个新的DataRow对象,用源对象中的值进行赋值,最后将该DataRow添加到DataTable中.这个过程中的关键方法是GetField().

    在所有的数据都被拷贝到DataTable中以后,它的EndLoadData()方法将会被调用,这个方法调用会告诉该对象这批修改已经完成,可以继续它正常的事件、索引和约束处理了.

    GetField()方法:

    真正为CopyData()做实际工作的是GetField()方法.这个方法负责将指定的字段属性或者域的值从源对象中提取出来.因为源对象可能是简单类型,也有可能是复杂类型.

    private static string GetField(object obj, string fieldName)
        {
            
    string result;
            DataRowView dataRowView 
    = obj as DataRowView;
            
    if (dataRowView != null)
            {
                
    // this is a DataRowView from a DataView
                result = dataRowView[fieldName].ToString();
            }
            
    else if (obj is ValueType && obj.GetType().IsPrimitive)
            {
                
    // this is a primitive value type
                result = obj.ToString();
            }
            
    else
            {
                
    string tmp = obj as string;
                
    if (tmp != null)
                {
                    
    // this is a simple string
                    result = (string)obj;
                }
                
    else
                {
                    
    // this is an object or Structure
                    try
                    {
                        Type sourceType 
    = obj.GetType();

                        
    // see if the field is a property
                        PropertyInfo prop = sourceType.GetProperty(fieldName);

                        
    if ((prop == null|| (!prop.CanRead))
                        {
                            
    // no readable property of that name exists - 
                            
    // check for a field
                            FieldInfo field = sourceType.GetField(fieldName);
                            
    if (field == null)
                            {
                                
    // no field exists either, throw an exception
                                throw new DataException("NoSuchValueExistsException"+fieldName);
                            }
                            
    else
                            {
                                
    // got a field, return its value
                                result = field.GetValue(obj).ToString();
                            }
                        }
                        
    else
                        {
                            
    // found a property, return its value
                            result = prop.GetValue(obj, null).ToString();
                        }
                    }
                    
    catch (Exception ex)
                    {
                        
    throw new DataException("ErrorReadingValueException"+fieldName, ex);
                    }
                }
            }
            
    return result;
        }
  • 相关阅读:
    PLINQ 简介
    windows phone 网易云阅读hubtile效果实现
    windows phone 生产含logo的二维码
    windows phone 生产二维码和解码本地二维码图片
    element loading源码
    element input-number源码
    element Image组件
    element form源码
    element dropdown源码
    element Divider源码
  • 原文地址:https://www.cnblogs.com/abcdwxc/p/1422295.html
Copyright © 2011-2022 走看看