Sample Application

[Previous] [Next]

A form in Visual Basic is represented as a special type of class that includes hooks into the Windows graphical user interface (GUI) technology. The gory details of the hooks remain suppressed within the Visual Basic run-time library. What the Visual Basic programmer has access to is a special type of class module officially referred to as a Form module. A Form module is associated with a particular window that can contain controls (children) such as buttons and list boxes. Both the window and its controls raise events in response to user interaction. Visual Basic auto-magically subscribes to events simply by allowing the programmer to stub out event handler subroutines made readily available in the Object drop-down list box in the Form class module editor. This means of event handling, which by the way should be considered an implementation of an Event Service design pattern, has been the cornerstone technology advantage of programming Windows GUI applications in Visual Basic.

The purpose of this sample is to create a localized Windows application. The typical approach to localizing an application calls for replacing string literals with variable references to strings that are obtained from a table. The form that would display the text usually follows one of two approaches: It incorporates some auto-proportioning algorithm to resize the form and its controls, and makes font changes appropriately to accommodate the language text; or it determines a static proportion that can accommodate all anticipated languages the application must display. Both approaches eventually fall short of an ideal solution mainly because there is such a great disparity between the number of characters required to represent the words that form a given phrase. For example, a phrase in German that requires 100 characters might require only one character in Japanese.

A third, less practiced alternative exists, which would be to maintain a completely separate form for each language. By using this approach, you can customize the display to the exact dimensions required. The important issue with this alternative is that you must figure out how to get all forms to publish identical events that a single subscriber can handle. Hence the behavior is written once and remains consistent across multiple language implementations that can be provided at any point. You would also want to package each language version in its own satellite DLL that is interchangeable in the Windows application.

What better way to implement this third alternative than by taking advantage of the ActiveX DLL technology available in Visual Basic? Unfortunately, Form classes must be private in an ActiveX project, making them inaccessible from a client application. My solution to this problem is to create a public ActiveX class that encapsulates a Form object and delegates through appropriate method calls such as IForm.Show and IForm.Hide. In addition, this class must be able to notify a subscriber of events that would normally be handled in the Form class. This is accomplished by creating the interface-based implementation solution of the Event Service design pattern that publishes the events captured in the private Form object defined in the ActiveX DLL.

To clearly demonstrate the benefits of this approach, I've created a simulated online banking window that allows you to proceed in English or in Spanish by the click of a button. Based on your selection, you get the Security form in English or in Spanish. (See Figure 13-2.) Notice that despite the difference in language, pressing the OK and Cancel buttons produces identical behavior in both windows. Under the hood, this application consists of the following components.

  • FormsEnglish.DLL and FormsSpanish.DLL Each ActiveX DLL defines the language-specific Security form for logging into the system.
  • Banker.exe A Standard EXE that defines the initial Welcome form. Banker.exe creates an IForm object that either privately references an English or a Spanish Form object.
  • FormLib.tlb A type library containing interfaces IForm and IFormEvents shared by the Banker EXE and the FormsEnglish and FormsSpanish DLLs.

The code in the following discussion highlights the participants of the Event Service design pattern that contribute to the successful implementation of a localized satellite Forms DLL. For a full source code disclosure, refer to the companion CD.

The following components are compiled in FormLib.tlb and defined using IDL rather than Visual Basic. (Appendix B explains how to define interfaces in IDL directly and the reasons for doing so.)

click to view at full size.

Figure 13-2. Sample application localized Security login window.

  • IForm (Implicit IPublisher and explicit IEventChannel) This interface defines the methods that invoke the encapsulated Form object and that register a subscriber interested in Form events. But it also provides Advise and UnAdvise methods for subscribing and unsubscribing, respectively, to events published by a concrete class of object that implements this interface. The events published in this case will coincide with the events initially captured in the encapsulated Form object.
  •  interface IForm : IDispatch { [id(0x60030000)] HRESULT Show( [in, optional, defaultvalue(0)] FormModalityConstants Modal, [in, optional] VARIANT OwnerForm); [id(0x60030001)] HRESULT Hide(); [id(0x60030002)] HRESULT Advise( [in] IFormEvents* frmEvt, [in, optional] BSTR Notify, [out, retval] long* ); [id(0x60030003)] HRESULT UnAdvise([in] long Cookie); }; 

  • IFormEvents Defines event signatures published by concrete implementations of IForm, which in this case is the FormLogin class.
  •  interface IFormEvents : IDispatch { [id(0x60030000), vararg] HRESULT OnEvent( [in] BSTR Evt, [in, out] SAFEARRAY(VARIANT)* Params); }; 

This next component is defined in both FormsEnglish.DLL and FormsSpanish.DLL:

  • FormLogin (hybrid of PublisherImpl and EventChannelImpl classes) Concrete class that implements the IForm interface. Its sole purpose is to delegate invocations to an associated private Form object and to publish events initially captured by the private Form object. Publishing is implicit because there isn't a separate IPublisher interface. Publishing occurs within the code, as the following code illustrates. Each satellite language ActiveX DLL must contain this class definition.
  •  ' FormLogin Class Implements FormLib.IForm ' Form frmLogin related variables Private m_frmLogin As frmLogin Private WithEvents cmdOK As CommandButton Private WithEvents cmdCancel As CommandButton ' IFormEvents Private m_FormEvents As IFormEvents  ' IForm interface implementation Private Function IForm_Advise(ByVal frmEvt As _ FormLib.IFormEvents, _ Optional ByVal Notify _ As String) As Long Set m_FormEvents = frmEvt End Function ' Form frmLogin event handlers that publish Form events to ' an IFormEvents object via its OnEvent method ' Private Sub cmdCancel_Click() ' Publish cmdCancel button click event If Not m_FormEvents Is Nothing Then Call m_FormEvents.OnEvent("cmdCancel.Click") End If End Sub Private Sub cmdOK_Click() ' Publish cmdOK button click event If Not m_FormEvents Is Nothing Then Call m_FormEvents.OnEvent("cmdOK.Click", _ m_frmLogin.txtUserName, _ m_frmLogin.txtPassword) End If End Sub 

This final component is defined in Banker.exe:

  • FormEventsImpl Concrete class that implements the IFormEvents interface. It implements event handlers to event signatures defined in the IFormEvents interface. In this particular sample application, this class is the only implemented subscriber. Hence consistent behavior is maintained across multiple satellite DLLs.
  •  ' FormEventsImpl Class Implements FormLib.IFormEvents ' Implementation of IFormEvents.OnEvent Private Sub IFormEvents_OnEvent(ByVal Evt As String, _ ParamArray Params() _ As Variant) If Evt = "cmdOK.Click" Then MsgBox "Ok button clicked" & vbLf & _ "UserId = " & Params(0) & vbLf & _ "Password = " & Params(1) Else MsgBox "Cancel button clicked" End If End Sub 



Microsoft Visual Basic Design Patterns
Microsoft Visual Basic Design Patterns (Microsoft Professional Series)
ISBN: B00006L567
EAN: N/A
Year: 2000
Pages: 148

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net