金色海洋工作室

——自然框架,自然而然,快速开发、快速修改!

 

能自己“跑”的表单控件,思路,雏形,源码。vs2005版本


下载地址
 http://www.cnblogs.com/jyk/archive/2008/07/29/1255891.html

大家是怎么处理CRUD的呢?

这里说一下添加、修改数据。

    一大堆的表,n多的字段,经常变化的表现形式(比如文本框换成下拉列表框等),是不是很头痛?反正我是很烦的,因为我太懒了,对于这种不是太重要的,但是有很繁琐的东东,我总是要向出来一种“简单”的方式来处理。

    怎么办?表单控件,我还一直使用VS2003,没有VS2005里面的表单控件,所以只好自己写了,另外好像VS2005里面的表单控件使用的也不是很多。

    我的表单控件要做的事情:

    1、自己描绘控件,比如能够自己添加文本框、下拉列表框这一类的控件。
    2、可以自己获取用户输入的信息,进行验证(前台的js验证和后台的数据的类型是否符合子段类型的验证),组合SQL语句或者调用存储过程来添加、修改数据。
    3、在修改数据的时候,可以从数据库里提取数据,填充到对应的控件里。

    这个好像和05的表单控件差不多,不过有两个明显的区别。

    1、05的需要另外设置文本框这样的控件。
    2、使用DataSource这一类的控件来保存关联信息,而这些信息都是通过属性的方式设置,而且默认情况下是放在了aspx文件里面了。

    对于第一点呢,操作繁琐,当然也是很灵活;第二点嘛,就不好了。一两个页面的话,还好办,如果有100个这样的页面的话,那管理就是一个问题了。

    那么怎么实现我想要的效果呢,我采用自定义控件的方式来实现。

    1、先定义一个结构(好像也可以使用类)。
    2、根据属性添加子控件,也就是具体的控件(比如文本框、下拉列表框等)。
    3、取值,保存数据。
    4、修改的时候显示数据。

    [具体实现]
    1、先定义一个结构(好像也可以使用类)。
[Serializable()] public struct ControlInfos
    
{
        
/// <summary>
        
/// 字段名称
        
/// </summary>

        public string ColSysName;   

        
/// <summary>
        
/// 中文名称
        
/// </summary>

        public string ColName;
        
        
/// <summary>
        
/// 控件类别
        
/// </summary>

        public string ControlKind;
        
        
/// <summary>
        
/// 描述信息
        
/// </summary>

        public string ColInfo;

    }

    2、根据属性添加子控件,也就是具体的控件(比如文本框、下拉列表框等)。
 protected override void CreateChildControls()
        
{
            
base.CreateChildControls();
            ShowData();
        }

 
public string ShowData()
        
{
            
foreach (ControlInfos info in this.CtrlInfo)
            
{
                
switch (info.ControlKind)
                
{
                    
case "201":     //单行文本框
                        TextBox txt = new TextBox();
                        txt.ID 
= "c_" + info.ColSysName ;
                        
this.Controls.Add(new LiteralControl(info.ColName ));
                        
this.Controls.Add(txt);
                        
this.Controls.Add(new LiteralControl("<BR>"));
                        
break;

                    
case "205":     //下拉列表框
                        DropDownList lst = new DropDownList();
                        lst.ID 
= "c_" + info.ColSysName;
                        
//lst.Items.Clear();
                        lst.Items.Add(new ListItem("测试项目1""1"));
                        lst.Items.Add(
new ListItem("测试项目2""2"));
                       
                        
this.Controls.Add(new LiteralControl(info.ColName));
                        
this.Controls.Add(lst);
                        
this.Controls.Add(new LiteralControl("<BR>"));
                        
break;

                }

            }


            
return "";

        }

    3、取值,保存数据。
public string SaveDate()
        
