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
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:
private
WorkspaceComposer<Control,
FlowLayoutPanelSmartPartInfo>
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)}
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.
//
Client called IWorkspace.Activate.
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> : IWorkspaceThe
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)// 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)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)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.
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.
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 |
|
8. Using CAB and SCSF with WPF |
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.
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.
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.