C#如何根据配置实现动态窗体
本文主要讲述如何根据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#如何根据配置实现动态窗体的更多相关文章
- Struts2-整理笔记(二)常量配置、动态方法调用、Action类详解
1.修改struts2常量配置(3种) 第一种 在str/struts.xml中添加constant标签 <struts> <!-- 如果使用使用动态方法调用和include冲突 - ...
- JavaWeb_(Struts2框架)struts.xml核心配置、动态方法调用、结果集的处理
此系列博文基于同一个项目已上传至github 传送门 JavaWeb_(Struts2框架)Struts创建Action的三种方式 传送门 JavaWeb_(Struts2框架)struts.xml核 ...
- 微软Azure配置中心 App Configuration (三):配置的动态更新
写在前面 我在前文: <微软Azure配置中心 App Configuration (一):轻松集成到Asp.Net Core>已经介绍了Asp.net Core怎么轻易的接入azure ...
- 前端引擎初步设计稿 -通过配置生成动态页面 ,LandaSugar平台 .NET-C#-MVC
公司准备开发出一款项目开发平台 LandaSugar,分为 前端引擎.工作引擎.数据引擎 三大块,开发人员只需要对三大模块进行相应的配置便能够完成一个定制项目的开发. 听起来貌似是异想天开,但是是否真 ...
- Nutch的配置以及动态网站的抓取
http://blog.csdn.net/jimanyu/article/details/5619949 一:配置Nutch: 1.解压缩的nutch后,以抓取http://www.163.com/为 ...
- HttpModule在Web.config的配置和动态配置
学习笔记 ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandler,HttpHandler处理完之后, ...
- Springboot多数据源配置--数据源动态切换
在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...
- 【原创】一篇学会vue路由配置 、 动态路由 、多层路由(实例)
先来看看效果图: 为了方便讲解,我没有使用vue脚手架,如果需要的,可以留言跟我要.不多说开工: 首先,html先组上 <div id="app"> <div&g ...
- MyBatis的核心配置、动态sql、关联映射(快速总结)
MyBatis的核心对象和配置 #1. SqlSessionFactory对象: 单个数据库映射关系经过编译的内存镜像: 作用:创建SQLSession对象. //读取配置文件 InputSteam ...
随机推荐
- IO流-文件管理
File f = new File(“test.txt”); File的构造器不会在文件不存在的情况下新建一个文件,从File对象中创建文件是由文件流的构造器或File类的createNewFile方 ...
- 用户代理字符串userAgent可实现的四个识别
定义 用户代理字符串:navigator.userAgent HTTP规范明确规定,浏览器应该发送简短的用户代理字符串,指明浏览器的名称和版本号.但现实中却没有这么简单. 发展历史 [1]1993年美 ...
- Cocos2d-x 3.2 学习笔记(五)Sprite Node
游戏中最重要的元素Sprite精灵,关于精灵的创建,精灵的控制等等. 涉及到的类Class: AnimationFrame 动画帧. Animation 动画对象:一个用来在精灵对象上表现动画的动画对 ...
- Git的奇技淫巧🙈
Git的奇技淫巧
- 《ASP.NET SignalR系列》第二课 SignalR的使用说明
从现在开始相关文章请到: http://lko2o.com/moon 接续上一篇:<ASP.NET SignalR系列>第一课 认识SignalR (还没有看的话,建议您先看看) 一.指定 ...
- 8.Fluent API in Code-First【Code-First系列】
在前面的章节中,我们已经看到了各种不同的数据注解特性.现在我们来学习一下Fluent API. Fluent API是另外一种配置领域类的方式,它提供了更多的配置相比数据注解特性. Mappings[ ...
- C#串口通信
通过COM1发送数据,COM2接收数据.当COM2接收完本次发送的数据后,向COM1发送信息通知COM1本次数据已发完,COM1接到通知后,再发下一段数据.这样可以确保每次发送的数据都可以被正确接收. ...
- 利用chrome调试JavaScript代码
看见网上很多人问怎么用chrome调试JavaScript代码,我也对这个问题抱着疑问,但是没有找到一篇能用的中文文章(可能我的google有问题),也不知道怎么点出一篇E文的,感觉作者写得不错,所以 ...
- 使用OWIN 为WebAPI 宿主 跨平台
OWIN是什么? OWIN的英文全称是Open Web Interface for .NET. 如果仅从名称上解析,可以得出这样的信息:OWIN是针对.NET平台的开放Web接口. 那Web接口是谁和 ...
- ASP.NET MVC Model绑定小结
Model绑定是指从URL提取数据,生成对应Action方法的参数这个过程.前面介绍的一系列Descriptor负责提供了控制器,行为方法和参数的元数据,ValueProvieder负责获取数据,剩下 ...