TN026:DDX 和 DDV 常式
注意
下列技術提示自其納入線上文件以來,未曾更新。 因此,有些程序和主題可能已過期或不正確。 如需最新資訊,建議您在線上文件索引中搜尋相關的主題。
此附註描述對話資料交換 (DDX) 和對話資料驗證 (DDV) 架構。 它也描述如何撰寫DDX_或DDV_程式,以及如何擴充 ClassWizard 以使用例程。
對話框數據交換概觀
所有對話框數據函式都是使用 C++ 程式代碼完成。 沒有特殊的資源或魔術宏。 機制的核心是虛擬函式,會在執行對話數據交換和驗證的每個對話類別中覆寫。 它一律會以下列形式找到:
void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX); // call base class
//{{AFX_DATA_MAP(CMyDialog)
<data_exchange_function_call>
<data_validation_function_call>
//}}AFX_DATA_MAP
}
特殊格式 AFX 批注可讓 ClassWizard 在此函式中尋找和編輯程式代碼。 與 ClassWizard 不相容的程式代碼應該放在特殊格式批注之外。
在上述範例中, <data_exchange_function_call> 的格式如下:
DDX_Custom(pDX, nIDC, field);
和 <data_validation_function_call> 是選擇性的,且格式如下:
DDV_Custom(pDX, field, ...);
每個 DoDataExchange
函式中可以包含一個以上的DDX_/DDV_組。
如需 MFC 所提供的所有對話資料交換例程和對話數據驗證例程的清單,請參閱 『afxdd_.h』。
對話框數據只是這樣:類別中的 CMyDialog
成員數據。 它不會儲存在結構或類似的任何內容中。
備註
雖然我們稱之為「對話數據」,但所有功能都可以在任何衍生自 CWnd
的類別中使用,而且不限於對話框。
數據的初始值是在標準 C++ 建構函式中設定,通常是在具有 //{{AFX_DATA_INIT
和 //}}AFX_DATA_INIT
批注的區塊中。
CWnd::UpdateData
是作業,會在呼叫 DoDataExchange
前後執行初始化和錯誤處理。
您可以隨時呼叫 CWnd::UpdateData
來執行資料交換和驗證。 UpdateData
預設會在預設CDialog::OnOK
處理程式中呼叫 (TRUE),預設UpdateData
CDialog::OnInitDialog
會呼叫 (FALSE) 。
DDV_例程應緊接該 欄位的DDX_例程。
其運作方式
您不需要瞭解下列專案,即可使用對話數據。 不過,瞭解這在幕後的運作方式可協助您撰寫自己的交換或驗證程式。
成員 DoDataExchange
函式與成員函式非常類似 Serialize
- 負責從外部表單取得或設定數據(在此案例中為控件在對話框中的控件)從 類別中的成員數據。 pDX 參數是執行資料交換的內容,與 參數CObject::Serialize
類似 CArchive
。 pDX (a CDataExchange
物件) 具有方向旗標,就像CArchive
有方向旗標:
如果
!m_bSaveAndValidate
為 ,則會將數據狀態載入控件。如果
m_bSaveAndValidate
為 ,則從控件設定數據狀態。
只有在設定時 m_bSaveAndValidate
,才會進行驗證。 的值 m_bSaveAndValidate
是由 BOOL 參數決定為 CWnd::UpdateData
。
還有其他三個有趣的 CDataExchange
成員:
m_pDlgWnd
:包含控制件的視窗(通常是對話框)。 這是為了防止DDX_和DDV_全域函式的呼叫端將 『this』 傳遞給每個 DDX/DDV 例程。PrepareCtrl
和PrepareEditCtrl
:準備數據交換的對話控制件。 儲存控件在驗證失敗時設定焦點的句柄。PrepareCtrl
用於非編輯控制項,並PrepareEditCtrl
用於編輯控制項。Fail
:在顯示消息框之後呼叫,提醒使用者輸入錯誤。 此例程會將焦點還原至最後一個控件(或的最後一個呼叫PrepareCtrl
PrepareEditCtrl
),並擲回例外狀況。 您可以從DDX_和DDV_例程呼叫這個成員函式。
用戶擴充功能
有數種方式可以擴充預設的 DDX/DDV 機制。 您可以:
新增數據類型。
CTime
新增交換程式(DDX_)。
void PASCAL DDX_Time(CDataExchange* pDX, int nIDC, CTime& tm);
新增驗證程式(DDV_)。
void PASCAL DDV_TimeFuture(CDataExchange* pDX, CTime tm, BOOL bFuture); // make sure time is in the future or past
將任意表達式傳遞至驗證程式。
DDV_MinMax(pDX, age, 0, m_maxAge);
注意
ClassWizard 無法編輯這類任意運算式,因此應該移至特殊格式批注之外(W{{AFX_DATA_MAP(CMyClass))。
DoDataExchange
讓成員函式包含條件式或任何其他有效的 C++ 語句,以及混合交換和驗證函式呼叫。
//{{AFX_DATA_MAP(CMyClass)
DDX_Check(pDX, IDC_SEX, m_bFemale);
DDX_Text(pDX, IDC_EDIT1, m_age);
//}}AFX_DATA_MAP
if (m_bFemale)
DDV_MinMax(pDX, age, 0, m_maxFemaleAge);
else
DDV_MinMax(pDX, age, 0, m_maxMaleAge);
注意
如上所示,ClassWizard 無法編輯這類程序代碼,而且應該只在特殊格式批注之外使用。
ClassWizard 支援
ClassWizard 支援 DDX/DDV 自定義的子集,可讓您將自己的DDX_和DDV_例程整合到 ClassWizard 使用者介面中。 如果您打算在項目或許多專案中重複使用特定的 DDX 和 DDV 例程,這樣做才具有成本效益。
若要這樣做,DDX.CLW 會建立特殊專案(舊版 Visual C++ 會將此資訊儲存在 APSTUDIO 中。INI) 或項目中的 。CLW 檔案。 您可以在專案的 [一般資訊] 區段中輸入特殊專案。CLW 檔案或 \Program Files\Microsoft Visual Studio\Visual C++\bin 目錄中 DDX.CLW 檔案的 [ExtraDDX] 區段中。 如果 DDX.CLW 檔案不存在,您可能需要建立它。 如果您打算只在特定專案中使用自定義DDX_/DDV_例程,請將專案新增至專案的 [一般資訊] 區段。請改用CLW檔案。 如果您打算在許多專案上使用例程,請將專案新增至 DDX.CLW 的 [ExtraDDX] 區段。
這些特殊專案的一般格式為:
ExtraDDXCount=n
其中 n 是表單中要追蹤的 ExtraDDX 數目? 行
ExtraDDX?=keys; vb-keys; prompt; type; initValue; DDX_Proc [; DDV_Proc; prompt1; arg1 [; prompt2; fmt2]]
在哪裡? 是數位 1 - n ,表示正在定義的清單中哪個 DDX 類型。
每個欄位都會以 ';' 字元分隔。 欄位及其用途如下所述。
鑰匙
單一字元清單,指出允許哪個對話框控制此變數類型。
字元 允許的控制件 E 編輯… C 雙狀態複選框 c [三狀態] 複選框 R 群組中的第一個單選按鈕 L 非排序列表框 l 已排序的清單框 月 下拉式方塊 (含編輯專案) 否 非排序的下拉式清單 n 已排序的下拉式清單 1 如果應該將 DDX 插入新增至清單前端(預設值為新增至尾部),這通常用於傳輸 『Control』 屬性的 DDX 例程。 vb-keys
此字段僅適用於 VBX 控件的 16 位產品(32 位產品不支援 VBX 控件)
prompt
要放在 [屬性] 下拉式方塊中的字串 (沒有引號)
type
要發出頭檔中之型別的單一標識碼。 在上述範例中,使用 DDX_Time,這會設定為 CTime。
vb-keys
未用於此版本,且應一律為空白
initValue
初始值 - 0 或空白。 如果是空白,則實作檔案的 《11){{AFX_DATA_INIT 區段中不會寫入任何初始化行。 空白項目應該用於 C++ 物件(例如
CString
、CTime
等等),其建構函式會保證正確的初始化。DDX_Proc
DDX_程式的單一標識碼。 C++ 函式名稱的開頭必須是 「DDX_」,但不包含DDX_Proc>標識碼中的 <「DDX_」。 在上述範例中 <,DDX_Proc> 標識符會是 Time。 當 ClassWizard 將函式呼叫寫入 {{AFX_DATA_MAP 區段中的實作檔案時,它會將此名稱附加至DDX_,因而到達DDX_Time。
comment
要在此 DDX 的變數對話框中顯示的批注。 將您想要的任何文字放在這裡,並且通常會提供描述 DDX/DDV 配對所執行作業的專案。
DDV_Proc
專案的 DDV 部分是選擇性的。 並非所有 DDX 例程都有對應的 DDV 例程。 通常,將驗證階段納入為傳輸不可或缺的一部分更為方便。 當您的 DDV 例程不需要任何參數時,通常是這種情況,因為 ClassWizard 不支援不含任何參數的 DDV 例程。
arg
DDV_程式的單一標識碼。 C++ 函式名稱的開頭必須是 「DDV_」,但不包含DDX_Proc>標識碼中的 <「DDX_」。
arg 後面接著 1 或 2 個 DDV 自變數:
promptN
要放在編輯專案上方的字串(搭配和 用於快捷鍵)。
fmtN
arg 類型的格式字元,其中一個:
字元 類型 d int u 不帶正負號的整數 D long int (也就是 long) U long unsigned (也就是 DWORD) f float F double s string