| digital dashboard is a customized application, built on Internet standards, that consolidates information and tools from a variety of sources and presents them in a single user interface. Digital dashboards aggregate information from designated sources, such as Microsoft® SQL Server™ and Microsoft Office, providing knowledge workers with one-stop shopping for task-critical information. An example of a digital dashboard is shown in Figure 1. A digital dashboard is made up of distinct parts (formerly called nuggets), each of which performs a dedicated task. Parts can be combined into one page or into a digital dashboard. Parts made up of HTML, called Web Parts, can be handled as separate objects. For another look at dashboards see Todd Abel's article in the July 2000 issue, "Microsoft Office 2000: Creating Dynamic Digital Dashboards Using Office, OLAP, and DHTML".|
Web Parts are easy to reuse in other digital dashboards. A user can easily move or copy Web Parts between digital dashboards and move complete digital dashboards around. It is even possible to mail digital dashboards and Web Parts to others and to save them for your own use.
Users can select their own combinations of parts for a digital dashboard. These parts allow the user to perform some action. The parts comprise the content, and the dashboard offers the infrastructure for choosing and displaying these parts. As I will show later, the resource kit for creating digital dashboards has complete support for sharing information between parts.
Why Use Dashboards? Dashboards can be useful in many scenarios. You can set up personal dashboards that incorporate links to Internet sites and parts that have been sent to you. This type of dashboard is conceptually similar to the Favorites list in Microsoft Internet Explorer, but it is more flexible, easier to use, provides a better overview of information available, and allows collaboration between parts and even between dashboards.
More importantly, organizations can build departmental, project-specific, or corporate dashboards to convey information to employees or project members. These dashboards will typically show ad-hoc content, links, and perhaps live data that has been specifically assembled for these dashboards. Companies can also set up application-specific dashboards using applications ranging from office services (such as document management) and order processing to payroll services, and everything in between. The dashboard in Figure 1 is a customer information dashboard.
Dashboards can also integrate Microsoft Office applications and line of business (LOB) applications. For example, a dashboard can recognize the selection of a contact in Outlook, gather the corresponding information from the backend system, be it employee or business partner information, sales orders, or the contacts' accounts receivable statement, and display the information on the client. I'll show how this works later on.
Flexible, personalized user interfaces can improve services offered on the Internet. Web Parts can provide this flexibility. For example, on a site that offers news feeds, a user can select feeds of interest such as sports, financial news, and so on. The site can display parts for each of these subjects, and users can add them to their dashboards. An example is a site that offers stock services. The site may offer the users Web Parts to manage their portfolio and parts to trade their stock using the site's Web services.
Users can combine different types of parts in their dashboards and navigate from one type of dashboard to another. Because their office work and LOB work will be integrated, they can use the results of one dashboard part as the input for another part across application boundaries. For example, a purchase order selected from the archiving system could be used to find the corresponding information in the backend system.
After I show you how to use the resource kit to create a Web Part and how to set its properties, I'll explain how the dashboard interacts with the browser, the dashboard storage, and other components. Then I'll discuss how to store Web Parts, resolve their naming conflicts, and debug them. Finally, I'll show you how to bring this all together to create Web Parts that communicate with each other and Web Parts that work in Outlook®.
The Digital Dashboard Resource Kit The Digital Dashboard Resource Kit (DDRK) 2.01 is an Internet standards-based framework and tool set you can use to create customizable digital dashboards. The DDRK can be downloaded from http://microsoft.com/business/digitaldashboard. Be sure to check the system requirements for the resource kit. In addition to documentation, references, and white papers, in the kit you'll find:
After installing the download from the Web site (choosing download and open) a Digital Dashboard Resource Kit 2.0 page will be displayed in the browser. This set of pages offer you access to the documentation and to the installation of the sample dashboards. To install the file-system-based dashboard, click on Building Digital Dashboards, then select "Install the Windows 2000 File System Sample Digital Dashboard." After this installation, you will be guided to a Welcome dashboard page. Add it your Favorites; if you forget to do that, this dashboard can always be reached by navigating to http://localhost/factory (assuming you have Internet Information Services installed). Dashboards that have been made with the DDRK can be displayed in the Web browser or as a Web page in Microsoft Outlook.
- Two sample dashboards—one that targets the Microsoft Windows® 2000 file system and one for SQL Server 7.0.
- The Digital Dashboard Services Component (DDSC), which allows Web Parts to communicate and to handle state.
- The Web Part Builder, an add-in for Visual InterDev® that can be used to build more complex Web Parts.
- The Web Part Gallery, a library of prebuilt Web Parts provided by Microsoft and third-party vendors that you can include in your digital dashboards to deliver customized services without writing any code.
Creating Your First Web Part To get you started with the resource kit, I will walk through the creation of a simple digital dashboard. Once you open the Welcome digital dashboard page, just select the Administration tab and the Administration digital dashboard should appear with four Web Parts. Select the My Catalog entry in the Dashboard View list and the New button should be enabled. Click the New button and you will have just created your first (empty) digital dashboard.
In the Web Part section for Dashboard Properties, you can rename this digital dashboard (NewDashboard1 is the default), and set other properties. Make sure to save your new dashboard before taking the next step.
To create a new Web Part, select New in the Web Part List. In the part labeled Web Part Properties, the properties of this new Web Part can be changed, as you can see in Figure 2. Select the Advanced tab at the top of the Web Part Properties pane. For your first Web Part, select an HTML content type and leave most of the properties unchanged, then enter some text in the eMbedded Content field.
Save the Web Part and click the Go button in the Dashboard View window. You will see your first digital dashboard with a Web Part and the HTML text you entered. Creating dashboards and Web parts will be very similar for the other pages, such as the content page. The Content button at the top of a dashboard takes you to a content page where you can change, add, and remove Web Parts. Two other buttons at the top of a dashboard are the Layout and Settings buttons. Click the Layout button to easily change the sequences of the Web Parts on a dashboard. Click the Settings button to change dashboard properties.
Creating dashboards in Visual InterDev using the Web Part Builder follows a different process, but should be self-explanatory. Once you've installed the Web Part Builder add-in from the Resource Kit, create a new project in Visual InterDev, select Digital Dashboard, and select the defaults at each step of the wizard. Once the project is created, right-click on the Dashboards folder and select Add Dashboard Folder. Right-click on any dashboard folder and select Add Web Part.
Web Part Properties Figure 3 contains some of the properties in the Web Part Properties list. Note that more properties may be added in the next release. A more extensive description of digital dashboard properties and Web Part properties can be found in the Web Parts Schema Reference and the Digital Dashboard Schema Reference in the Building Web Parts section of the resource kit.
Any user who is authorized to change the layout of the dashboard can set the properties listed in Figure 3. Only the author or administrator should set the properties listed in Figure 4 since they influence the behavior of the Web Parts. These properties can be reached by selecting the Ad-vanced tab in the Web Part Propertiespane.
The Dashboard Components Before I get into the sample Web Parts, let's take a quick look at the components of the dashboard. Figure 5 shows a diagram of the components. At the heart of the digital dashboard architecture is the dashboard factory. It consists of a set of ASP scripts that collect all the Web Parts and glue them together on one page.
Figure 5 Dashboard Components
The browser goes to the factory and asks it for a dashboard. A URL that is used to retrieve a dashboard may look like http://localhost/Factory/dashboard.asp?DashboardID=http%3A//localhost/Dashboards/Pivot, where http://localhost/Factory/dashboard.asp is the address of the factory and DashboardID=http%3A//localhost/Dashboards/Pivot is the ID of the dashboard to be displayed. (Note that the colon in the address has been replaced with the %3A characters to conform with standard URL creation specs.) The dashboard factory will take the DashboardID and ask the dashboard store for the properties of the dashboard, a list of subdashboards, and a list of Web Parts.
In many cases, the contents of a Web Part will be stored with the part itself. In those cases, it suffices to ask the dashboard store for the properties and the content. Otherwise, the dashboard factory will have to retrieve the contents elsewhere. This may be somewhere on the intranet (if the content has to be generated by ASP scripts), or it may be somewhere on the Internet (for live information like real-time stock quotes).
The factory assembles the contents of all the Web Parts, guided by the properties that tell it where to put each part, and then sends the parts to the browser. The factory uses standard HTTP to communicate with the content providers and it uses Web Distributed Authoring and Versioning (WebDAV) to communicate with the store. For more information on WebDAV, see the WebDAV interview with Jim Whitehead at http://msdn.microsoft.com/workshop/standards/webdav.asp.
Storing Web Parts Web Parts and dashboards can easily be transported from one storage system to another. You currently have two options for storing Web Parts: the Windows file system, which gives you complete integration with Visual InterDev, and SQL Server 7.0 or SQL Server 2000, which is the best choice for an organization-wide store. In later releases of the Digital Dashboard SDK, dashboards will be storable as Microsoft Exchange (or Outlook) folders and the individual Web Parts as Microsoft Exchange items, just like e-mail messages, appointments, notes, or to-do items. This will probably be the most widely used type of Web Part for digital dashboards.
For the samples I provide with this article, I have chosen to work with the file system so that I can use the Visual InterDev add-in.
Resolving Naming Conflicts using Tokens Let's go back to the dashboard you've just created. Close the dashboard and create another Web Part with the embedded content shown in Figure 6. Again, save the Web Part and click the Go button. The text changes color when you move the mouse over it. Now, if you create yet another Web Part with this same content and run the dashboard, you'll get the error message "Error: MyDIV.style is null or not an object" when you hover the mouse over the text. This is because MyDIV is now a collection (with two elements). The two Web Parts have the same name for the DIVs and for the event handlers. The DDRK offers a simple mechanism to solve this problem. If you add Web Part Qualifiers (named with WPQ), unique tokens are automatically inserted when the dashboard is generated. The problem is resolved by changing the code, as shown in Figure 7.
By viewing the source code of the dashboard, you can see that _WPQ_ has been changed to WPQ2 and WPQ3, respectively. It is good practice to extend all function names, all global variables, and all IDs with the _WPQ_ qualifier. Figure 8 shows other tokens that the DDRK provides.
You can use WebPart_WPQ_ to access the enclosing DIV of your Web Part, like this:
You may also want to change the dashboard title using:
WebPart_WPQ_.style.backgroundColor = "Yellow"
But I should warn you, the way you change the title might vary between implementations of dashboards. This will work in the current dashboard implementation on desktop versions of Windows, but in the dashboard for the Pocket PC or in any other dashboard implementation, this may crash.
DashTitle.InnerHTML = "<nobr>" + sNewTitle + "</nobr>"
Debugging Web Parts As soon as you start writing slightly more complicated code for your Web Parts, you'll want to debug it. Attaching to a running dashboard may be slightly problematic. A way around this, although not perfect, is to start your dashboard and save it as C:\Inetpub\wwwroot\Factory\debug.htm; then set that page as the Start Page in Visual InterDev.
Web Part Collaboration As mentioned earlier, Web Parts can interact with other parts on the dashboard, and they can even pass information to parts on other dashboards. For example, a part that is designed to select customers can collaborate with a part that shows a customer satisfaction chart, or a dashboard displaying order information can also show the order information for the selected customer. The DDRK offers excellent support for this type of communication between Web Parts.
The sample I implemented demonstrates collaboration between Web Parts using a part that shows a PivotTable® view and a part that shows a graph (see Figure 9)—I'll call the former the "pivot part." If the user selects cells in the PivotTable view, the graph updates to reflect the data in the selected cells whether the Web Parts are on the same dashboard or on two separate dashboards. The sample I implemented requires Microsoft Office to be installed in order to access the PivotTable object and the chart object, and it requires the Data Warehouse services in order to access the data.
The Digital Dashboard Service Component (DDSC) offers all services necessary for communication between Web Parts and for saving and retrieving state including registering for events, raising events, getting server state, and saving server state. The DDSC component is always available.
State can only be stored for the duration of the session and any Web Part on any dashboard can retrieve it within the same session. As soon as the browser (or Outlook) is closed, the session state will be lost. Thus, for the pivot part to store the information about the cells selected by the user, you need to save the state with the following code:
The chart part can retrieve that information using:
DDSC.PutSessionState(gNamespace_WPQ_, "selection", sXml_WPQ_)
The first argument in the calls to PutSessionState and GetSessionState is the namespace. In my sample, the pivot part and chart part are given the same namespace so they can communicate. Namespaces circumvent clashes between Web Parts that have nothing to do with each other, but would like to use the same name for an event or for their session state. Namespaces can be found in all XML-related standards, where they are used to identify the XML schema or document type. A new document type can make use of existing document types by referring to their namespaces. (See "Using XML Namespaces".) This is how namespaces can also be used to uniquely identify the properties of the digital dashboards and the Web Parts. Most of the dashboard properties and most of the Web Part properties use the namespace urn:schemas-microsoft-com:Webpart.
sXml = DDSC.GetSessionState(gNamespace_WPQ_, "selection")
If the pivot part stores the information, then the chart part will be able to retrieve it; however, the chart part needs to be notified that new information has been stored. The chart part subscribes to information by calling:
Or in VBScript:
The OnSelectionChange_WPQ_ function will be called whenever the event is fired. The signature of the function is:
<SCRIPT LANGUAGE = VBScript>
Note the additional call in VBScript to the GetRef function in order to translate the method name into a function pointer.
When the user selects different cells, the pivot part raises an event by calling:
The info parameter will then be handed to the OnSelectionChange method. I believe it is good practice to set the session state first, and then raise the event. This will work with the same code whether the Web Parts are on the same dashboard. The receiving Web Part will use the session state to initialize itself and it will call the same method after an event has been raised.
DDSC.RaiseEvent(gNamespace_WPQ_, "selectionChange", info)
Initializing Web Parts Many Web pages and Web Parts need some kind of initialization. There are two ways to run initialization code. One way is to insert the initialization code in the Web Part itself. The code will then be executed while the page is loading. In many cases that will suffice, but not all Web Parts will be available before the page has loaded, and the DDSC won't be completely initialized.
Alternatively, the Web Part can register for the onload event. The window onload event, however, can't be used because only one of the parts would be callable! The code in Figure 10 shows how to register a handler for the event and how to simulate the event for debugging purposes.
A complete list of system events can be found in the "Digital Dashboard Services Component" reference in the Building Web Parts section of the resource kit documentation.
In the Onload_WPQ_ method of the pivot table part in my sample, I use the PartStorage property to store the layout of the PivotTable view. The PartStorage property is intended for use by the Web Parts to store user-specific information for the Web Part. To do this, I will ask the DDSC for the Web Part object, ask the Web Part object for the property, and then use the property value to initialize the pivot part, as you can see in the following code.
If the property has not been set—for instance, on first use of the Web Part—I perform a default initialization of the pivot table and save the layout like this:
var oPart = DDSC.Dashboard.Parts.Item("_WPQ_");
var oProp = oPart.Properties(
PivotTable_WPQ_.XMLData = oProp.Value;
In the real code I need to do some error checking, since not every store will automatically add the PartStorage property. I may have to add it myself using:
var oPart = DDSC.Dashboard.Parts.Item("_WPQ_");
var oProp = oPart.Properties(
oProp.Value = PivotTable_WPQ_.XMLData;
After initializing the PivotTable view, the pivot part retrieves the namespace it will use for storing the selection and for raising the events. The namespace you use depends on your dashboard's requirements. If the requirement is to have different combinations of pivot parts and chart parts, where each chart part has to listen to a specific pivot part, then the pivot part and the corresponding chart part should use their own unique namespace for storing state and for raising events.
oProp = oPart.Properties.Add(
However, if you want to design a number of dashboards with different PivotTable views and one dashboard with a chart that displays the latest selection from any one of the PivotTable views, then all pivot parts and this single chart part should use the same namespace. In my sample, the pivot part will either use the namespace I have defined or create a namespace using the data source and the catalog as defined in the connection string of the PivotTable view.
The chart part in my sample has a similar initialization. It will use the given namespace when provided; otherwise it will try to find a Web Part with a namespace beginning with urn:microsoft.com.northwind:pivot, as you can see in the following code from my sample.
var i = 0;
for ( ; i < DDSC.Dashboard.Parts.Count; i++)
oPivotPart = DDSC.Dashboard.Parts.Item(i);
// Look for the correct Web Part
Sending Data Between Controls The PivotTable control and the chart control are not simple to use because there is no direct data binding. The data has to be collected from the selection of the PivotTable view, then handed off to the chart control.
Gathering the data from the PivotTable view is not a trivial task. Both axes are tree-shaped, which means some of the branches of those trees may be collapsed whereas others are expanded. The PivotTable control doesn't have good support for working with the current selection. The type of selection (row, column, range of cells, and so on) that the user has made cannot easily be determined using JScript® because each is handled by a different class. Although getting this information is much easier with the use of TypeName(PivotTable_WPQ_.Selection), it is still tricky in VBScript. Therefore, in my sample, I ignored the case of selecting a single cell or selecting a total.
To store information about the selected cells, the pivot part creates an XML string that is stored in the session state before an event is fired. The selection is stored as a simple table with column headers and rows, each row containing the name of the row and the cells. A typical selection in the pivot part coded in XML can be seen in Figure 11. As you can see, nested information is flattened before it's translated into XML. California, Portland, Salem, and Washington are at the same level because Oregon has been expanded in the PivotTable view.
Whenever the range of cells that are selected in the PivotTable view changes, or when the content changes, the function PivotTable_WPQ__ViewChange is called to give the new data to the chart function. I implemented this call with a slight delay. Since the PivotTable control sends numerous events whenever it loads the data, handling each of these events would lead to poor performance. Instead, I handle only the last event after the delay.
The PivotTable_WPQ__ViewChange function in turn calls PivotTable_WPQ__SaveSelection. The task of this method is to find out the shape of the selection, to set the start and end row, then to set the start and the end column. If all visible rows are to be handled, the start row and the end row will be set to null; the same is done for the columns. Since I cannot request the type of selection, I will assume that a range of cells has been selected (the selection is of type PivotRange) and I will handle this selection. I walk from the TopLeft to the BottomRight element. For any other type of selection, this would cause an exception (because TopLeft doesn't exist). In the catch block I will assume that I have either a set of selected columns or rows, either of which results in a selection of type PivotMembers. The other types of selection will fail this assumption. This will lead to a satisfactory result in almost all cases.
Once the begin points and end points of the cell selection have been established, the handleRows function is called. This function handles the shape of the XML that is used to transfer the data. First I make sure that I have the surrounding table nodes, and then I add the names of the column headers. Finally, I add all the rows; I first add the name of the row and then all of the values. For each top-level row, I call the expandRow function, sending subRow as the parameter. The function expandRow recursively checks to see whether the row is expanded. If the top-level row is expanded, expandRow calls itself for each of the child-rows; otherwise it calls handleColumns with the subRow parameter. The handleColumns function works in a similar way. It just traverses the top-level elements and calls expandCol with these parameters:
The expandCol function works the same as expandRow, except that it appends the data to the XML stream when the column is not expanded. Both expandRow and expandCol handle the begin and end conditions of the selection and try to skip everything that comes after the selection has been processed. If the last selected row or column has been handled, the function exits, and since the function is recursive, it will unwind the recursion. Since both axes are tree-shaped, I have to walk to the first selected element in order to find it, but I can jump out of the recursion after handling the last element.
Integrating with Outlook Although digital dashboards can run in a normal Web browser, many people will want to use Outlook to display their digital dashboards. The Folder List (my favorite), and the Outlook bar offer easy access to the dashboards, and Outlook allows easy navigation between mail, calendar, contacts, and the dashboards. Dashboards in Outlook are especially handy for people who spend their days working within Outlook.
Web Parts can make use of Outlook features to provide integration between the individual parts. For example, Web Parts could communicate between Outlook-based contact information and a CRM system, an order system, or anything else the user may want to link to Outlook contacts. My sample doesn't use Outlook, but this section describes how to set up collaboration between Web Parts and Outlook.
If you're using scripting, you can call window.external.OutlookApplication to get to the Outlook object model. But there's a glitch in this plan. It will work fine if the user navigates using the folder list or the Outlook bar, but if the user navigates away from the page, the following pages will have no access to the Outlook object model. Even if the user navigates back to the original page, access will be denied. As shown in the code in Figure 12, a Web Part can access the Contacts folder and search for a contact with the correct customer number.
In the code, you can also see that I check the full name, since I may have multiple contacts for the same company. The information about the contact is stored in the session state and an event is raised. The additional assignment of oContactItems = f.Items is necessary; without it, the calls to Find and FindNext would be using two different objects pointing to the same collection and FindNext would always return null.
You can design an invisible Web Part that reacts to a selection of a customer and automatically gets the contact information. The Web Part can also do the reverse: catch the event raised when a contact is selected and send the information back to the user who linked to the contact. Hidden Web Parts can be useful under a variety of other scenarios.
If the code in Figure 12 is used in one dashboard, then the code in Figure 13 could provide the only Web Part for another dashboard. After selecting a contact in the first dashboard, thus setting the context for the other dashboards, this Web Part would show the contact's home page.
Defining your own IFrame in a Web Part instead of using the isolation property is a useful technique for adding scroll bars in your Web Part while maintaining easy access to the DDSC. Another reason for offering your own IFrame is to allow the user to access the links on the page and navigate within the IFrame, while the parent page maintains access to the Outlook object model.
Using the Outlook View Control in a Dashboard Readers who have attempted to use the Outlook View control in a dashboard may have noticed that it does not raise any events, making it very hard to use in applications. The solution I have used may not be elegant, but it works. I have added an ActiveX® component that raises an event whenever the selection changes in Outlook. This method will also work if the selection changes in the Outlook View control, but only if the view control is hosted in a Web page that is hosted in Outlook. The code in Figure 14 shows a minimal implementation of such an ActiveX control in Visual Basic®. It can easily be extended to send notifications only when a certain type of object, such as a contact, is selected, or only when selections are being made in a specific folder.
Note that the ActiveX control will also work if the dashboard runs in the Web browser and the selection is made in Outlook! This allows you to make parts that interact with either the Inbox or the Contacts folder.
It is also possible to make an Outlook form that integrates with dashboards. I have made an Outlook form that has a customer number and a button called ShowDashboard. When the button is pressed, Outlook will be directed to navigate to a specific dashboard that shows customer information, and that dashboard will be initialized with the customer number.
Although it is not directly possible to set the session state from such a form (or from any external application for that matter), it is possible to change the PartStorage. The code in Figure 15 shows how this could be done. The method is called when the ShowDashboard button is clicked. It uses a customerid property (Item.UserProperties("customerid")) that is defined on the form to set the dashboard context. The DDSC is used to change the Web Part property.
This method makes the DDSC believe it is being used by a dashboard. First the DDSC is created, then initialized with a Dashboard ID. This gives the DDSC access to the dashboard properties, though it doesn't know anything about the Web Parts that are contained. Registering the Web Part that will handle the customer context gives the DDSC and my code access to the Web Part's properties. Now the DDSC thinks it is working with a dashboard having a single Web Part, so it can be used to change the Web Part's properties. To see how this works, you can copy this code to a Visual Basic project. After adding a reference to "MSDDSC 1.0 Type Library", the comments in the Dim statements can be replaced with the appropriate code.
Conclusion In this article, I have built Web Parts that can communicate with each other whether they are on the same dashboard or on different dashboards. By using the techniques shown in this article, you will be able to create Web Parts that can communicate with those created by other developers. As a result, you will be able to write Web Parts that can be used in ways you haven't yet anticipated, making your solution both flexible and scalable. The DDRK 2.01 is a great step forward, and I am looking forward to seeing the solutions that will be built using this new technology.
You can use the code I've written for creating a Web Part by pasting the code from PivotTableWebPart.htm and ChartPart.htm into the content property of the new Web Part. The HTML files can be found in the code download at the link at the top of this article.