Target: DHTML

Using WFC's HTML Package to Write Client-Side Browser Applications

By Shawn Burke

Many developers are beginning to target Dynamic HTML (DHTML) and the browser for application development. However, most of them soon realize that working with DHTML and Cascading Style Sheets (CSS) is quite unlike the development they're accustomed to in traditional Win32 programming with Visual Basic or C++. Instead of spending the time learning something entirely unfamiliar, the Windows Foundation Classes HTML package - wfc.html - allows developers to target DHTML with compiled object-oriented code, more sophisticated development tools, and a traditional framework architecture.

In developing WFC, Microsoft wanted to create an interface to Microsoft Internet Explorer's Document Object Model (DOM) that was more developer friendly than the current script interface. The DOM is a rich interface, but using it efficiently requires a vast amount of specific knowledge about CSS and DHTML. So Microsoft created the wfc.html library as part of WFC, and delivered it with Microsoft Visual J++ 6.0 (VJ6).

The wfc.html library allows something not possible using just HTML: a true separation of the UI description (the markup script) from the application logic (the code). In the script scenario, the code and the HTML are in one file, all mixed together. In the wfc.html world, they're completely separate, except for an <OBJECT> tag. This allows developers to create browser-based applications with a traditional Java development tool, which offers much better debugging and code management facilities than are available for script. Design specialists are then free to create the look-and-feel of the HTML document as they like, which can then be cleanly paired with the application logic and deployed to users of Internet Explorer (IE).

Preparing an HTML Document for Use with wfc.html

There are two steps to adding a wfc.html class to an HTML document. The first is to add the <OBJECT> tag, which provides the wfc.html class access to the DOM. The second is to decorate any HTML elements of interest with the appropriate "ID=" attributes.

