This post is part of a series which discusses the journey I took building a smart client membership application using Microsoft's Smart Client Software Factory (SCSF). You can navigate the entire series from here.
Work Items are one of the SCSF/CAB artifacts that causes angst amongst smart client developers. Part of the problem lies with the early whitepaper Architecting Composite Smart Clients Using CAB and SCSF and the early CAB examples reflecting the thinking of the p&p team at that time. The section entitled Use-Case-Driven-Strategy would have you create work items based upon each use case. In the banking case study, there would be 17 work items created! After pages and pages of details and diagrams on turning use cases into work items there's about half a page of text following that almost casually mentions another approach- mapping work items to business entities.
In my membership application I took the business entity approach which I felt was reasonable, easier to develop, manage and it seems the p&p team's thinking is also evolving. Peter Provost, Development Lead for the p&p team, sums it up best in this podcast (sorry for their crappy, annoying splash ad!) - "there might not be enough value in creating that many work items". He goes on to say, "a work item is a scoping container" which David Platt echoes in his book, Programming Microsoft Composite UI Application Block and Smart Client Software Factory (Pro-Best Practices)*, equating a work item to a Win32 Process.
Given the major business entities previously mentioned in this article series, it was natural for me to create a PersonWorkItem and HouseholdWorkItem. Each of these scopes the data, views and logic related to a specific business entity during runtime. There aren't any recipes for creating a work item so ya' gotta do it the old fashioned way - writing code by hand. Work Items are just simple classes that derive from Microsoft.Practices.CompositeUI.WorkItem. The example screen shot shown on the right contains a list of people on the left side. Clicking a person's name displays the person's information on the right side.
The Members module contains a ModuleController class which is a specialized work item of type ControlledWorkItem - part of the recipe-generated code. I've added an EventSubscription there to respond to the person being chosen in the list view (see the article about views for more detail regarding the event handling specifics). Here's the logic that's executed within the event subscription:
int personId = eventArgs.Data;
//Create a key for the workitem so we can check
//later if the workitem has already been created.
string key = "Person" + personId;
PersonWorkItem workItem = WorkItem.WorkItems.Get<PersonWorkItem>(key);
if (workItem == null)
// add a new work item representing this instance to the
// collection of work items in this module
workItem = WorkItem.WorkItems.AddNew<PersonWorkItem>(key);
// add a new detail view smart part to the collection of smart parts
Remember, this code is in ModuleController.cs which is a work item so the reference WorkItem.WorkItems is the collection of work items within the ModuleController - WorkItem is a reference to the controller's work item and WorkItems is a collection within. Thus, I am attempting to retrieve the existing work item for the selected person and, if it doesn't exist, then a new PersonWorkItem is created and added to the ModuleController's collection of work items that it maintains. Therefore, each person selected for display causes a PersonWorkItem instance to be created and managed. Of course, how many get created and how they are disposed is up to you. In my case, since I'm using a TabWorkspace with one tab per person shown (see the bottom tabs on the above screen shot) I may have several PersonWorkItem instances managed in memory at once.
As the comment shows above, a PersonDetailView smart part is created and added to the new PersonWorkItem instance's collection of smart parts it manages. The new PersonWorkItem instance's Run method is then called and the right hand workspace is passed as an argument telling it where to display itself. Additional smart parts are nested within the detail view using smart part placeholders and it all displays "like magic".
The key concept here is how I scoped work relating to a business entity - a Person - within a work item. That work item instance contains a smart parts collection which holds all the views related to displaying a person as well as the logic and event handling that takes place when the user interacts with the views (a.k.a. smart parts).
* David's book must be vying for the award of longest title for the thinnest technical book :). It is great as an overall introduction and I recommend it if you're just getting started in CAB/SCSF but the "programming" part is light compared to some programming books. Don't get me wrong - David is a gifted technical writer but if you're looking for a lot of meat and in-depth programming examples then you'll be disappointed. If you're looking for a good foundational understanding of SCSF before embarking on a project then by all means buy the book - I wish I had it when I started out but it was just published a couple of weeks before I wrote this article.