1. 程式人生 > 其它 >【實現】表單控制元件的UI佈局,實現方式

【實現】表單控制元件的UI佈局,實現方式

 一、先說一下表單控制元件要實現的功能吧。

     1、繪製UI,包括表格(Table)的繪製,也就是TR 、TD,TR是多少行,TD是有多少列;包括子控制元件的控制元件,TextBox、DropDownList、CheckBoxList等控制元件的載入、描述(寬度、最大字元數、填充item)等。

     2、提取使用者輸入的資料,拼接引數化的SQL語句,給儲存過程的引數賦值。

     3、把儲存過程的名稱(引數化SQL)、儲存過程的引數,通過“我的資料訪問函式庫”提交給資料庫執行。

     4、在顯示資料和修改資料的時候,可以從資料庫顯示資料進行控制元件繫結。就是顯示資料。

     5、支援兩種儲存資料的方式:引數化SQL和儲存過程。

     6、可以向SQL Server2000、SQL Server2005、Access、Excel資料庫裡新增、修改資料,已測試。

     7、可以向OleDb、ODBC連線的資料庫新增、修改資料,只對Access、Excel進行了測試,沒有測試其他的資料庫。

     8、表格的樣式交給CSS來控制。

     9、可以單列、也可以多列(通過屬性來控制),在“多列”顯示的時候,如果最後一行欄位不夠的話,可以自動補充TD。見圖7。

表單控制元件的有點:

1、自動生成子控制元件(文字框、下拉列表框等) 2、當資料庫的欄位有變化的時候,只需要修改一個地方就可以搞定,不用到許多的地方修改。 3、不用做過多的測試,因為每一個專案、每一個新增、修改的地方都在測試這個控制元件,到最後就可以不用測試了。

     二、說一下表格的繪製,也就是TR TD的處理。可以支援四種顯示方式。

     1、單列。所有的欄位都在“一列”裡面顯示。圖1

     2、多列。 圖2 、 圖3

     3、一個欄位佔多個TD。圖4 、 圖5

     4、多個欄位佔用一個TD。圖6

     5、可以綜合應用。圖8

     圖片演示:

  圖1:“單列”形式的表格

 圖2 :兩列的形式。

 圖3:四列的形式。這個用在查詢的時候,也就是說給查詢控制元件準備的。

 圖4:一個欄位佔用多個TD,居住地區和備註佔了“兩列”,標籤佔用了一個TD,控制元件佔用了三個TD。

 圖5:三列,一個欄位佔用多個TD,居住地區和備註佔了“三列”,標籤佔用了一個TD,控制元件佔用了五個TD。

  圖6:多個欄位擠在一個TD裡面。姓名、性別在一行,籍貫、省、市在一行。性別、省、市前面的空格數量可以控制,也就是說可以控制和前一個控制元件的距離。

  圖7:最後一行只有兩個欄位,還少兩個TD,這個控制元件會自動補充,不會像DataList那樣,少了就不管了。這裡的a、b是測試用,正式的時候會用  替換。

 圖8:綜合應用:“兩列”的表格,省、市兩個欄位擠在一個TD裡面,備註獨佔“兩列”。

 三、根據配置資訊來顯示錶格的程式碼和說明。

     1、配置資訊(描述資訊)

     配置資訊分別放在11個表裡面,分別是表的描述、欄位的描述、模組資訊的描述、列表頁面需要的欄位和描述、表單頁面需要的欄位和描述、查詢功能需要的欄位和描述等。關聯關係如下圖:(這個只是通過檢視來表示一下關係。)

     再來詳細看一下表單控制元件需要的配置資訊。

     這個圖好像有點亂。總之就是根據這些資訊,顯示出來右上角的那個表格的。

     2、BaseColumnsInfo類 和 Dictionary

BaseColumnsInfo的一個例項記錄一個欄位的描述資訊,多個欄位就需要放在Dictionary裡面,我們先寫一個函式用來載入配置資訊。

     然後我們就可以在 CreateChildControls 裡面通過BaseColumnsInfo的資訊來進行表格繪製和載入子控制元件了。

private void aa()
        {
            Dictionary<int, BaseColumnsInfo> dic_BaseCols = new Dictionary<int, GridColumnsInfo>();
            //載入資訊的函式略

            //定義介面,通過介面操作子控制元件
            IGetControlValue iControl = null;
            Control tmpControl = null;      //子控制元件

            BaseColumnsInfo bInfo;

            //開始繪製表格
            this.Controls.Add(new LiteralControl("<Table rules="all" class="css_Form">"));

            Int32 index = 0;        //用於多列的設定

            //遍歷Dictionary,繪製表格
            foreach (KeyValuePair<int, BaseColumnsInfo> info in dic_BaseCols)
            {
                bInfo = (BaseColumnsInfo)info.Value;

                生成需要的子控制元件#region 生成需要的子控制元件
                switch (bInfo.ControlKind)
                {
                    case "201":     //單行文字框
                        tmpControl = new myTextBox(); break;

                    //其他控制元件略

                }
                #endregion

                iControl = (IGetControlValue)tmpControl;        //定義介面,通過介面操作子控制元件
                tmpControl.ID = "c_" + bInfo.ColumnID;         //設定ID
                iControl.ShowMe(bInfo);                         //讓子控制元件自己描繪自己

                顯示欄位#region 顯示欄位
                this.Controls.Add(new LiteralControl("<TR>"));
                this.Controls.Add(new LiteralControl("<TD align="right" width="200px">"));
                this.Controls.Add(new LiteralControl(bInfo.ColName));
                this.Controls.Add(new LiteralControl(":</TD>"));
                this.Controls.Add(new LiteralControl("<TD>"));
                this.Controls.Add(tmpControl);                      //載入子控制元件
                this.Controls.Add(new LiteralControl("</TD>"));
                this.Controls.Add(new LiteralControl("</TR>"));
                #endregion


            }
            this.Controls.Add(new LiteralControl("</Table>"));
        }

     這是一個簡化後的程式碼,只能實現“單列”的表格。這樣寫可以比較清晰的把思路顯示出來。下面的是真正實現多行多列的程式碼,看起來就比較費解了。

