Thunderclap, the Newsletter of Rolling Thunder Computing

Volume 9, Number 2, Winter 2008

In this issue:

Public Training Class on Composite UI Application Block and Smart Client Software Factory in Boston on Jan 29-Feb2

Rolling Thunder Classes Now Available Over The Web

Feature Article: Incredibly Easy Custom Workspace in CAB

New Book from  David Platt: Why Software Sucks (and What You can Do About It)

ANOTHER New Book from  David Platt: Programming CAB and SCSF from Microsoft Press

Blatant Self-Promotion: New  in-house class on Composite UI Application Block and SCSF

Annabelle and Lucy's Latest

Subscription Information

 


Feature Article: Incredibly Easy Custom Workspace in CAB

Now that Acropolis is gone from the public consciousness, it's clear that CAB and SCSF will be around for a good deal longer. So I'll be writing more of these newsletters on its internal details, and teaching classes on it as well. Here's one about developing custom workspaces, which turned out to be a whole lot easier than I thought it would when I first  started looking at it.

You remember that a CAB workspace is a frame, a visual container in which modules can display their views in a loosely coupled fashion. The base release of CAB contains several types of workspaces, the most popular of which are the deck and the tab. But what happens if you want a type of workspace that CAB doesn’t support?

Suppose you have a Windows Forms control whose behavior you like, for example, the FlowLayoutPanel, which displays child controls in a horizontal or vertical flow, wrapping to a new line when it hits the end of the available space, conceptually similar to the way elements flow on a web page. You would like to use it in your CAB application, adding views to it and displaying them in CAB’s loosely-coupled fashion. But the control right out of the box isn’t a CAB workspace, by which I mean that it doesn’t support CAB’s IWorkspace interface. How do we  solve this problem?

We could add a number of deck workspaces to the FlowLayoutPanel, each with a separate name. A module wanting to display a view would locate the desired workspace by means of that name and place the view into the workspace. It might take a bit of fiddling to get the workspace sizes right and to place them in the right location in the work item chain, but this approach would definitely work, and one might reasonably argue that it’s a decent solution to the problem of ordering the views within the FlowLayoutPanel  – have one central location create the workspaces in the desired order.

A second way would be to look for workspace controls written by third parties, either commercially such as those from Infragistics, or from the open source community on Codeplex.com.  But sometimes you can’t find what you need from a third party. What then?

It is surprisingly easy to graft CAB workspace behavior onto a Windows Forms control (or, using the SCSFContrib projects on Codeplex.com, a WPF control) that you already have.  And by easy, I mean almost trivial, as in about 10 lines of code, most of them no-brainers, not even an hour’s work.  Too good to be true? No. Not only does it really work, but it’s the technique used by Microsoft, so it’ll be relatively easy to sell to your boss. Don't tell him your rolling your own brand new workspace. Tell him that you're reusing Microsoft's code, both for the control and for its workspace behavior.

For a control to be a CAB workspace means  implementing the IWorkspace interface – five methods, one property, two events. This allows a module to add or remove views without knowing about the parent control’s internal structure – does it keep its children in a collection called Controls or one called Items, for example. The method IWorkspace.Show abstracts away these differences.

You might think that these members would be relatively simple to implement, and you’d be right. But they’re tedious. You have to, for example, maintain a read-only collection of the views that your workspace contains, and modify this collection in response to calls to IWorkspace.Show and IWorkspace.Close. You have to check for null parameters. You have to deal with the different types of SmartPartInfo structures that you might be passed. Not difficult, but tedious, and you have enough tedium in your life, no? Since much of a workspace’s functionality is common from class of workspace to another, we have to ask ourselves if there might be some utility class that can help.

Indeed there is, and using it, you can implement your own workspace classes with surprisingly little effort. CAB provides a class called WorkspaceComposer, hereafter called the composer, that implements the basic functionality of the IWorkspace interface. You can derive a workspace directly from this if you’re building the control from System.Object up, but the most common case is to graft workspace behavior onto a control that you already have and like. In this case you can’t change the base class. Instead, your derived class implements the IComposableWorkspace interface, which derives from IWorkspace. It instantiates a composer object at construction time, and delegates the IWorkspace methods to that composer. The composer then uses the addition methods of IComposable workspace to talk to the control. This is the technique that Microsoft uses in the CAB libraries to implement the TabWorkspace and others.
 
