TN026:DDX 和 DDV 例程

注释

自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。

此说明介绍了对话数据交换(DDX)和对话数据验证(DDV)体系结构。 它还介绍了如何编写DDX_或DDV_过程,以及如何扩展 ClassWizard 以使用例程。

对话框数据交换概述

所有对话数据函数均使用C++代码完成。 没有特殊资源或 magic 宏。 机制的核心是在执行对话数据交换和验证的每个对话类中重写的虚拟函数。 它始终以以下形式找到:

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(TRUE)在默认 CDialog::OnOK 处理程序中调用,并在 UpdateData默认值 CDialog::OnInitDialog中调用 (FALSE)。

DDV_例程应紧跟该 字段的DDX_例程。

工作原理

无需了解以下内容即可使用对话数据。 但是,了解后台的工作原理将有助于编写自己的交换或验证过程。

DoDataExchange成员函数与成员函数非常类似 Serialize - 它负责从外部窗体(在本例中控制对话中的控件)从/向类中的成员数据获取或设置数据。 pDX 参数是用于执行数据交换的上下文,类似于参数CArchiveCObject::SerializepDX(对象CDataExchange)的方向标志非常类似于CArchive方向标志:

  • 如果 !m_bSaveAndValidate,则将数据状态加载到控件中。

  • 如果 m_bSaveAndValidate,则从控件设置数据状态。

仅当设置时 m_bSaveAndValidate ,才会进行验证。 值 m_bSaveAndValidate 由 BOOL 参数确定为 CWnd::UpdateData

还有三个有趣的 CDataExchange 成员:

  • m_pDlgWnd:包含控件的窗口(通常是对话框)。 这是为了防止DDX_的调用方和DDV_全局函数必须将“this”传递给每个 DDX/DDV 例程。

  • PrepareCtrlPrepareEditCtrl:准备用于数据交换的对话框控件。 存储控件的句柄,以便在验证失败时设置焦点。 PrepareCtrl 用于非编辑控件, PrepareEditCtrl 用于编辑控件。

  • Fail:在显示一个消息框后调用,提醒用户输入错误。 此例程会将焦点还原到最后一个控件(最后一次调用 PrepareCtrlPrepareEditCtrl)并引发异常。 可以从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 编辑,因此应移出特殊格式注释(//{{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_例程集成到 ClassWizard 用户界面中,支持 DDX/DDV 自定义的子集。 如果计划重复使用项目中或许多项目中的特定 DDX 和 DDV 例程,则这样做才具有成本效益。

为此,DDX.CLW(Visual C++早期版本的 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

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 已排序列表框
    M 组合框(带有编辑项)
    N 非排序的下拉列表
    n 已排序的下拉列表
    1 如果应将 DDX 插入添加到列表头(默认添加到结尾),这通常用于传输“Control”属性的 DDX 例程。
  • vb-keys

    此字段仅用于 VBX 控件的 16 位产品(32 位产品不支持 VBX 控件)

  • 提示

    要放置在属性组合框中的字符串(无引号)

  • 类型

    标头文件中要发出的类型的单个标识符。 在上面的示例中,使用 DDX_Time,这将被设置为 CTime。

  • vb-keys

    此版本未使用,应始终为空

  • initValue

    初始值 - 0 或空白。 如果为空,则不会在实现文件的 //{{AFX_DATA_INIT 节中写入任何初始化行。 空条目应用于C++对象(例如CStringCTime,等等),这些对象具有保证正确初始化的构造函数。

  • DDX_Proc

    DDX_过程的单个标识符。 C++函数名称必须以“DDX_”开头,但不包括DDX_Proc>标识符中的<“DDX_”。 在上面的示例中, <DDX_Proc> 标识符为 Time。 当 ClassWizard 将函数调用写入 {{AFX_DATA_MAP 节中的实现文件时,它会将此名称追加到DDX_,从而到达DDX_Time。

  • 评论

    要在此 DDX 的变量对话框中显示的注释。 在此处放置想要的任何文本,通常提供描述 DDX/DDV 对执行的作的内容。

  • DDV_Proc

    条目的 DDV 部分是可选的。 并非所有 DDX 例程都具有相应的 DDV 例程。 通常,将验证阶段作为传输不可或缺的一部分包括在内更为方便。 通常,DDV 例程不需要任何参数,因为 ClassWizard 不支持不带任何参数的 DDV 例程。

  • 精 氨 酸

    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 漂浮
      F 翻倍
      s 字符串

另请参阅

按编号列出的技术说明
按类别列出的技术说明