protected override void CreateChildControls()
        {
            base.CreateChildControls();
            ShowForm();

            //base.Page.Response.Write(DateTime.Now);
        }

        /**//// <summary>
        /// 繫結資料
        /// </summary>
        public override void DataBind()
        {
            if ((base.Site != null) && base.Site.DesignMode)
            {
                //設計模式,退出
                return;
            }
        }

        顯示錶單#region 顯示錶單
        /**//// <summary>
        /// 顯示錶單
        /// </summary>
        public void ShowForm()
        {
            if ((base.Site != null) && base.Site.DesignMode)
            {
                //設計模式,退出
                return;
            }

            載入配置資訊#region 載入配置資訊
            if (dic_BaseCols == null)
                LoadBaseColumnsInfo();

            //沒有配置資訊,退出
            if (dic_BaseCols == null)
            {
                CommandClass.MsgBox("沒有設定配置資訊", true);
                return;
            }
            #endregion

            //定義介面,通過介面操作子控制元件
            IGetControlValue iControl = null;
            Control tmpControl = null;

            BaseColumnsInfo bInfo;

            //開始繪製表格
            this.Controls.Add(new LiteralControl("<Table rules="all" class="css_Form">"));

            Int32 index = 0;        //用於多列的設定

            //迴圈配置資訊
            foreach (KeyValuePair<int, BaseColumnsInfo> info in dic_BaseCols)
            {
                bInfo = (BaseColumnsInfo)info.Value;

                載入需要的子控制元件,有待完善#region 載入需要的子控制元件,有待完善
                switch (bInfo.ControlKind)
                {
                    case "201":     //單行文字框
                        tmpControl = new myTextBox(); break;

                    case "205":     //下拉列表框
                        //tmpControl = new JYKDropDownList(); 
                        break;

                }
                #endregion

                iControl = (IGetControlValue)tmpControl;        //定義介面,通過介面操作子控制元件
                tmpControl.ID = "c_" + bInfo.ColumnID ;         //設定ID
                iControl.ShowMe(bInfo);                         //讓子控制元件自己描繪自己

                顯示欄位#region 顯示欄位
                SetStartTR(index, bInfo);      //判斷是否顯示<TR>

                //新增到表單控制元件裡
                SetStartTD(bInfo);      //設定開始的TD
                this.Controls.Add(new LiteralControl(bInfo.ColName));
                
                index += SetTDcolspan(bInfo);          //設定中間的TD,一個欄位佔用幾個TD
                this.Controls.Add(tmpControl);
                SetEndTD(bInfo);      //設定結束的TD
                
                SetEndTR(index,bInfo);        //判斷是否顯示</TR> ,有了</TR>就相當於換行了

                #endregion

                index++;

                if (index >= TDColumns) index = 0;

                //iControl.ControlValue = "sss";   //賦值測試

            }

            if (index != 0 && index <= TDColumns - 1)
            {
                //表格不滿需要補充TD
                for (Int32 i = index; i < TDColumns; i++)
                {
                    this.Controls.Add(new LiteralControl("<TD>a</TD>"));
                    this.Controls.Add(new LiteralControl("<TD>b</TD>"));
                }
                this.Controls.Add(new LiteralControl("</TR>"));
            }
            this.Controls.Add(new LiteralControl("</Table>"));

        }
        #endregion

        設定table#region 設定table

        設定開始的TD#region 設定開始的TD
        /**//// <summary>
        /// 設定開始的TD
        /// </summary>
        /// <param name="bInfo">欄位的描述</param>
        private void SetStartTD(BaseColumnsInfo bInfo)
        {
            if (bInfo.clearTDStart > 0)
            {
                //需要合併到上一個TD裡面,不顯示中間的TD
                string s = "&nbsp;";
                for (int i = 1; i < bInfo.clearTDStart; i++)
                    s += "&nbsp;";

                this.Controls.Add(new LiteralControl(s));
            }
            else
            {
                this.Controls.Add(new LiteralControl("<TD align="right" width="200px">"));
            }

        }
        #endregion

        設定結束的TD#region 設定結束的TD
        /**//// <summary>
        /// 設定一個欄位佔用幾個TD
        /// </summary>
        /// <param name="bInfo">欄位的描述</param>
        private void SetEndTD(BaseColumnsInfo bInfo)
        {
            if (bInfo.clearTDEnd > 0)
            {
                //需要合併下面的TD,不顯示結束的TD
            }
            else
            {
                //不需要合併下面的TD,顯示結束的TD
                this.Controls.Add(new LiteralControl("</TD>"));
            }

        }
        #endregion

        設定一個欄位佔用幾個TD#region 設定一個欄位佔用幾個TD
        /**//// <summary>
        /// 設定一個欄位佔用幾個TD
        /// </summary>
        /// <param name="bInfo">欄位的描述</param>
        private Int32 SetTDcolspan(BaseColumnsInfo bInfo)
        {
            if (bInfo.clearTDStart > 0)
            {
                //需要合併到上一個TD裡面,不顯示中間的TD
                this.Controls.Add(new LiteralControl(":"));
                return -1;
            }

            else
            {
                //不合併到上一個TD,顯示中間的TD
                this.Controls.Add(new LiteralControl(":</TD>"));
                if (bInfo.TDColspan >= 2)
                {
                    //判斷一個欄位需要佔用幾個TD
                    this.Controls.Add(new LiteralControl("<TD colspan="" + (bInfo.TDColspan * 2 - 1).ToString() + "">"));
                    return bInfo.TDColspan - 1;
                }
                else
                {
                    this.Controls.Add(new LiteralControl("<TD>"));
                    return 0;
                }
            }
        }
        #endregion

        設定是否顯示開始的 TR#region 設定是否顯示開始的 TR
        /**//// <summary>
        /// 設定是否顯示開始的 TR
        /// </summary>
        /// <param name="index">迴圈的序號</param>
        /// <param name="bInfo">欄位的描述</param>
        private void SetStartTR(Int32 index, BaseColumnsInfo bInfo)
        {
            if (bInfo.clearTDStart > 0)
            {
                //合併到上一個TD,不顯示TR
            }
            else
            {
                if (index == 0)
                    this.Controls.Add(new LiteralControl("<TR>"));
            }
        }
        #endregion

        設定是否顯示結束的 TR#region 設定是否顯示結束的 TR
        /**//// <summary>
        /// 設定是否顯示結束的 TR
        /// </summary>
        /// <param name="index">迴圈的序號</param>
        /// <param name="bInfo">欄位的描述</param>
        private void SetEndTR(Int32 index, BaseColumnsInfo bInfo)
        {
            if (bInfo.clearTDEnd > 0)
            {
                //合併下一個TD,不顯示TR
            }
            else
            {
                if (index == TDColumns - 1)
                    this.Controls.Add(new LiteralControl("</TR>"));
            }
        }
        #endregion

     最後就是獲取使用者輸入的資訊的程式碼,由於採用了介面,所以程式碼就很簡單了。

