CWnd:: UpdateData
BOOL UpdateData ( BOOL bSaveAndValidate = TRUE );
|
Cette fonction comme son nom l'indique permet :
- La mise à jour des variables attachées aux contrôles lorsque bSaveAndValidate est égal à TRUE ;
- La mise à jour des contrôles depuis les variables lorsque bSaveAndValidate est égal à FALSE.
Jusque là rien d'extraordinaire.
Il faut quand même savoir que ce mécanisme de mise à jour dans
les deux sens est assujetti à une fonction essentielle dans la classe fenêtre
où sont situés les contrôles :
CWnd:: DoDataExchange
virtual void DoDataExchange ( CDataExchange* pDX );
|
Cette fonction virtuelle sera générée automatiquement par ClassWizard lors
de la génération d'une classe Fenêtre. Le code de conversion approprié sera
placé automatiquement en fonction des types de variables que l'utilisateur
aura sélectionnées. Les fichiers include et source étant bien sûr mis à jour
automatiquement.
Exemple de DoDataExchange
void CBnqView:: DoDataExchange (CDataExchange* pDX)
{
CMyFormView:: DoDataExchange (pDX);
DDX_Control (pDX, IDC_CEDITCDEBNQ, m_EditCdeBnq);
DDX_Control (pDX, IDC_CEDITCDEGUICHET, m_EditCdeGuichet);
DDX_Control (pDX, IDC_CEDITDOM, m_EditDom);
}
|
Il existe d'autres formes d'échanges :contrôle vers entiers,string .
DoDataExchange sera appelée chaque fois que UpdateData sera invoquée,
L'échange des données se fera par la fonction DDX_xxxx qui établira le lien entre le numéro d'identité du contrôle (IDC_) et sa variable.
Dans le cas de la fonction DDX_Control d'autres mécanismes sont mis en jeu.
void AFXAPI DDX_Control (CDataExchange* pDX, int nIDC, CWnd& rControl);
|
Au premier UpdateData le contrôle est « subclassé » ,c'est-à-dire qu'on va intercepter les messages Windows à destination du contrôle (tous les processus par défaut de Windows) pour lui donner un autre « moteur » de gestion des messages ,celui de l'objet mentionné dans la fonction DDX_Control .
Ce travail est fait par la fonction CWnd ::SubclassWindow(HWND hWnd) qui fait appel elle-même à
LONG SetWindowLong (
HWND hWnd,
int nIndex,
LONG dwNewLong);
|
C'est à la fin de ce traitement dont je viens de résumer les grandes lignes que la donnée membre m_hWnd de la variable contrôle sera affectée.
Autre point un UpdateData est fait à votre « insu » dans la fonction CDialog ::OnInitDialog
BOOL CDialog:: OnInitDialog ()
{
if (! UpdateData (FALSE))
{
TRACE0 (" Warning: UpdateData failed during dialog init.\n " );
EndDialog (- 1 );
return FALSE;
}
}
|
Les conséquences de ce qui vient d'être dit sont nombreuses :
- Toute variable contrôle déclarée dans une fenêtre dialogue (CDialog ou CFormView etc ..) qui ne fera pas partie de la fonction DoDataExchange ne sera pas « subclassée » son handle de fenêtre sera égal à NULL et son utilisation provoquera une assertion.
- Toute variable contrôle non présente dans la fonction DoDataExchange ne sera pas affectée par l'action de UpdateData.
- Pour subclasser un contrôle manuellement on pourra utiliser la fonction SubClassDlgItem :
BOOL CAboutDlg:: OnInitDialog ()
{
CDialog:: OnInitDialog ();
m_myButton.SubclassDlgItem (IDC_BUTTON1, this );
|
Pour placer dans la fonction DoDataExchange une variable dynamique utiliser la technique suivante :
void CBnqView:: DoDataExchange (CDataExchange* pDX)
{
CMyFormView:: DoDataExchange (pDX);
DDX_Control (pDX, IDC_CEDITCDEBNQ, m_EditCdeBnq);
if (m_pEditDynamique)
{
DDX_Control (pDX, IDC_CEDITDYN, * m_pEditDynamique);
}
DDX_Control (pDX, IDC_CEDITCDEGUICHET, m_EditCdeGuichet);
DDX_Control (pDX, IDC_CEDITDOM, m_EditDom);
}
|
L'appel à la fonction DDX_Control se fera uniquement si le pointeur est différent de NULL.
Une cause de plantage classique :le contrôle est enlevé dans la ressource et on oublie de supprimer la variable par ClassWizard au premier UpdateData on aura une belle assertion d'erreur dans le source DLGDATA.CPP.
Pour clôturer la question, il existe dans la documentation MSDN une note d'information intéressante sur tous les problèmes d'assertions avec les macros DDX_ :
INFO : Foundation Classes Common Asserts, Causes, and Solutions
Q117326
|
|