{
            
//调用数据访问函数库来保存数据
            ControlInfos[] info = this.CtrlInfo;

            
string[] str1 = new string[info.Length];
            
string[] str = new string[info.Length];
            
for (int i = 0; i < info.Length; i++)
            
{
                str1[i] 
= info[i].ColSysName;

                
switch (info[i].ControlKind)
                
{
                    
case "201":
                        TextBox txt 
= new TextBox();
                        txt 
= (TextBox)this.FindControl("c_" + info[i].ColSysName);
                        str[i] 
= txt.Text.Trim().Replace("'","");
                        
break;

                    
case "205":
                        DropDownList lst 
= new DropDownList();
                        lst 
= (DropDownList)this.FindControl("c_" + info[i].ColSysName);
                        str[i] 
= lst.SelectedValue ;
                        
break;
                }

            }


            
//测试输出
            for (int i = 0; i < info.Length; i++)
            
{
                
base.Page.Response.Write(str1[i]);
                
base.Page.Response.Write(":");
                
base.Page.Response.Write(str[i]);
                
base.Page.Response.Write("<BR>");

            }


            
return "";

        }

    4、修改的时候显示数据。
        这个部分还没有写呢,不过也是类似的方法。
    5、调用。
protected void Page_Load(object sender, EventArgs e)
    
{
        Response.Cache.SetNoStore();

        
//设置控件的属性
        if (!Page.IsPostBack)
        
{
            ControlInfos[] info 
= new ControlInfos[2];
            info[
0].ColSysName = "NewsName";
            info[
0].ColName = "新闻标题";
            info[
0].ControlKind = "201";

            info[
1].ColSysName = "NewsKind";
            info[
1].ColName = "新闻分类";
            info[
1].ControlKind = "205";

            
this.myForm.CtrlInfo = info;
        }

    }


    
protected void Button1_Click(object sender, EventArgs e)
    
{
        myForm.SaveDate();
    }


    缺点。说到缺点嘛,由于这里只是一个雏形,所以缺点是很多的,但是这里写的就是一个“核心”代码,关键代码都在这里面。其他的就是在这个基础上去完善、扩展、优化和美化 。

    1、case 。对控件判断的地方使用了case ,目前也没有其他的更好的方法。
    2、case 里面的代码。这里只是两种控件,最简单的代码,就已经好几行了,多了就不可想象了。虽然case 没有什么办法解决,但是case 里的代码,可以使用接口的方式来分散开。
        就是定义一个接口,在继承系统的控件(比如文本框)实现这个接口,然后表单控件里case的代码就可以简化很多了。
    3、调用的时候需要设置一个结构数组,这个是很烦的,代码行数也是很多的,好像还没有直接设置控件(文本框等)来得方便。对于这一点,我是把这些属性放在了一个配置文件(xml或者数据库)里面,然后在表单控件内部读取属性,自己就可以幅值了,外部只需要设置一个“编号”就可以了(告诉控件读取哪些信息)。


posted on 2008-05-25 17:32 金色海洋(jyk)阳光男孩 阅读(6740) 评论(40) 编辑 收藏

评论

#1楼 2008-05-25 19:02 怪怪      

不用case, 用字典存储“ControlKind”和相应过程之间的对应关系就可以了。


 回复 引用 查看   

#2楼 2008-05-25 19:27 大大的[未注册用户]

不错  回复 引用   

#3楼 2008-05-25 19:33 皇帝的新装      

是个思路  回复 引用 查看   

#4楼[楼主] 2008-05-25 19:45 金色海洋(jyk)      

对了,可以说是第一次使用vs2005来写程序,一直是使用vs2003来着,所以对一05里面的新下技术不太熟悉。

还想问一个问题,我现在用的是结构数组,换成类的话,哪个效率更高一点。
 回复 引用 查看   

#5楼 2008-05-25 19:53 kiler      

利用数据库表结构生成asp.net页面代码和后台代码。
更灵活,以后想怎么改就怎么改,做成这种动态控件的形式,有点死,用户要求一点特殊方式的输入方式就适应不了。
 回复 引用 查看   

#6楼 2008-05-25 19:55 kiler      

@金色海洋(jyk)
结构数组改成泛型数组
ControlInfos[] info
List<ControlInfos> list = new List<ControlInfos>()
 回复 引用 查看   

#7楼[楼主] 2008-05-25 20:01 金色海洋(jyk)      

@kiler
因为一直在使用vs2003,范型一直没有研究。
泛型数组 就是一种类的集合吧。

List<ControlInfos> 这里面的 ControlInfos 是结构还是类?

我最关心的是在范型内部,是否可以使用 T 的的具体的属性?


数据库表结构里面没有对控件的描述,我不知道使用什么控件,所以才要加一写描述信息。

对于一些特殊要求,可以变成一个子控件,加进去。

 回复 引用 查看   

#8楼 2008-05-25 20:22 kiler      

@金色海洋(jyk)
刚才写错了应该是泛型集合不是泛型数组。
ControlInfos是类的类型
你说的泛型内部是什么啊
 回复 引用 查看   

#9楼[楼主] 2008-05-25 20:47 金色海洋(jyk)      

就是说我好像可以这么写

public class aa
{
public void AddControls<T>(T t)
{
t.ColSysName = "1";
}
}

这里的t,就不能写具体的属性或者函数。可能是我对范型的理解不对吧。

我想达到的效果是这样的

public void myBind<T>(T t)
{
...
//获取记录集,然后绑定控件,控件有外部传入,比如DataGrid、DataList等。
t.DataSource = myDataTable;
t.DataBind();
}

这个是不行的,不知道有没有其他的方法,我想在分页控件件里使用。

如果使用vb.net的话,可以这么写

Public Sub myBind(ByVal obj As Object)
...
'获取记录集,然后绑定控件,控件有外部传入,比如DataGrid、DataList等。
obj.datasource = myDataTable
obj.databind()

End Sub

编译是可以通过的。只要在运行的时候传递进来的对象拥有 datasource和databind() 就可以正确运行。

这个是我一直很郁闷的,不知道改成c#要怎么写?
 回复 引用 查看   

#10楼 2008-05-25 20:58 魔兽RPG地图联盟[未注册用户]

有点意思  回复 引用   

#11楼 2008-05-25 21:20 私家侦探      

照你这么搞的话美工都不用干活了,
其实用代码生成工具可以实现懒人的梦想,包括界面代码,比如李天平的代码生成工具
,还能自己写插件扩展它,很方便的
 回复 引用 查看   

#12楼 2008-05-25 21:21 kiler      

@金色海洋(jyk)
你那样写是不行的


这么写也许行 public void AddControls<T>(T t) where T : baseT
{
t.ColSysName = "1";
}

baseT为一接口或者抽象类
里面有ColSysName 属性
 回复 引用 查看   

#13楼[楼主] 2008-05-26 08:31 金色海洋(jyk)      

和美工是不冲突的,这个实用在后台管理、OA这方面的,至于网站的前台页面是不适用的。

代码生成器,生成的代码如何维护呢?不要告诉我,生成的代码永远都不会变了。

我不是发明重复的轮子,我是发明更好用的轮子。

 回复 引用 查看   

#14楼 2008-05-26 08:44 横刀天笑      

可能你写的实例代码太简单了,我有几个疑问:
第一:生成的界面如何控制了?你这完全是cs生成界面代码
第二:你这就处理了三种类型的控件,要是十几种呢,那里的case不像意大利面条一样?如何维护,如何扩展?有了新的控件需要添加进来我该怎么办?

如果你真的要这样干何不使用asp?我想能更好的满足你的需求
 回复 引用 查看   

#15楼[楼主] 2008-05-26 08:48 金色海洋(jyk)      

@横刀天笑
你说的这些我都是我要解决的呀。
asp 不能保存状态,不能写自定义控件。或者说根本就没有控件的概念。
 回复 引用 查看   

#16楼 2008-05-26 09:19 横刀天笑      

如果用cs生成前台界面代码,我很难想象是什么结果,为什么不考虑使用一些框架?使用模板引擎也很灵活,或者使用代码生成器,这种重复劳动就交给代码生成器吧。或者做几个codesmith模板,需求改变的时候运行一下就ok了

asp里面是没有viewstate,不过要自己实现一个也不是很困难,asp里面虽然没有控件的概念不过可以实现控件的样子,我说使用asp纯粹是开玩笑的,只是看了LZ的代码回忆起那个年代
 回复 引用 查看   

#17楼 2008-05-26 09:43 zzticzh2[未注册用户]