As always, it’s easiest to see by examining a sample. To I’ve written a class that extends the Windows Forms FlowLayoutPanel control and turns it into a CAB workspace. You can download the project from this link. The new class looks like this:

public class FlowLayoutPanelWorkspace : FlowLayoutPanel,
   
IComposableWorkspace <Control, FlowLayoutPanelSmartPartInfo>
{

// This is the composer object

    private WorkspaceComposer<Control, FlowLayoutPanelSmartPartInfo> composer;

// In the constructor, instantiate the composer

    public FlowLayoutPanelWorkspace()
    {
      
 composer =
new WorkspaceComposer<Control, FlowLayoutPanelSmartPartInfo>(this);
    }
}

The new workspace class derives from the FlowLayoutPanel control class, and implements the IComposableWorkspace interface. The first generic parameter that is passed to the interface is the base class of the smart parts that this workspace supports. While the IWorkspace interface methods define the SmartPart parameters as System.Object, most workspaces can't handle just anything as a SmartPart. They need to restrict what they accept, and this is the place that you specify it. In this case, our FlowLayoutPanel base class can contain anything derived from System.Windows.Forms.Control, so that's what we pass here. The second parameter is the type of SmartPartInfo structure this workspace accepts. As you know, a SmartPartInfo structure contains additional information about the way the SmartPart would like to be displayed, which varies from one type of workspace to another. In this example, the FlowLayoutPanel can optionally put a flow break after any control. So I derived a SmartPartInfo class providing that capability, thus:

public class FlowLayoutPanelSmartPartInfo : SmartPartInfo
{

    // Property and backing field

    private
bool _FlowBreak;
   
public bool FlowBreak
    {
       
get { return _FlowBreak; }
    }

   

// Constructors -- empty one is necessary, as we'll see
// Parameterized one is not necessary, but is convenient


public
FlowLayoutPanelSmartPartInfo()
{ }

public FlowLayoutPanelSmartPartInfo(string Title, string Description, bool FlowBreak)
    :
base(Title, Description)
{
   
this._FlowBreak = FlowBreak;
}

}

The workspace sample in my book, as well as the TabWorkspace class provided by Microsoft, show the derived class as requesting injection of its WorkItem, which is then set into the composer object. This injection appears to already be done in the composer's base class, which is Microsoft.Practices.CompositeUI.SmartParts.Workspace. The sample in this article omits this injection in the derived class, and seems to be working properly. Your mileage will vary.

Next, let’s implement the methods of the IWorkspace interface. The composer contains prefabricated functionality for doing exactly this. Using it not only saves us time and trouble, but also means that our workspace’s behavior will be consistent with that of Microsoft-provided workspaces because they use this class internally. We delegate all these methods to the composer. The code below shows only the Activate method. So far, I really have to call it trivial, no?

// Client called IWorkspace.Activate.
//
Delegate the call to the composer object.

public void Activate(object smartPart)
{
    composer.Activate(smartPart);
}

The IComposableWorkspace interface deals with the connection from the composer to the control from which we derive. We now need to implement its methods, which are:

public interface IComposableWorkspace<TSmartPart, TSmartPartInfo> : IWorkspace
   
where TSmartPartInfo : ISmartPartInfo, new()
{
   
void OnActivate(TSmartPart smartPart);
   
void OnApplySmartPartInfo(TSmartPart smartPart, TSmartPartInfo smartPartInfo);
   
void OnShow(TSmartPart smartPart, TSmartPartInfo smartPartInfo);
   
void OnHide(TSmartPart smartPart);
    void OnClose(TSmartPart smartPart);
   
void RaiseSmartPartActivated(WorkspaceEventArgs e);
   
void RaiseSmartPartClosing(WorkspaceCancelEventArgs e);
    TSmartPartInfo ConvertFrom(
ISmartPartInfo source);
}

