You can achieve what you want with a modeless dialog, though it's a bit strange:
- call the dialogs Create
in ParentWindow.OnCreate
. Pass ParentWindow as parent
- the dialog needs to be created invisibly, IIRC you need to override CMyDialog::PreCreateWindow
for that
- to open the dialog, use dlg.ShowWindow(SW_SHOW)
and parent.EnableWindow(false)
- to close, use dlg.ShowWindow(SW_HIDE)
and parent.EnableWindow(true)
However, I'd advice against that.
- It doesn't even attempt to separate view from controller, but that might be forgivable.
- It binds the dialog to one parent, i.e. it can't be shown from another window.
- It doesn't allow to implement "Cancel" correctly
- Last not least, it feels very strange - which might be a code smell or a matter of taste.
Here's what I'd consider "normal":
All my settings dialogs are associated with a Settings class, and end up following roughly the following interface:
class CSettings
{
double speed;
EDirection direction;
bool hasSpeedStripes;
bool IsValid(CString & diagnostics);
};
class CSettingsDialog
{
CSettings m_currentSettings;
public:
// that's the method to call!
bool Edit(CWnd * parent, CSettings & settings)
{
m_currentSettings = settings; // create copy for modification
if (DoModal(parent) != IDOK)
return false;
settings = m_currentSettings;
return true;
}
OnInitDialog()
{
// copy m_cuirrentSettings to user controls
}
OnOK()
{
// copy user controls to m_currentSettings
CString diagnostics;
if (!m_currentSettings.IsValid(diagnostics))
{
MessageBox(diagnostics); // or rather, a non-modal error display
return;
}
EndDialog(IDOK);
}
};
The copy is necessary for the validate. I use the settings class for the "currentSettings" again, since I am not much in favor of MFC's DDX/UpdateData() mechanism, and often do the transfer manually.
However, if you follow MFC's ideas, you would
- use class wizard to map the controls to data members, where you can do basic range validation
- In OnInitDialog, copy the settings to the data members and call UpdateData(false)
- In OnOK, call UpdateData(true), and "return" the data members.
You could even manually edit the DoDataExchange to map the controls directly to m_currentSettings members, but that doesn't work always.
A interdependency validation should be done on the copy since the user might change the values, see that the new values aren't ok, and then press cancel, expecting the original values to be preserved. Example:
if (speed < 17 && hasSpeedStripes)
{
diagnsotics = "You are to slow to wear speed stripes!";
return false;
}
the validation should be separate from the dialog class (though one could argue that generating the diagnostics don't belong into the settings class either, in that case you'd need a third "controller" entity indeed. Though I usually get by without)
Best Answer
Set a flag in
OnInitDialog
Use your dialog's
m_hWnd
: