C#編寫第三方控制項,實現表單控制項的一鍵賦值,
、
事出有因
在寫程式的時候,經常會寫上面這樣的代碼,把查詢的結果顯示到表單上,我們怎麼做的呢? 一行一行的進行賦值,這樣的代碼寫起來最枯燥,而且還容易出錯。大家有沒有發現,上面的代碼都在做相同的事情—賦值。相類似的代碼寫了三遍以上,就要考慮是不是能對這個過程進行封裝。封裝出一個方法,幫我們自動完成這些重複性的操作。
思考過程
所接觸項目中也有寫好的類似方法。只是它涉及到了很多其它的方法,一個套一個,抽離出來特別不方便。而且還有幾個令人不爽的地方: 第一是,控制項在命名的時候必須和相對應實體屬性相同。比如說,姓名這一項,實體的屬性名稱為sname,那麼控制項的名稱也必須是sname,顯然這和我們所遵循的一般命名規範是相違背的。第二是,控制項的可見度層級必須設定為Public ,要不然會賦不上值。
所以,在研究完他的方法後,對它重新進行了編寫,做出了一些改進。彌補了上面的兩個缺點,使其應用起來更加方便一些。
所用到的方法,題目中寫提到了。編寫第三方控制項,聽著挺高大上,其實就是對C#原有的控制項,進行重寫,增加一條自己用到的屬性而已。在這裡增加的屬性我將它命名為DataField,用來儲存資料庫欄位的名稱。作用嘛?往下看就知道了。。
筆者在這用C#編寫了一個Demo,用來說明如何編寫第三方控制項以及表單的一鍵賦值。
具體實現過程
建立一個C#項目
添加一個介面 Interface1:
<span style="font-size:18px;"> interface Interface1 { //定義DataField屬性 string DataField { get; set; } }</span>
添加兩個類ComboxEx、ComboxEx:
using System.Windows.Forms; //添加引用 internal class TextBoxEx : TextBox, Interface1 { //該類繼承TextBox控制項和介面Interface1 #region Interface1 成員 public string DataField { get; set; } #endregion } internal class ComboxEx : ComboBox, Interface1 { #region Interface1 成員 public string DataField { get; set; } #endregion }
然後開啟工具箱,我們會看到:
這就是我們封裝的第三方控制項。把它拖到表單上,右擊查看其屬性
它多了一條DataField屬性,我們可以給他賦上值SID(學生表的欄位名—學號)同樣再拖拽出幾個控制項並且賦值。
然後開始正式編寫代碼,添加一個實體類StuEntity:
注意:實體屬性的名稱要和資料庫欄位名稱保持一致!
public class StuEntity { /// <summary> /// 學號 /// </summary> public string SID { get; set; } /// <summary> /// 姓名 /// </summary> public string sname { get; set; } /// <summary> /// 性別 /// </summary> public string sex { get; set; } /// <summary> /// 系別 /// </summary> public string department { get; set; } /// <summary> /// 年級 /// </summary> public string grade { get; set; } /// <summary> /// 班級 /// </summary> public string sclass { get; set; } }
需要說明的一點:這隻是一個小Demo並沒有採用分層的寫法,把編寫的方法全部放在了FrmHelper類中
public class FrmHelper { /// <summary> /// 擷取實體,將DataTable的行賦值給實體類enStudent /// 這裡可以採用機房中封裝好的方法,將DataTable轉換 /// 成實體類的泛型集合,可以省去這些賦值。 /// </summary> /// <param name="dr">DataTable的行</param> /// <returns>返回實體類enStudent</returns> public static StuEntity GetEntity(DataRow dr) { StuEntity enStudent = new StuEntity(); enStudent.SID = dr["SID"].ToString(); enStudent.sname = dr["sname"].ToString(); enStudent.sex = dr["sex"].ToString(); enStudent.department = dr["department"].ToString(); enStudent.grade = dr["grade"].ToString(); enStudent.sclass = dr["sclass"].ToString(); return enStudent; } /// <summary> /// 將實體類中屬性的值,填充到表單的控制項上 /// </summary> /// <param name="enStudent"></param> public static void FillFormByEntity(StuEntity enStudent, Form thisfrm) { //遍曆表單上的控制項 foreach (Control ctrl in thisfrm.Controls) { //是否繼承了介面 if (ctrl is Interface1) { //是否屬於文字框 if (ctrl is TextBoxEx) { ctrl.Text = GetValue(enStudent, ((TextBoxEx)ctrl).DataField); }//如果屬於下拉框 else if (ctrl is ComboxEx) { ((ComboxEx)ctrl).Text = GetValue(enStudent, ((ComboxEx)ctrl).DataField); } //如果還有其他類型的控制項,可在此進行擴充。 } } } /// <summary> /// 利用反射技術,動態從實體中擷取與控制項相對應的值 /// </summary> /// <param name="enStudent">實體類</param> /// <param name="DataFiled">欄位值</param> /// <returns></returns> public static string GetValue(StuEntity enStudent, string DataFiled) { PropertyInfo field = enStudent.GetType().GetProperty(DataFiled); return field.GetValue(enStudent, null).ToString(); } /// <summary> /// 執行查詢語句,返回一個DateTable /// </summary> /// <returns>DateTable</returns> public static DataTable QueryTable() { using (SqlConnection connection = new SqlConnection("server=.; database=Re_Charge_sys;user id=sa;password=123456")) { SqlCommand cmd = connection.CreateCommand(); cmd.CommandText = @"select * from Student_info where SID ='110'"; DataTable dt = new DataTable(); DataSet ds = new DataSet(); try { connection.Open(); SqlDataAdapter sqlAdapter = new SqlDataAdapter(cmd); sqlAdapter.Fill(ds); dt = ds.Tables[0]; } catch (System.Data.SqlClient.SqlException ex) { throw new Exception(ex.Message); } return dt; } } }
用戶端調用:
private void btnFillValue_Click(object sender, EventArgs e) { DataTable dt = FrmHelper.QueryTable(); StuEntity enStudent = FrmHelper.GetEntity(dt.Rows[0]); FrmHelper.FillFormByEntity(enStudent, this); } private void Form1_Load(object sender, EventArgs e) { cmbGrade.Items.AddRange(new String[] { "一年級", "二年級", "三年級", "四年級" }); cmbSex.Items.AddRange(new String[] { "男", "女" }); //cmbSex.Items.Add(new KeyValuePair<string, string>("男", "男")); //cmbSex.Items.Add(new KeyValuePair<string, string>("女", "女")); //cmbSex.DisplayMember = "Key"; //cmbSex.ValueMember = "Value"; }
點擊賦值按鈕,從資料庫讀取出的資料就會自動填寫到介面控制項當中。
談談第三方控制項
當然通過這種方法也能增加其他的屬性,比如NotEmpty ,把判斷是否為空白的方法寫在介面裡,然後讓控制項去繼承。通過設定該屬性的值為 True / False 決定控制項內容是否可為空白。通過這種方式就避免再去寫方法去一個個判斷,省時省力。說到這裡我不得不感歎一下了:站在巨人的肩膀上。 其實現在互連網上已經有很多已經封裝好的,強大的第三方控制項。比如說現在所用的C1Studio,對常用控制項進行了封裝,增加很多特別方便實用的屬性,
不得不說第三方控制項現在挺吃香的,因為他給原來死的控制項增加了生命力和色彩。
寫在最後:
做程式員或者說做人,不能太實在、按部就班。
要多思考,多去尋找能“偷懶”的方法。
時刻想著,站在巨人的肩膀上。
給表單控制項賦值就寫到這裡,當然有賦值就有取值,將控制項的值賦給實體,傳到資料訪問層再進行操作。也是MIS系統中經常用到的。方法和賦值類似,具體代碼將在下篇部落格中呈現給大家。
oノo════════════════════════════╲
│ヽ.學無止境, 分享至上。 │
│ 出自: http://blog.csdn.net/u010028869 .ヽ│
╲═════════════════════════════ヾ
C語言中->是什?
->是一個整體,它是用於指向結構體、C++中的class等含有子資料的指標用來取子資料。換種說法,如果我們在C語言中定義了一個結構體,然後申明一個指標指向這個結構體,那麼我們要用指標取出結構體中的資料,就要用到“->”.
舉個例子:
struct Data
{
int a,b,c;
}; /*定義結構體*/
struct Data * p;/*定義結構體指標*/
struct Data A = {1,2,3};/*聲明變數A*/
int x;/*聲明一個變數x*/
p = &A ; /*讓p指向A*/
x = p->a;/*這句話的意思就是取出p所指向的結構體中包含的資料項目a賦值給x*/
/*由於此時p指向A,因而 p->a == A.a,也就是1*/
對於一開始的問題 p = p->next;這應該出現在C語言的鏈表,這裡的next應該是一個與p同類型的結構體指標,其定義格式應該是:
struct Data
{
int a;
struct Data * next;
};/*定義結構體*/
…………
main()
{
struct Data * p;/*聲明指標變數p*/
……
p = p->next;/*將next中的值賦給p*/
}
鏈表指標是C語言的一個痛點,但也是重點,學懂了非常有用。要仔細講就必須先講變數、指標。
什麼是變數?所謂變數,不要淺顯的認為會變得量就是變數。套用我們院長的問話:“教室變不變?”變,因為每天有不同的人在裡面上課,但又不變,因為教室始終在那,沒有變大或變小。這就是變數:有一個不變的地址和一塊可變的儲存空間。正常情況下,我們只看到變數這個房間裡面的東西,也就是其內容,但不會關注變數的地址,但是C語言的指標,就是這個房間的地址。我們聲明變數就相當於蓋了間房子存放東西,我們可以直接觀看房子裡的東西,而聲明指標,就是相當於獲得了一個定位器,當用指標指向某個變數時,就是用指標給變數定位,以後我們就可以用指標找到他所“跟蹤”的變數並可以獲得裡面的內容。
那結構體呢?結構體就相當於是有好幾個房子組成的別墅,幾個房子綁定在一起使用。假設現在有很多這種別墅分布在一個大迷宮裡,每間別墅裡都有一間房子。裡面放了另一個別墅的位置資訊,現在你手拿定位器找到了第一棟別墅,從裡面得到了你想要的東西(鏈表的資料部分),然後把下一棟別墅的位置計入你的定位器(p = p->next),再走向下一棟別墅……如此走下去,知道走到某地下一棟別墅資訊沒有了(p->next == NULL),你的旅行結束。這就是鏈表一次遍曆的過程。現在你能明白 p=p->next的含義了吧!
寫了這麼多。希望你能明白。
如果想學好c和C++,鏈表和指標必須熟練掌握!
C語言中->是什?
->是一個整體,它是用於指向結構體、C++中的class等含有子資料的指標用來取子資料。換種說法,如果我們在C語言中定義了一個結構體,然後申明一個指標指向這個結構體,那麼我們要用指標取出結構體中的資料,就要用到“->”.
舉個例子:
struct Data
{
int a,b,c;
}; /*定義結構體*/
struct Data * p;/*定義結構體指標*/
struct Data A = {1,2,3};/*聲明變數A*/
int x;/*聲明一個變數x*/
p = &A ; /*讓p指向A*/
x = p->a;/*這句話的意思就是取出p所指向的結構體中包含的資料項目a賦值給x*/
/*由於此時p指向A,因而 p->a == A.a,也就是1*/
對於一開始的問題 p = p->next;這應該出現在C語言的鏈表,這裡的next應該是一個與p同類型的結構體指標,其定義格式應該是:
struct Data
{
int a;
struct Data * next;
};/*定義結構體*/
…………
main()
{
struct Data * p;/*聲明指標變數p*/
……
p = p->next;/*將next中的值賦給p*/
}
鏈表指標是C語言的一個痛點,但也是重點,學懂了非常有用。要仔細講就必須先講變數、指標。
什麼是變數?所謂變數,不要淺顯的認為會變得量就是變數。套用我們院長的問話:“教室變不變?”變,因為每天有不同的人在裡面上課,但又不變,因為教室始終在那,沒有變大或變小。這就是變數:有一個不變的地址和一塊可變的儲存空間。正常情況下,我們只看到變數這個房間裡面的東西,也就是其內容,但不會關注變數的地址,但是C語言的指標,就是這個房間的地址。我們聲明變數就相當於蓋了間房子存放東西,我們可以直接觀看房子裡的東西,而聲明指標,就是相當於獲得了一個定位器,當用指標指向某個變數時,就是用指標給變數定位,以後我們就可以用指標找到他所“跟蹤”的變數並可以獲得裡面的內容。
那結構體呢?結構體就相當於是有好幾個房子組成的別墅,幾個房子綁定在一起使用。假設現在有很多這種別墅分布在一個大迷宮裡,每間別墅裡都有一間房子。裡面放了另一個別墅的位置資訊,現在你手拿定位器找到了第一棟別墅,從裡面得到了你想要的東西(鏈表的資料部分),然後把下一棟別墅的位置計入你的定位器(p = p->next),再走向下一棟別墅……如此走下去,知道走到某地下一棟別墅資訊沒有了(p->next == NULL),你的旅行結束。這就是鏈表一次遍曆的過程。現在你能明白 p=p->next的含義了吧!
寫了這麼多。希望你能明白。
如果想學好c和C++,鏈表和指標必須熟練掌握!