Visual Basic

Toward a General Modality Class

You can both create and manipulate value-added forms by building a CFormAttributes class (see the "Forms Are Classes Too") and adding the function modality mechanism to it. The central requirement for such a mechanism is to associate a parent with each form you create. You can do this by adding a Parent property to the CFormAttributes class:

Public Parent As Form

Now you have somewhere to store a reference to the parent form, so you need to arrange for this reference to be set when the form is loaded. Since you can't pass parameters to a form's Show method (or to the CFormAttributes instance), you need to do this manually from outside the CFormAttributes class. You want to be able to do something like this:

Public Sub ShowChild Child:=frmReview, Parent:=Me

You could make this a global procedure and give it its own BAS file, but it's better to keep all the code in one place by making ShowChild a method of the CFormAttributes class. Obviously, this means you can't invoke ShowChild to display the first form in a hierarchy, but the only implication of this is that you need to make sure that the CFormAttributes class recognizes that it has no parent when it is destroyed. You can also dispense with the Parent parameter since you already have a Self reference in the CFormAttributes class. Here's the method in the CFormAttributes class, which is named NewChild:

Public Sub NewChild(ByVal frmiChild As Form)
      frmiChild.Show
      Set frmiChild.My.Parent = frmPiSelf
      frmPiSelf.Enabled = False
  End Sub

The last statement is the significant one because it's the one that disables the parent form and creates a new mode. You need a reciprocal action to reenable the parent when the form unloads, so you need to define another method:

Public Sub EnableParent()
      If Not Me.Parent Is Nothing Then Me.Parent.Enabled = True
  End Sub

Unfortunately, there's no elegant way to bind this to a form unload; you must ensure that you call this method from each Form_Unload event:

Private Sub Form_Unload()
      My.EnableParent
  End Sub

In fact, the sample code in CHAP13\atribcls\pubatrib.cls has a generic UnloadActions method, which takes the place of EnableParent, but this discussion is clearer if I continue to refer to an EnableParent method.

That takes care of modal child forms, as long as you invoke them with My.NewChild and include the appropriate reciprocal call in the Form_Unload event. You can now build on this to extend the mechanism. To cope with the swapping in the sample program, for example, you need to do a couple of extra things: pass on the outgoing form's parent reference to the new form and then prevent the parent from being reenabled when the old form unloads. You can do this by adding a new method and modifying the EnableParent method slightly so that the two communicate through a module-level flag:

Private bPiKeepParentDisabled As Boolean
  Public Sub SwapMe(ByVal frmiNewChild As Form)
      frmiNewChild.Show vbModeless
      If frmiNewChild.Enabled Then
          Set frmiNewChild.My.Parent = Parent
          bPiKeepParentDisabled = True
      End If
      Unload frmPiSelf
  End Sub
  Public Sub EnableParent()
      If Not bPiKeepParentDisabled Then
          If Not Parent Is Nothing Then Parent.Enabled = True
      End If
  End Sub

Notice the check to find out whether the form you're trying to swap to is enabled. If it isn't, it must already have been loaded, in which case you'll just leave the Parent property alone. This is an ad hoc test that works in the simple examples shown here, but it might not be general, and so you'll need to extend the mechanism to cope with other situations. For example, the mechanism as it stands won't prevent you from trying to swap to a form that's in the middle of a modal cascade-in fact, this would orphan any child forms in the cascade. With a little thought, you should be able to extend the mechanism to allow swapping to remove child forms of the form you're trying to swap to, to prevent swapping between forms belonging to other functions in a function modal situation, or to support any other flavors of modality you care to invent.