public void GetInputValue()
        {
            IGetControlValue ControlValue = null;   //取值的介面
            
            BaseColumnsInfo bInfo;  

            string tmpDataValue = "";   //臨時存放資料

            foreach (KeyValuePair<int, BaseColumnsInfo> info in dic_BaseCols)
            {
                bInfo = (BaseColumnsInfo)info.Value;

                ControlValue = (IGetControlValue)this.FindControl("c_" + bInfo.ColumnID);

                tmpDataValue = ControlValue.GetControlValue("1");

                驗證資料是否符合欄位的要求#region 驗證資料是否符合欄位的要求
                #endregion

                bInfo.DataValue = tmpDataValue;
            }
        }

     新增儲存過程的引數的程式碼

private void AddParameter()
        {
            //根據配置資訊新增儲存過程(引數化SQL語句)需要的引數。

            BaseColumnsInfo bInfo;

            dal.LoadParameter();

            foreach (KeyValuePair<int, BaseColumnsInfo> info in dic_BaseCols)
            {
                bInfo = (BaseColumnsInfo)info.Value;

                switch (bInfo.ColType)
                {
                    case "bigint":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, Int64.Parse(bInfo.DataValue));
                        break;

                    case "tinyint":
                    case "smallint":
                    case "int":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName , Int32.Parse(bInfo.DataValue));
                        break;

                    case "uniqueidentifier":
                    case "char":
                    case "nchar":
                    case "varchar":
                    case "nvarchar":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, bInfo.DataValue,bInfo.ColSize);
                        break;

                    case "text":
                    case "ntext":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, bInfo.DataValue);
                        break;

                    case "real":
                    case "float":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, double.Parse(bInfo.DataValue));
                        break;


                    case "numeric":
                    case "smallmoney":
                    case "money":
                    case "decimal":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, decimal.Parse(bInfo.DataValue));
                        break;

                    case "smalldatetime":
                    case "datetime":
                        dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, DateTime.Parse(bInfo.DataValue));
                        break;

                    default :   //
                        //dal.ParameterMgr.AddNewParameter("@" + bInfo.ColSysName, Int32.Parse(bInfo.DataValue));
                        break;
                }
            }
        }