Creating Validation Routines

In a previous column, I talked about UpdateData(), which moves data

between member variables and controls. Timothy Purves, Director of

Systems Architecture at the Henry Ford Health System, wrote me about

UpdateData(). The code given for the OK button handler was:

void CSetWinner::OnOK()

{

UpdateData(TRUE);

if (m_winning_value < 1 || m_winning_value > 40)

{

AfxMessageBox("Value out of range");

}

else

CDialog::OnOK();

}

He noted that "This code should check the return from UpdateData...,

otherwise if you have a mixture of hand validate and DDX_Validate you

might get into a condition where you call OnOK with bad values."

UpdateData(TRUE) returns a BOOL value. The value is meaningful if the

parameter is TRUE (updating the member values from the controls).

(Note: I think that this emphasizes why this function should have been

broken into two functions. The return value is not meaningful if you

FALSE to update the controls from the member values).

If you used ClassWizard to set up a minimum and maximum value for a

member variable, there will be a line in your AFX_DATA_MAP(CSetWinner)

that looks like:

DDV_MinMaxInt(pDX, m_winning_value, 1, 40);

DDV stands for Dialog Data Validation. When UpdateData(TRUE) is

called, this validation is performed. If the value is not valid, then

a message is displayed to the user and they are directed back to the

appropriate control. UpdateData() will return FALSE if any validation

fails. If you use both DDV validation and manual validation, the user

will get two error messages - one from DDV and one you generate. To

avoid this, you should test the result of UpdateData(). The code will

then look like:

void CSetWinner::OnOK()

{

if (!UpdateData(TRUE))

return;

if (m_winning_value < 1 || m_winning_value > 40)

{

AfxMessageBox("Value out of range");

}

else

CDialog::OnOK();

}

The test is then redundant since the value has already been checked by

DDV. However you might want to put additional validation for other

fields in this routine. If you use DDV, you'll get a set of error

messages that may not resemble the error messages you want to manually

code.

You can create your own DDV routines. If you've got a field whose

validation is going to be used several times (in a single program or a

set of programs), then that's a good idea. If the field is only used

in a single dialog box, then it's probably overkill to create a

separate validation routine.

You can use the standard DDV routines in a more dynamic manner. The

ClassWizard only allows fixed values for the minimum and maximum

values. If you move the DDV line from inside the DATA_MAP, ClassWizard

will not worry about it. You'll probably need to move the DDX line as

well, since the DDV line for a control needs to immediately follow the

DDX line for that control. Once the DDV is outside, you can set the

values dynamically from variables or expressions. For example:

void CSetWinner::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CSetWinner)

//}}AFX_DATA_MAP

DDX_Text(pDX, IDC_WINNING_VALUE, m_winning_value);

int low_number = 1;

int high_number = 40;

DDV_MinMaxInt(pDX, m_winning_value, low_number,

high_number);

}

In the next column, we'll return to our examination of controls.

What’s wrong? The new clean desk test
Join the discussion
Be the first to comment on this article. Our Commenting Policies