不错 支持一下。
发现个错误 顺便提醒一下 “自己就可以幅值了”
 回复 引用   

#18楼 2008-05-26 10:33 airwolf2026      

哈哈.楼主总算换了模板  回复 引用 查看   

#19楼 2008-05-26 11:21 紫色阴影      

一个factory加多个strategy就可以避免case了
我前段时间做了一个infopath控件生成,用的NVelocity,比较方便,而且UI也容易修改
 回复 引用 查看   

#20楼 2008-05-26 11:41 chiaovincent[未注册用户]

以前也做过这方面的东西
最难解决的就是 表单内部元素间的计算关系
比如
订货金额=订户单价×订货数量
计算去税金额 因为税率的不同 计算公式又不相同

不过处理简单的CRUD操作还是挺方便的
 回复 引用   

#21楼 2008-05-26 18:32 rex xiang      

针对你的代码,我认为这样的结构比较好,嘿嘿.

//---------------------------------------------------------------
public class DataItem{
public string DisplayName;
public string ColumnName; //
public ControlType ControlType;
public object Value;
public string Discription;
}

public enum ControlType{
Textbox,
DropDownList,
...
...
}

private static Dictionary controlManagers; //也可以是Hashtable.

private static void InitControlManagers(){
controlManagers = new Dictionary();

controlManagers.Add(ControlType.Textbox, new TextboxManager());
controlManagers.Add(ControlType.DropDownList, new DropDownListManager());
...
}

//
public interface ControlManager{
Control Create(DataItem dataItem);
object GetValue(DataItem dataItem);
}

public class TextboxManager: ControlManager{
public Control Create(DataItem dataItem){
TextBox textbox = new TextBox();
textbox.Text = dataItem.Value.ToString();
textbox.Name = dataItem.ColumnName; //
return textbox;
}

public object GetValue(DataItem dataItem){
... // get control value by dataItem.ColumnName
return ...;
}
}

public class DropDownListManager: ControlManager{
public Control Create(DataItem dataItem){
DropDownList ddl = new DropDownList();
...
return ddl;
}
}

//---------------------------------------------------------------



//----------------- 页面调用显示的时候 ---------------------
public void ShowData(DataItem[] dataItems){
foreach(DataItem item in dataItems){
if(controlManagers.ContainsKey(item.ControlType)){
Control ctl = controlManagers[item.ControlType].Create(item);
this.Controls.Add(ctl);
}
}

}

public void GetDatas(DataItem[] dataItems){

foreach(DataItem item in dataItems){
if(controlManagers.ContainsKey(item.ControlType)){
object value = controlManagers[item.ControlType].GetValue(item);
...
...
}
}
}
 回复 引用 查看   

#22楼 2008-05-26 21:24 菜菜灰      

提出一点问题,没有办法对控件的布局进行样式控制,这里好像只能固定的格式,不方便维护。  回复 引用 查看   

#23楼 2008-05-29 22:50 江水滔滔      

看你的東西真能讓人極髮寫代碼的情緒

如果我們公司現在的模式能做成一個通用的.如果可以有多人討論.

興趣是最好的朋友.

加油!你的思路,我也在想!只是有些蒙懂.多謝你的思維!

你的思路肯定因為做多了太重複的事情.就和我現在做的一樣!
 回复 引用 查看   

#24楼[楼主] 2008-06-12 20:51 金色海洋(jyk)      

我很懒,我没有做什么重复的事情,因为我在作第二次(也许是第三次)的时候就在想偷懒的方法了。所以重复的事情做得不是太多。  回复 引用 查看   

#25楼 2008-09-30 15:52 clefoo      

这里有个问题,就是生成出的控件位置摆放  回复 引用 查看   

#26楼 2008-12-05 14:48 relax      

呵。喜欢楼主的帖子。

以前我在ASP中做过类似的功能。

也就是自动生成表单,我们有自己的叫法“屏幕配置”

大概总的结构是这样的:系统 -> 模块 -> 屏幕 -> 表(视图) -> 字段

就是将表或者视图的一些基本信息配置一下然后就能自动生成程序界面

生成的基本界面包括:录入、修改、查询、EXCEL导入/导出、审核、反审核等基本功能。

