WTL 学习笔记 -- DDX 和 DDV
DDX 初看时有点神秘,它把控件和相关变量关联起来了,两者在适当的时候自动进行同步。比如你在初始化时给变量赋了初值,控件上自动显示该值; 而在界面上修改了控件上的值后,它自动反应到对应的变量上去。
我们先看看如何使用DDX:
1. 包含相关头文件
#include <atlddx.h> |
2. 让对话框从CWinDataExchange类继承过来
class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>, public CMessageFilter, public CIdleHandler, public CWinDataExchange<CMainDlg>
|
3. 建立DDX映射
BEGIN_DDX_MAP(CMainDlg) DDX_INT(IDC_EDIT, m_nValue) END_DDX_MAP() |
4. 在OnInitDialog里把变量的值更到控件
DoDataExchange(); |
5. 在OnOK里把控件的值更新到变量
DoDataExchange(TRUE); |
用这么简单的代码,实现这么有用的功能,不错吧。DDX是怎么实现的呢?其实只要看一下那些宏是怎么定义,就一目了然了:
#define BEGIN_DDX_MAP(thisClass) / BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) / { / bSaveAndValidate; / nCtlID;
#define DDX_INT(nID, var) / if(nCtlID == (UINT)-1 || nCtlID == nID) / { / if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) / return FALSE; / } template <class Type> BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0) { T* pT = static_cast<T*>(this); BOOL bSuccess = TRUE;
if(bSave) { nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned); } else { ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned); }
if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nMin != nMax); if(nVal < nMin || nVal > nMax) { _XData data = { ddxDataInt }; data.intData.nVal = (long)nVal; data.intData.nMin = (long)nMin; data.intData.nMax = (long)nMax; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } |
你看,这些宏不过是代替你调用了SetDlgItemInt和GetDlgItemInt之类的函数罢了。其它类型的数据大同小异,而控件则需要调用SubclassWindow。
DDV也不过是同时加上了数据检验功能吧,比如检查字符串的长度,整数的范围等。