The composer doesn’t, can’t, know what it means for our workspace to host a view—for example, which method to call on the base class to add or remove a view. When the client calls IWorkspace.Show, telling it to add a new view, the composer calls our method IComposableWorkspace.OnShow. When the client calls IWorkspace.Close, telling it to close an existing view, the composer calls our method IComposableWorkspace.OnClose, and so on. It’s up to our code to take that new view and do whatever it is that our base control needs done in order to show it (in the former case) or get rid of it (in the latter case). In the sample code, we know that our FlowLayoutPanel base class handles these operations with its own internal collection called Controls. The only code that our implementation needs to provide is the bridge between the composer and this collection, thus:

// Client called IWorkspace.Close, which we delegated to the  composer,
// which calls this method to tell us 
to remove the SmartPart from the
// workspace's collection. We need to know how to do that on the
//
FlowLayoutPanel from which we derive, and we do

public void OnClose(Control smartPart)
{
   
this.Controls.Remove(smartPart);
}

// Client called IWorkspace.Show, which we delegated to the composer,
// which checks to see if the SmartPart is already in its internal
// collection. If not, then the composer adds it internally, then calls
// this method to tell us to add that SmartPart to our workspace.
// Otherwise, the composer will call OnActivate instead of OnShow. We
// need to know how to do that on the FlowLayoutPanel, and we do.

public void OnShow(Control smartPart, FlowLayoutPanelSmartPartInfo smartPartInfo)
{
   
// Add SmartPart to the workspace's child controls collection

   
this.Controls.Add(smartPart);

   
// Delegate internally to this method to apply the information
    // in the SmartPartInfo provided.


   
OnApplySmartPartInfo(smartPart, smartPartInfo);
}

The OnApplySmartPartInfo method takes our FlowLayoutPanelSmartPartInfo and uses its information in a way that makes sense in terms of the workspace's specific capabilities. In this case, we apply a flow break, as specified by the boolean property in the SmartPartInfo. The method SetFlowBreak is provided by the base class. Thus:

// The only piece of information in the FlowLayoutPanelSmartPartInfo that
// we use in the boolean property called FlowBreak, which specifies
// whether or not to break the flow (insert a return character) after the
// specified child control

public void OnApplySmartPartInfo(Control smartPart, FlowLayoutPanelSmartPartInfo smartPartInfo)
{
   
this.SetFlowBreak (smartPart, smartPartInfo.FlowBreak);
}

What about the SmartPartInfo object? The IWorkspace.Show method contains two overloads, one with a SmartPartInfo and one without. Yet our OnShow method only has one flavor, that being with, and it contains our specialized FlowLayoutPanelSmartPartInfo. What happens here? If the client doesn’t pass any type of SmartPartInfo structure with Show, then the composer automatically creates a default instance of our specialized FlowLayoutPanelSmartPartInfo to pass to our OnShow. This class must therefore contain a default empty constructor so that the composer can do this. What happens if the client passes a different type of SmartPartInfo structure, either just the base SmartPartInfo class or a different derived one? That’s the purpose of the method IComposableWorkspace.ConvertFrom. If the client passes any type of SmartPartInfo other than our specific one, the composer calls this method so that we can turn it into our specific one. That way we don’t have to handle all the possible cases in our OnShow or OnApplySmarpartInfo methods. The composer simply ensures that we have what we need before these get called. Thus:

// The client passed a different type of SmartPartInfo to an
// IWorkspace method. The composer calls this method so that we
// can convert it into our own specific type. In this case, we
// return a new one, containing the Title and Description strings
// provided by the caller, and a FlowBreak property (our own addition)
// set to false.


public FlowLayoutPanelSmartPartInfo ConvertFrom(ISmartPartInfo source)
{
   
return (new FlowLayoutPanelSmartPartInfo (source.Title, source.Description, false)) ;
}

