MFC 提供對話框資料交換 (DDX) 與資料驗證 (DDV) 機制,自動完成「成員變數 ⇄ 控制項」的雙向同步與輸入合法性檢查,減少手工 GetDlgItemInt/SetDlgItemText 等樣板碼。
CDialog::OnInitDialog 預設呼叫 UpdateData(FALSE),將成員變數值推送至控制項。UpdateData(TRUE),框架執行:
CDataExchange 物件(封裝交換方向、錯誤狀態)。DoDataExchange(CDataExchange*)。DoDataExchange 內依序呼叫 DDX_ 函數(交換)與 DDV_ 函數(驗證)。CDataExchange 擲出例外,框架捕獲並彈出錯誤訊息,焦點定位到違規控制項。OnCancel,不執行 任何資料交換,DoModal 返回 IDCANCEL。
void CMyDialog::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX); // 必須呼叫基類版本
// 交換範例
DDX_Check(pDX, IDC_MY_CHECKBOX, m_bOption); // BOOL ⇄ CheckBox
DDX_Text(pDX, IDC_MY_EDIT, m_strName); // CString ⇄ Edit Control
DDX_Radio(pDX, IDC_RADIO_START, m_nChoice); // int ⇄ Radio Group
// 驗證範例
DDV_MaxChars(pDX, m_strName, 20); // 字串長度 ≤ 20
DDV_MinMaxInt(pDX, m_nAge, 0, 150); // 整數範圍 0~150
DDV_MinMaxDouble(pDX, m_dPrice, 0.0, 10000.0); // 浮點數範圍
}
| 控制項類型 | DDX 函數 | 成員變數類型 | 常用 DDV |
|---|---|---|---|
| Edit Control | DDX_Text | CString, int, double, BYTE 等 | DDV_MaxChars, DDV_MinMaxInt/Double |
| Check Box | DDX_Check | BOOL / int | — |
| Radio Group | DDX_Radio | int (0-based 索引) | — |
| Combo Box | DDX_CBString / DDX_CBIndex | CString / int | — |
| List Box | DDX_LBString / DDX_LBIndex | CString / int | — |
| Slider | DDX_Slider | int | — |
| DateTimePicker | DDX_DateTimeCtrl | COleDateTime / CTime | — |
| IP Address | DDX_IPAddress | DWORD | — |
OnInitDialog 給予預設值,UpdateData(FALSE) 才會正確顯示。DDX_ 第二參數一致。DDV_ 失敗會拋出 CUserException,框架自動呼叫 Fail() 彈出訊息並 SetFocus 到違規控制項,無需手動 try-catch。UpdateData(TRUE/FALSE);若控制項通知訊息(如 EN_CHANGE)中呼叫,注意避免遞迴。DDX_Custom 支援第三方控制項,簽名為 void AFXAPI DDX_Custom(CDataExchange*, int, YourType&)。DoDataExchange 骨架,僅需補充驗證規則。CDialog::DoDataExchange(pDX) → 基類控制項(如 IDOK/IDCANCEL)無法正常運作。DDX_Text 對應 int 成員,但使用者輸入非數字 → 框架自動彈出「請輸入整數」訊息,屬正常行為。DDV_MaxChars 用於 int 型別 → 編譯錯誤,DDV_MaxChars 僅支援 CString。DoModal 返回 IDOK 但資料未更新 → 確認是否在 OnOK 覆寫中漏呼 UpdateData(TRUE)(預設 OnOK 已處理)。DDX/DDV 是 MFC 對話框開發的基石,掌握其「雙向交換 + 聲明式驗證」模式,能大幅縮減 UI 邏輯代碼,提升維護性。建議新專案全面採用,並配合 Class Wizard 管理成員變數與控制項綁定。