C#反射与特性应用实例

应用场景:1用SQL语句从数据库返回一个DataTable对象,2然后绑定到DataGridView控件上,DataGridView列头显示的是数据库里的英文字段名,3要显示中文,需要建个对应的EM实体模型,并设置DisplayName特性;4DataGridView的某一行数据赋值给EM实体实例;5EM实体实例绑定到PropertyGrid控件上;6在PropertyGrid上进行增删改查的操作是很方便的。

1窗口布局

新建一个WinForm项目:ReflectionAndAttribute;摆放一个SplitContainer,Dock=Fill;左边放一个DataGridView:dgv,Dock=Fill;右边放一个PropertyGrid:pg,Dock = Fill;创建好后布局大概如下图:


反射与特性窗口布局

2绑定DataGridView:dgv

-窗口创建Load事件,代码如下:

 private void Form1_Load(object sender, System.EventArgs e)
        {
            OracleDML.ConnectionString = "Data Source=CQYH;User Id=nmis;password=nmis";
            DataTable dt = OracleDML.AllTables();
            dgv.DataSource = dt;
        }

-其中OracleDML.AllTables()代码如下:

/// <summary>
        /// 数据库的全部表
        /// </summary>
        /// <returns></returns>
        public static DataTable AllTables()
        {
            string sql_tables = @"select TABLE_NAME,COMMENTS ,TABLE_TYPE
                            from user_tab_comments
                            where table_type = 'TABLE'
                            order by table_name";
            DataTable allTables = OracleDML.GetDataTable(sql_tables);
            allTables.TableName = "allTables";
            return allTables;
        }

-其中OracleDML.GetDataTable()代码如下:

/// <summary>
        /// 查询SQL_select,返回一个DataTable , 200207 add by Sufuq 
        /// </summary>
        /// <param name="cmdText"></param>
        /// <returns></returns>
        public static DataTable GetDataTable(string SQL_select)
        {
            //OracleCommand cmd = new OracleCommand();

            using (OracleConnection connection = new OracleConnection(ConnectionString))
            {
                OracleDataAdapter ada = new OracleDataAdapter(SQL_select, connection);
                //OracleCommandBuilder ocb = new OracleCommandBuilder(ada); //更新时需要这个
                DataTable dt = new DataTable();
                ada.Fill(dt);
                return dt;
            }
        }

-绑定后的运行效果

直接绑定后列名和SQL语句的名称是一样的英文

3创建EM实体类AllTables

创建换一个EM实体类,并加上[DisplayName()]特性

using System.ComponentModel;

namespace ReflectionAndAttribute
{
    class AllTables
    {
        [DisplayName("表名")]
        public string TABLE_NAME { get; set; }
        [DisplayName("中文名")]
        public string COMMENTS { get; set; }
        [DisplayName("类型")]
        public string TABLE_TYPE { get; set; }
    }
}

4重点来了列头变中文名

-Form1_Load添加如下一样代码:

//列头设置为中文
            AttributeHelper.SetColumnDisplayName(typeof(AllTables), dgv);

-其中SetColumnDisplayName()用到反射和特性

/// <summary>
        /// 根据DataGridView绑定数据源的列名获取EM实体模型的显示名,用来设置列标题。
        /// </summary>
        /// <param name="em"></param>
        /// <param name="dgv"></param>
        public static void SetColumnDisplayName(Type em , DataGridView dgv)
        {
            for (int i = 0; i < dgv.Columns.Count; i++)
            {
                string colName = dgv.Columns[i].Name;
                string DisName = GetDisplayName(em, colName);
                dgv.Columns[i].HeaderCell.Value = DisName;
            } 
        }

        /// <summary>
        /// 获取类的DisplayName显示名
        /// </summary>
        /// <param name="modelType">类名</param>
        /// <param name="propertyDisplayName">类属性名</param>
        /// <returns></returns>
        public static string GetDisplayName(Type modelType, string propertyDisplayName)        
        {
            DisplayNameAttribute dna = TypeDescriptor.GetProperties(modelType)[propertyDisplayName].Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute ;
            string displayName = "";
            if (dna == null)
            {
                displayName = propertyDisplayName;
            }
            else
            {
                displayName = dna.DisplayName;
            }
            return displayName;
            //return (TypeDescriptor.GetProperties(modelType)[propertyDisplayName].Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute).DisplayName;        
        } 
看到没真变中文名显示了

5DataGridView某行数据实例化allTables并绑定PropertyGrid

-Form1上dgv添加RowEnter事件

private void dgv_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
            {
                int row = e.RowIndex;
                //DataGridview行数据实例化AllTables
                AllTables em = AttributeHelper.DgvRowBindTOEM(dgv, row, typeof(AllTables)) as AllTables;
                //绑定到PropertyGrid
                pg.SelectedObject = em;
            }
        }

-其中DgvRowBindTOEM用到反射和特性

 /// <summary>
        /// DataGridView的某行绑定到实体模型EM 
        /// </summary>
        /// <param name="dgv"></param>
        /// <param name="row"></param>
        /// <param name="em"></param>
        /// <returns></returns>
        public static object DgvRowBindTOEM(DataGridView dgv ,int row,Type tEM)
        {
            //根据类型实例化一个对象
            object emReturn = System.Activator.CreateInstance(tEM);
            //dgv的一行数据复制给实体模型对象
            for (int i = 0; i < dgv.Columns.Count; i++)
            {
                string colName = dgv.Columns[i].Name.ToLower(); //数据库名 = 列名.ToLower = 属性名

                //string pName = StringHelper.FirstUpper(colName);//这里还可以加列名转属性名 
                
                PropertyInfo pInfo = tEM.GetProperty(colName); //根据列名取属性信息
                object value = dgv.Rows[row].Cells[colName].Value; //列的数据值
                if (value == System.DBNull.Value) value = value.ToString(); //数据库null转换为string
                pInfo.SetValue(emReturn,value,null); //赋值给实例对象colName属性
            }          
            return emReturn;
        }    

-最终完成效果

看到没就是这么神奇

6对数据的增删改查

6.1查询, DataGridView的查询过滤参阅https://www.jianshu.com/p/b3d6ff3c93d6

6.2新增,只要把绑定在PropertyGrid的类清空即可

比如这样:

AllTables em = new AllTables();
pG.SelectedObject = em;

6.3删除,只要把PropertyGrid绑定的类传给数据访问层操作即可

 AllTables em = (AllTables )pG.SelectedObject;
OracleDML.Delete(em);

6.4修改,只要把PropertyGrid绑定的类传给数据访问层操作即可

 AllTables em = (AllTables )pG.SelectedObject;
OracleDML.Update(em);

。。。。。。。。到此结束。。。。。。。。。。。。

==========我是有底线的===============

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容