The methods OnHide and OnActivate are also called by the composer when necessary, the former meaning to make the specified view invisible and the latter to make it visible if necessary and to make it the active view. Our code (not shown here but available in the sample project) needs to know what that means in terms of our workspace’s base class and perform these operations. In the case of the FlowLayoutPanel, these don’t really have any meaning, as they have in the tab or deck workspaces, so the sample code doesn’t do anything in these methods. But in the case of, say, a tab control, that’s where our code would go to bring the specified tab to the front (Activate) or bury it in the back (Hide)

Finally we reach the events that the IWorkspace interface calls for. When the composer internally activates or closes a SmartPart, it calls a method on the IComposableWorkspace interface to tell our code to do so. We can apply whatever logic we care to at this juncture before or after firing the event. In this case we don't have any, so we simply fire the event, thus:

// Composer has told us to fire the SmartPartActivated event which
// is defined on the IWorkspace interface. It's a normal .NET
// event, so fire it in the usual fashion.


public void RaiseSmartPartActivated(WorkspaceEventArgs e)
{
   
if (SmartPartActivated != null)
    {
        SmartPartActivated(
this, e);
    }
}

You can see that I created this fully functional workspace using very little code. In fact, not counting function names or curly braces or variable declarations, and not counting the delegation in the IWorkspace interface members, this required just 13 lines of C# code (where a line of code is defined as a semi-colon, optionally preceded by statements). If you have a control whose functionality you like, and it derives from any of the usual Microsoft control base classes or the equivalent, then grafting workspace functionality onto it is as close to trivial as things get.

If you'd like to learn more about CAB and SCSF, I'm teaching a public classes on it in January, and I'll be scheduling others. Or I can teach it in-house at your company, which you'd probably cost-effective if you had five or more attendees. Information on both is online at http://www.programcab.com.

Until next time,  as Red Green  would say, "Keep your stick on the ice."


Another New Book from David S Platt

Programming CAB and SCSF

ISBN 0-735-62414-3

Click here to order from Amazon.com

 

To complement my course offerings in CAB and SCSF, I've compiled my notes and sample code into a book, published by Microsoft Press. Get hands-on guidance for developing smart client applications using Windows Forms with the Composite UI Application Block (CAB) and the Smart Client Software Factory.  This book details a simple, approachable method for building these applications. With just your fundamental Visual Basic or Visual C# skills, this guide will help you understand the prefabricated classes of CAB and the proven patterns that the Smart Client Software Factory provides. This book offers classroom-tested guidance, hands-on instruction, and a proven building-block approach. Through eight modular lessons, developers of moderate experience with learn how to create functional, robust smart client applications.

Chapter List:


  1. Introduction     
 
  5. Shared User Interface

  2. Shell and Services
 
  6. Events

  3. WorkItems
 
  7. Action Catalog Service


  4. Workspaces and Views
 

  8. Using CAB and SCSF with WPF

             


New Book from David S Platt

Why Software Sucks (and What You Can Do About It)

ISBN 0-321-46675-6

Sample Chapter Online at www.whysoftwaresucks.com

       

It's finally out! Anyone whose spoken with me in the last couple of years probably got an earful about the latest bee in my bonnet, the book entitled Why Software Sucks. I’m sure that I’ve inflicted sample chapters on just about everyone I know.

It's gotten a storm of publicity, primarily from a Reuters wire service article that ran during the first week of the new year. It was picked up in the electronic editions of such publications as the such as the New York Times (http://www.nytimes.com/reuters/technology/tech-software-platt.html) , Fox News, (http://www.foxnews.com/story/0,2933,241578,00.html), and PC Magazine (http://www.pcmag.com/article2/0,1759,2078820,00.asp).

I've started a new blog based on it, at www.suckbusters.com . It's dedicated to the notion that software shouldn't suck. Instead, software should Just Work.

The title was originally my idea, but I also love the subtitle, suggested by my editor at A-W. I’ve always thought that the right subtitle can really make a book. Like the 60’s bestseller Everything You Always Wanted to Know About Sex (But Were Afraid to Ask). Or Werner von Braun’s autobiography, entitled I Aim for the Stars. Humorist Mort Sahl suggested that its subtitle ought to be, But Sometimes I Hit London. (If you don’t get that last one, go look up von Braun online. As Tom Lehrer famously sang about him in the sixties:  “ … A man whose allegiance is ruled by expedience … ‘Once the rockets are up, who cares where they come down? That’s not my department,’ says Werner von Braun.”) 

This is my first book aimed at end users, not programmers. Early returns from this market are highly positive. My barber, the librarian at my local public (dead tree edition) library, and the contractor who built my house, all report that early chapters are informative, entertaining, and easy to read.

I’m still working on the “what you can do about it,” piece. If you have any thought as to how ordinary users can make their voices heard, I’d like to hear them. Use the contact info link of this web site, if you don’t already have my email. Thanx.


Blatant Self Promotion: Would you buy a used car from this guy?

 

4-day In-House Training Class on Composite UI Application Block. Available In-House, or to the Public in Waltham MA, Jan 29-Feb 2

The CAB that I describe above is useful, but has a steeper learning curve than other parts of .NET. My in-house training class on it will get you up and spinning in no time. See the online syllabus here, then call me to schedule yours.

5-day In-House Training Class on .NET or .NET for Insurance

.NET is here, and it's hot. It changes everything in the software business, and you can't afford to be without it. Rolling Thunder Computing now offers in-house training classes on .NET, using my book as the text.  See the syllabi online here, then call to schedule yours. 

ACORD XML for Insurance In Depth, Including Web Services 

Insurance carriers, learn ACORD XML from David Platt. This 5-day class will give you everything you need to know to jump-start your application development. Learn about security and plug-and-play, and combining ACORD XML with XML Web Services. See the syllabus online here. It can be customized to your needs. 


 Annabelle And Lucy's Latest

And now, the moment for which I know you've all been waiting -- the pictures of my two girls. Lucy is just turning 5 this week. She's in Yellow Rose Kindergarten at  Cape Ann Waldorf School, actually RUNS onto the playground when we drop her off. Annabelle turned 7 in June. She's in first grade at Cape Ann Waldorf. And believe it or not, her teacher is a burned-out computer geek, who used to work for Powersoft, remember them? Small world, ain't it? .

Here my girls show their American Girl dolls (Nelly and Samantha, for you readers who follow such things), wearing nightgowns that Mommy made by hand to match the ones that Santa brought the girls at Christmas.  They're gorgeous, with fabulous detail, and it took her one entire day to make them, non-stop from dawn to dusk. With true merchandising brilliance, it's not the doll that breaks the bank, it's the infinite number of accessories. In addition to clothes and furniture, did you know that each of these dolls has her own doll that you can buy for an additional sum? I don't mind buying my girls dolls (actually I didn't, my parents did, last Chanukah), or even doll clothes, since they're only this age once. But I'll be damned if I'm going to jet around the world busting my ass teaching CAB and SCSF to buy a doll for the doll. We geeks recognize infinite recursion when we see it.

   

Here's Lucy wearing the dress that Annabelle outgrew (it fit her for about 5 minutes. She has her face painted from a birthday party.

And finally, here's Annabelle in Mommy's studio.  Her grownup teeth have come in, if you recall her vampire look from last year at this time.


Subscription Information

Thunderclap is free, and is distributed via e-mail only. We never rent, sell or give away our mailing list, though occasionally we use it for our own promotions. To subscribe, jump to the Rolling Thunder Web site and fill in the subscription form.


Legal Notices

Thunderclap does not accept advertising; nor do we sell, rent, or give away our subscriber list. We will make every effort to keep the names of subscribers private; however, if served with a court order, we will sing like a whole flock of canaries. If this bothers you, don't subscribe.

Source code and binaries supplied via this newsletter are provided "as-is", with no warranty of functionality, reliability or suitability for any purpose.

This newsletter is Copyright © 2005 by Rolling Thunder Computing, Inc., Ipswich MA. It may be freely redistributed provided that it is redistributed in its entirety, and that absolutely no changes are made in any way, including the removal of these legal notices.

Thunderclap is a registered trademark ® of Rolling Thunder Computing, Inc., Ipswich MA. All other trademarks are owned by their respective companies.