业务逻辑再通过特殊的接口添加进去。

刚刚完成的时候很兴奋,例如我想屏蔽页面上某些字段直接在“屏幕配置”表里将该字段的isView从 1 改成 0 就OK了。权限也能通过“屏幕配置信息表”进行管理。

我几年前做的几个项目用这样的原理,那些系统现在还有人在用,发现一些小问题现在自己都不愿意去维护了……
 回复 引用 查看   

#27楼[楼主] 2008-12-11 14:13 金色海洋(jyk)      

@relax
你能用asp就做到这些,真是太厉害了。
我还只能依靠asp.net的强大的控件功能,来做到这些。
 回复 引用 查看   

#28楼 2008-12-15 08:57 heyuyun[未注册用户]

@金色海洋(jyk)
感觉C#好难啊!啥也看不懂!这周还在搞实训!!今天就是做什么名片查询@##¥%% 啥也不懂啦!!!!
 回复 引用   

#29楼 2008-12-18 08:33 Astar      

支持,我想做一个了。  回复 引用 查看   

#30楼 2009-06-02 15:21 彦斌      

楼主.下载地址那边好像找不到下载文件.  回复 引用 查看   

#31楼[楼主] 2009-06-02 19:21 金色海洋(jyk)      

http://www.cnblogs.com/jyk/archive/2008/07/29/1255891.html
这是新的下载地址,谢谢提醒,已经修改。
 回复 引用 查看   

#32楼 2009-06-17 09:15 rgqancy      

大哥,sharepoint不知道你了解过吗?偶觉得和你的思路有点像啊。只是猜测。  回复 引用 查看   

#33楼[楼主] 2009-06-17 10:01 金色海洋(jyk)      

@rgqancy

sharepoint还没听说过,不过这一方面的,基本思想都差不多。大同小异,只是实现方式上会有比较大的差别。
 回复 引用 查看   

#34楼 2009-08-28 12:12 亚历山大同志      

应该加上一个条件就是在MIS系统很好用,但是在某些条件下是不适用的,罗列出最适用的场景好方便大家选择  回复 引用 查看   

#35楼 2009-09-08 22:49 Crazy20090908[未注册用户]

搞个设计器;
按你的思路设计数据定义,将这个定义保存成XML(数据库表可以从这里生成)
根据B/S或者是C/S需求,按数据定义生成画面定义数据
比如:B/S的可以生成Html文件,

有点MVC

拙见
 回复 引用   

#36楼 2009-09-09 16:41 HOHOHAHA[未注册用户]

引用Crazy20090908:
搞个设计器;
按你的思路设计数据定义,将这个定义保存成XML(数据库表可以从这里生成)
根据B/S或者是C/S需求,按数据定义生成画面定义数据
比如:B/S的可以生成Html文件,

有点MVC

拙见



赞同, 配置界面的时候只需要改文件配置就行了。。不过首先界面要进行布局。  回复 引用   

#37楼 2009-09-16 12:33 xiaosuo      

赞同楼主的想法  回复 引用 查看   

#38楼 2009-12-12 10:27 iSun自由软件团件      

SaveDate?SaveData!  回复 引用 查看   

#39楼 2010-01-27 10:43 Allen Zhang      

维护一大堆表单确实很烦,楼主的方法我也想过,
只是这样的方法,表单只能一行一个控件,UI上没办法控制,最好是能做到控件位置在Web界面上直接拖拉定位,这方法我已经有一些想法,但还没时间去实现出来。
还有,比如下拉列表,怎么去初始化控件的值?
有的下拉列表选项是固定的,而有的取值于另一个数据表,楼主可以讨论一下。
 回复 引用 查看   

#40楼[楼主] 2010-01-27 17:49 金色海洋(jyk)      

也是可以一行多个控件的呀,并不是不可以解决的,只是没有想到方法,想到方法就可以解决了。

下拉列表框的问题,早就解决了,没有什么问题的。
 回复 引用 查看   

导航

统计

公告



昵称:金色海洋(jyk)阳光男孩
园龄:5年6个月
荣誉:推荐博客
粉丝:367
关注:130

随笔分类(337)

最新评论