【實現】表單控制元件的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 = " ";
for (int i = 1; i < bInfo.clearTDStart; i++)
s += " ";
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;
}
}
}