Task Dialog Wizard

Task Dialog Wizard

This article was submitted .

One of the features of the new TaskDialog API in Windows Vista is the ability to run it as a multi-paged control, with a forward progressing Wizard-like flow.

It is not a widely know feature of the Task Dialog, perhaps because Microsoft didn't bother to initially document the TDM_NAVIGATE_PAGE message that invokes this function. In multi-page mode you can replace the existing page shown in the Task Dialog on the fly. This allows you to instantly provide a new page if the user presses a button or some other event happens on the page shown.

The Task Dialog offers several improvements to the old MessageBox API, including custom buttontext, hyperlinks, expanding footer areas and a callback programming style. Still, because the Task Dialog internally uses Microsoft's DirectUser layout library you are limited to exactly the functionality defined in the Task Dialog, since traditional window subclassing is likely not to work properly.
There are however a number of simple tasks that would span several dialogs that can be implemented much faster by using the functionality already available in the Task Dialog APIs. I have found that scenarios where the user is prompted to start one of several long-running work processes are good candidates to be used with a multi-paged Task Dialog: First the user is prompted to choose the work to be done, then it immediately continues to the progress page and eventually ends with the presentation of a completion page.

Using the control

This is a wrapper for the TaskDialog API, allowing you to easily set up several pages and to navigate between these pages. To use this control, you'll need to create a CTaskDialogWizard instance and add pages to it. Each page must derive from the C++ template CTaskDialogWizardPageImpl which is a basic wrapper for the native WTL class CTaskDialogImpl. The CTaskDialogImpl class is managing the TaskDialog notifications and eases the creation of dialog configurations as we'll see later.
CMyPage1 dlgPage1;
CMyPage2 dlgPage2;

CTaskDialogWizard dlgWizard;
dlgWizard.SetTitle(L"Burn CD Wizard");

// Show dialogs...
This sets up a wizard with two pages. You can apply a few settings on the wizard level that trickle down to the pages. This is great for setting a common window title for instance.

Each Wizard page ends up deriving from the WTL CTaskDialogImpl class that offers many wrapper functions for manipulating the TASKDIALOGCONFIG structure and for processing the Task Dialog callback notifications from a C++ class. Here is an example:

class CMyPage1 : public CTaskDialogWizardPageImpl<CMyPage1>
  enum { IDD = IDD_PAGE1 };

    // Set page texts and stuff...
    SetMainInstructionText(L"Begin Work");
    SetContentText(L"This is the description text.");
    ModifyFlags(0, TDF_ENABLE_HYPERLINKS);
    SetFooterText(L"Visit <a></a>");

  void OnHyperlinkClicked(LPCWSTR pszHREF)
    ::ShellExecute(m_hWnd, L"open", L"", 
This is a standard Task Dialog implementation as you would do it with the CTaskDialogImpl WTL class. The only new thing is the IDD constant that identifies the page for navigation.
Once you have added several pages to the wizard, you'll want to navigate between the pages. This is done by handing one of the events triggered in the Task Dialog (such as a button click) and then decide which page to navigate to.
  BOOL OnButtonClicked(int nButton)
    if( nButton == TDCBF_OK_BUTTON ) return NavigatePage(IDD_PAGE2);
    return FALSE;  // Otherwise close dialog
The new NavigatePage() override takes the IDD constant of a page previously added to the wizard.

Source Code Dependencies

Microsoft WTL 8.5 Library

Download Files

DownloadSource Code and Sample (30 Kb)

To the top