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 ...
随机推荐
- Linux快速入门01-基础概念
4年多前,刚到上海时报过一个关于Oracle的培训班,在那里接触到了Linux,不过一直都没真正去试着使用它.现在经过慢慢的成长,越来越觉得,Linux是每一个服务端工程师必须掌握的系统,即使是现在最 ...
- 面试小记---外部脚本必须包含 <script> 标签吗?
外部脚本必须包含 <script> 标签吗? 答案是否定的. 身为小白的我一开始也是以为这句话的对了,因为本来嘛,引用外部脚本不都用的是<script>标签中的src属性吗.所 ...
- java 显示透明背景png图片
首先理由ps生成一个背景透明的png图片,然后设置JPanel面板的透明属性,也就是panel.setOpaque(false);设置为透明 class MyPanel extends JLayere ...
- NYOJ995硬币找零(简单dp)
/* 题意:给你不同面额的硬币(每种硬币无限多),需要找零的面值是T,用这些硬币进行找零, 如果T恰好能被找零,输出最少需要的硬币的数目!否则请输出剩下钱数最少的找零方案中的最少硬币数! 思路:转换成 ...
- 【原创】C#搭建足球赛事资料库与预测平台(6) 赔率数据表设计2
本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新 开源C#彩票数据资料库系列文章总目录:[目录]C#搭建足球赛事资料库与预测平台与彩票数据分析目录 本篇文章开始将逐步介 ...
- SWFUpload简介及中文参考手册(share)
SWFUpload SWFUpload 版本 2 概览 (Overview) 入门( Getting Started) js对象 (SWFUpload JavaScript Object) 构造器(C ...
- node.js + mongodb 做项目的详解(一)
想写博客很长时间了,因为一直身患懒癌,所以一直拖到了现在.markdown的语法也是刚刚学,试验一下效果好了不说了,直接上干货了.----------------------------------- ...
- 参与github上开源项目的大致流程和注意事项
Foreword github是一个很火的代码托管服务网站,可能好多人都想参与一两个项目玩一玩学习一下,但由于是纯英文的网站,可能又会止步于想法上没有动手实践.接下来我就介绍一下参与github上开源 ...
- PHP 中的Closure
PHP 中的Closure Closure,匿名函数,又称为Anonymous functions,是php5.3的时候引入的.匿名函数就是没有定义名字的函数.这点牢牢记住就能理解匿名函数的定义了. ...
- 前端构建:Source Maps详解
一.前言 当使用CoffeeScript.ClojureScript编写前端脚本时,当使用Less.Sacc编写样式规则时,是否觉得调试时无法准确找到源码位置呢?当使用jquery.min.js等经压 ...