SamuelRobinson.com
A resource for Windows programmers
The CDialogBar class is a powerful, but sometimes difficult to use, class. This article will discuss some of the more common problems experienced when implementing a CDialogBar.
The accepted usage model for the CDialogBar is to include a CDialogBar as a member of the CMainFrame, and instantiate it in the OnCreate for the CMainFrame with the resource id for the dialog used. You can then add handlers for dialog items that are part of the dialog resouce contained in the CDialogBar to the CMainFrame or the document. This works fairly well but is not well encapsulated way as it puts knowledge of the dialog bar's controls into external classes. This tightly couples those classes to the CDialogBar. The logical thing to do is to derive a class from CDialogBar and put the handlers in it. This is more elegant, and allows easier re-use of the CDialogBar derived class.
Deriving a class from CDialogBar is easy. Start by using the ClassWizard to create a generic CWnd, and then modify the base class. Add the DECLARE_DYNCREATE(CYourClass) macro to the definition (.h) file. Then modify the implementation file (.cpp) by adding the IMPLEMENT_DYNCREATE(CYourClass, CDialogBar) macro. Also change the default handler in the implementation's message map from CWnd to CDialogBar. Failure to make the second change produces a fairly cryptic assertion in Dockcont.cpp deep in the MFC source. If you see that you're failing at the following line, check for this.
ASSERT(pBar->m_pDockSite != NULL);
The next step is to create a dialog resource to use with your dialog bar. I simply used the resource created by default when using the resource editor. It is necessary to change a few properties so that the resource can be used. The dialog resource should be made child, and non-visible. If this fails you will trigger an assert in CDialogBar::Create() that reads as follows:
// dialog template must exist and be invisible with WS_CHILD set
if (!_AfxCheckDialogTemplate(lpszTemplateName, TRUE))
{
-> ASSERT(FALSE); // invalid dialog template name
PostNcDestroy(); // cleanup if Create fails too soon
return FALSE;
}
Clear all style check boxes, set the window style (on the second tab of the properties dialog) to child, and set the border (also on the second tab of the properties dialog)to none.
Now the class can be added to the definition of the CMainFrame.
CDlgBarDemo m_wndDlgBar;
In the implementation CMainFrame::OnCreate() add the creation code for the dialog bar. Also add the code to enable docking for the dialog bar and to dock it.
if (!m_wndDlgBar.Create(this, IDD_DLGBARDEMO,
WS_CHILD|WS_VISIBLE| CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC,
IDD_DLGBARDEMO))
{
TRACE0("Failed to create DlgBar\n");
}
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndDlgBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
DockControlBar(&m_wndDlgBar,AFX_IDW_DOCKBAR_RIGHT);
At this point it is appropriate to build and run the project. The dialog will be docked on the right side of the client area. It can be docked to any of the normal dock sites. The job is not finished though because there are no handlers for the OK and Cancel buttons.
// Operations void OnIDOK();
In the implementation add a handler by adding a ON_BN_CLICKED macro to the message map and the OnIDOK handler.
BEGIN_MESSAGE_MAP(CDlgBarDemo, CDialogBar)
//{{AFX_MSG_MAP(CDlgBarDemo)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDOK,OnIDOK)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDlgBarDemo message handlers
///////////////////////////////////////////////////////////////////////////
void CDlgBarDemo::OnIDOK()
{
AfxMessageBox(_T("Handled by CDlgBarDemo"));
}
Unfortunately adding a handler to the dialog bar class does not enable the OK button. This is caused by the way that CCmdUI::DoUpdate() is implemented. The best solution to this is to tell the OnUpdateCmdUI() not to disable any of the controls.
void CDlgBarDemo::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
bDisableIfNoHndler = FALSE;
CDialogBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
}
At this point, addtional functionality is a matter of adding more controls to the dialog, and more handlers to the dialog class. Most of the difficulty is in doing the exact steps required to get to this point.
Please tell me what you think about this content and how I might improve it.