前言
今天給了一個新的需求:要在原來只有一頁表的基礎上,增加另一張表。也就是分頁,表里面放數據網格,存放的是數據庫的SELECT展示內容,還要支持增刪改。還要和之前一個實現方式一樣,對分頁進行約束,比如未保存無法切換表格。
算是一個全新的需求,之前沒接觸過WinForm的控件。
結果展示
WinForm實現分頁
結果未保存無法切換頁面
系統環境
Windows 10 專業版
Visual Studio 2010
C#/.NET 4.0
需求分析
這次的需求並不明確,只是一句話,所以要把需求先確認。
控件理解
開始不清楚控件的含義,經過同事講解,大概明白屬性和事情的意義。這對后面進行分頁約束的實現有很大幫助。
具體實現
-
引入TabControl,添加標簽頁/選項卡。添加后會在.Designer文件自動生成代碼。
-
在空白處點擊,選中標簽頁/選項卡,右鍵屬性。
-
Name、Text都是標簽頁/選項卡的屬性,都可以修改。修改會直接體現在.Designer文件。
-
按照自己需要進行修改。
引入DataGridView(DGV),展現數據庫內容
-
找到工具箱
-
找到DataGridView,添加后也會在.Designer文件自動生成代碼
-
在屬性卡里面也可以看到各種信息
在DGV里面展示數據庫
_dtOverdueSecuInst = SimpleDal.Query<DataTable>(xQuant.Accounting.Interface.ExternalProvider.ExternalInterface.TRD,
"SELECT * FROM TTRD_UT_TC_OVERDUE_SECU_INST WHERE 1=1 " + whereIn + " ORDER BY TSK_ID, SET_DATE");
dgvOverDueSecuInst.DataSource = _dtOverdueSecuInst;
dgvOverDueSecuInst.Columns["ID"].ReadOnly = true;
dgvOverDueSecuInst.Columns["ID"].DefaultCellStyle.BackColor = System.Drawing.Color.LightGray;
dgvOverDueSecuInst.Refresh();
-
代碼說明
-
_dtOverdueSecuInst 類型是DataTable,也是WinForm的一個控件,以表格形式存儲數據。
-
dgvOverDueSecuInst類型是DataGridView,就是數據網格。
-
上述代碼實現了數據庫的SELECT結果通過DataTable,展示到DataGridView上面。
-
結果如圖
到此,展示功能完成
下面實現展示結果的增刪改
代碼使用了.NET自帶的TransactionScope事務函數。具體實現也復雜的,不多寫了。
模板參考:https://docs.microsoft.com/zh-cn/dotnet/api/system.transactions.transactionscope?redirectedfrom=MSDN&view=net-5.0
Save保存函數具體實現
private void SaveOverdueSecuInst()
{
try
{
using (TransactionScope trans = new TransactionScope())
{
TestCaseOverdueSecuInst tcOverdueSecuInst = new TestCaseOverdueSecuInst();
foreach (DataRow dr in _dtOverdueSecuInst.GetChanges().Rows)
{
if (dr.RowState != DataRowState.Deleted)
{
tcOverdueSecuInst.ID = UTUtils.ToInt(dr["ID"].ToString());
}
else
{
tcOverdueSecuInst.ID = UTUtils.ToInt(dr["ID", DataRowVersion.Original].ToString());
}
TestCaseDal4InpuOther.SaveOverdueSecuInst(tcOverdueSecuInst, dr.RowState);
}
InitData();
trans.Complete();
MessageBox.Show("逾期券指令輸入表保存成功", "提示");
}
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString(), "提示");
}
}
- 代碼說明
- TestCaseOverdueSecuInst是自己寫的類,里面存放ID等屬性。
- DataRowState是C#自帶,用於枚舉。
- 上述代碼通過switch選擇,實現了數據庫增(.Added)刪(.Deleted)改(.Modified)的。
- 詳細的增刪改代碼實現,我另外寫一個博客,內容很多。
保存按鈕調用Save保存函數
private void btnSave_Click(object sender, EventArgs e)
{
if (this.tabOverDue.SelectedTab == tpOverDueSecuInst)
{
SaveOverdueSecuInst();
}
}
- 代碼說明
- if判斷是判斷是否為當前頁,只有是當前頁才會執行保存。也就是點擊保存按鈕只進行單張保存,進行頁與頁的隔離。
對分頁進行約束
比如未保存無法切換表格
這是當時實現的一個難點,因為不清楚控件事件的具體實現。在參考相似代碼之后,成功實現了。
- 首先編寫has判斷函數,判斷當前頁是否有改動未保存
private bool hasUnSavedChange()
{
bool isChange = false;
if (tabOverDue.SelectedTab != null)
if (_dtOverdueSecuInst != null && _dtOverdueSecuInst.GetChanges() != null)
isChange = true;
}
return isChange;
}
- 然后寫成控件的內置函數TabControlCancelEventHandler(object sender, TabControlCancelEventArgs e)的參數形式
private void tabOverDue_BeforeSelect(object sender, TabControlCancelEventArgs e)
{
//打開其他表前判斷有無存在未保存數據
if (hasUnSavedChange())
{
MessageBox.Show("存在未保存數據", "提示");
e.Cancel = true;
return;
}
}
-
最后添加到TabControl的控件代碼里面
this.tabOverDue.Selecting += new System.Windows.Forms.TabControlCancelEventHandler(this.tabOverDue_BeforeSelect);
-
代碼說明
-
tabOverDue是TabControl的名字,Selecting 內置函數來判斷是否點擊別的表。如果點擊就調用tabOverDue_BeforeSelect函數,看全部表是否有未保存數據。
-
TabControlCancelEventHandler是TabControl內置函數,起到監視的目的。這些內置函數都是配套的,包括上面的TabControlCancelEventArgs 類。
-
只有使用TabControl配套的內置函數才可以實現,不然會發生語法錯誤。
-
參考代碼的控件是treeViewTable,內置函數和TabControl並不相同。這是實現的一個困難。
后記
從“需求明確” -> “控件學習” -> “控件源碼理解” -> “編程實現” -> “不斷調試/優化”,是一次新的挑戰。成就也已獲得。
這次用TabControl控件的內置函數勉強實現原來treeViewTable控件的需求。但是如果需求對擴展性要求再提高,C#估計就無法完成了。
因為所有的內置類/函數,都是封裝寫好的。你不能去修改任何微軟給你的函數,雖然大部分封裝函數都很好用。
但是正是這種封閉性,讓.NET離時代主流的開源越來越遠。不久的將來,我還是會回到Java。