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 в любое время для обмена данными и проверки. По умолчанию (TRUE) вызывается в обработчике по умолчанию UpdateDataи UpdateData(FALSE) вызывается по умолчанию CDialog::OnOKCDialog::OnInitDialog.

Подпрограмма DDV_ должна немедленно следовать DDX_ подпрограмме для этого поля.

Как это работает

Чтобы использовать данные диалога, вам не нужно понимать следующее. Однако понимание того, как это работает за кулисами, поможет вам написать собственную процедуру обмена или проверки.

Функция-член DoDataExchange очень похожа Serialize на функцию-член — она отвечает за получение или настройку данных во внешнюю форму (в этом случае элементы управления в диалоговом окне) из/в данные-члены в классе. Параметр pDX — это контекст для обмена данными и аналогичен параметру CArchiveCObject::Serialize. PDX (CDataExchangeобъект) имеет флаг направления так же, как CArchive и флаг направления:

  • Если !m_bSaveAndValidate, загрузите состояние данных в элементы управления.

  • Если m_bSaveAndValidate, задайте состояние данных из элементов управления.

Проверка происходит только в том случае, если m_bSaveAndValidate задано значение. Значение m_bSaveAndValidate определяется логическим параметром CWnd::UpdateData.

Есть три других интересных CDataExchange члена:

  • m_pDlgWnd: окно (обычно диалоговое окно), содержащее элементы управления. Это позволит предотвратить передачу вызовов DDX_ и DDV_ глобальных функций в каждую подпрограмму 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);
    

    Примечание.

    Такие произвольные выражения не могут быть изменены классомWizard и поэтому следует перемещать вне специальных комментариев формата (/{{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);

Примечание.

Как показано выше, такой код не может быть изменен классомWizard и должен использоваться только за пределами специальных комментариев формата.

Поддержка ClassWizard

ClassWizard поддерживает подмножество настроек DDX/DDV, позволяя интегрировать собственные DDX_ и DDV_ подпрограммы в пользовательский интерфейс ClassWizard. Это полезно, только если планируется повторно использовать определенные подпрограммы DDX и DDV в проекте или во многих проектах.

Для этого специальные записи создаются в DDX.CLW (предыдущие версии Visual C++ хранят эти сведения в APSTUDIO. INI) или в проекте. CLW-файл. Специальные записи можно ввести в разделе [Общие сведения] проекта. CLW-файл или в разделе [ExtraDDX] файла DDX.CLW в каталоге \Program Files\Microsoft Visual Studio\Visual C++\bin. Если файл DDX.CLW еще не существует, может потребоваться создать файл DDX.CLW. Если вы планируете использовать пользовательские подпрограммы DDX_/DDV_ только в определенном проекте, добавьте записи в раздел [Общие сведения] проекта. Вместо этого файл CLW. Если вы планируете использовать подпрограммы во многих проектах, добавьте записи в раздел [ExtraDDX] DDX.CLW.

Общий формат этих специальных записей:

ExtraDDXCount=n

где n число строк ExtraDDX, которые следует следовать, формы

ExtraDDX?=keys; vb-keys; запрос; тип; initValue; DDX_Proc [; DDV_Proc; prompt1; arg1 [; prompt2; fmt2]]

Где? — число 1 — n , указывающее, какой тип DDX в списке определяется.

Каждое поле разделено символом ";". Поля и их назначение описаны ниже.

  • keys

    Список отдельных символов, указывающих, для каких диалоговых окон разрешен этот тип переменной.

    Символ Разрешенный элемент управления
    E изменить
    О Поле проверка с двумя состояниями
    в поле проверка три состояния
    R первая переключатель в группе
    L поле несортированного списка
    l поле с сортировкой списка
    Пн. поле со списком (с элементом редактирования)
    N несортный список раскрывающихся списков
    n отсортированный список раскрывающихся списков
    1 Если вставка DDX должна быть добавлена в голову списка (по умолчанию добавляется к хвосту). Обычно это используется для подпрограмм DDX, которые передают свойство Control.
  • vb-keys

    Это поле используется только в 16-разрядном продукте для элементов управления VBX (элементы управления VBX не поддерживаются в 32-разрядном продукте).

  • prompt

    Строка для размещения в поле со списком свойств (без кавычки)

  • type

    Один идентификатор для типа, который будет выдаваться в файле заголовка. В нашем примере выше с DDX_Time это значение будет иметь значение CTime.

  • vb-keys

    Не используется в этой версии и всегда должен быть пустым

  • initValue

    Начальное значение — 0 или пустое. Если она пуста, строка инициализации не будет записана в разделе //{{AFX_DATA_INIT файла реализации. Пустая запись должна использоваться для объектов C++ (например CString, CTimeи т. д.), которые имеют конструкторы, гарантирующие правильную инициализацию.

  • DDX_Proc

    Один идентификатор для процедуры DDX_. Имя функции C++ должно начинаться с "DDX_", но не включать "DDX_" в <идентификатор DDX_Proc> . В приведенном выше <примере идентификатор DDX_Proc> будет временем. Когда ClassWizard записывает вызов функции в файл реализации в разделе {{AFX_DATA_MAP, он добавляет это имя к DDX_, таким образом, поступающим к DDX_Time.

  • комментарий

    Комментарий для отображения в диалоговом окне для переменной с помощью этого DDX. Поместите любой текст, который вы хотите здесь, и обычно укажите что-то, что описывает операцию, выполняемую парой DDX/DDV.

  • DDV_Proc

    Часть DDV записи является необязательной. Не все подпрограммы DDX имеют соответствующие подпрограммы DDV. Часто более удобно включить этап проверки в качестве неотъемлемой части передачи. Это часто происходит, когда подпрограмма DDV не требует каких-либо параметров, так как ClassWizard не поддерживает подпрограммы DDV без каких-либо параметров.

  • arg

    Один идентификатор процедуры DDV_. Имя функции C++ должно начинаться с "DDV_", но не включать "DDX_" в <идентификатор DDX_Proc> .

    arg следует 1 или 2 DDV args:

    • запрос

      Строка для размещения над элементом редактирования (с и для акселератора).

    • fmtN

      Формат символа для типа arg, одно из следующих элементов:

      Символ Тип
      d INT
      u unsigned int
      D long int (т. е. длинный)
      U long unsigned (т. е. DWORD)
      f с плавающей запятой
      F двойной точности
      s строка

См. также

Технические примечания по номеру
Технические примечания по категории