company logo

Implementing wizard patterns

After designing wizard's step controls, usually, one has to implement appropriate context classes for each step control. By default, wizard step controls should be associated with the cStdWizardBase (or cosiStdWizardBase ) context class, which is provided with the template. One may, however, create more specific context classes in order to control the wizard properly.

The wizard_frame context class cStdWizard (or cosiStdWizard ) is rather generic. Nevertheless, it has to be overloaded in many cases in order to provide proper wizard inizialization.

Buttons on bottom of the wizard frame are controlled by the wizard status field. This information also influences the process flow, i.e. the rules for skipping wizards steps or selecting the next wizard step.

The wizard pattern context class ( cosiStdWizard / cStdWizard ) and its base class ( cosiStdDialog / cStdDialog ) provide wizard initialization, which includes initializing an object instance for the current property handle (wizard's data source) and handling transaction behavior ( cosiStdDialog ::begin() , commit() and rollBack() ).

Wizard initialization

In order to initialize the wizard properly, the wizard_frame context class cosiStdWizard has to be extended. By overloading the doAfterOpen() event handler, specific wizard resources may be initialized, which are typically defined as properties of the derived context class.

The wizard uses a property handle for managing wizard's data ( data_ph ). By default, this is a cursor copy of the property handle of the parent control. In order to provide an application defined data property handle, data_ph has to be initialized before opening calling cosiStdWizard:: doAfterOpen() (see example below).

A new (initialized) instance will be created immediately before starting the first step ( do_StartAction() ). Hence, initalization should be performed when starting the first wizard step. When terminating the first wizard step, the instance will be saved.

In order to avoid multiple initialization, the wizard_frame context class defines an initialized property, which is set to true after doAfterOpen() has been called ones. In order to initialize basic wizard frame setting properly, the base class function has to be called in any case when overloading the doAfterOpen() event handler.

// osi fragment

FUNCTION virtual int32 cPersonWizard :: doAfterOpen ( ) {

VARIABLES

  ControlContext      &high_ctx = highContext();

  SET< VOID >         &par;

  int32                iExecutionError = false;

PROCESS

  if ( initialized )                                LEAVE;

  par &= high_ctx.property();

  if ( !par.isValid() )                             ERROR;

  data_ph.open(par.database(),"Auftrag",AccessModes::Update);

  cosiStdWizard::doAfterOpen();

  ...

  return ( iExecutionError );

}

Wizard step controls

Each wizard step control may influence further processing flow of the wizard. The default context class associated with a wizard step control is the cStdWizardBase (or cosiStdWizardBase ) context class. When implementing an extended wizard step context class inheriting from the default context class, typically, the following functions should be overloaded:

  • initializing: doAfterOpen(), doAfterShow(), doAfterHandleOpen()
  • start step: do_StartAction()
  • validate state: do_ValidateAction()
  • terminate step: do_StopAction()

Moreover, field defined in the wizard step needs to be associated with specific context classes in order to inform the wizard step about relevant changes (e.g. filling data in an mandatory field).

Button states for wizard navigation buttons (next, previous etc) depend on the current wizard step status . The next button remains disabled as long as the wizard step status in not valid ( DLGS_valid ). Wizard status is typically maintained in the do_ValidateAction() handler.

Skipping wizard steps becomes possible by denying the do_StartAction() handler (returning true ). Processing data entered in the wizard step is typically the task of the do_StopAction() handler.

In order to communicate directly with the wizard_frame context class, each wizard step refers to this class via the frame_ctx property. Even though the property is simply defined as cosiStdDialog reference (base type of cosiStdWizard ), properties for the extension context class implemented for the wizard are accessible immediately when using OSI. Implementing a C++ or C# context class (inheriting from cStdWizard ) requires dynamic cast operation in order to provide proper type for calling object.

Initialize wizard step control

For providing more sophisticated wizards, wizard step fields may be initialized from additional information available in the current context. In order to initialize the wizard step control, one may overload one of open event handlers doAfterOpen(), doAfterHandleOpen() or the doAfterShow() handler. Open handlers have the disadvantage, the subordinated resources are often not yet available. The doAfterShow() handler does not have this problem, but it is called always when showing the wizard step window, i.e. it will also be called, when stepping backwards using the previous button, i.e initialization has to be validated (e.g. by checking whether fields are still empty).

// OSI implementation

FUNCTION virtual int32 cPersonWizardDate :: doAfterShow ( ) {

  cosiStdWizardBase::doAfterShow();

  if ( field("date").text().isEmpty() )

    field("date").value().assign(Date().now());

  return(false);

}

Start wizard step

Always when starting a new wizard step, the do_StartAction() handler for the wizard step context class will be called. In order to skip the wizard step and proceed with the next one, the handler may return false .

The handler may also be implemented in order to set states for wizard step fields and buttons (enable/disable or hide).

In order to be able to react properly when mowing forward or backward, the handler passes the direction parameter, which is greater than 0 in case of moving forward and less than 0 otherwise.

FUNCTION virtual bool cPersonWizardCreate :: do_StartAction (int32 direction )

{

VARIABLES

  SET< Person >      &person = property();

  bool                bState = true;

PROCESS

// skip step when person does already exist

  if ( !person.isNewInstance() )                   ERROR;

  cosiStdDialogBase::do_StartAction(direction);

ON_ERROR

  bState = false;

FINAL

  return ( bState );

}

Validate wizard step state

Typically, button states have to be controlled in order to release or disable the Next button depending on the data entered into the wizard step. In order to activate the Next button, the wizard step status has to be set to DLGS_valid .

When the wizard step contains mandatory fields, those should be associated with a context class signaling changes in the field as shown in the example below. When changes have been made, the event handler implemented in the field context class calls the do_ValidateAction() handler of the upper context (wizard step context class, that checks the fields in order to set the proper wizard step status .

// check mandatory field (OSI)

FUNCTION virtual int32 cMandatory :: doAfterValueChanged ( ) {

  highContext.do_ValidateAction(true);

  return(false);

}

// update wizard step status (OSI)

FUNCTION virtual int32 cPersonWizardName :: do_ValidateAction (bool bCheckOpt )

{

VARIABLES

  DialogStatus        alt = status;

PROCESS

  if ( status != DialogStatus::DLGS_cancel ) {

    status = DialogStatus::DLGS_invalid;

    if ( !field("name").text().isEmpty() )

      status = DialogStatus::DLGS_valid;

  }

  if ( alt != status )

    valueChanged(bCheckOpt);  //signal status change to wizard frame

  return(false);

}

Terminate wizard step

The handler is called when requesting the previous or next wizard step. Typically, the handler is used to perform final actions resulting from the wizard step data.

Process flow