在 Delphi 或 Visual Basic 時代,「資料導航器」是內建元件,拖拉即可實現資料庫記錄的首筆、末筆、上一筆、下一筆瀏覽。進入 Visual C# 後,雖然沒有同名元件,但透過 ADO.NET 的 DataSet、DataAdapter 搭配 Windows Forms 的 資料繫結 機制,配合 BindingManagerBase(具體為 CurrencyManager)控制記錄指標,同樣能輕鬆打造功能完整的記錄瀏覽器。本文以 Access 資料庫為例,完整示範從連線、繫結到導航邏輯的實作全過程。
sample.mdb 內含 books 資料表(欄位:bookid、booktitle、bookauthor、bookprice、bookstock)若直接指派 textBox.Text = row["field"],游標移動時介面不會自動更新。正確做法是利用控制項的 DataBindings 集合,將控制項屬性(如 Text)繫結至 DataSet 的特定資料表欄位:
// 語法:控制項.DataBindings.Add(控制項屬性, 資料來源, "資料表.欄位")
t_bookid.DataBindings.Add("Text", myDataSet, "books.bookid");
t_booktitle.DataBindings.Add("Text", myDataSet, "books.booktitle");
t_bookauthor.DataBindings.Add("Text", myDataSet, "books.bookauthor");
t_bookprice.DataBindings.Add("Text", myDataSet, "books.bookprice");
t_books.DataBindings.Add("Text", myDataSet, "books.bookstock");
繫結完成後,BindingContext 會自動建立對應的 CurrencyManager 管理該資料來源的當前記錄位置,TextBox 會隨著記錄指標自動刷新顯示值,無需手動寫入迴圈。
透過表單的 BindingContext[DataSet, "TableName"] 取得 BindingManagerBase 實例(實際為 CurrencyManager),其兩個核心屬性:
四個導航按鈕的邏輯由此直觀實現:
// 首記錄
myBind.Position = 0;
// 尾記錄
myBind.Position = myBind.Count - 1;
// 下一筆
if (myBind.Position == myBind.Count - 1)
MessageBox.Show("已經是最後一筆記錄!");
else
myBind.Position += 1;
// 上一筆
if (myBind.Position == 0)
MessageBox.Show("已經是第一筆記錄!");
else
myBind.Position -= 1;
public class DataView : Form
{
private DataSet myDataSet;
private BindingManagerBase myBind;
// UI 控制項宣告...
public DataView()
{
GetConnected(); // 先連資料庫、填充 DataSet
InitializeComponent(); // 再初始化 UI 與繫結
}
// ...
}
順序關鍵:必須先 GetConnected() 填充 myDataSet,再執行 InitializeComponent() 進行 DataBindings.Add,否則繫結時資料來源為空會拋出例外。
public void GetConnected()
{
try
{
string strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=sample.mdb";
using (OleDbConnection myConn = new OleDbConnection(strCon))
{
string strCom = "SELECT * FROM books";
myDataSet = new DataSet();
OleDbDataAdapter myCommand = new OleDbDataAdapter(strCom, myConn);
myCommand.Fill(myDataSet, "books"); // 關鍵:指定 DataTable 名稱 "books"
myConn.Close();
}
}
catch (Exception ex)
{
MessageBox.Show("連接錯誤!" + ex.ToString(), "錯誤");
}
}
在 InitializeComponent 中:
DataBindings.Add("Text", myDataSet, "books.欄位名")myBind = this.BindingContext[myDataSet, "books"]; 取得管理器protected void GoFirst(object sender, EventArgs e) { myBind.Position = 0; }
protected void GoPrevious(object sender, EventArgs e)
{
if (myBind.Position == 0) MessageBox.Show("已經到了第一條記錄!");
else myBind.Position -= 1;
}
protected void GoNext(object sender, EventArgs e)
{
if (myBind.Position == myBind.Count - 1) MessageBox.Show("已經到了最後一條記錄!");
else myBind.Position += 1;
}
protected void GoLast(object sender, EventArgs e) { myBind.Position = myBind.Count - 1; }
| 原教學做法 | 現代最佳實踐 |
|---|---|
| OleDbConnection 手動 Open/Close | 使用 using 區塊確保釋放 |
| 硬編碼連線字串 | 存放於 app.config / appsettings.json |
| DataSet 離線模式 | 小資料量可用;大資料量建議 DataReader + 分頁查詢 |
| WinForms 絕對座標佈局 | 使用 TableLayoutPanel / FlowLayoutPanel 或 WPF/XAML |
| 同步封鎖 UI | 資料載入改用 async/await 非同步模式 |