本文主要讲述如何根据UI配置来动态生成控件, 并添加到窗体上来构建UI窗体,当用户在每个控件上完成输入操作后,程序通过遍历控件并用拼接字符串的方式动态生成Insert SQL语句,进而实现了将UI上的值,保存到数据库。

1 UI配置

  首先第一步,需要在数据库中定义UI配置,这里为了简便,用DataTable模拟了数据,如果是复杂的情况,可以再多一些属性的定义,如下所示:

             //实际从数据库加载
DataTable dtUIConfig = new DataTable();
dtUIConfig.Columns.Add("name");
dtUIConfig.Columns.Add("title");
dtUIConfig.Columns.Add("size");
dtUIConfig.Columns.Add("location");
dtUIConfig.Columns.Add("type");
dtUIConfig.Columns.Add("config"); dtUIConfig.Rows.Add(new object[] { "ID", "ID:", "160,30", "0,0", "textbox", "" });
dtUIConfig.Rows.Add(new object[] { "name", "用户名:", "160,30", "0,0", "textbox", "" });
dtUIConfig.Rows.Add(new object[] { "password", "密码:", "160,30", "0,0", "passwordtext", "" });
dtUIConfig.Rows.Add(new object[] { "sex", "性别:", "160,30", "0,0", "combobox", "Man,Female" });
dtUIConfig.Rows.Add(new object[] { "emp", "职员:", "160,30", "0,0", "CustomComboBox", "datagridview" });
dtUIConfig.Rows.Add(new object[] { "dept", "部门:", "160,30", "0,0", "CustomComboBox", "treeview" });
dtUIConfig.Rows.Add(new object[] { "details", "明细:", "440,200", "0,0", "datagridview", "select * from test" });
dtUIConfig.Rows.Add(new object[] { "btnSave", "保存", "160,30", "0,0", "button", "" });

2 获取最长的标签

  由于一般的控件,例如文本框等,前面都有一个标签,由于不同的标题长度不一,为了界面整齐,可以动态计算所有标题的长度,并获取最大的长度,作为所有标签的长度。同理获取所有控件的最大配置长度,当然了类似表格等控件需要独立换行,不在此处理范围,如下所示:

             int leftMargin = ;
int topMargin = ;
int totolwidth = this.Width - - leftMargin; Point currentLocation = new Point(leftMargin, topMargin);
Point nextLocation = new Point(leftMargin, topMargin);
int label_control_width = ;
int y = nextLocation.Y; int labelMaxLength = ;
int controlMaxLength = ; int lastY = ;
//UI engine
foreach (DataRow dr in dtUIConfig.Rows)
{ //计量字符串长度
SizeF maxSize = this.CreateGraphics().MeasureString(dr["title"].ToString(), this.Font);
if (labelMaxLength < maxSize.Width)
{
labelMaxLength = int.Parse(maxSize.Width.ToString(""));
}
if (controlMaxLength < int.Parse(dr["size"].ToString().Split(',')[]))
{
controlMaxLength = int.Parse(dr["size"].ToString().Split(',')[]);
}
}

3 UI Builder

  在获得最长的标签后,可以根据UI配置的控件类型,用程序来动态生成控件,并添加到窗体上,如果有自定义的控件,也可以添加,如下所示:

             //ui builder
