DevExpress GridView 中選中行彈出編輯窗口,子窗口保存數據關閉後,父窗口(MDI 子窗體)的 GridView 未自動刷新顯示最新數據。
Windows Forms 控件非線程安全,子窗口嘗試直接訪問父窗口控件屬性/方法會導致跨線程調用異常或 UI 不更新。MDI 結構下更需注意窗體層級的同步上下文。
public partial class ParentForm : DevExpress.XtraEditors.XtraForm {
// 1. 定義委托類型
public delegate void RefreshGridDelegate();
// 2. 實現刷新邏輯(含線程檢查)
public void RefreshGridData() {
if (this.gridView1.InvokeRequired) {
// 跨線程調用:通過 Invoke 執行
this.Invoke(new RefreshGridDelegate(RefreshGridData));
return;
}
// UI 線程安全執行區
try {
// 重新綁定數據源
this.gridControl1.DataSource = GetLatestData(); // 你的數據獲取方法
this.gridView1.RefreshData();
} catch (Exception ex) {
// 日誌記錄
}
}
// 3. 子窗體調用入口
public void OnChildDataSaved() {
RefreshGridData();
}
}
public partial class EditForm : DevExpress.XtraEditors.XtraForm {
private ParentForm _parentForm;
public EditForm(ParentForm parentForm) {
InitializeComponent();
_parentForm = parentForm;
}
private void btnSave_Click(object sender, EventArgs e) {
// 保存業務邏輯...
if (SaveData()) {
// 關鍵:通知父窗體刷新
_parentForm.OnChildDataSaved();
this.Close();
}
}
}
private void gridView1_DoubleClick(object sender, EventArgs e) {
var row = gridView1.GetFocusedDataRow();
if (row != null) {
using (var editForm = new EditForm(this)) { // 傳遞 this
editForm.LoadData(row);
editForm.ShowDialog();
}
}
}
// 父窗體定義事件
public event Action DataSaved;
// 子窗體觸發事件
public event Action OnSaveSuccess;
private void btnSave_Click(...) {
if (SaveData()) {
OnSaveSuccess?.Invoke();
this.Close();
}
}
// 父窗體訂閱
var editForm = new EditForm();
editForm.OnSaveSuccess += () => RefreshGridData();
editForm.ShowDialog();
// 父窗體使用 BindingSource
BindingSource bs = new BindingSource();
bs.DataSource = GetDataList();
gridControl1.DataSource = bs;
// 子窗體修改同一數據源對象(引用傳遞)後
// 父窗體只需調用
bs.ResetBindings(false); // 通知 UI 更新
private async void btnEdit_Click(object sender, EventArgs e) {
var editForm = new EditForm();
editForm.LoadData(selectedRow);
// 非阻塞等待關閉
await Task.Run(() => {
editForm.ShowDialog();
});
// UI 線程自動恢復,直接刷新
RefreshGridData();
}
| 現象 | 可能原因 | 解決 |
|---|---|---|
| Invoke 後仍不刷新 | DataSource 未重新賦值 | 重新賦值或調用 ResetBindings |
| 跨線程異常 | 未檢查 InvokeRequired | 統一使用 Invoke 模式 |
| MDI 子窗體找不到父窗體 | MdiParent 屬性未正確設置 | 子窗體構造函數接收父窗體參數 |
| 數據已更新但界面舊值 | 緩存/狀態管理問題 | 調用 gridView1.RefreshData() 或 LayoutChanged() |
RefreshGridData() 公共方法,內部處理 InvokeRequiredBindingSource 簡化數據綁定同步