C# DataGridView實(shí)戰(zhàn)攻略:從小白到高手的數(shù)據(jù)表格開發(fā)秘籍
還在為WinForm數(shù)據(jù)展示發(fā)愁?還在被DataGridView的各種屬性搞得頭暈眼花?作為一個(gè)在數(shù)據(jù)表格開發(fā)路上摸爬滾打多年的老程序員,我深知DataGridView這個(gè)"看似簡單,實(shí)則復(fù)雜"的控件給無數(shù)C#開發(fā)者帶來的困擾。今天就來和大家分享一套完整的DataGridView實(shí)戰(zhàn)攻略,從基礎(chǔ)綁定到高級(jí)應(yīng)用,讓你徹底掌握這個(gè)強(qiáng)大的數(shù)據(jù)展示利器。
本文將通過3個(gè)遞進(jìn)式的實(shí)戰(zhàn)案例,幫你解決數(shù)據(jù)綁定混亂、編輯功能不生效、數(shù)據(jù)庫集成踩坑等常見問題,讓你的WinForm應(yīng)用秒變專業(yè)級(jí)!
DataGridView核心武器庫
在開始實(shí)戰(zhàn)之前,我們先來認(rèn)識(shí)一下DataGridView的幾個(gè)關(guān)鍵"武器":
必知核心屬性
// 數(shù)據(jù)源綁定 - 你的數(shù)據(jù)展示基礎(chǔ)
DataSource: 支持DataTable、DataSet、List<T>等多種數(shù)據(jù)源
// 自動(dòng)列生成控制 - 避免列顯示混亂的關(guān)鍵
AutoGenerateColumns: false// 強(qiáng)烈建議手動(dòng)控制列
// 用戶操作權(quán)限控制
ReadOnly: true/false// 是否允許編輯
AllowUserToAddRows: false// 是否允許用戶添加行
AllowUserToDeleteRows: false// 是否允許用戶刪除行
// 選擇模式設(shè)置
SelectionMode: FullRowSelect // 整行選擇,用戶體驗(yàn)更好常用操作方法
// 列操作三件套
dataGridView.Columns.Add() // 添加列
dataGridView.Columns.Remove() // 移除列
dataGridView.Columns.Clear() // 清空所有列
// 數(shù)據(jù)刷新
dataGridView.Refresh() // 手動(dòng)刷新顯示實(shí)戰(zhàn)案例一:基礎(chǔ)數(shù)據(jù)綁定 - 告別顯示混亂
很多初學(xué)者在數(shù)據(jù)綁定時(shí)經(jīng)常遇到"列顯示不正確"、"數(shù)據(jù)對不上號(hào)"等問題。這里有一個(gè)完整的解決方案:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppDataGridViewBasic
{
publicclass Person
{
publicstring Name { get; set; }
publicint Age { get; set; }
publicstring City { get; set; }
}
}namespace AppDataGridViewBasic
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// 創(chuàng)建DataGridView實(shí)例
DataGridView dataGridView = new DataGridView();
this.Controls.Add(dataGridView);
// ?? 關(guān)鍵配置:阻止自動(dòng)生成列
dataGridView.AutoGenerateColumns = false;
dataGridView.AllowUserToAddRows = false;
dataGridView.Dock = DockStyle.Fill;
dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
// 步驟3:手動(dòng)創(chuàng)建列(避免顯示混亂)
CreateColumns(dataGridView);
// 步驟4:綁定數(shù)據(jù)源
BindData(dataGridView);
}
private void CreateColumns(DataGridView dgv)
{
// 姓名列
var nameColumn = new DataGridViewTextBoxColumn
{
DataPropertyName = "Name", // ?? 必須與模型屬性名一致
HeaderText = "姓名",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
};
dgv.Columns.Add(nameColumn);
// 年齡列
var ageColumn = new DataGridViewTextBoxColumn
{
DataPropertyName = "Age",
HeaderText = "年齡",
Width = 80
};
dgv.Columns.Add(ageColumn);
// 城市列
var cityColumn = new DataGridViewTextBoxColumn
{
DataPropertyName = "City",
HeaderText = "城市",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
};
dgv.Columns.Add(cityColumn);
}
private void BindData(DataGridView dgv)
{
var people = new List<Person>
{
new Person { Name = "張三", Age = 28, City = "北京" },
new Person { Name = "李四", Age = 35, City = "上海" },
new Person { Name = "王五", Age = 42, City = "廣州" }
};
// ?? 金句:數(shù)據(jù)綁定一行代碼搞定
dgv.DataSource = people;
}
}
}
圖片
避坑指南:
- DataPropertyName必須與模型屬性名完全一致
- 設(shè)置AutoGenerateColumns = false避免列重復(fù)
- 使用AutoSizeMode.Fill讓列自適應(yīng)寬度
實(shí)戰(zhàn)案例二:實(shí)時(shí)編輯功能 - 讓數(shù)據(jù)"活"起來
單純展示數(shù)據(jù)太無聊?讓我們給DataGridView加上編輯功能,實(shí)現(xiàn)數(shù)據(jù)的實(shí)時(shí)更新:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AppDataGridViewBasic
{
public partial class Form2 : Form
{
// 數(shù)據(jù)源
private List<Person> people;
public Form2()
{
InitializeComponent();
InitializeForm();
LoadSampleData();
}
private void InitializeForm()
{
// ?? 開啟編輯模式的正確姿勢
dataGridView.ReadOnly = false;
// 注冊數(shù)據(jù)變更事件
dataGridView.CellValueChanged += OnCellValueChanged;
// ?? 關(guān)鍵:確保編輯完成后觸發(fā)事件
dataGridView.CellEndEdit += OnCellEndEdit;
// 單元格開始編輯事件
dataGridView.CellBeginEdit += OnCellBeginEdit;
// 數(shù)據(jù)錯(cuò)誤處理
dataGridView.DataError += OnDataError;
// 行刪除事件
dataGridView.UserDeletingRow += OnUserDeletingRow;
}
private void LoadSampleData()
{
// ?? 初始化示例數(shù)據(jù)
people = new List<Person>
{
new Person { Name = "張三", Age = 25, City = "北京", Email = "zhangsan@email.com", CreateDate = DateTime.Now.AddDays(-10) },
new Person { Name = "李四", Age = 30, City = "上海", Email = "lisi@email.com", CreateDate = DateTime.Now.AddDays(-5) },
new Person { Name = "王五", Age = 28, City = "廣州", Email = "wangwu@email.com", CreateDate = DateTime.Now.AddDays(-3) },
new Person { Name = "趙六", Age = 35, City = "深圳", Email = "zhaoliu@email.com", CreateDate = DateTime.Now.AddDays(-1) }
};
// 綁定數(shù)據(jù)源
dataGridView.DataSource = people;
// ?? 列設(shè)置優(yōu)化
SetupColumns();
}
private void SetupColumns()
{
if (dataGridView.Columns.Count > 0)
{
// 設(shè)置列標(biāo)題
dataGridView.Columns["Name"].HeaderText = "姓名";
dataGridView.Columns["Age"].HeaderText = "年齡";
dataGridView.Columns["City"].HeaderText = "城市";
dataGridView.Columns["Email"].HeaderText = "郵箱";
dataGridView.Columns["CreateDate"].HeaderText = "創(chuàng)建時(shí)間";
// 設(shè)置列寬比例
dataGridView.Columns["Name"].FillWeight = 20;
dataGridView.Columns["Age"].FillWeight = 15;
dataGridView.Columns["City"].FillWeight = 20;
dataGridView.Columns["Email"].FillWeight = 25;
dataGridView.Columns["CreateDate"].FillWeight = 20;
// 設(shè)置創(chuàng)建時(shí)間為只讀
dataGridView.Columns["CreateDate"].ReadOnly = true;
// 年齡列只允許數(shù)字
dataGridView.Columns["Age"].ValueType = typeof(int);
}
}
// ?? 核心事件處理方法
private void OnCellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0) return; // 避免標(biāo)題行觸發(fā)事件
var dgv = sender as DataGridView;
if (dgv.DataSource is List<Person> people && e.RowIndex < people.Count)
{
// 獲取被修改的對象
Person updatedPerson = people[e.RowIndex];
// ?? 實(shí)戰(zhàn)應(yīng)用:這里可以調(diào)用業(yè)務(wù)邏輯
SavePersonToDatabase(updatedPerson);
// 更新狀態(tài)欄或給用戶反饋
this.Text = $"可編輯數(shù)據(jù)表格 - 已更新:{updatedPerson.Name} 的信息 [{DateTime.Now:HH:mm:ss}]";
}
}
private void OnCellEndEdit(object sender, DataGridViewCellEventArgs e)
{
// 確保數(shù)據(jù)驗(yàn)證和格式化
var dgv = sender as DataGridView;
var cell = dgv[e.ColumnIndex, e.RowIndex];
string columnName = dgv.Columns[e.ColumnIndex].Name;
switch (columnName)
{
case"Age":
// 年齡列數(shù)據(jù)驗(yàn)證
if (!int.TryParse(cell.Value?.ToString(), out int age) || age < 0 || age > 150)
{
MessageBox.Show("請輸入有效的年齡(0-150)!", "數(shù)據(jù)驗(yàn)證", MessageBoxButtons.OK, MessageBoxIcon.Warning);
cell.Value = 0; // 設(shè)置默認(rèn)值
}
break;
case"Email":
// 郵箱格式驗(yàn)證
string email = cell.Value?.ToString();
if (!string.IsNullOrEmpty(email) && !IsValidEmail(email))
{
MessageBox.Show("請輸入有效的郵箱格式!", "數(shù)據(jù)驗(yàn)證", MessageBoxButtons.OK, MessageBoxIcon.Warning);
cell.Value = ""; // 清空無效郵箱
}
break;
case"Name":
// 姓名不能為空
if (string.IsNullOrWhiteSpace(cell.Value?.ToString()))
{
MessageBox.Show("姓名不能為空!", "數(shù)據(jù)驗(yàn)證", MessageBoxButtons.OK, MessageBoxIcon.Warning);
cell.Value = "未命名";
}
break;
}
}
private void OnCellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
// 可以在這里添加編輯前的邏輯
var dgv = sender as DataGridView;
string columnName = dgv.Columns[e.ColumnIndex].Name;
// 例如:某些條件下禁止編輯
if (columnName == "CreateDate")
{
e.Cancel = true; // 取消編輯
MessageBox.Show("創(chuàng)建時(shí)間不可編輯!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void OnDataError(object sender, DataGridViewDataErrorEventArgs e)
{
// 處理數(shù)據(jù)類型轉(zhuǎn)換錯(cuò)誤等
MessageBox.Show($"數(shù)據(jù)錯(cuò)誤:{e.Exception.Message}", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Cancel = true;
}
private void OnUserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
// 刪除行前的確認(rèn)
if (MessageBox.Show("確定要?jiǎng)h除這條記錄嗎?", "確認(rèn)刪除",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
e.Cancel = true; // 取消刪除
}
}
// ?? 收藏級(jí)代碼模板:數(shù)據(jù)保存方法
private void SavePersonToDatabase(Person person)
{
try
{
// 這里實(shí)現(xiàn)你的數(shù)據(jù)保存邏輯
// 可以是數(shù)據(jù)庫更新、API調(diào)用等
Console.WriteLine($"保存數(shù)據(jù):{person.Name}, {person.Age}, {person.City}, {person.Email}");
// 模擬異步保存
Task.Run(() => {
System.Threading.Thread.Sleep(100); // 模擬網(wǎng)絡(luò)延遲
// 實(shí)際保存到數(shù)據(jù)庫的代碼
});
}
catch (Exception ex)
{
MessageBox.Show($"保存失敗:{ex.Message}", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// ?? 按鈕事件處理
private void BtnAdd_Click(object sender, EventArgs e)
{
// 添加新記錄
people.Add(new Person
{
Name = "新用戶",
Age = 20,
City = "北京",
Email = "new@email.com",
CreateDate = DateTime.Now
});
// 刷新數(shù)據(jù)源
RefreshDataSource();
}
private void BtnDelete_Click(object sender, EventArgs e)
{
// 刪除選中行
if (dataGridView.SelectedRows.Count > 0)
{
var selectedIndex = dataGridView.SelectedRows[0].Index;
if (selectedIndex < people.Count)
{
if (MessageBox.Show("確定要?jiǎng)h除選中的記錄嗎?", "確認(rèn)刪除",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
people.RemoveAt(selectedIndex);
RefreshDataSource();
}
}
}
else
{
MessageBox.Show("請先選擇要?jiǎng)h除的行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void BtnSaveAll_Click(object sender, EventArgs e)
{
// 保存所有數(shù)據(jù)
try
{
foreach (var person in people)
{
SavePersonToDatabase(person);
}
MessageBox.Show($"成功保存 {people.Count} 條記錄!", "保存成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"批量保存失敗:{ex.Message}", "錯(cuò)誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// ?? 輔助方法
private void RefreshDataSource()
{
dataGridView.DataSource = null;
dataGridView.DataSource = people;
SetupColumns();
}
private bool IsValidEmail(string email)
{
try
{
var addr = new System.Net.Mail.MailAddress(email);
return addr.Address == email;
}
catch
{
returnfalse;
}
}
private void Button_MouseEnter(object sender, EventArgs e)
{
if (sender is Button btn)
{
btn.FlatAppearance.BorderSize = 1;
btn.FlatAppearance.BorderColor = System.Drawing.Color.White;
}
}
private void Button_MouseLeave(object sender, EventArgs e)
{
if (sender is Button btn)
{
btn.FlatAppearance.BorderSize = 0;
}
}
// ?? 窗體關(guān)閉時(shí)的清理工作
protected override void OnFormClosed(FormClosedEventArgs e)
{
// 取消事件訂閱,避免內(nèi)存泄漏
if (dataGridView != null)
{
dataGridView.CellValueChanged -= OnCellValueChanged;
dataGridView.CellEndEdit -= OnCellEndEdit;
dataGridView.CellBeginEdit -= OnCellBeginEdit;
dataGridView.DataError -= OnDataError;
dataGridView.UserDeletingRow -= OnUserDeletingRow;
}
base.OnFormClosed(e);
}
}
}
圖片
編輯模式最佳實(shí)踐:
- 同時(shí)監(jiān)聽CellValueChanged和CellEndEdit事件
- 做好數(shù)據(jù)驗(yàn)證,避免無效數(shù)據(jù)
- 提供用戶反饋,提升體驗(yàn)
實(shí)戰(zhàn)案例三:數(shù)據(jù)庫集成 - 企業(yè)級(jí)應(yīng)用必備
真實(shí)項(xiàng)目中,數(shù)據(jù)往往來自數(shù)據(jù)庫。下面展示如何實(shí)現(xiàn)DataGridView與數(shù)據(jù)庫的完美集成:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Windows.Forms;
namespace AppDataGridViewBasic
{
public partial class Form3 : Form
{
private DatabaseDataGridManager databaseManager;
private readonly string connectionString = "Server=.;Database=dbtest;Integrated Security=true;";
public Form3()
{
InitializeComponent();
}
private void InitializeForm()
{
try
{
// 初始化數(shù)據(jù)庫管理器
databaseManager = new DatabaseDataGridManager(connectionString, dataGridView);
// 加載數(shù)據(jù)
databaseManager.LoadDataFromDatabase();
// 更新狀態(tài)
toolStripStatusLabel.Text = "? 數(shù)據(jù)庫連接成功,數(shù)據(jù)已加載";
}
catch (Exception ex)
{
MessageBox.Show($"初始化失敗:{ex.Message}", "錯(cuò)誤",
MessageBoxButtons.OK, MessageBoxIcon.Error);
toolStripStatusLabel.Text = "? 數(shù)據(jù)庫連接失敗";
}
}
// ?? 按鈕事件處理
private void BtnRefresh_Click(object sender, EventArgs e)
{
try
{
databaseManager?.LoadDataFromDatabase();
toolStripStatusLabel.Text = $"?? 數(shù)據(jù)已刷新 - {DateTime.Now:HH:mm:ss}";
}
catch (Exception ex)
{
MessageBox.Show($"刷新失敗:{ex.Message}", "錯(cuò)誤",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void BtnAddNew_Click(object sender, EventArgs e)
{
try
{
databaseManager?.AddNewRecord();
toolStripStatusLabel.Text = $"? 新記錄已添加 - {DateTime.Now:HH:mm:ss}";
}
catch (Exception ex)
{
MessageBox.Show($"添加失敗:{ex.Message}", "錯(cuò)誤",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void BtnDelete_Click(object sender, EventArgs e)
{
try
{
if (dataGridView.SelectedRows.Count > 0)
{
var result = MessageBox.Show("確定要?jiǎng)h除選中的記錄嗎?", "確認(rèn)刪除",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
databaseManager?.DeleteSelectedRecord(dataGridView.SelectedRows[0].Index);
toolStripStatusLabel.Text = $"??? 記錄已刪除 - {DateTime.Now:HH:mm:ss}";
}
}
else
{
MessageBox.Show("請先選擇要?jiǎng)h除的行!", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (Exception ex)
{
MessageBox.Show($"刪除失敗:{ex.Message}", "錯(cuò)誤",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void BtnSaveChanges_Click(object sender, EventArgs e)
{
try
{
databaseManager?.SaveAllChanges();
toolStripStatusLabel.Text = $"?? 所有更改已保存 - {DateTime.Now:HH:mm:ss}";
}
catch (Exception ex)
{
MessageBox.Show($"保存失敗:{ex.Message}", "錯(cuò)誤",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// 按鈕懸停效果
private void Button_MouseEnter(object sender, EventArgs e)
{
if (sender is Button btn)
{
btn.FlatAppearance.BorderSize = 1;
btn.FlatAppearance.BorderColor = Color.White;
}
}
private void Button_MouseLeave(object sender, EventArgs e)
{
if (sender is Button btn)
{
btn.FlatAppearance.BorderSize = 0;
}
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
databaseManager?.Dispose();
base.OnFormClosed(e);
}
private void Form3_Load(object sender, EventArgs e)
{
InitializeForm();
}
}
// ?? 企業(yè)級(jí)數(shù)據(jù)庫管理器
publicclass DatabaseDataGridManager : IDisposable
{
private readonly string connectionString;
private DataGridView dataGridView;
private DataTable dataTable;
private SqlDataAdapter dataAdapter;
private SqlCommandBuilder commandBuilder;
public DatabaseDataGridManager(string connStr, DataGridView dgv)
{
connectionString = connStr;
dataGridView = dgv;
InitializeDataGrid();
}
private void InitializeDataGrid()
{
// ?? 企業(yè)級(jí)配置
dataGridView.AutoGenerateColumns = true; // 數(shù)據(jù)庫場景可以自動(dòng)生成
dataGridView.ReadOnly = false;
dataGridView.AllowUserToDeleteRows = false; // 安全起見
dataGridView.AllowUserToAddRows = false; // 通過按鈕控制
// 注冊事件
dataGridView.CellValueChanged += OnDatabaseCellChanged;
dataGridView.CellEndEdit += OnCellEndEdit;
}
// ?? 收藏級(jí)方法:加載數(shù)據(jù)庫數(shù)據(jù)
public void LoadDataFromDatabase()
{
try
{
using (var connection = new SqlConnection(connectionString))
{
// 創(chuàng)建適配器和命令構(gòu)建器
dataAdapter = new SqlDataAdapter("SELECT * FROM People ORDER BY Id", connection);
commandBuilder = new SqlCommandBuilder(dataAdapter);
dataTable = new DataTable();
// ?? 關(guān)鍵:Fill方法一次性完成連接、查詢、斷開
dataAdapter.Fill(dataTable);
dataGridView.DataSource = dataTable;
// 美化顯示
FormatColumns();
}
}
catch (SqlException sqlEx)
{
if (sqlEx.Number == 2) // 服務(wù)器未找到
{
thrownew Exception("無法連接到SQL Server,請檢查服務(wù)器是否運(yùn)行");
}
elseif (sqlEx.Number == 208) // 表不存在
{
CreateSampleTable();
LoadDataFromDatabase(); // 重新加載
}
else
{
thrownew Exception($"數(shù)據(jù)庫錯(cuò)誤:{sqlEx.Message}");
}
}
catch (Exception ex)
{
thrownew Exception($"數(shù)據(jù)加載失敗:{ex.Message}");
}
}
private void CreateSampleTable()
{
try
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var createTableCommand = new SqlCommand(@"
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='People' AND xtype='U')
CREATE TABLE People (
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(50) NOT NULL,
Age INT NOT NULL,
City NVARCHAR(50),
Email NVARCHAR(100),
CreateDate DATETIME DEFAULT GETDATE()
)", connection);
createTableCommand.ExecuteNonQuery();
// 插入示例數(shù)據(jù)
var insertCommand = new SqlCommand(@"
INSERT INTO People (Name, Age, City, Email) VALUES
(N'張三', 25, N'北京', 'zhangsan@email.com'),
(N'李四', 30, N'上海', 'lisi@email.com'),
(N'王五', 28, N'廣州', 'wangwu@email.com'),
(N'趙六', 35, N'深圳', 'zhaoliu@email.com')", connection);
insertCommand.ExecuteNonQuery();
}
}
catch (Exception ex)
{
thrownew Exception($"創(chuàng)建示例表失敗:{ex.Message}");
}
}
private void FormatColumns()
{
// 等待列生成完成
if (dataGridView.Columns.Count == 0)
{
dataGridView.Refresh();
Application.DoEvents(); // 確保UI更新完成
}
try
{
// ?? 安全檢查每一列
var idColumn = dataGridView.Columns["Id"];
if (idColumn != null)
{
idColumn.HeaderText = "編號(hào)";
idColumn.ReadOnly = true;
idColumn.DefaultCellStyle.BackColor = Color.LightGray;
idColumn.Width = 60;
}
var nameColumn = dataGridView.Columns["Name"];
if (nameColumn != null)
{
nameColumn.HeaderText = "姓名";
nameColumn.Width = 100;
}
var ageColumn = dataGridView.Columns["Age"];
if (ageColumn != null)
{
ageColumn.HeaderText = "年齡";
ageColumn.Width = 60;
}
var cityColumn = dataGridView.Columns["City"];
if (cityColumn != null)
{
cityColumn.HeaderText = "城市";
cityColumn.Width = 100;
}
var emailColumn = dataGridView.Columns["Email"];
if (emailColumn != null)
{
emailColumn.HeaderText = "郵箱";
emailColumn.Width = 150;
}
var createDateColumn = dataGridView.Columns["CreateDate"];
if (createDateColumn != null)
{
createDateColumn.HeaderText = "創(chuàng)建時(shí)間";
createDateColumn.ReadOnly = true;
createDateColumn.DefaultCellStyle.Format = "yyyy-MM-dd HH:mm:ss";
}
}
catch (Exception ex)
{
// 記錄日志但不中斷程序
System.Diagnostics.Debug.WriteLine($"列格式化警告: {ex.Message}");
}
}
private void OnDatabaseCellChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0) return;
try
{
// 標(biāo)記行為已修改
DataRow modifiedRow = dataTable.Rows[e.RowIndex];
// DataRow會(huì)自動(dòng)跟蹤更改狀態(tài)
}
catch (Exception ex)
{
MessageBox.Show($"數(shù)據(jù)更改失敗:{ex.Message}", "錯(cuò)誤");
// 回滾更改
dataTable.RejectChanges();
dataGridView.Refresh();
}
}
private void OnCellEndEdit(object sender, DataGridViewCellEventArgs e)
{
var dgv = sender as DataGridView;
var cell = dgv[e.ColumnIndex, e.RowIndex];
string columnName = dgv.Columns[e.ColumnIndex].Name;
// 數(shù)據(jù)驗(yàn)證
switch (columnName)
{
case"Age":
if (!int.TryParse(cell.Value?.ToString(), out int age) || age < 0 || age > 150)
{
MessageBox.Show("請輸入有效的年齡(0-150)!", "數(shù)據(jù)驗(yàn)證");
cell.Value = DBNull.Value;
return;
}
break;
case"Name":
if (string.IsNullOrWhiteSpace(cell.Value?.ToString()))
{
MessageBox.Show("姓名不能為空!", "數(shù)據(jù)驗(yàn)證");
cell.Value = "未命名";
return;
}
break;
case"Email":
string email = cell.Value?.ToString();
if (!string.IsNullOrEmpty(email) && !IsValidEmail(email))
{
MessageBox.Show("請輸入有效的郵箱格式!", "數(shù)據(jù)驗(yàn)證");
cell.Value = DBNull.Value;
return;
}
break;
}
}
// ?? 企業(yè)級(jí)更新方法:批量保存所有更改
public void SaveAllChanges()
{
try
{
if (dataAdapter != null && dataTable != null)
{
// ?? 重新創(chuàng)建連接和適配器
using (var connection = new SqlConnection(connectionString))
{
// 重新設(shè)置適配器的連接
dataAdapter.SelectCommand.Connection = connection;
// 重新生成Insert、Update、Delete命令
commandBuilder = new SqlCommandBuilder(dataAdapter);
// 執(zhí)行更新
dataAdapter.Update(dataTable);
dataTable.AcceptChanges();
}
}
}
catch (Exception ex)
{
thrownew Exception($"保存失敗:{ex.Message}");
}
}
public void AddNewRecord()
{
try
{
DataRow newRow = dataTable.NewRow();
newRow["Name"] = "新用戶";
newRow["Age"] = 20;
newRow["City"] = "北京";
newRow["Email"] = "new@email.com";
dataTable.Rows.Add(newRow);
}
catch (Exception ex)
{
thrownew Exception($"添加記錄失敗:{ex.Message}");
}
}
public void DeleteSelectedRecord(int rowIndex)
{
try
{
if (rowIndex >= 0 && rowIndex < dataTable.Rows.Count)
{
dataTable.Rows[rowIndex].Delete();
}
}
catch (Exception ex)
{
thrownew Exception($"刪除記錄失敗:{ex.Message}");
}
}
private bool IsValidEmail(string email)
{
try
{
var addr = new System.Net.Mail.MailAddress(email);
return addr.Address == email;
}
catch
{
returnfalse;
}
}
public void Dispose()
{
dataAdapter?.Dispose();
commandBuilder?.Dispose();
dataTable?.Dispose();
if (dataGridView != null)
{
dataGridView.CellValueChanged -= OnDatabaseCellChanged;
dataGridView.CellEndEdit -= OnCellEndEdit;
}
}
}
}
圖片
數(shù)據(jù)庫集成避坑指南:
- 使用using語句確保連接正確釋放
- 做好異常處理,避免程序崩潰
- 實(shí)現(xiàn)數(shù)據(jù)回滾機(jī)制,保證數(shù)據(jù)一致性
高手進(jìn)階技巧
性能優(yōu)化秘籍
// 大量數(shù)據(jù)加載時(shí)暫停重繪,提升性能
dataGridView.SuspendLayout();
// ... 進(jìn)行數(shù)據(jù)操作
dataGridView.ResumeLayout();
// 虛擬模式處理海量數(shù)據(jù)
dataGridView.VirtualMode = true;用戶體驗(yàn)增強(qiáng)
// 隔行變色
dataGridView.AlternatingRowsDefaultCellStyle.BackColor = Color.LightGray;
// 鼠標(biāo)懸停高亮
dataGridView.DefaultCellStyle.SelectionBackColor = Color.DodgerBlue;總結(jié):掌握DataGridView的三個(gè)關(guān)鍵點(diǎn)
通過以上三個(gè)遞進(jìn)式案例,相信你已經(jīng)對DataGridView有了全面的認(rèn)識(shí)。讓我來總結(jié)三個(gè)最重要的要點(diǎn):
- 數(shù)據(jù)綁定的正確姿勢手動(dòng)控制列生成,避免顯示混亂
- 編輯功能的完整實(shí)現(xiàn)事件處理+數(shù)據(jù)驗(yàn)證+用戶反饋
- 數(shù)據(jù)庫集成的企業(yè)級(jí)方案異常處理+事務(wù)管理+性能優(yōu)化
DataGridView雖然功能強(qiáng)大,但掌握了正確的使用方法,它就會(huì)成為你開發(fā)WinForm應(yīng)用的得力助手。記住,實(shí)踐是最好的老師,建議大家把這些代碼在自己的項(xiàng)目中跑一遍,相信會(huì)有更深的理解!



