foreach (DataRow dr in dtUIConfig.Rows)
{
if (dr["type"].ToString().ToLower() == "button")
{
Label label = new Label();
label.Location = new Point(nextLocation.X, nextLocation.Y);
label.Width = labelMaxLength;//max size
label.Text ="";
//-----------------------------------
Button ctrlItem = new Button();
ctrlItem.Location = new Point(label.Right + label_control_width, nextLocation.Y);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString();
ctrlItem.Text = dr["title"].ToString();
// ctrlItem.Font = this.Font;
ctrlItem.Click += new EventHandler(ctrlItem_Click);
//-------------------------------------------------------------
nextLocation.X = ctrlItem.Right + ;
lastY = ctrlItem.Bottom + ;
if (nextLocation.X >= totolwidth)
{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
}
this.Controls.Add(label);
this.Controls.Add(ctrlItem); } //-------------------------------------------------
if (dr["type"].ToString().ToLower() == "CustomComboBox".ToLower())
{
Label label = new Label();
label.Location = new Point(nextLocation.X, nextLocation.Y);
label.Width = labelMaxLength;//max size
label.Text = dr["title"].ToString();
//----------------------------------- //datagridview
if((dr["config"].ToString().ToLower()=="datagridview"))
{
CustomComboBox ctrlItem = new CustomComboBox();
ctrlItem.Location = new Point(label.Right + label_control_width, nextLocation.Y);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString();
DataGridView gridView = new DataGridView();
gridView.Columns.Add("ID", "ID");
gridView.Columns.Add("Name", "Name");
gridView.Columns.Add("Level", "Level");
ctrlItem.DropDownControl = gridView;
gridView.Rows.Add(new object[] { "", "jack", "" });
gridView.Rows.Add(new object[] { "", "wang", "" });
gridView.Font = this.Font;
ctrlItem.DropDownControlType = enumDropDownControlType.DataGridView;
ctrlItem.DisplayMember = "Name";
ctrlItem.ValueMember = "ID";
//-------------------------------------------------------------
nextLocation.X = ctrlItem.Right + ;
lastY = ctrlItem.Bottom + ;
if (nextLocation.X >= totolwidth)
{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
}
this.Controls.Add(label);
this.Controls.Add(ctrlItem);
}
else if (dr["config"].ToString().ToLower() == "treeview")
{
CustomComboBox ctrlItem = new CustomComboBox();
ctrlItem.Location = new Point(label.Right + label_control_width, nextLocation.Y);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString();
//静态变量 2个时候默认就是最后一个
treeView1.Font = this.Font;
ctrlItem.DropDownControlType = enumDropDownControlType.TreeView;
ctrlItem.DropDownControl = this.treeView1;
//not empty
ctrlItem.DisplayMember = "Name";
ctrlItem.ValueMember = "ID";
//-------------------------------------------------------------
nextLocation.X = ctrlItem.Right + ;
lastY = ctrlItem.Bottom + ;
if (nextLocation.X >= totolwidth)
{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
}
this.Controls.Add(label);
this.Controls.Add(ctrlItem); }
else
{
} }
//---------------------------------------------------------------
//强制换行
if (dr["type"].ToString().ToLower() == "datagridview")
{
//Label label = new Label();
//label.Location = new Point(nextLocation.X, nextLocation.Y);
//label.Width = labelMaxLength;//max size
//label.Text = dr["title"].ToString();
//-----------------------------------
DataGridView ctrlItem = new DataGridView();
//强制换行
ctrlItem.Location = new Point(currentLocation.X, lastY);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString(); string connString = "server=.\\sql2008r2; database=GC管理; Trusted_Connection=True; ";
MkMisII.DAO.SqlHelper.DefaultConnectionString = connString;
DataTable dtC = MkMisII.DAO.SqlHelper.GetDataTableBySQL(dr["config"].ToString());
if (dtC != null)
{
ctrlItem.DataSource = dtC;
}
//-------------------------------------------------------------
//nextLocation.X = ctrlItem.Right + 8;
//lastY = ctrlItem.Bottom + 16;
//if (nextLocation.X >= totolwidth)
//{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
//} this.Controls.Add(ctrlItem); }
//-------------------------------------------------
if (dr["type"].ToString().ToLower() == "textbox")
{
Label label = new Label();
label.Location = new Point(nextLocation.X, nextLocation.Y);
label.Width = labelMaxLength;//max size
label.Text = dr["title"].ToString();
//-----------------------------------
TextBox ctrlItem = new TextBox();
ctrlItem.Location = new Point(label.Right + label_control_width, nextLocation.Y);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString(); //-------------------------------------------------------------
nextLocation.X = ctrlItem.Right + ;
lastY = ctrlItem.Bottom + ;
if (nextLocation.X >= totolwidth)
{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
}
this.Controls.Add(label);
this.Controls.Add(ctrlItem); }
//----------------------------------------------------------
if (dr["type"].ToString().ToLower() == "combobox")
{
Label label = new Label();
label.Location = new Point(nextLocation.X, nextLocation.Y);
label.Width = labelMaxLength;
label.Text = dr["title"].ToString(); //-----------------------------------
ComboBox ctrlItem = new ComboBox();
ctrlItem.Location = new Point(label.Right + label_control_width, nextLocation.Y);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString();
string[] items = dr["config"].ToString().Split(',');
foreach (string item in items)
{
ctrlItem.Items.Add(item);
}
//-------------------------------------------------------------
nextLocation.X = ctrlItem.Right + ;
lastY = ctrlItem.Bottom + ;
if (nextLocation.X >= totolwidth)
{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
} this.Controls.Add(label);
this.Controls.Add(ctrlItem); } if (dr["type"].ToString().ToLower() == "passwordtext")
{
Label label = new Label();
label.Location = new Point(nextLocation.X, nextLocation.Y);
label.Width = labelMaxLength;
label.Text = dr["title"].ToString(); //-----------------------------------
TextBox ctrlItem = new TextBox();
ctrlItem.PasswordChar = '*';
ctrlItem.Location = new Point(label.Right + label_control_width, nextLocation.Y);
ctrlItem.Width = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Height = int.Parse(dr["size"].ToString().Split(',')[]);
ctrlItem.Name = dr["name"].ToString(); //-------------------------------------------------------------
nextLocation.X = ctrlItem.Right + ;
lastY = ctrlItem.Bottom + ;
if (nextLocation.X >= totolwidth)
{
nextLocation.Y = ctrlItem.Bottom + ;
nextLocation.X = currentLocation.X;
}
this.Controls.Add(label);
this.Controls.Add(ctrlItem); }
}

4 生成保存SQL

  单击保存按钮,我们通过遍历窗体控件,来动态获取值,然后进行SQL 拼接,有了SQL就可以对数据进行CURD操作了,如下所示:

         string SQL = "";
//save
void ctrlItem_Click(object sender, EventArgs e)
{
try
{
string preSQL="Insert into Users(";
string postSQL = " ) values ( ";
foreach (DataRow dr in dtUIConfig.Rows)
{
if (dr["type"].ToString() != "button" && dr["type"].ToString() != "datagridview")
{
Control[] ctrl = this.Controls.Find(dr["name"].ToString(), true);
if (ctrl != null)
{
if (ctrl.Length == )
{
if (!dic.Keys.Contains(dr["name"].ToString()))
{
preSQL += string.Format("'{0}',", dr["name"].ToString());
postSQL += string.Format("'{0}',", ctrl[].Text);
//dic.Add(dr["name"].ToString(), ctrl[0].Text);
}
} }
} }
SQL = preSQL.TrimEnd(',') + postSQL.TrimEnd(',') + ")";
MessageBox.Show(SQL,"insert SQL");
//Save data to database ...
}
catch (Exception ex)
{ } }

5 效果

  运行程序,界面如下所示:

  大小调整后,会自动进行UI重新布局,如下图所示:

  单击保存,生成SQL

C#如何根据配置实现动态窗体的更多相关文章

  1. Struts2-整理笔记(二)常量配置、动态方法调用、Action类详解

    1.修改struts2常量配置(3种) 第一种 在str/struts.xml中添加constant标签 <struts> <!-- 如果使用使用动态方法调用和include冲突 - ...

  2. JavaWeb_(Struts2框架)struts.xml核心配置、动态方法调用、结果集的处理

    此系列博文基于同一个项目已上传至github 传送门 JavaWeb_(Struts2框架)Struts创建Action的三种方式 传送门 JavaWeb_(Struts2框架)struts.xml核 ...

  3. 微软Azure配置中心 App Configuration (三):配置的动态更新

    写在前面 我在前文: <微软Azure配置中心 App Configuration (一):轻松集成到Asp.Net Core>已经介绍了Asp.net Core怎么轻易的接入azure ...

  4. 前端引擎初步设计稿 -通过配置生成动态页面 ,LandaSugar平台 .NET-C#-MVC

    公司准备开发出一款项目开发平台 LandaSugar,分为 前端引擎.工作引擎.数据引擎 三大块,开发人员只需要对三大模块进行相应的配置便能够完成一个定制项目的开发. 听起来貌似是异想天开,但是是否真 ...

  5. Nutch的配置以及动态网站的抓取

    http://blog.csdn.net/jimanyu/article/details/5619949 一:配置Nutch: 1.解压缩的nutch后,以抓取http://www.163.com/为 ...

  6. HttpModule在Web.config的配置和动态配置

    学习笔记 ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandler,HttpHandler处理完之后, ...

  7. Springboot多数据源配置--数据源动态切换

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

  8. 【原创】一篇学会vue路由配置 、 动态路由 、多层路由(实例)

    先来看看效果图: 为了方便讲解,我没有使用vue脚手架,如果需要的,可以留言跟我要.不多说开工: 首先,html先组上 <div id="app"> <div&g ...

  9. MyBatis的核心配置、动态sql、关联映射(快速总结)

    MyBatis的核心对象和配置 #1. SqlSessionFactory对象: 单个数据库映射关系经过编译的内存镜像: 作用:创建SQLSession对象. //读取配置文件 InputSteam ...

随机推荐

  1. silverlight中 Storyboard(动画)的使用,实现球的上下循环移动,左右移动,及旋转功能

    话说,总结应该是个收获的心情,可现在的自己似乎没感觉到哪个喜悦的心情,说明自己做得还不够好,现在还是把一些做好的东西总结下.“总结”是学习,工作中必须的,不能偷这个懒 o(╯□╰)o 实现上下循环移动 ...

  2. Android_文件存储

    因为项目的需求,想实现一个指导使用的欢迎页效果,通过在网上的询问,给的一种解决办法是通过SharedPreferences文件存储方式来实现,具体的实现类似于通过第一次取得SharedPreferen ...

  3. 编译原理LL1文法分析表算法实现

    import hjzgg.first.First; import hjzgg.follow.Follow; import hjzgg.tablenode.TableNode; import hjzgg ...

  4. 邻接表无向图(一)之 C语言详解

    本章介绍邻接表无向图.在"图的理论基础"中已经对图进行了理论介绍,这里就不再对图的概念进行重复说明了.和以往一样,本文会先给出C语言的实现:后续再分别给出C++和Java版本的实现 ...

  5. Linux演示 dd测试IO

    dd测试IO,经常会用到,用来简单测试某个目录的读写性能. 本次测试环境:自己电脑的ubuntu系统-其他Unix/Linux系统也可以用dd. Tips:dd操作需要三思而行,搞清楚确认没问题再进行 ...

  6. 借助 CSS Colorguard 来避免使用重复的颜色

    每一个 CSS 项目开始时愿望都是很美好的,但不可避免地,多人协作的项目相互之间可能重复使用了相似的颜色,而你从来不知道它们的存在.CSS Colorguard 帮助您保持您想要的颜色设置,当你添加的 ...

  7. Android一些关于分辨率和布局的设置

      1.Android手机屏幕大小不一,有480x320, 640x360, 800x480.怎样才能让App自动适应不同的屏幕呢? drawable- hdpi.drawable- mdpi.dra ...

  8. JAVA 设计模式 策略模式

    用途 Title 它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. 策略模式是一种行为型模式. 结构

  9. 关于WEB Service&WCF&WebApi实现身份验证之WCF篇(2)

    因前段时间工作变动(换了新工作)及工作较忙暂时中断了该系列文章,今天难得有点空闲时间,就继续总结WCF身份验证的其它方法.前面总结了三种方法(详见:关于WEB Service&WCF& ...

  10. Android Studio快捷键每日一练(2)

    原文地址:http://www.developerphil.com/android-studio-tips-of-the-day-roundup-2/ 12.复制行 苹果:Cmd+D    Windo ...