The <OBJECT> tag is added for you when you create a project using the Code-behind HTML wizard in VJ6 (available on the New page of the Open Project dialog box under Visual J++ Projects | Web Pages. If you wish to change the base class name, you must change the corresponding <PARAM> value in the <OBJECT> tag, as shown in bold here:

<OBJECT classid="java:com.ms.wfc.html.DhModule"
  HEIGHT=0 WIDTH=0 ... VIEWASTEXT ID=OBJECT1>
<PARAM NAME=__CODECLASS VALUE=HelloWorld>
<PARAM NAME=CABBASE VALUE=HelloWorld.CAB>
</OBJECT>

In this case, the default:

VALUE=Class1

has been changed to:

VALUE=HelloWorld

to reflect our DhDocument-derived base class. Because the <OBJECT> tag only provides access to the DOM and is never a visible component, its HEIGHT and WIDTH are set to zero, so it doesn't take up space or otherwise affect the layout of the HTML page.

The com.ms.wfc.html.DhModule class is the bridge between your Java code and the COM interface of IE (the DOM). It implements all the ActiveX plumbing and interfaces to do that job, and knows how to create and launch your DhDocument-derived class.

The second step is to assign ID values to any elements that you're interested in binding to, and creating corresponding elements in your Java code with the same IDs (as shown in the examples later in this article). If you attempt to bind an HTML element to the improper wfc.html class type, a WFCException will be thrown.

Getting Started with HelloWorld

Creating a basic wfc.html application is easy with VJ6. The HelloWorld example demonstrates a simple wfc.html application that binds to elements existing in the HTML page, and dynamically adds some new ones at run time. (The HelloWorld example project is available for download; see end of article for details.)

The main entry point of any wfc.html application - in this case the HelloWorld class - derives from the class com.ms.wfc.html.DhDocument, which automatically binds to the HTML document itself, including the <TITLE> and <BODY> tags. It's also the root container element of the application, to which you can add other elements.

The wfc.html library supplies clean, stateless Java classes that know how to bind to, and manipulate, objects running inside IE. These objects are usually referred to as "elements." Referring to the classes as "stateless" means you can perform any operation on them at any time, and the library takes care of the rest.

What's "binding" all about? If you look in HelloWorld.htm, you will see the following HTML:

<SPAN ID="bindText">WFC HTML classes, are you out there?
</SPAN>

In the HelloWorld.java file, you'll see the corresponding Java code that "binds" to this HTML and changes its text and font:

boundText = new DhText();
// Note that the ID matches the HTML ID.
boundText.setID("bindText");
boundText.setText("Hello, World!");
boundText.setFont(Font.ANSI_VAR);
setBoundElements(new DhElement[] {boundText});

The most important thing to note is that the:

boundText.setID("bindText")

call corresponds to the:

ID="bindText"

attribute of the <SPAN> tag in the HTML. This is the basis of all wfc.html binding. (HelloWorld.java is shown in its entirety in Listing One, beginning on page XX.)

The table in Figure 1 describes the mapping of some of the basic HTML elements and their wfc.html classes. The setBoundElements method then informs the framework of element instances you would like to bind to HTML. This binding will be completed before the framework calls the onDocumentLoad method of DhDocument, which is called when IE has finished processing a document's HTML and will allow access to it.

Tag(s) Class
SPAN DhText
DIV, FORM DhForm*
INPUT type=text, TEXTAREA DhEdit
INPUT type=button DhButton
INPUT type=checkbox DhCheckBox
INPUT type=radiobutton DhRadioButton
INPUT type=submit DhSubmitButton
INPUT type=reset DhResetButton
TABLE DhTable*
TR DhRow*
TD DhCell*
IMG DhImage
UL, OL DhBulletedList*
IFRAME DhInlineFrame*

Figure 1: The com.ms.wfc.html class names and their associated HTML tags (*container elements).

In the HelloWorld sample, a few new elements are also added to the HTML stream at run time. Adding new elements to any container element can be done with the add method. In initForm, which is called by the class constructor, you can also call setNewElements, which is just a convenient way to add several new elements at one time. Although there are overloads of the add method that allow you to add items at any position within a container, we won't use them here. In both methods, the elements are added to the end of the container, the DhDocument-derived class HelloWorld in this case:

cycleColors = new DhButton("Cycle Background Color");
cycleColors.addOnClick(new EventHandler(onCycleClick));
setNewElements(
  new DhElement[] {new DhBreak(), cycleColors});

The class then adds a new button to the document with the text "Cycle Background Color" (see Figure 2). When the button is clicked, the onCycleClick event handler will be invoked and cycle the background color of the document. It also adds a line break to the document so the button will appear on a new line.

Figure 2: The HelloWorld application at run time.

Below is the code for onCycleClick:

int curColor = 0;

Color[] colorList = new Color[]
  {Color.WHITE, Color.RED, Color.BLUE,
   Color.GREEN, Color.PURPLE, Color.GOLD};

void onCycleClick(Object s, Event e)
{
  if (curColor++ >= colorList.length)
  {
  curColor = 0;
  }
  setBackColor(colorList[curColor]);
}
Elements, Styles, and Containers

Two classes are the superclasses of most of the classes in the wfc.html library. The first is DhStyleBase which has all the member functions needed for manipulating the appearance (known as CSS attributes) of an element, such as font, foreground and background color, size, position, z-index, etc. The second is DhElement, which exposes all the member functions needed for setting and getting ID values, event handlers, and references to a parent element. The diagram in Figure 3 illustrates the basics of this hierarchy.

Figure 3: Basic class hierarchy of the DhStyleBase class.

Another useful class that derives from DhStyleBase is DhStyle. DhStyle is a stand-alone style that can be applied to multiple elements. When a DhStyle property is changed, it also changes all the elements currently using that style. For example, suppose your company color is red, and you write the code shown in Figure 4.

import com.ms.wfc.html.*;
import com.ms.wfc.ui.*;

// ...

void setupItems()
{
  DhStyle mainStyle = new DhStyle();
  mainStyle.setBackColor(Color.RED);
  mainStyle.setFont(new Font("Arial", 14);

  DhText text1 = new DhText("One");
  DhText text2 = new DhText("Two");
  DhButton button1 = new DhButton("Uno");
  text1.setStyle(mainStyle);
  text2.setStyle(mainStyle);
  button1.setStyle(mainStyle);

  form.add(text1);
  form.add(text2);
}

Figure 4: This code demonstrates how the DhStyle property can be used to make an application easier to maintain.

One day, you are informed that the company color has changed to blue. Rather than having to change all the background colors to blue line by line, you can simply change:

mainStyle.setBackColor(Color.RED);

to:

mainStyle.setBackColor(Color.BLUE);

The colors of all the elements using mainStyle will be updated accordingly.

It is worth taking a moment to describe the concept of "cascading style" since styles in wfc.html follow the semantics of cascading styles (such as CSS). Cascading styles (e.g. fonts and colors) are inherited by elements from their parent elements, unless explicitly set on the element itself. In the case of a DhStyle-imposed style, styles from the DhStyle instance will also be overridden by styles on a particular element. In the example, setting:

text1.setBackColor(Color.GREEN);

would override the inherited style, and render text1 in green.

The other special type of element is the container element. Certain DhElement-derived classes, such as DhDocument, DhForm, DhTable, DhRow, and DhCell are container elements. That is, they can have elements added to, or removed from, them using their add and remove methods, respectively. Some add methods on containers are type-safe; for example, DhTable's add can only take DhRow elements, and DhRow's add can only take DhCell elements. However, most other containers have an add method that can take any DhElement-derived class.

Building an Application: The TicTacToe Example

As an example of a more complicated wfc.html project, the source code for TicTacToe is also available for download (see end of article for details). As you may have guessed, it implements a tic-tac-toe game in a browser that allows the player to challenge either a human opponent or the computer (see Figure 5).

Figure 5: The TicTacToe sample application at run time in IE.

It includes two Java files, TicTacToe.java and BoardManager.java, and an HTML file, TicTacToe.htm. TicTacToe.java includes the main DhDocument-derived class file that manages the UI logic of the application. BoardManager.java contains the code that manages the tic-tac-toe board, checks for wins, draws, and losses, and selects moves for the computer opponent. TicTacToe.htm holds the HTML template that is the UI of the application, as well as the <OBJECT> tag that will load and launch our wfc.html application (see Figure 6).

<HTML>
<HEAD>
<META NAME="GENERATOR" 
Content="Microsoft Visual Studio 98">
<META HTTP-EQUIV="Content-Type" content="text/html">
<TITLE>TicTacToe wfc.html Example</TITLE>
</HEAD>
<BODY bgColor=khaki style= "MARGIN: 0px; PADDING-BOTTOM: 
0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px;
PADDING-TOP: 0px">
<DIV style=
"BACKGROUND-COLOR: black; COLOR: white; WIDTH: 100%">
<table border=0 width=100% cellpadding=0 cellspacing=0>
<tr>
<td align=left>
<INPUT type="button" value="Restart" id=restart>
<SPAN id=status style="FONT-FAMILY: arial; FONT-SIZE: 18pt;
FONT-WEIGHT: bold; color:white"></SPAN> 
</td>
<td align=right>
<label><span style="color:white">Computer opponent</span>
<INPUT type="checkbox" id=computerPlayer checked></label>
</td>
</tr>
</table>
</DIV>
<p>
<CENTER>
<TABLE id=gameTable bgColor=green border=2 width=75%
 height=75% style="BACKGROUND-COLOR: gray" borderColor=white>    
<TR>
  <TD id=cell00 style="HEIGHT: 33%; WIDTH: 33%"></TD>
  <TD id=cell01 style="HEIGHT: 33%; WIDTH: 33%"></TD>
  <TD id=cell02 style="HEIGHT: 33%; WIDTH: 33%"></TD></TR>
<TR>
  <TD id=cell10 style="HEIGHT: 33%; WIDTH: 33%"></TD>
  <TD id=cell11 style="HEIGHT: 33%; WIDTH: 33%"></TD>
  <TD id=cell12 style="HEIGHT: 33%; WIDTH: 33%"></TD></TR>
<TR>
  <TD id=cell20 style="HEIGHT: 33%; WIDTH: 33%"></TD>
  <TD id=cell21 style="HEIGHT: 33%; WIDTH: 33%"></TD>
  <TD id=cell22 style="HEIGHT: 33%; WIDTH: 33%"></TD></TR>
</TABLE>
</CENTER>
<OBJECT classid=java:com.ms.wfc.html.DhModule height=1 
width=1 ... VIEWASTEXT>
<PARAM NAME=__CODECLASS VALUE=TicTacToe>
<PARAM NAME=CABBASE VALUE=TicTacToe.CAB>        
</OBJECT>
</BODY>
</HTML>

Figure 6: TicTacToe.htm.

The first step to creating the application is to create the UI. In this case, the UI layout and design was done using the HTML designer included in VJ6. Take a moment to look at the HTML. You'll notice that many of the elements in the HTML have ID values, and many do not. Those items with ID values are what the application intends to bind to. The <TABLE> at the center of the file (with ID "gameTable") will be our tic-tac-toe game board. It is a table of three rows and three cells, and we will use those cells as the squares in the game.

In the initForm method of TicTacToe (see Figure 7), the bindings to the game square cells is set up. A DhStyle object is created with a font and border style, and that style is applied to each cell. The ID values of the cells are named in a way that allows for easy mapping from a cell to its position in the board. "cell00" is the upper-left square, "cell12" is the middle-right square, and so on. Event handlers for mouse clicks, mouse-enters, and mouse-leaves are also set on each cell. Because we want the same behavior for each cell, we can share one handler per event among all the cells. We then notify the framework of our bindings with a call to setBoundElements.

private void initForm()
{
  // Create the cell array.
  cells = new DhCell[9];

  // Create the style to apply to the cells.
  cellStyle = new DhStyle();
  cellStyle.setBorder(DhBorderStyle.INSET, 3,
            DhUnits.PIXEL, Color.WHITE);
  cellStyle.setFont(
  new Font("Arial", 24, FontSize.POINTS, FontWeight.BOLD,
       false, false, false));

  // Set up each cell.
  for (int i = 0; i < 9; i++)
  {
  cells[i] = new DhCell();
  cells[i].setText("-");
  cells[i].setAlign(DhAlignment.CENTER);

  // Build the ID from the positon;
  // the HTML has the corresponding ID's.
  cells[i].setBindID("cell" + (i/3) + (i%3));
  cells[i].addOnClick(
    new EventHandler(this.onCellClick));
  cells[i].addOnMouseEnter(
    new MouseEventHandler(this.onCellEnter));
  cells[i].addOnMouseLeave(
    new MouseEventHandler(this.onCellLeave));
  cells[i].setStyle(cellStyle);
  }

  // Notify the framework we want to bind to these cells.
  setBoundElements(cells);
}

Figure 7: The initForm method of TicTacToe.

Binding to Elements at Run Time

Along with setBoundElements, there is a way to bind to elements after the class constructor has been called (initForm is called from the constructor). That method is called findElement, which differs from setBoundElements in that you don't need to create the elements beforehand, and can be called anytime during or after the library calls onDocumentLoad (see Figure 8).

protected void onDocumentLoad(Object sender, Event e)
{
  // Bind to the table,
  // and get its default background color.
  DhTable tttTable = (DhTable)findElement("gameTable");
  bgColor = tttTable.getBackColor();

  // Wire up the restart button, status,
  // and "computer opponent" items.
  DhButton restartButton =
  (DhButton)findElement("restart");
  restartButton.addOnClick(new EventHandler(onRestart));

  status = (DhText)findElement("status");
  status.setText("Ready to play!");

  computerPlayer =
  (DhCheckBox)findElement("computerPlayer");
  onRestart(null, null);
}

Figure 8: The onDocumentLoad routine.

Simply pass in the ID of the element you are interested in. The library will attempt to retrieve it from IE, and will return a wfc.html class representing that element. The only caveat is that you need to know the type of element you're asking for if you need to perform any element-specific operations. This is because findElement returns an object of type DhElement, which you can then cast to the appropriate type. If no object of the specified ID exists, the library throws a DhElementNotFoundException. After you have received a reference to the object from findElement, you can treat it as you would any other element by setting event handlers, properties, styles, etc.

Responding to User Interaction

Whenever the user clicks on a board cell, the Restart or Computer opponent buttons, or moves the mouse into or out of a board cell, an event is fired by the library. Looking at the TicTacToe.java code (see Listing Two, beginning on page XX), you'll see several event handlers characterized by names starting with "on", such as onRestart, onCellLeave, and onCellClick. These handlers share parameter types and ordering with the handlers used in other WFC applications.

When a handler is fired, the Object sender parameter is the instance of the object that the event was clicked on. In the case of onCellEnter:

// When the mouse enters an unused cell, highlight it.
void onCellEnter(Object sender, MouseEvent e)
{
  if (!gameOver && boardManager.canMove(
     getPosFromCellID((DhCell)sender)))
  {
  ((DhCell)sender).setBackColor(Color.MAROON);
  }
}

sender is the DhCell object the mouse pointer has entered, and the sender parameter can be cast to an object of type DhCell. Events of this type are multicast as well, i.e. if multiple handlers are set on an object's event, they will be fired sequentially.

The majority of the game logic is performed in the onCellClick event handler (again, see Listing Two). Within that method, the application updates the game board, and asks the BoardManager if there has been a win or draw. If there has been, the UI is updated and further moves are disallowed until the game is reset. Otherwise, the application prompts the BoardManager to execute a computer opponent move, if appropriate.

A Few Notes on Performance

There are several tricks you can use to maximize the performance of your wfc.html applications. First, manipulating unbound elements is more efficient than manipulating elements that are bound to IE. Therefore, it's advantageous to set up new elements as completely as possible before adding them to document. An element becomes bound when it, or an element up its parent chain, is added to IE.

Another expensive operation is removing complex elements with many children, such as DhTable elements. Whenever possible, avoid removing such types of elements from the document. Instead, use setVisible(false) to hide them.

Finally, because the library is written in a way that allows the developer to perform any operation on an element at any time, regardless of state, certain operations require more work by the library "under the covers." Generally, these operations are modifications of properties that are otherwise considered read-only or static in DHTML. In the case of these types operations, it's especially important to get the properties set up before the element is bound to IE. Some examples of these properties include ID, setting location or size of previously unpositioned elements, changing DhEdit elements from multi-line to single (or vice versa), and changing the display mode of a DhText element.

Conclusion

The wfc.html library provides unprecedented capability to develop sophisticated applications based on Microsoft Internet Explorer and Dynamic HTML. In addition to the rich layout and display capabilities of DHTML, the browser offers the compelling, low-cost of administration deployment scenario that many developers and IT professionals are looking for.

By sharing as much as possible with the other WFC packages, developers can now also leverage experience with the WFC framework (or other traditional development frameworks) to easily begin creating applications that target the browser. For complex applications, the separation of layout from logic allows for much easier code management and maintenance than is offered by the current script-behind-HTML solutions.

Shawn Burke drinks the free sodas at Microsoft. In between trips to the cooler (and the restroom), he works as a Software Design Engineer on Microsoft Visual J++ and the WFC framework.