本文轉自http://www.cnblogs.com/chf/archive/2009/07/07/1518742.html
園子裡的大蝦們總是討論System.Web的控制項,大多數以Web的使用者自訂控制項為主,卻很少有人寫些關於Windows.Forms的使用者控制項或者自訂控制項,原因大概是都開發web的,相比之下Windows.Forms的自訂控制項的介面難繪製。誒,想起去年為了實現一個Winform程式,自己琢磨使用者控制項在院子裡連點資料都找不到。。。
首先聲明,我封裝的是Windows.Forms的使用者控制項,不是自訂控制項。至於為什麼寫使用者控制項而不是自訂控制項,我相信大家都知道使用者控制項只要繼承UserControl即可,拖拽幾個Win內建的控制項進來寫幾句即可。我寫使用者控制項的目的是為了提高開發效率,同時為了美觀統一,所以介面效果自然是沒有控制項商的產品漂亮。
當然,最後是有原始碼下載,先上幾張圖圖。
圖1 標題文字框
圖2 快顯視窗
圖3 分頁表格
圖4 下拉樹
怎麼開發使用者控制項很簡單,不做介紹,寫這篇文章是想向大家介紹一下思想。
通常我們寫應用程式的時候,都會出現那種資訊錄入介面,就像是“標題然後後面緊接著加一個文字框”(見圖1),像福士設計的話,肯定是拖拽兩個控制項進來,一個是Label,一個是TextBox,然後布局一下。其實很多時候我們只用到了簡單的一個文字框內容的讀取以及一個文本標題的顯示,所以很多情況下我們就可以把這兩個合并成一個帶標題的文字框使用者控制項,這樣就能節省更多的開發時間了。當然還有其他更多的好處就不在這裡作過多介紹,讀者請看代碼自去體會。
以上只是一個非常簡單的場合,介紹一個比較複雜點的場合吧。寫應用程式的同志們肯定會遇到那種需要快顯視窗進行選擇某條記錄然後返回到主視窗來進行繼續操作的時候(見圖2),若像普通設計的話,我們每個這種場合都需要設計同樣的工作,所以為了節省工作量,我把這個封裝了,為了能讓快顯視窗和主視窗進行通訊,我定義了介面並且定義了參數。當然這樣是有點局限性,但是能解決很大部分情況。可能大家會問,不會那麼簡單吧,實際上是不簡單,但是只要按照約定進行開發就容易了。
被快顯視窗需要繼承的介面(用來觸發選擇動作以及傳遞參數使用,PS:實際改成委託更好點,好像其他控制項有這麼做)
public interface ISelectButtons
{
DialogValue MyDialogValue { get; set; }
void SetSelect();
}
彈出主視窗需要將控制項MyTextBoxButtonSelect拖拽進來,並設定相關參數,注意一下重要參數:
string DialogAssemblyName,被快顯視窗的命名空間。(為反射作準備)
string DialogAddForm,若建立,被彈出的視窗類別名。(為了統一快顯視窗的介面風格,故定義了MyForm使用者控制項,其他所有與內容相關的都定義成了功能性使用者控制項)
string DialogAddUserControl,若建立,被彈出的使用者控制項類名。
同樣還有選擇的快顯視窗,叫做DialogSelectForm和DialogSelectUserControl。
在這裡把控制項的部分原始碼貼出,下面是點擊建立按鈕的動作:
private void buttonAdd_Click(object sender, EventArgs e)
{
base.OnClick(e);
try
{
if (String.IsNullOrEmpty(DialogAddForm) && String.IsNullOrEmpty(DialogAddUserControl))
return;
Form f = GetForm(DialogAddForm);
UserControl u = GetUserControl(DialogAddUserControl);
MyDialogValue = new DialogValue();
((ISelectButtons)u).MyDialogValue = MyDialogValue;
((ISelectButtons)u).MyDialogValue.FromValue = GetMyTextBox();
((ISelectButtons)u).MyDialogValue.ReturnValue = MyValue;
f.AutoSize = true;
f.Controls.Add(u);
if (u.Tag != null)
f.Text = " " + u.Tag.ToString();
f.ShowDialog();
if (!String.IsNullOrEmpty(MyDialogValue.ReturnText) && !String.IsNullOrEmpty(MyDialogValue.ReturnValue))
SetSelectValue();
}
catch (Exception ex)
{
ex.Source += String.Format(" DialogAddUserControl:{0}", DialogAddUserControl);
ExceptionHelper.Exception(ex);
}
}
不要以為到了這裡我的山寨版使用者控制項就沒了,其實不然,還有很多很多東西,拿出來分享給大家,希望能讓大家看懂,看不懂的就不能理解我的一番苦心,誒,能理解我的人太少了,曾經很長一段時間號稱孤狼,最近才把真名換出來。好了不多說了,這裡介紹一下大家常用的DataGridView列表展示情景(見圖3),我封裝了一個即能分頁又能匯出Excel的控制項,而且裡面的功能跟業務毫無關係,當然要用它也要按照約定來進行開發,即它的容器(視窗)需要實現介面IPagination。
介面代碼很簡單:
public interface IPagination
{
void BindData();
//void SelectRow(); //(PS:此處為什麼注釋,不記得了。反正去年寫的時候是想實現行選擇動作來觸發什麼事件的,今年沒事才拿出來給大家分享。)
}
MyDataGridView有幾個參數需要重視:
int PageSize
int CurrentPageIndex
int RowsTotalCount
Object DataSource
貼出一下MyDataGridView使用者控制項的部分代碼:
public int GetPageCount()
{
if ((RowsTotalCount == 0) || (PageSize == 0))
return 0;
int i = RowsTotalCount / PageSize;
if (RowsTotalCount % PageSize > 0)
i++;
return i;
}
private IPagination FindControlIPagination()
{
Control c = this.Parent;
while (c != null)
{
if (c is IPagination)
break;
c = c.Parent;
}
if (!(c is IPagination))
throw new Exception("No IPagination Control in this UserControl or Form.");
return c as IPagination;
}
public void DataBind()
{
dataGridViewDefault.DataSource = DataSource;
toolStripLabelRowsTotalCount.Text = String.Format("共計:{0}條 {1}條/頁", RowsTotalCount, PageSize);
toolStripLabelCurrentPage.Text = String.Format("{0}/{1}", CurrentPageIndex, GetPageCount());
SetEnabled();
}
private void ReDataBind()
{
IPagination page = FindControlIPagination();
page.BindData();
}
恩恩,寫到這裡本打算就此收筆了,但是突然看到了一個曾經折騰了好久才搞出來的一個控制項DropDownTreeView,這個控制項是實現了下拉樹選擇功能(見圖4),與其他使用者控制項比,比較特殊點就是他不是繼承自UserControl,而是來自於ComboBox,然而其實ComboBox是間接繼承自Control,所以DropDownTreeView可以定義自己的TreeView控制項來進行展示與承載資料,唯一需要處理的就是找到Windows控制代碼擷取點擊ComboBox的動作來進行展收樹,看部分代碼:
private void ShowDropDown()
{
if (dropDown != null)
{
treeViewHost.Size = new Size(DropDownWidth - 2, DropDownHeight);
dropDown.Show(this, 0, this.Height);
}
}
protected override void WndProc(ref Message m)
{
try
{
if (m.Msg == WM_LBUTTONDBLCLK || m.Msg == WM_LBUTTONDOWN)
{
ShowDropDown();
return;
}
base.WndProc(ref m);
}
catch (Exception ex)
{
CHF.Windows.Command.ExceptionHelper.Exception(ex);
}
}
算了,算了,再看就寫不完了,貼出一下我的類庫裡有多少個使用者控制項,很多都是見了名字就能知道什麼意思的。
最後貼出原代碼:下載山寨版Windows.Form使用者控制項CHF.Windows.FormControl
至於調用的Demo,我就不便把我整個項目代碼都給出來,畢竟它已經在市面上還活著呢http://soft.bxren.cn
(給了幾個調用的Demo檔案,但是會報錯,因為我沒有給出完整的Demo部分,我相信大蝦們能通過源碼看出效果來)
由於是早期做程式用的,也沒有特意去進行重構和封裝,但是很實用。這次拿出來也是臨時應付,也沒有作很好的介紹和修剪代碼,不會用就問,本人臉皮厚,好不好用我也不害臊,反正磚頭砸我頭不會疼~ 不信試試。。。。