Sie sind auf Seite 1von 115

Page |1

Table of Contents

1. Modules and Shells ................................................................................................................................... 2


2. WorkItems................................................................................................................................................. 6
3. Dependency Injection ............................................................................................................................... 8
4. An Aside on Inversion of Control, Dependency Inversion and Dependency Injection ........................... 12
5. Dependency Injection and the Composite Application Block ................................................................. 16
6. Constructor Injection in the CAB............................................................................................................. 24
7. Introduction to Services in the CAB ........................................................................................................ 26
8. Creating and Using services in the CAB .................................................................................................. 30
9. The Command Design Pattern ................................................................................................................ 37
10. Commands in the CAB........................................................................................................................... 40
11. Introduction to events in the CAB......................................................................................................... 45
12. Events in the CAB .................................................................................................................................. 48
13. Introduction to UI Extension sites......................................................................................................... 54
14. More on UI Extension Sites ................................................................................................................... 58
15. Introduction to Smart parts and Workspaces....................................................................................... 66
16. More detail on WorkSpaces and SmartParts ........................................................................................ 73
17. Workspace Types .................................................................................................................................. 77
18. Introduction to Smart Client Software Factory ..................................................................................... 83
19. Business Modules and Interfaces in the SCSF Smart Client Solution.................................................... 88
20. SCSF Business Modules: Start Up and the ControlledWorkItem .......................................................... 93
21. Foundational Modules and Names as Constants.................................................................................. 96
22. Model – View – Controller .................................................................................................................... 99
23. Model – View – Presenter................................................................................................................... 104
24. Model – View – Presenter................................................................................................................... 108
25. Model – View – Presenter using the Smart Client Software Factory.................................................. 112
Page |2

1. Modules and Shells

Introduction

Microsoft‟s Smart Client Software Factory (SCSF) and associated application blocks are
excellent pieces of software. However, for a developer coming to them for the first time they can
be extremely daunting. There are many things that can be confusing. Firstly we have modules,
workitems, workspaces, and shells, all of which sound similar. Then there‟s dependency
injection, command patterns, event brokers, model-view-presenter patterns and other high-level
concepts, none of which are easy to understand. There‟s a load of other concepts as well,
multiple example applications, and plenty of documentation. Microsoft‟s documentation has a
very steep learning curve indeed.

I‟m going to write a series of short articles that assume you are a developer coming to this for the
first time and are confused as I was. To do this I‟m going to focus on one or two basic concepts
in each article. There‟s quite a lot of blogging about CAB/SCSF on the web, but I couldn‟t find
anything that gave me a quick, basic introduction with a gentle learning curve. This is what I will
try to achieve here.

To start I‟m going to look at the basic set up of modules and shells in the Composite Application
Block. This is the starting point for most SCSF projects. I‟m not going to cover WorkItems until
my second article as I found them quite confusing initially.

Composite Application Block

The starting point for many developers coming to the Composite Application Block (CAB) is the
need to either

1. To design a complex user interface that has some kind of separate components that can be
developed and released independently, or
2. To take several existing user interface applications and combine them in such a way that they
can continue to be developed independently, but appear in the same window with common
menus etc and can interoperate on some level.

This is certainly where I started. The key point in both cases is that if we want our components to
be released independently then they can‟t have direct references to each other. In short we want
„applications‟ or components that appear in the same user interface (same window) with
common menus and some ability to talk to each other, but don‟t directly reference each other.

The CAB allows us to do this. It clearly offers us a lot more than just this, but in this article I will
show the basics.
Page |3

Modules and Shells

The first concept you need to understand for this is that of a „module‟. This is what I am referring
to as a „application‟ or „component‟ in the paragraph above: a block of code, usually with a user
interface that can be displayed in a common window, but which doesn‟t reference other modules.
In reality these are separate .NET projects within our solution that don‟t reference each other.

The second concept is that of the „shell‟. This is simply the „common window‟ I‟m referring to in
the paragraph above. It will contain our modules, or at least the visual parts of them. In reality
the shell is usually contained in its own .NET project, but one that doesn‟t reference any of the
modules, nor is referenced by them.

So, simplistically:

Module = standalone project to be used in a composite user interface


Shell = the host form for the composite user interface

Our Example

Let‟s start with a really simple example. Assume we have a C# project that just displays a red
form, and another separate project that just displays a blue form. These are going to be our two
modules. Then we want a third project to contain a shell, which in this case will just be another
form that we want displayed. To keep this example really simple we won‟t try to display the red
and blue forms actually inside the shell: this will be done in part 2.

The difficult bit is that although all these projects will be in the same solution, none of them will
reference each other directly, yet all three forms will display at start up. Obviously we could do
this fairly simply with reflection, but we will use the CAB to do it.

Naïve Application Example

The code for this example is available.(http://www.richnewman.plus.com/CABPart1.zip)

To implement the example:

1. We set up three projects (all Windows applications) in a solution. We‟ll call these Red, Blue,
and Shell. For the Red and Blue projects (which will be our modules) we simply change the
BackColor property of the form to red and blue as appropriate.
2. We add references to the CAB dlls (Microsoft.Practices.CompositeUI.dll,
.Practices.CompositeUI.WinForms.dll, and Microsoft.Practices.ObjectBuilder.dll) to all three of
the projects. We also make sure all three build into the same build directory (via the
Properties/Build tab). Shell is the startup project.
3. Now if we run the projects all three will build, but clearly only the form from the Shell project
will get displayed, since that is the start up project. We need to tell the other modules to show
their forms. To do this we change Program.cs in Shell (our start up code) to inherit from
FormShellApplication<,> as below:
Page |4

using System;
using Microsoft.Practices.CompositeUI.WinForms;
using Microsoft.Practices.CompositeUI;

namespace Shell
{
public class Program : FormShellApplication<WorkItem, Form1>
{
[STAThread]
static void Main()
{
new Program().Run();
}
}
}

The two types passed in to FormShellApplication<,> both get instantiated when Program is
instantiated and .Run() is called (this calls into the base classes clearly). Form1 is our shell form
and gets displayed, WorkItem I will discuss in part 2. After this change the application will still
only display the MDI form, but the .Run() call will enable us to show the other two screens with
some other simple changes.

4. In fact the application is now looking for an XML file telling it what other modules to load.
Again this happens as a result of the call to .Run(). The XML file has to be called
ProfileCatalog.xml, has to be copied always into the output directory, and has to look like the
XML below:

<?xml version="1.0" encoding="utf-8" ?>


<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile">
<Modules>
<ModuleInfo AssemblyFile="Red.exe" />
<ModuleInfo AssemblyFile="Blue.exe" />
</Modules>
</SolutionProfile>

We add this file to the Shell project. Now if you get the names of the modules wrong and then
run the application it will throw an exception, showing that it‟s trying to find the relevant files.

5. Finally we need something in the Red and Blue projects that will actually run as a result of this
(the CAB doesn‟t just call the usual start up code). We can do this by adding a class that inherits
from Microsoft.Practices.CompositeUI.ModuleInit and overrides its Load() method. The CAB
code will call this Load method from the .Run() call above:

using Microsoft.Practices.CompositeUI;
namespace Blue
{
public class BlueModuleInit : ModuleInit
{
public override void Load()
{
Page |5

base.Load();
Form1 form = new Form1();
form.Show();
}
}
}

That‟s it: if we put the code above in the Blue project, and the equivalent in the Red project, the
three forms will now load and we have our first composite application. None of the three
separate projects has a direct reference to any other.

Summary

The difficult thing to understand when you see this for the first time is that the CAB is doing a
lot of work for us when we call that .Run() method on a FormShellApplication class. It‟s
instantiating and showing our Form1 (our shell). It‟s checking for an XML file called
ProfileCatalog.xml. If it finds ProfileCatalog.xml, it is loading the assemblies it finds listed in
there. It‟s then looking for any ModuleInit classes in them, and calling .Load if it finds them.
None of that‟s too complicated, but it can feel a bit like smoke and mirrors are being used.
Page |6

2. WorkItems
Introduction

There are two other core concepts that you need to understand to be able to use even the most
basic functionality of the CAB. These are WorkItems, and dependency injection. This part of the
article will discuss WorkItems.

WorkItems – Basic Concepts

Microsoft‟s documentation defines a WorkItem as „a run-time container of components that are


collaborating to fulfill a use case‟. In many ways the best way to think of them is as classes that
contain collections of other classes that are logically grouped together. The name is a little
strange: „work items‟ in general tend to be individual tasks that need to be performed in, say, a
workflow, or, in the .NET Framework, in a thread pool. The WorkItems in the CAB are broader
than that.

In code terms WorkItems are just objects of type „WorkItem‟ (a class in the
Microsoft.Patterns.CompositeUI library). Each WorkItem has collection classes associated with
it to allow it to „contain‟ components. Three of these collection classes that are reasonably easy
to understand are:

1. The Items collection, which can contain almost anything since it‟s a (special) collection
of System.Objects
2. The Services collection, which is a collection of CAB services.
3. The WorkItems collection, which is a collection of other „child‟ WorkItems.

However there are several other collections of CAB code objects on the WorkItem class.
WorkItems also have state (used to track changes), and status (active/inactive).

Container Hierarchy and the Root WorkItem

There‟s a second important aspect of WorkItems: they can be arranged into a hierarchy. This
hierarchy typically starts with a root WorkItem that contains components (code objects) and
other WorkItems, the other WorkItems again can contain components and other WorkItems, and
so on.

This is particularly useful since we can construct the hierarchy across modules, even though the
individual modules may not reference each other. We can then use the WorkItem hierarchy to
use components in other modules.

I‟ll show exactly how this works in a minute, but in our example from part 1 we could add a
WorkItem class to each of our three projects. We could then instantiate one WorkItem object per
Page |7

project at runtime. The WorkItem object in the Shell program could be a root WorkItem. It could
contain the other two WorkItems.

If we add a component from the Shell project to the root WorkItem we can access that from, say,
the Red application‟s WorkItem by simply using
this.ParentWorkItem.Items[“ComponentName”].

One obvious difficulty with this approach is that we are then tightly-coupling our two modules
together to some extent, which is what we were trying to avoid by not having direct
dependencies between our modules. However, as we‟ll see we can still release new versions of
each module independently of the rest of the code.

WorkItems and the FormShellApplication

In part 1 of this article we saw that to start a CAB application we inherit from
FormShellApplication<,>. We provide two types when we declare the new class to close the
generic definition:

public class Program : FormShellApplication<WorkItem, Form1>


{

As we have seen the second of these (Form1) is the shell for the application and gets instantiated
and shown at start up (when we do new Program().Run()). The WorkItem also gets instantiated
at start up. This will be the root WorkItem for the application, sitting at the top of the hierarchy
described above. It can be referred to in the Program class using the RootWorkItem property
(this.RootWorkItem).
Page |8

3. Dependency Injection
Introduction

This article is actually part 3 of an introductory series of articles on Microsoft‟s Composite


Application Block (CAB) and Smart Client Software Factory (SCSF). However, this particular
article will only talk about dependency injection in general terms and not discuss the
CAB/SCSF. Part 5 of the series will address dependency injection in the CAB. Part 4 of the
series expands the discussion here by talking about inversion of control (IoC) and dependency
inversion.

Dependency Injection

Dependency injection as a general concept is explained far better than I could do it by Martin
Fowler at http://www.martinfowler.com/articles/injection.html. However, in short it is a means
of allowing a main class to use a second, dependent class without directly referencing that class.
Some external entity will provide the second class to the main class at runtime – it will „inject‟
the „dependency‟. Obviously to be useful the second class will need to implement an interface
that the main class knows about.

The aim of this is to let us change the behaviour of our class structure by changing which second
class is injected into the main class. Because the main class has no hard dependency on the
second class this can be done at runtime. Thus our code is very flexible, easy to modify and
loosely coupled.

Class Diagram

The class diagram looks something like this:

MainClass contains a reference to an object that implements IDependentClass, and can thus call
the DoSomethingInDependentClass method on that object. DependentClass1, DependentClass2,
and DependentClass3 implement the interface.

Some client code will then create the appropriate dependent class and tell the main class to use it
(via the interface). It‟s easiest to understand this via some example code, which I‟ll demonstrate
below.
Page |9

Strategy Pattern?

In many ways this is the classic Gang of Four Strategy pattern with a twist. The class diagram
above is very similar to the usual one given for the strategy pattern: see
http://www.dofactory.com/Patterns/PatternStrategy.aspx (don‟t worry if you don‟t know the
strategy pattern at this stage though). The difference is that with dependency injection exactly
which class is going to be provided as the dependency (strategy) is often left to configuration at
runtime. That is, it can be abstracted out of the code entirely.

In the Spring framework, for example, XML configuration files can be used to specify which
class gets created and used. This is an extreme example of deciding which class to use at
runtime: you can change the dependencies without changing the compiled code at all.

However, there are some reasons for not using external configuration files to specify these
dependencies: it makes it difficult to debug, and you‟re probably not going to want to change
application behaviour via a configuration file in any case. Dependency injection frameworks in
general will allow you to specify your injection in code (Spring allows this).

Dependency Injection Example

We can easily create an example that does this using


.NET(http://richnewman.wordpress.com/dependency-injection-example-setter-injection/).

Full code for all these examples is available for


download(http://www.richnewman.plus.com/DependencyInjectionTypes.zip).

Firstly we create an interface that will be used to call our dependent class:

public interface IdependentClass


{
void DoSomethingInDependentClass();
}

Then we create dependent classes that implement this interface to do something. Which one of
these classes will actually be used will only be decided at runtime based on a setting in the
App.Config file:

public class DependentClass1 : IdependentClass


{
public void DoSomethingInDependentClass()
{
Console.WriteLine(“Hello from DependentClass1: I can be injected
into MainClass”);
}
}

public class DependentClass2 : IdependentClass


{
P a g e | 10

public void DoSomethingInDependentClass()


{
Console.WriteLine(“Hello from DependentClass2: I can be injected
as well, just change App.Config”);
}
}

Now we create a class that will use the dependent classes, calling their functionality via the
interface. This „main‟ class has no knowledge of the dependent classes types, only of the
interface that they implement:

public class MainClass


{
IdependentClass dependentClass;
public IdependentClass DependentClass
{ get { return dependentClass; }
set { dependentClass = value; }
}

public void DoSomething()


{
dependentClass.DoSomethingInDependentClass();
}
}

Now we need some code that will use this structure. Clearly we need to instantiate the main class
and tell it (using the interface) which dependent class to use. We can then call the functionality
on the main class.

Static void Main(string[] args)


{
// Get the correct dependency based on configuration file
IdependentClass dependency = GetCorrectDependency();

// Create our main class and inject the dependency


MainClass mainClass = new MainClass();
mainClass.DependentClass = dependency;

// Use the main class, the method references the dependency


// so behaviour depends on the configuration file
mainClass.DoSomething();

Console.ReadLine();
}

Finally we need some code in GetCorrectDependency() that decides which dependent class we
are going to use, and instantiates it. We do this by examining the „ClassName‟ setting in
App.Config, and instantiating that using Activator.CreateInstance:
P a g e | 11

static IdependentClass GetCorrectDependency()


{
string classToCreate =
System.Configuration.ConfigurationManager.AppSettings[“ClassName”];
Type type = System.Type.GetType(classToCreate);
IdependentClass dependency =
(IdependentClass)Activator.CreateInstance(type);
return dependency;
}
The App.Config file is as below:
<?xml version=”1.0” encoding=”utf-8” ?>
<configuration>
<appSettings>
<add key=”ClassName” value=”DependencyInjection.DependentClass1” />
</appSettings>
</configuration>

So we can compile this code and run it as above and it will output the message in
DependentClass1. If we then just change the configuration file so that the ClassName value is
DependencyInjection.DependentClass2 and re-run the code will output the message in
DependentClass2.

Note that what is powerful about this code is we could write a DependentClass3, with new
behaviour, and use it by changing the configuration file without the need to change any of the
existing code.

Types of Dependency Injection

Martin Fowler‟s article talks about three different types of dependency injection: constructor
injection, interface injection and setter injection. The example above uses setter
injection(http://richnewman.wordpress.com/dependency-injection-example-setter-injection/): we
give the main class its dependency via a setter in the line:

mainClass.DependentClass = dependency;

In constructor injection we give the main class its dependency in the constructor. With interface
injection we define another interface that the main class will implement that sets the dependency.

I have reworked the example above for both constructor


injection(http://richnewman.wordpress.com/dependency-injection-example-constructor-
injection/) and interface injection(http://richnewman.wordpress.com/dependency-injection-
example-interface-injection/). As you can see these are relatively trivial changes in this simple
example.

Full C# code for these examples is


available(http://www.richnewman.plus.com/DependencyInjectionTypes.zip).
P a g e | 12

4. An Aside on Inversion of Control, Dependency Inversion and


Dependency Injection

Introduction

To understand what the CAB is doing for you it‟s important to have an understanding of
dependency injection, and I will be talking more about it in part 5.

This short article is something of an aside however, and is not critical for an understanding of the
CAB. Here I will discuss two concepts that sound similar: inversion of control („IoC‟) and
dependency inversion. I will also discuss how both relate to dependency injection.

‘Inversion of Control’

„Inversion of Control‟ is currently something that everyone agrees is a good thing, even though
no-one seems to be able to agree exactly what it is. For example, on Wikipedia there‟s no
definition of Inversion of Control, only an admission that we can‟t define it.

Inversion of control is closely related to dependency injection, as I will describe below, and is
often used synonymously with it. However, it has a wider meaning, and is arguably not strictly
accurate when applied to dependency injection as an abstract concept. Martin Fowler discusses
inversion of control at length, but in his article on dependency injection decides to avoid the
term.

Inversion of Control in Relation to Frameworks

The conventional definition of inversion of control relates to frameworks and code re-use.
Normally to re-use someone else‟s code you would call into a library. You do this all the time in
the .NET framework. For example, if you call Math.Tan() you are using someone else‟s code,
but you make the call and you have control.

However, there are times using .NET when the framework calls you back. An example is when
you write a custom array sort algorithm using the IComparable or IComparer interfaces. Another
is when you implement a custom enumerator by implementing IEnumerable on a collection
class. In these cases the usual direction of control is inverted: something else is calling your
code, rather than you calling something else.

Example

If we implement IComparable on a class we have to write a method called CompareTo(). This


defines when one object of the class‟ type is bigger than another. Then when we call Array.Sort
on an array of objects of this class the framework itself calls our routine to sort the objects
according to our definition.

I‟ve written a simple example to illustrate this.


P a g e | 13

Here the .NET framework is calling my code, and as a result I have to write it with a specific
method signature – int CompareTo(object obj). I don‟t have direct control over when this call is
made. We can think of this as an „inversion‟ of „control‟ from the Math.Tan example.

For obvious reasons, the inversion of control concepts described above are often called the
„Hollywood Principle‟, or „don‟t call us we‟ll call you‟.

Summary

Inversion of control is discussed in relation to frameworks in „Design Patterns: Elements of


Reusable Object-Oriented Software‟ by Gamma, Helm, Johnson and Vlissides (also known as
the „Gang of Four‟ book). They summarize quite nicely:

“Frameworks emphasize „design reuse‟… Reuse on this level leads to an inversion of control
between the application and the software on which it‟s based. When you use a toolkit (or a
conventional subroutine library for that matter), you write the main body of the application and
call the code you want to reuse. When you use a framework, you reuse the main body and write
the code it calls. You‟ll have to write operations with particular names and calling conventions,
but that reduces the design decisions you have to make.”

Inversion of Control and Dependency Injection

So how does inversion of control relate to dependency injection? At first glance the concepts
above and my examples in the previous article have little in common. Yet the two terms are often
used synonymously. Indeed I have some course notes from a major computer trainer that actually
says „IoC and dependency injection are terms that mean the same thing‟.

The answer is that dependency injection is usually done via a framework of some kind. I will
discuss this more in part 5, but typically you define your classes and then tell the framework to
„inject‟ them into other classes in some way. The framework is then calling back your code to do
the injection, and we have inversion of control as described above.

Inversion of Control = Dependency Injection?

As I‟ve discussed, dependency injection is just one very specific example of how inversion of
control can be used. As a result it is probably wrong to treat IoC and dependency injection as
terms that mean the same thing. IoC is a wider concept.

However, in spite of it not strictly being accurate, when people talk about „IoC Containers‟ and
„IoC Frameworks‟ what they usually mean are containers or frameworks that do dependency
injection.

Inversion of Control and the CAB

The Composite Application Block really is an inversion of control framework in all senses by the
way. It allows us to do dependency injection, as I‟ll describe below (eventually). It also is often
P a g e | 14

calling us rather than us calling it. An example of this is the call to the „Load() method in a
ModuleInit class at start up that we saw in Part 1 of this series of articles. We have to just know
that method will be called when the module starts, and code to the method signature.

Dependency Inversion

A related concept that causes further confusion is dependency inversion. Once again dependency
inversion is a wider concept that is used in dependency injection. The aim of dependency
inversion is to prevent high-level classes directly depending on lower-level classes and thus
introducing tight-coupling between them. Instead we get both sets of classes to depend on
interfaces.

Dependency Inversion in the Example from Part 3

Consider my example of a main class and dependent classes from part 3. If you were writing this
example in a „traditional‟ way you might have the client code (class Program) create the
MainClass which in turn would decide which dependent class it needed and instantiate it. The
dependencies between classes would look something like this:

As we know, direct dependencies between classes are in general a bad thing as they make it
harder to change the code in the dependent classes. So in our dependency injection pattern we
introduce a specific interface that all our classes depend on in some sense:

Now, as discussed previously, the code is less brittle as we can change the dependent classes
without worrying too much about breaking MainClass, as long as we don‟t change the interface.
P a g e | 15

Dependency Inversion and Inversion of Control

We have inverted the dependencies for the dependent classes here. Previously they were being
referred to directly by MainClass. Now nothing refers to them directly, instead they refer to the
interface. The arrows from the dependent classes now point up instead of down.

Note that this is NOT inversion of control. We are inverting dependencies between classes. This
is not an example of a framework calling the code rather than the code calling the framework. In
both cases here ultimately MainClass calls code that runs in a dependent class.
P a g e | 16

5. Dependency Injection and the Composite Application Block

Introduction

In part 1 of this series of articles I described a simple CAB application. This had three Windows
Application C# projects with no references to each other. In spite of this, with some very simple
code we could get all three to launch their individual screens. That very simple application didn‟t
have the projects interacting in any other way, however.

Part 2 of the series described WorkItems, which can be thought of as containers for code, and
how we could add a WorkItem to each of our projects in a hierarchy.

Part 3 introduced dependency injection as a way of structuring our code so that our class
structure was loosely coupled and behaviour could be easily changed by changing which class
was „injected‟ into another.

In this article I will bring all of these ideas together and explain how dependency injection works
in the CAB.

The Problem

We want to get our three projects from part 1 (Red, Blue and Shell) to interact with each other
without having them reference each other. As discussed in part 2, WorkItems are designed to
allow us to do this: we can put a WorkItem in each project, put code into their various
collections, share the WorkItems and thus share the code.

But how does one project know about the WorkItem from another project? Bear in mind that
there are no direct references between the projects. This could be done manually in code using
reflection, of course. But the CAB framework gives us a much cleaner way to do this.

Dependency Injection and the CAB

The answer is we can use dependency injection to inject a WorkItem from one project or
„module‟ into another.

This is clearly an appropriate thing to do here: we want loose coupling between our modules and
flexibility to change how they interact. As I‟ve discussed in another article, in extreme cases we
might have different development teams responsible for different modules, with different release
cycles. Using dependency injection one team could change a class that‟s injected and thus
change the behaviour of another module without that module needing to be re-released.

However, unlike in my example in part 3, dependency injection in the CAB doesn‟t use
configuration files to specify which class should be used. Instead attributes are used to tell the
code that a dependency needs to be injected.

Example
P a g e | 17

This is most easily seen with an example. We have already seen that a root WorkItem is created
in our CAB application at start up. We have also seen that all modules listed in the
ProfileCatalog.xml file will get loaded at the start up of a CAB application, and that a Load()
method in a ModuleInit class gets called in each module.

We want a reference to the root WorkItem in a module that is not the shell. We can achieve this
by putting a setter for a WorkItem in our ModuleInit class for the module, along with an
attribute:

private WorkItem parentWorkItem;

[ServiceDependency]
public WorkItem ParentWorkItem
{
set { parentWorkItem = value; }
}

As you can see we decorate the setter with the attribute „ServiceDependency‟. This tells the CAB
framework that when it is loading this module it should look for an appropriate WorkItem to
„inject‟ into this setter.

If we put this code into the RedModuleInit class in our example, and put a breakpoint in the
setter we can see that the root WorkItem is being passed into here at start up and stored in the
parentWorkItem variable.

How is this Working (1)?

You may wonder how the CAB knows what to inject and where to inject it here. After all there
may be multiple WorkItems in our project: which one should it choose? Furthermore we can
inject different types (i.e. not WorkItems) in a similar way. If we have several instantiated
classes of the same type how do we inject a specific one? And how does the CAB find the
ServiceDependency attribute? Does it scan all classes in all modules?

I‟m going to leave these issues for now: just accept that the root WorkItem gets injected in this
case. I‟ll return to this later in this article.

Red and Blue Forms Application

So we can get a reference to the root WorkItem as above. In our naïve CAB application from
part 1 we‟d quite like to tell the red and blue forms in the modules to load as MDI children into
the shell form.

We can do this by firstly adding the shell form to the Items collection of the root WorkItem.
Then if the root WorkItem is available in our Red and Blue projects we can access the shell form
through the Items collection.
P a g e | 18

There‟s an AfterShellCreated event of the FormShellApplication class that we can override in


our program class to add the shell form to the Items collection:

public class Program : FormShellApplication<WorkItem, Form1>


{
[STAThread]
static void Main()
{
new Program().Run();
}
protected override void AfterShellCreated()
{
base.AfterShellCreated();
this.Shell.IsMdiContainer = true;
RootWorkItem.Items.Add(this.Shell, "Shell");
}
}

Note that the shell gets a name in the Items collection (“Shell”). Note also that we‟re making the
shell form into an MDIContainer here, accessing it via the Shell property of the
FormShellApplication class.

In the Load method of our modules we can now retrieve the shell form and set it to be the
MDIParent of our red and blue forms. So our ModuleInit class looks as below:

public class RedModuleInit : ModuleInit


{
private WorkItem parentWorkItem;

[ServiceDependency]
public WorkItem ParentWorkItem
{
set { parentWorkItem = value; }
}

public override void Load()


{
base.Load();
Form shell = (Form)parentWorkItem.Items["Shell"];
Form1 form = new Form1();
form.MdiParent = shell;
form.Show();
}
}

If we now run the application our red and blue forms will appear as MDI children of the main
shell.
P a g e | 19

The code for this is available. By the way you should know that there are better ways of setting
up an MDI application in the CAB: this example is intended to just show the basic concepts of
dependency injection.

How is this Working (2)?

Earlier in this article I posed several questions about how all this could be working. I‟ll attempt
to answer those questions now.

As discussed earlier, WorkItems are generic containers for code to be passed between modules,
and are capable of being arranged in a hierarchy. But in addition they are actually „Inversion of
Control containers‟ or „Dependency Injection containers‟. I mentioned these in part 4 of this
series of articles. However, I‟ve rather glossed over them up until now. Note that both Spring
and PicoContainer use containers to control their dependency injection.

WorkItems as Dependency Injection Containers

These containers work in the CAB as follows. Suppose we want to inject object A into object B.
The dependency injection only happens when object B is added into an appropriate collection on
a WorkItem. This can be on creation of the object if we create object B with the AddNew
method, or it can happen with an existing object if we use the Add method to add it to a
WorkItem collection.

Furthermore normally the injection can only work if object A is already in an appropriate
collection of the same WorkItem. The exception is if we are using the „CreateNew‟ attribute (see
below). In this case object A will be created and added to the Items collection of the WorkItem
before being injected.

As you can see, in a way dependency injection in the CAB is „scoped‟ to a WorkItem.

Types of Dependency Injection in the CAB

There are three attributes that can be attached to setters and used for dependency injection in the
CAB:

1. ComponentDependency(string Id)
This attribute can be used to inject any object that already exists in a WorkItem‟s Items
collection. However, because we can have multiple objects of the same type in this
collection we have to know the ID of the item we want to inject (which is a string). We
can specify an ID when we add our object into the collection. If we don‟t specify an ID
the CAB assigns a random GUID to the item as an ID. Note that if the object does not
exist in the appropriate Items collection when we try to inject it then the CAB will throw
a DependencyMissingException.
2. ServiceDependency
We‟ve seen this attribute already. An object must be in the WorkItem‟s Services
collection to be injected using this attribute. The Services collection can only contain one
P a g e | 20

object of any given type, which means that the type of the setter specifies the object
uniquely without the need for an ID. I will discuss Services further in part 6 of this series
of articles.
3. CreateNew
A new object of the appropriate type will be created and injected if this attribute is
attached to a setter. The new object will be added to the WorkItem‟s Items collection.

As usual this is best seen with an example.

Example

We set up a CAB project with two component classes. Component1 is just an empty class, whilst
Component2 has two private Component1 member variables that will be injected. One will be
injected by name (and so needs to be created and added to the WorkItem‟s Items collection prior
to injection). One will be injected by being created:

public class Component2


{
private Component1 component11;
[ComponentDependency("FirstComponent1")]
public Component1 Component11
{
set { component11 = value; }
}

private Component1 component12;


[CreateNew]
public Component1 Component12
{
set { component12 = value; }
}
}

To use this we put the following code in the AfterShellCreated method of our
FormShellApplication class:

protected override void AfterShellCreated()


{
RootWorkItem.Items.AddNew<Component1>("FirstComponent1");
Component2 component2 = new Component2();
RootWorkItem.Items.Add(component2);
DisplayRootItemsCollection();
}

Notice the syntax of the AddNew command for the Items collection. It‟s a generic method.
Remember that a generic is simply a way of providing a type (in this case a class) at runtime.
Here we are providing the type “Component1” to the AddNew generic method. A generic
method can do anything it likes with the type provided. Here AddNew will instantiate that type
and add it to the items collection.
P a g e | 21

As you can see, we create a Component1 object with ID “FirstComponent1” and add it to the
Items collection. We then create a Component2 object using the „new‟ keyword. We would
usually do this using AddNew, but I want to demonstrate that we don‟t have to do this. Next we
add the Component2 object to the Items collection.

At this point the “FirstComponent1” object will be injected into component2 in the setter marked
with the “ComponentDependency” attribute. Also another Component1 object will be created
and injected into component2 in the setter marked with the “CreateNew” attribute.

Finally in this code we call a routine called DisplayRootItemsCollection:

private void DisplayRootItemsCollection()


{
System.Diagnostics.Debug.WriteLine("ITEMS:");

Microsoft.Practices.CompositeUI.Collections.ManagedObjectCollection<object>
coll = RootWorkItem.Items;
foreach (System.Collections.Generic.KeyValuePair<string, object>
o in coll)
{
System.Diagnostics.Debug.WriteLine(o.ToString());
}
}

This just dumps out all the objects in the Items collection to the debug window. The results are
as below:

ITEMS:
[4e0f206b-b27e-4017-a1b2-862f952686da, Microsoft.Practices.CompositeUI.State]
[14a0b6a2-12a4-4904-8148-c65802af763d, Shell.Form1, Text: Form1]
[FirstComponent1, Shell.Component1]
[4c7e0a20-90b7-42c6-8912-44ecba40523f, Shell.Component2]
[c40a4626-47e7-4324-876a-6bf0bf99c754, Shell.Component1]

As you can see we‟ve got two Component1 items as expected, one with ID “FirstComponent1”
and one with ID a GUID. And we have one Component2 item as expected. We can also see that
the shell form is added to the Items collection, as well as a State object.

The code for this is available, and if you single-step through it you can see the two Component1
objects being injected into component2.

Where Was All This in the Original Example?

Note that in the original example in this article the root WorkItem was injected into a ModuleInit
class apparently without the ModuleInit class being added to any WorkItem. This seems to
contradict the paragraphs above that say that we can only inject into objects that are put into
WorkItems. However, the CAB framework automatically adds ModuleInit classes into the root
P a g e | 22

WorkItem when it creates a module, so we don‟t need to explicitly add them ourselves for the
dependency injection to work.

Futhermore, the root WorkItem that was injected as a ServiceDependency even though it had not
been explicitly added to any Services collection. Again this seems to contradict the statements
above that any object being injected must be in an appropriate collection. But the code works
because any WorkItem is automatically a member of its own Services collection.

You can see this if you download and run this example. It is an extension of the original example
that allows you to output both the Items collection and the Services collection to the output
window via a menu option. If you do this after the application has loaded you get the output
below:

ITEMS:
[336ad842-e365-47dd-8a52-215b951ff2d1, Microsoft.Practices.CompositeUI.State]
[185a6eb5-3685-4fa7-a6ee-fc350c7e75c4, Shell.Form1, Text: Form1]
[10d63e89-4af8-4b0d-919f-565a8a952aa9, Shell.MyComponent]
[Shell, Shell.Form1, Text: Form1]
[21ac50d7-3f22-4560-a433-610da21c23ab, Blue.BlueModuleInit]
[e66dee6e-48fb-47f0-b48e-b0eebbf4e31b, Red.RedModuleInit]
SERVICES:
[Microsoft.Practices.CompositeUI.WorkItem, Microsoft.Practices.CompositeUI.WorkItem]
…(Complete list truncated to save space)

You can see that both the BlueModuleInit and RedModuleInit objects are in the Items collection
in spite of not being explicitly added by user code, and the WorkItem is in the Services
collection.

ObjectBuilder

To understand and use the Composite Application Block you don‟t need to understand in detail
its underlying code. It‟s intended to be used as a framework after all. However, it‟s useful to
know that the dependency injection here is all done by the ObjectBuilder component.

When we call AddNew or Add on a collection of a WorkItem it‟s the ObjectBuilder that looks at
the dependency attributes on the class we‟re adding and injects the appropriate objects.

The ObjectBuilder is a „builder‟ in the classic design patterns sense. The builder pattern
„separates the construction of a complex object from its representation so that the same
construction process can create different representations‟.

Note that this pattern is often called a „factory pattern‟, although factories in the Gang of Four
„Design Patterns‟ book are slightly different things (we‟re not creating families of objects
(Abstract Factory) or „letting „the subclasses decide which class to instantiate‟ (Factory
Method)).
P a g e | 23

WorkItems in a Hierarchy and Dependency Injection of Items

As discussed previously, one of the strengths of WorkItems is that multiple instances can be
instantiated in different modules, and they can all be arranged in a hierarchy. This is because
each WorkItem has a WorkItems collection. However, you should be aware that dependency
injection only works for items in the current WorkItem. If you attempt to inject an object in a
different WorkItem in the hierarchy into an object in your WorkItem you will get a
DependencyMissingException.

We can see this by modifying the AfterShellCreated event of our FormShellApplication in the
example using Component1 and Component2 above:

WorkItem testWorkItem = null;


protected override void AfterShellCreated()
{
testWorkItem = RootWorkItem.WorkItems.AddNew<WorkItem>();
RootWorkItem.Items.AddNew<Component1>("FirstComponent1");
// The next line throws an exception as the testWorkItem
// container doesn't know about FirstComponent1, and Component2
// is asking for it to be injected.
testWorkItem.Items.AddNew<Component2>();
DisplayRootItemsCollection();
}

Here we add a new WorkItem to our RootWorkItem. We add an instance of Component1 with
ID “FirstComponent1” to our RootWorkItem as before. Then we add an instance of Component2
to our testWorkItem.

Remember that Component2 asks for a Component1 object with ID “FirstComponent1” to be


injected when it is created. Because the testWorkItem knows nothing about such an object we get
an exception thrown.

We can fix the code by adding our Component1 into the testWorkItem instead of the
RootWorkItem:

testWorkItem.Items.AddNew<Component1>("FirstComponent1");

The code for this example is available.

WorkItems in a Hierarchy and Dependency Injection of Services

Services behave differently to the example given above.

We can make Component1 a service by adding it to the Services collection of the RootWorkItem
instead of the Items collection, and telling Component2 it‟s a ServiceDependency and not a
ComponentDependency. Then the code will work. This is because the CAB includes a service
locator that looks in all parent WorkItems of the current WorkItem to see if a given service is
available. I will discuss this in more detail in part 6.
P a g e | 24

6. Constructor Injection in the CAB

Introduction

Part 3 of this series of articles described the different types of dependency injection that we can
use in general. These are setter injection, constructor injection and interface injection.

Part 5 showed how dependency injection works in the CAB. The examples given there
exclusively used setter injection. In general we don‟t use interface injection in CAB projects, but
we can use constructor injection. This short article will show you how.

Constructor Injection Example

As is fairly obvious, constructor injection injects your dependencies in a constructor rather than a
setter. To do this in the CAB we once again use attributes.

We can return to our original example of setter injection and rework it to use constructor
injection. To do this we add a constructor to our Component2 class as below, and we remove the
setters we were using previously (they are commented out below):

public class Component2


{
private Component1 component11;
//[ComponentDependency("FirstComponent1")]
//public Component1 Component11
//{
// set { component11 = value; }
//}

private Component1 component12;


//[CreateNew]
//public Component1 Component12
//{
// set { component12 = value; }
//}

[InjectionConstructor]
public Component2([ComponentDependency("FirstComponent1")]Component1
component, [CreateNew]Component1 component2)
{
component11 = component;
component12 = component2;
}
}

The constructor will inject the same dependencies as the setters did previously if we create
Component2 with the AddNew method of a WorkItem‟s Items collection as below:
P a g e | 25

RootWorkItem.Items.AddNew<Component2>("Component2");

When the CAB creates a component with AddNew it looks for a constructor decorated with the
InjectionConstructor attribute. If it finds one it calls that constructor, and injects dependencies
via the constructor parameters as shown. It applies the usual rules if any of the constructor
parameters are decorated with the CreateNew, ServiceDependency or ComponentDependency
attributes.

The code for this example is available.

Constructor Injection Issues

Note that if there‟s only one constructor in the class you don‟t actually need the
InjectionConstructor attribute. The CAB assumes you mean to use that one constructor as the
injection constructor. Our example above will work without the attribute. If you have more than
one constructor in the class you do need the attribute, and in general it‟s probably good practice
to include the attribute if you are using constructor injection.

Note also that in the original example in part 5 we created the Component2 instance with a
standard „new‟ keyword and then added it to the items collection:

Component2 component2 = new Component2();


RootWorkItem.Items.Add(component2);

If we do this with our new Component2 the injection will not work. In fact the code won‟t even
compile as we no longer have a constructor that doesn‟t take any arguments. Even if we put a
constructor with no arguments into Component2 we‟re clearly not going to get any dependency
injection as we are not creating the component with the CAB and the standard „new‟ keyword
doesn‟t know how to do constructor injection.

Finally it‟s worth noting that if you don‟t put any attribute on an argument of an injection
constructor the CAB treats it as if it had a ServiceDependency attribute. That is, it tries to inject a
service of the appropriate type. If there‟s no such service it creates a new one and adds it to the
Services collection. This is NOT the behaviour you get with the ServiceDependency attribute: if
you apply the ServiceDependency attribute and there‟s no such service you get a
ServiceMissingException when you try to create the new object.

Setter Injection vs Constructor Injection

Whether you use setter injection or constructor injection is really a personal choice. There isn‟t
much to choose between them in terms of functionality. As we‟ve seen if you create your object
with the „new‟ keyword initially and then add it to a CAB collection you can‟t use constructor
injection. Also arguably the syntax for the constructors is a little cumbersome. But normally your
CAB objects will be created and added to CAB collections with the AddNew keyword or
something equivalent. In this case both setter injection and constructor injection inject the
dependencies on creation of the object, and the two types of injection are functionally equivalent.
P a g e | 26

7. Introduction to Services in the CAB

Introduction

Part 6 of this series of articles concluded our discussion of dependency injection in the CAB.

This article and part 8 of the series will discuss services in the CAB in some more detail. This
article discusses services in general terms, whilst part 8 will show in detail the various ways of
creating and using services.

What is a ‘Service’?

You probably already have an intuitive idea of what a „service‟ is in computer programming.
Wikipedia defines a service in the context of a Service-oriented architecture as „a discretely
defined set of contiguous and autonomous business or technical functionality‟. The CAB
documentation defines a service as „a supporting class that provides functionality to other
components in a loosely coupled way‟. CabPedia has a good definition:

„Services allow easy access to a chunk of functionality that may be used frequently throughout
an application. Error handlers, loggers and the event broker are good examples of functionality
that can be exposed as a service.‟

So think of a service as a chunk of related functionality. In the CAB each service is exposed
through one class (and maybe an associated interface) that provides a gateway into the
functionality.

We have already seen how to use CAB services in earlier articles in this series. Part 2 described
how one of the collection classes on a WorkItem is the Services collection. Part 5 showed how
we can inject a service (which is just any item in the Services collection) by using a setter with a
ServiceDependency attribute. We saw that we can inject the WorkItem itself in this way. This is
because a WorkItem is automatically a „service‟ in its own Services collection.

The Services Collection versus the Items Collection

Part 5 of this series of articles also touched on the fact that the Services collection on a WorkItem
has some important differences with the Items collection. This is separate from the fact that the
intent of the two collections is different: services are meant to be objects that expose chunks of
related functionality, whereas items are just any objects that we want to be able to access through
the WorkItem.

The differences between the collections can be confusing so I‟ll start this discussion by
comparing the two collections.
P a g e | 27

Services vs Items (1): Unique Types

The most obvious of these conceptual differences is the fact that the Services collection can only
ever contain one object of a given type. If we attempt to add a second service of the same type to
a Services collection we get an ArgumentException with message „A service of this type already
exists‟.

In contrast, the Items collection of a WorkItem can contain multiple objects of the same type. To
accommodate this all objects added to the Items collection are assigned a unique string ID, either
by the user explicitly, or by the CAB implicitly (a random GUID is assigned).

However, this means that if we want to access a specific object in the Items collection we have to
know its ID. Hence the ComponentDependency attribute, which injects an object from the Items
collection, needs an ID passed as an argument.

We don‟t need an ID to access an object in the Services collection. Because we can identify a
service uniquely by its type the ServiceDependency attribute can be used to inject a service
without the need for any ID.

Services vs Items (2): Searching the Hierarchy

Another difference between the Services collection and the Items collection is what happens if
we request a specific object from the collection and the CAB can‟t find it in the WorkItem‟s
collection. When trying to retrieve a service the CAB will then search in any parent WorkItem‟s
Services collections for the object, and return it if found. With the Items collection the CAB will
just return null if the object cannot be found in the specific Items collection for the WorkItem.

Basic Service Example without Dependency Injection

A simple example of how to create and use a service without using dependency injection is
available. The „service‟ here is just one class (MyService) with one method (GetHello) that
returns the string “Hello World”:

public class MyService


{
public string GetHello()
{
return "Hello World";
}
}

We can make this simple class into a CAB service by adding it to the Services collection of a
WorkItem. In this case we add it to the Services of the RootWorkItem in AfterShellCreated:

protected override void AfterShellCreated()


{
RootWorkItem.Services.AddNew<MyService>();
UseMyService();
P a g e | 28

...

We use the service in routine UseMyService. Here we retrieve the service using the Get method
of the Services collection, telling it the type of the service we want to retrieve. We then call our
method and output the results to the Output window:

private void UseMyService()


{
MyService service = RootWorkItem.Services.Get<MyService>();
System.Diagnostics.Debug.WriteLine(service.GetHello());
}

It‟s as simple as that. The full code also outputs all of the services that have been set up in the
application, and shows that our MyService service is in there. You can see that there are a
surprisingly large number of services set up by default by the CAB even in a simple application
of this kind:

SERVICES:
[Microsoft.Practices.CompositeUI.WorkItem, Microsoft.Practices.CompositeUI.WorkItem]
[Microsoft.Practices.CompositeUI.Services.ICryptographyService,
Microsoft.Practices.CompositeUI.Collections.ServiceCollection+DemandAddPlaceholder]
[Microsoft.Practices.CompositeUI.ITraceSourceCatalogService,
Microsoft.Practices.CompositeUI.TraceSourceCatalogService]
[Microsoft.Practices.CompositeUI.Services.IWorkItemExtensionService,
Microsoft.Practices.CompositeUI.Services.WorkItemExtensionService]
[Microsoft.Practices.CompositeUI.Services.IWorkItemTypeCatalogService,
Microsoft.Practices.CompositeUI.Services.WorkItemTypeCatalogService]
[Microsoft.Practices.CompositeUI.IWorkItemActivationService,
Microsoft.Practices.CompositeUI.SimpleWorkItemActivationService]
[Microsoft.Practices.CompositeUI.Services.IAuthenticationService,
Microsoft.Practices.CompositeUI.Services.WindowsPrincipalAuthenticationService]
[Microsoft.Practices.CompositeUI.Services.IModuleLoaderService,
Microsoft.Practices.CompositeUI.Services.ModuleLoaderService]
[Microsoft.Practices.CompositeUI.Services.IModuleEnumerator,
Microsoft.Practices.CompositeUI.Services.FileCatalogModuleEnumerator]
[Microsoft.Practices.CompositeUI.Commands.ICommandAdapterMapService,
Microsoft.Practices.CompositeUI.Commands.CommandAdapterMapService]
[Microsoft.Practices.CompositeUI.UIElements.IUIElementAdapterFactoryCatalog,
Microsoft.Practices.CompositeUI.UIElements.UIElementAdapterFactoryCatalog]
[Microsoft.Practices.CompositeUI.WinForms.IControlActivationService,
Microsoft.Practices.CompositeUI.WinForms.ControlActivationService]
[Shell.MyService, Shell.MyService]

Splitting the Interface from the Implementation

As we all know, for services it is considered good practice to separate our interface from our
implementation. This allows us to vary the way the service is implemented without having
P a g e | 29

necessarily to change the interface and thus affect client code. This can be important in a
composite smart client application where different teams may be working on different parts of
the application.

This can be very easily done for our basic example. We simply set up an interface with our
method signature in it:

public interface IMyService


{
string GetHello();
}

We then implement this interface on our MyService class:

public class MyService : IMyService


{
public string GetHello()
{
return "Hello World";
}
}

Another change we need to make is how we create the service. We want the type associated with
it in the Services collection to be IMyService, but clearly we need to tell the CAB that it is
creating an object of type MyService (it can‟t just instantiate the interface). The syntax for this is
as below:

RootWorkItem.Services.AddNew<MyService, IMyService>();

The UseMyService method now retrieves the service using the IMyService interface. It doesn‟t
need to know about the MyService class:

private void UseMyService()


{
IMyService service = RootWorkItem.Services.Get<IMyService>();
System.Diagnostics.Debug.WriteLine(service.GetHello());
}

These are the only changes that need to be made. The code for this example is available.
P a g e | 30

8. Creating and Using services in the CAB

Introduction

Part 7 of this series of articles gave us a general introduction to services in the CAB. This article
will go into more detail on the various ways we can create and use such services.

Ways of Creating a Service

We start with the various ways services can be created. This can be done with the various „Add‟
methods, with XML configuration files or by using the „Service‟ attribute.

Ways of Creating a Service (1) – Add Methods

In the basic example in part 7 we used the AddNew method to create a service:

RootWorkItem.Services.AddNew<MyService>();

We have seen this before: it both instantiates the object and adds it to the collection. As before,
we can also add objects that already exist to the Services collection with the Add method.

The Services collection also has an „AddOnDemand‟ method. If we use this in place of AddNew
in the example in part 7 the service does not immediately get created (the MyService class is not
instantiated). Instead a placeholder is added to the Services collection until such time as some
client code retrieves the service (using the same syntax as before). When this happens the service
object will get instantiated so that it can be used. This example shows this:

// Use AddOnDemand to set up the service: the MyService


constructor
// is not called
RootWorkItem.Services.AddOnDemand<MyService>();
// When we dislay the Services collection we can see there's a
placeholder
// for MyService in there
DisplayWorkItemCollections(RootWorkItem);
// Only when we use .Get to retrieve the service is MyService
actually
// instantiated (note we have code in MyService to show when the
constructor
// is called by writing to the Output window)
UseMyService();
// Now our Services collection has a fully fledged MyService
service available
DisplayWorkItemCollections(RootWorkItem);

There are also Contains and Remove methods on the Services collection. Remember we can only
have one service of a given type: if a service already exists and we want to replace it these
methods can be useful.
P a g e | 31

Ways of Creating a Service (2) – XML Configuration File

It is also possible to create services using the app.config file. To do this in our simple example
we just take out the line:

RootWorkItem.Services.AddNew<MyService>();

Then in an App.Config file we add a „services‟ section with an „add‟ element to a CompositeUI
config section as below:

<?xml version="1.0" encoding="utf-8" ?>


<configuration>
<configSections>
<section name="CompositeUI"
type="Microsoft.Practices.CompositeUI.Configuration.SettingsSection,
Microsoft.Practices.CompositeUI" allowExeDefinition="MachineToLocalUser" />
</configSections>
<CompositeUI>
<services>
<add serviceType ="Shell.MyService, Shell" instanceType
="Shell.MyService, Shell" />
</services>
</CompositeUI>
</configuration>

The code for this is available.

In general I‟m not a fan of writing code in XML if there are proper C# alternatives. Here the
XML is certainly less transparent than the one-line C# equivalent, and as usual debugging
becomes more difficult with XML. However, one potential advantage of using the configuration
file is that we could in theory change our service at runtime without having to recompile the
code.

Ways of Creating a Service (3) – the Service Attribute

As mentioned previously, we can create a service simply by decorating our concrete class with
the „Service‟ attribute. We can register the service with a separate interface (as in the section
„Splitting the Interface from the Implementation‟ in part 7) by providing a positional type
parameter. We can also make our service one that gets added on demand to the Services
collection by adding a named boolean parameter called „AddOnDemand‟. These attributes are
illustrated below:

[Service(typeof(IMyService), AddOnDemand=true)]
public class MyService : IMyService
{
public string GetHello()
{
return "Hello World";
}
P a g e | 32

If we declare our service class in this way we have no need to explicitly add it to the Services
collection before using it. There‟s also no need to explicitly instantiate the class. Just adding the
attribute ensures that when the code runs the service will get set up. The code showing this
working is available.

Why the Service Attribute is Unusual

The „Service‟ attribute is in some ways quite different from other attributes we‟ve seen used with
the CAB. Most CAB attributes only work for objects that are already in a collection associated
with a WorkItem. For examples see the discussion about ComponentDependency,
ServiceDependency and CreateNew in part 5 of this series of articles. In particular CreateNew
will only work on a setter if that setter is in an object that is already in a WorkItem collection.
We can‟t just put CreateNew in any old class and expect it to work.

In contrast the Service attribute will work with „any old class‟, provided it‟s in a module (see part
1 for a discussion of modules). The Service attribute really couldn‟t work any other way. The
attribute when applied to a class is telling the CAB to add an object of that type to the Services
collection of the WorkItem. It wouldn‟t make much sense if it only worked if the object was
already in a collection of the WorkItem.

Where the CAB is Looking for the Service Attribute

So how does the CAB find these Service objects and use them? The answer is that when a
module loads the CAB uses reflection to find all public classes in the assembly which have the
„Service‟ attribute applied. All of these classes get instantiated and added in to the Services
collection of the root WorkItem of the CAB application.

Note that the CAB only scans assemblies that are explicitly listed as modules (in
ProfileCatalog.xml usually). An assembly won‟t get scanned if it‟s just referenced from a
module project.

Drawbacks of the Service Attribute

One problem with this is that we don‟t have a lot of control over where the service gets created.
Our new service always gets added to the root WorkItem, meaning we can‟t create services at a
lower level in the WorkItem hierarchy. Another problem is that we have no control over when
our service is created: in particular we have no way of ensuring that our services are created in a
specific order.

My personal opinion is that setting up services using the Service attribute can be a little
confusing. The services appear magically as if from nowhere. If we explicitly create the service
and add it to the appropriate WorkItem we have more control and what we are doing is more
transparent.
P a g e | 33

Ways of Retrieving a Service

There are two main ways of retrieving a service. We have already seen examples of these, but a
recap is given below.

Ways of Retrieving a Service (1) – Get Method

In the basic example in part 7 we used the Get method of the Services collection to retrieve
MyService. For example, the code below is taken from the final example („Splitting the Interface
from the Implementation‟):

private void UseMyService()


{
IMyService service = RootWorkItem.Services.Get<IMyService>();
System.Diagnostics.Debug.WriteLine(service.GetHello());
}

Ways of Retrieving a Service (2) – Dependency Injection

We can also retrieve a service via dependency injection by using the ServiceDependency
attribute. We saw some examples of this in part 5.

To set up a service in a class we can decorate a setter of the appropriate type in a class with the
ServiceDependency attribute. The class can then use the service:

public class ServiceClient


{
private IMyService service;

[ServiceDependency]
public IMyService Service
{
set
{
service = value;
}
}

internal string UseMyService()


{
return service.GetHello();
}
}

As discussed previously, the CAB looks for the ServiceDependency attribute when an object of
type ServiceClient is added to one of the WorkItem collections. When that happens the CAB
looks for a service of type IMyService in the Services collection of the WorkItem. When it finds
one it retrieves it and sets it on the ServiceClient object by calling the setter.
P a g e | 34

So to set up this class we need to ensure that an IMyService service has been created, and then
we can just create a ServiceClient object in our WorkItem:

// Create the service


RootWorkItem.Services.AddNew<MyService, IMyService>();

// Add a ServiceClient object to our Items collection:


// this causes the CAB to inject our service into the
ServiceClient
// because it has a setter decorated with ServiceDependency
ServiceClient serviceClient =
RootWorkItem.Items.AddNew<ServiceClient>();

Now we can call the service on the ServiceClient object:

System.Diagnostics.Debug.WriteLine(serviceClient.UseMyService());

The code for this example is available.

We can also use the ServiceDependency attribute with constructor injection as discussed in part
6. This is a simple change to the ServiceClient class in the example above:

public class ServiceClient


{
private IMyService service;

public ServiceClient([ServiceDependency]IMyService service)


{
this.service = service;
}

internal string UseMyService()


{
return service.GetHello();
}
}

The code for this example is also available.

Finding Services Higher Up the Hierarchy

As already discussed, if the CAB can‟t find a service in the Services collection of the current
WorkItem it will look in the Services collections of parent WorkItems. We can illustrate this by
adding a new WorkItem called „testWorkItem‟ to our basic example from part 7. We still add our
service to the RootWorkItem:
P a g e | 35

WorkItem testWorkItem = null;


protected override void AfterShellCreated()
{
testWorkItem = RootWorkItem.WorkItems.AddNew<WorkItem>();

RootWorkItem.Services.AddNew<MyService, IMyService>();
UseMyService();
DisplayWorkItemCollections(RootWorkItem);
}

private void UseMyService()


{
IMyService service = testWorkItem.Services.Get<IMyService>();
System.Diagnostics.Debug.WriteLine(service.GetHello());
}

When we come to use the service in UseMyService (immediately above) we try to retrieve it
from the testWorkItem. The code still works even though the service isn‟t in testWorkItem‟s
Services collection: the CAB retrieves it from the parent RootWorkItem. Once again the code for
this example is available.

Services Not Found

If the CAB attempts to retrieve a service and can‟t find it at all it usually does not throw an
exception. It simply returns null. Consider the changes to our basic example from part 7 below:

protected override void AfterShellCreated()


{
//RootWorkItem.Services.AddNew<MyService, IMyService>();
UseMyService();
DisplayWorkItemCollections(RootWorkItem);
}

private void UseMyService()


{
// There's no IMyService available, so the CAB sets service =
null below
IMyService service = RootWorkItem.Services.Get<IMyService>();
// We get a NullReferenceException when we try to use the service
System.Diagnostics.Debug.WriteLine(service.GetHello());
}

Here we have commented out the line that creates the service so it never gets created. As a result
the call to „Get‟ the service returns null, and we get a NullReferenceException when we try to
call GetHello.

This may not be the behaviour we want. It may be better to throw an exception as soon as we
know the service does not exist before we attempt to use it. Fortunately the Get method is
overloaded to allow us to do this. It can take a boolean argument, EnsureExists, which if set to
true throws a ServiceMissingException immediately the service cannot be retrieved:
P a g e | 36

IMyService service = RootWorkItem.Services.Get<IMyService>(true);

The code for this example is available.


P a g e | 37

9. The Command Design Pattern

Introduction

Part 8 of this series of articles concluded our discussion of services in the CAB.

This article and part 10 of this series will talk about commands in the CAB. Commands are a
neat way of implementing the Command design pattern. This article will briefly recap what the
Command pattern is and why it is useful. Part 10 will show how this is implemented in the CAB.

The Basics of the Command Pattern

„Command‟ is a design pattern from the original „Design Patterns‟ book by Gamma, Helm,
Johnson and Vlissides (the „Gang of Four‟). The intent of the pattern is to:

“Encapsulate a request as an object, thereby letting you parameterize clients with different
requests.”

The class diagram for this is below:

The Command Class and Interface

The diagram looks more difficult than it is. What it is saying is that we define a simple interface,
ICommand, which always has just one method, Execute (with no parameters and no return
value). We then implement this interface on various Command classes. So a Command is just a
class that does something useful in response to an „Execute‟ call. However, because all our
commands implement Execute using the same interface we have polymorphism: we can use
them interchangeably in client code without having to change the client code.

The Invoker

In the class diagram above the Invoker is just any code that calls the Execute method on a
Command object through its ICommand interface. This will usually be done in a way that allows
us to use the polymorphism discussed above. That is, we should be able to swap around which
underlying Command object the Invoker is calling, without the Invoker having to change.
P a g e | 38

The Receiver

In the simplest case the Execute method itself can just „be‟ the command: it will do something
useful. That may lead to our Command objects being very complicated however, so we may split
out the underlying functionality into another class. This is the Receiver in the class diagram
above. With a Receiver, whenever the Execute method is called on our Command it simply
relays the call to the Receiver class which then does the work. If the command is complex there
may be more than one Receiver class, with the Command class calling the Receivers as
appropriate.

The Client

In the diagram above we also have the usual Gang of Four „Client‟ class. This is code that gets us
started by creating the other classes and hooking them up appropriately so that they will work. In
real applications this may well be more than one class, but it makes the diagram neater to bucket
all this functionality into one neat little box.

In the Command pattern the client code will instantiate our Commands and Receivers and give
the Command objects appropriate references to the Receiver objects.

Finally note that in this pattern we are not passing any parameters to our Command objects, or
returning any values from them. The method signature we are using is void Execute().

Why Is This Useful?

This pattern is useful because it decouples the code for actually executing a command from the
code that calls the command code, providing a logical separation of duties and making the code
easier to maintain.

Furthermore the pattern encapsulates the command logic in classes (the Receivers, if any, and the
Command) that have a clearly defined interface. This lets us flexibly change which command we
use in different circumstances using polymorphism.

For example we may have a class or set of classes that perform actions (our invokers), but want
to vary those actions in a simple way based on the current state of the system. We can
encapsulate the varying actions themselves into Command classes and then tell the invoker
which one to use depending on the system state.

Menu Systems

The canonical example here, as discussed in the Design Patterns book, is a menu system in an
application. The book describes how menu „toolkits‟ are usually written as part of a framework,
meaning that we need some way to allow a developer to write code to respond to menu events
without having access to the menu code itself. We can do this by allowing the developer to write
the commands and assign them to the Invokers (the menu items), without having to change the
P a g e | 39

Invokers. Also, with menus we DO have the situation where we might want to swap around the
commands that an Invoker is invoking.

For example, we might have a File/New menu item. This might create a different sort of „new‟
item depending on what screen the application was displaying. If the application was displaying
a report it might create a new report; if the application was displaying a list of users it might
create a new user; and so on. We could set this up so that the menu item was given a Command
object and simply invoked it when File/New was selected. We could then have
CreateNewReportCommand and CreateNewUserCommand objects that the client code would
give to the menu item as the screens in the application changed. The menu itself wouldn‟t then
need any business logic, nor would the code behind the screen it was hosted on.

.NET Delegates, .NET Events and the Command Pattern

It‟s also worth bearing in mind that in many ways a simple use of a .NET delegate is a Command
pattern, albeit a cumbersome one. The delegate itself is the command. It points to one or more
methods in classes which are our Receivers. There will be some code to create the delegate and
point it at the methods, which is the Client. Finally there will be some code to invoke the
delegate (via the Invoke method), which is our Invoker.

Similarly .NET events, which are just special sorts of delegates, can be viewed as an
implementation of the Command pattern.

This is fine, and of course very useful. But as we will see in part 10 the CAB gives us a more
explicit way of using the pattern which is both simple and powerful.

.NET Menu Systems and the Command Pattern

Menu systems are a key use for the Command pattern as far as the Gang of Four are concerned.
Normally in the .NET framework we use events for hooking up menu and toolbar items to
underlying code. As discussed above, this can be regarded as an implementation of the
Command pattern. However, the CAB implementation of the Command pattern is specifically
intended to be used for menu systems and to replace the normal approach. We will examine the
benefits it gives in part 10.
P a g e | 40

10. Commands in the CAB

Introduction

Part 9 of this series of articles discussed the Command design pattern. Commands in the CAB
are a neat way of implementing this pattern. This article will examine them in some detail.

Commands and Events

As already discussed in part 9, commands in the CAB are closely related to events. In fact one of
the ways that commands are intended to be used in the CAB is to hook up menus and toolbars in
your application to the underlying code. This, of course, is something that is normally done in
.NET using events. To make matters somewhat confusing, the CAB also has its own way of
handling events. Part 11 of this series of articles will discuss CAB events, and how they relate to
commands. In a later article I will discuss the Action Catalog (which is part of the SCSF code)
and how that relates to both commands and events.

Basic Example

The easiest way to understand what we can do with CAB commands is to look at a simple
example. The code for this is available.

This is a normal CAB application as described earlier in this series of articles. The main Shell
Form has a standard ToolStrip with a button labelled „Call Command‟ on it. When we click this
button the application will display a message box saying „Hello World using CAB commands‟.

Normally to do this in .NET we‟d set up a standard event handler in the code behind the Shell
Form, probably by just double-clicking the button in the designer, and then put our message box
code in the handler. An example of this is also in the simple example code. We have a second
button labelled „Call Event‟. When it‟s clicked it uses .NET events to display a message box
saying „Hello World using .NET events‟.

To use CAB commands we assign a named command to the button‟s click event. We do this by
referring to a named command in a WorkItem‟s Commands collection:

Command helloCommand = RootWorkItem.Commands["HelloCommand"];

When the CAB sees this code it lazy-initializes the Command. That is, if a Command called
„HelloCommand‟ already exists in the collection it returns it, if it doesn‟t exist it creates it and
returns it.

(In the sample application the Command object actually gets created before this code, because
the CAB scans for the CommandHandler attribute and creates commands based on that.)

Next we obtain a reference to our button (a ToolStripItem), and assign an „Invoker‟ to the
Command object:
P a g e | 41

ToolStripItem toolStripItem =
this.Shell.mainToolStrip.Items["toolStripButton1"];
helloCommand.AddInvoker(toolStripItem, "Click");

In our Command design pattern discussion above we saw that an invoker is any piece of code
that calls the Execute method on a Command object. Here we are saying that the toolStripItem‟s
Click event is an invoker for the helloCommand object. That is, when the event fires the Execute
method on the Command will get called.

In simple terms we are just hooking up the Click event to our Command object.

Now we want to set up a receiver for the Command. Remember that a Receiver, if we have one,
is code that actually does the work for the command. In the CAB we always have a Receiver: we
never put the underlying functionality into the Command object. Note that this means the
Command class itself is just plumbing code, and as developers we don‟t need to change it.

We do this by simply applying the CommandHandler attribute to a method with an appropriate


signature as below:

[CommandHandler("HelloCommand")]
public void HelloHandler(object sender, EventArgs e)
{
MessageBox.Show("Hello world using CAB commands");
}

For this to work the object the code is in must be in a WorkItem collection of some kind. Of
course, this is true of most of the CAB functionality as we‟ve seen before. Here we really are
using WorkItems as Inversion of Control containers. We set up the code as above and the
framework calls us back as appropriate.

In the example code the command handler is in the code behind the Shell Form, which as we‟ve
seen before is in the WorkItem‟s Items collection.

That‟s all there is to it. Now when we click our toolstrip button the handler gets called and „Hello
world‟ gets displayed.

Points to Note

1. The command handler‟s method signature has to be as shown. It has to be public, and it
has to have object and EventArgs parameters. I‟ll discuss the parameters further below.
2. There‟s no ICommand interface in the CAB‟s implementation. The interface to a
Command object is just the default public interface on the Command class.
3. As we‟d expect, the Command object also has a RemoveInvoker method that lets us
detach a command from its invoker.
P a g e | 42

Why Are We Doing This?

An obvious question at this point is „why we would want to do this?‟ After all, we already have a
perfectly good way of handling menu and toolstrip click events in .NET. Using a Gang of Four
design pattern is nice, but is it giving us any real advantages?

We discussed one advantage of the Command pattern approach above. We can easily swap one
command for another. This is particularly useful, for example, if we set up a standard toolbar that
is going to be used with slightly different functionality for multiple screens in an application.

Another advantage is that our command handlers don‟t have to be in the same class as the
toolbar or menu they are supporting. This can make the code a lot cleaner. For example, suppose
you have a Help/About menu item that shows a dialog, and you want the same functionality on
all your menus. With .NET events you‟d have to mess around setting up all the handlers to work
correctly, probably with some singleton class to actually accept the calls. With the CAB
command approach you can just set up a class with command handlers in it, add it to a WorkItem
collection (Items) and then just call AddInvoker for every menu you want hooked up.

In fact the Command pattern lets us write incredibly simple and powerful menu systems for
enterprise applications. We can do this in a way that is difficult to do with the standard event
approach. I will write specifically about this at a later date, as there seems to be a lot of
confusion about how you‟re meant to set up menus using the CAB/SCSF.

Command Status

One other useful thing that you can do with CAB commands is to enable, disable or hide the
ToolStrip buttons or menu items associated with a command simply by setting the status
property on the associated command (the one that will be invoked when you click the button).

An example of this is available. This has two buttons on a ToolStrip on its Shell Form. If you
click the „Enable/Disable CAB Command‟ button the command handler below will run:

[CommandHandler("EnableDisableHelloCommand")]
public void EnableDisableHelloCommandHandler(object sender, EventArgs
e)
{
Command helloCommand = _workItem.Commands["HelloCommand"];
if (helloCommand.Status == CommandStatus.Enabled)
helloCommand.Status = CommandStatus.Disabled;
// Change this to the line below if you want to hide the
cabCommandToolStripButton
//helloCommand.Status = CommandStatus.Unavailable;
else
helloCommand.Status = CommandStatus.Enabled;
}

As you can see this gets a reference to the helloCommand command in the Commands
collection. This is the command associated with another button on the ToolStrip. The handler
P a g e | 43

just flips the Status associated with the command from CommandStatus.Enabled to
CommandStatus.Disabled or vice-versa. If you run this code you will see that this disables or re-
enables the associated button.

Command Handler Parameters

Note that our command handler has the usual .NET event parameters. These are sender (an
object) and e (EventArgs). However, if you put a breakpoint in the command handler you‟ll see
that sender is the Command object, and e is set to EventArgs.Empty. It isn‟t possible to pass
other values to these parameters if you are using commands.

In the discussion on the Command design pattern above we saw that we don‟t pass any
parameters to our Execute method. This is true of the Execute method in the CAB framework as
well. However, behind the scenes the CAB uses normal .NET events to implement the Command
pattern, and this allows it to pass more normal parameters to the command handler.

Note also that this is not significantly different from the .NET events we would normally use
with a ToolStripItem. If we set up a normal event handler this has the same parameters, but again
the EventArgs parameter is always set to EventArgs.Empty, and the object parameter is set to the
ToolStripItem. Again, there‟s no easy way of passing other values to these parameters.

When you are using .NET events in this way it can be useful to have access to the ToolStripItem
that raised the event, which you can do via the object parameter. This is more difficult with
commands. We can access a list of invokers for the command, and get the associated
ToolStripItems from the list (although even this is difficult). However, we don‟t necessarily
know which of the invokers called the command handler.

Where’s the Execute Method?

In the examples here we haven‟t seen any reference to an Execute method, in spite of this
seeming to be a key part of the Command design pattern as described above.

Rest assured that behind the scenes in the CAB code the Command object DOES have an
Execute method that gets called by the invoker. However, all we needed to do in our example
was to set up the invoker with some simple syntax to get it to call the Execute method. We didn‟t
need to call it ourselves.

We can call the Execute method on our Command object directly from code, as this example
shows. This lets us use commands in other ways than the standard invoker example seen above.

Which Events can we use as Invokers?

We‟ve seen in our example that a ToolStrip button „Click‟ event can be an invoker for a
command. As mentioned above, the key use of commands is intended to be for menu systems,
where they are very powerful.
P a g e | 44

However, we can only use the syntax in the examples above for standard .NET events on
ToolStripItems and anything that derives from the Control class. If we want to hook anything
else up as an invoker we need to do a little more work. Behind the scenes the CAB is using
something called a CommandAdapter to hook up these events as invokers to our commands. The
only CommandAdapters that are registered by default are those for ToolStripItem and Control.

We can use standard .NET events on one of our own classes as an invoker. However, to do this
we need to create a CommandAdapter and tell the CommandAdapterMapService that it relates to
our own class. Fortunately there is a generic EventCommandAdapter<> class that we can use
(with our class type as the generic), rather than having to write our own CommandAdapter class.

A full code example of how to do this is available.

We would have to write our own CommandAdapter class if we wanted to use something other
than a .NET event as an invoker (and still wanted to use the CommandHandler etc pattern). To
do this we inherit the abstract base class CommandAdapter and override its abstact methods
(which, predictably, include AddInvoker and RemoveInvoker).

Conclusion

CAB commands provide a powerful way of setting up flexible menus. However, using the
Command pattern in a more general way can be a little confusing. Writing your own
CommandAdapter class, or indeed using your own events as invokers as illustrated above, isn‟t
necessarily straightforward. Also, as we shall see in the part 11, in fact CAB events are probably
better suited for this sort of thing. It may be better to think of CAB commands as primarily
something you use to get powerful menu systems, and to move on.
P a g e | 45

11. Introduction to events in the CAB

Introduction

Part 10 of this series of articles described how the CAB implements commands. The CAB also
provides a new way of raising and sinking events. This article will describe how this works.

Overview of events in .NET

Events in .NET are a publish-subscribe mechanism. We declare an event in a publisher class,


instantiate the class, and then other objects can subscribe to the event. When they subscribe these
objects identify a method that will be called when the event is fired.

We can then „publish‟ by firing the event from the original publisher object. The methods on the
subscriber objects are called.

This is an implementation of the Observer design pattern, and gives the benefits and liabilities of
that pattern as outlined in the book „Design Patterns‟ by Gamma, Helm, Johnson and Vlissides.
In particular it allows for loose coupling between classes. Events are a callback mechanism,
allowing code to be called without the caller necessarily having any direct reference to the object
being called.

This mechanism is used throughout the .NET framework, particularly for such things as handling
events raised by user interface components (e.g. button clicks).

This article assumes you know and understand all this.

Why do we need a new way of handling events?

Events in .NET are based on delegates and are extremely powerful. In many ways they are a key
advantage of the language. For instance Java, which doesn‟t have delegates, has some pretty
nasty syntax for dealing with GUI events, and has no standard way of setting up the Observer
pattern in more general cases.

So if events in .NET are so good, why have we got a new way of dealing with them in the CAB?
What‟s wrong with the usual events in .NET?

Problems with Events in .NET (1): Syntax

One problem with the current .NET eventing mechanism is that the syntax isn‟t all that
transparent. This is particularly true in C# (Visual Basic has neater syntax). You have to declare
a delegate, declare an event based on that delegate in your publisher class, hook subscriber
methods up to the event by creating an instance of the delegate and using the „+=‟ syntax, and
then fire the event with the Invoke method. The event can only be fired directly from your
publisher class, so often we‟ll additionally expose a method on the publisher class to allow other
objects to fire the event (this is customarily called something like „OnMyEvent‟).
P a g e | 46

Actually things have got a little simpler than that in .NET 2.0: now there are some syntactic
shortcuts (we don‟t need to create an instance of the delegate directly to add our event handler to
the event, for instance). But to be able to use events effectively you really need to understand the
previous paragraph, which clearly isn‟t straightforward.

Problems with Events in .NET (2): Hooking Up Publishers and Subscribers

Another problem with events in .NET is that it isn‟t always easy to structure your code well. The
aim is to have a publisher object and a subscriber object linked by an event, but without
necessarily having a direct reference to each other.

To set up the event code somewhere has to be able to add the method in the subscriber object to
the event in the publisher object (with the „+=‟ syntax). This code clearly has to have a reference
to both objects. This can be tricky to do in a clean way in a highly object-oriented system.

For example, I‟ve seen systems where we construct a switchboard object. This is a global
singleton that caches references to all of our publisher objects. The switchboard object exposes
methods that allow our subscribers to subscribe to our publishers‟ events, and other methods to
allow the events to be raised. It can also ensure that the publisher objects can be cleanly disposed
of. This works, but can get messy as the temptation is to put all publishers into the switchboard,
even if they are completely unrelated.

An alternative is to create all our publishers and subscribers at start up, and to hook up the events
in the start up code. This is a more standard approach, and is also in many ways the approach
used by the .NET framework when it auto-generates code to hook up user interface events.
However, it isn‟t always practical to do it in this way.

Events in the CAB

The CAB gives us the ability to handle events in a much cleaner way. Our WorkItem containers
give us a way of handling scope issues for objects, and this enables us to hook up events with a
more straightforward syntax than the usual .NET syntax.

Basic Example

Yet again the easiest way to understand what we can do with CAB events is to look at a simple
example.

Events can be confusing, but if you think about the basics they are actually quite simple. We
want to identify some code in one or more objects (our subscribers) that will get called when
another object (the publisher) says so. The difficulty is that we don‟t want the publisher to have
to call the subscribers directly itself: this is a callback mechanism, and we want loose coupling
between our objects. We just want the publisher to be able to say „fire my event‟.
P a g e | 47

To do this in the CAB we first give our event a string name. We then identify all the code that
will get executed when the event fires by applying an attribute with this name as a parameter, as
below:

[EventSubscription("MyEvent")]
public void MyEventHandler(object sender, EventArgs e)
{
MessageBox.Show("Hello from the CAB event handler");
}

Note that the method has to be public, and to have a method signature as shown. Of course this is
the usual method signature for events in .NET, although usually event handlers don‟t have to be
public.

This is all the set up we need to do. We can now fire the event whenever we want, again using
the string name to identify it:

workItem.EventTopics["MyEvent"].Fire(this, EventArgs.Empty, null,


PublicationScope.Global);

That‟s all there is to it. When this code is executed the event will fire and all methods decorated
with the EventSubscription(“MyEvent”) attribute will get executed. We don‟t have to create
delegates and events specifically, or hook anything up with the „+=‟ syntax. It‟s also much
clearer what‟s happening.

Note that the containing classes for both the pieces of code above must be in the Items collection
of a CAB WorkItem for this to work (although not necessarily the same WorkItem, as we shall
see in part 11). Also, as shown, you need to have access to the WorkItem itself to fire the event,
which you can obtain by dependency injection. If you‟ve been reading this series of articles you
should be used to that by now.

Sample Code

Code demonstrating this is available. This has an event example with separate Publisher and
Subscriber classes. However the CAB events really don‟t need a specific Publisher class: you
can just fire the event with the syntax shown when you need it. A second example in the same
code demonstrates this. The sample code also shows that you can easily have multiple publishers
of and multiple subscribers to the same event by just duplicating the syntax above.
P a g e | 48

12. Events in the CAB

Introduction

Part 11 of this series of articles gave a general introduction to events in the CAB. This article
investigates what we can do with these events in a little more detail.

Parameters of the Fire Method

As shown in part 11, the Fire method has four parameters:

workItem.EventTopics["MyEvent"].Fire(this, EventArgs.Empty, null,


PublicationScope.Global);

The first two are easily understood: they are the parameters that will be passed into the
EventSubscription method. The first is an object, and is intended to contain the sender of the
event. The second is an EventArgs parameter, and can be used to pass data into the
EventSubscription method as with normal EventArgs classes.

The third and fourth parameters control the scope that the CAB will use for searching for
appropriate EventSubscription methods to be called. The third parameter is a WorkItem, and the
fourth an item from the CAB PublicationScope enum. It is expected that you will pass in the
WorkItem that contains the code firing the event, although you don‟t have to. For these purposes
the EventSubscription is treated as being contained in the WorkItem that its parent subscriber
object is in (remember it has to be in the Items collection of a WorkItem for the eventing to
work).

The PublicationScope enum has the following possible values:

Global: the WorkItem parameter is ignored and ANY EventSubscription method with the
correct name in the entire WorkItem hierarchy will be called.
WorkItem: ONLY EventSubscription methods with the correct name in the WorkItem
passed in as the third parameter will be called. If no WorkItem is passed in no
EventSubscription method will be called.
Descendants: EventSubscription methods with the correct name in the WorkItem passed
in and any child WorkItems of that WorkItem will be called.

Code Example

A code example that shows these possibilities is available. This defines a hierarchy of
WorkItems. Each WorkItem has its own Subscriber class to an event (“MyEvent”). The
EventSubscriptions in each Subscriber class display an appropriate message when the event is
fired. We then have three buttons that fire the event. The calls to the Fire method pass in as
parameters a WorkItem in the middle of the hierarchy, with different PublicationScopes
depending on which button is clicked.
P a g e | 49

Thus clicking the buttons shows how the PublicationScope affects which EventSubscriptions get
called.

The EventTopics Collection

There are actually two WorkItems in the call to the Fire method:

workItem.EventTopics["MyEvent"].Fire(this, EventArgs.Empty, childWorkItem1,


PublicationScope.WorkItem);

„childWorkItem1‟ is used to control the scope of the Fire method as discussed above.

„workItem‟ is used to access the EventTopics collection and hence our specific „MyEvent‟
EventTopic.

Note that ANY WorkItem in the hierarchy can be used here to access the EventTopics collection,
and the same EventTopic will be returned. In fact, behind the scenes there is only one
EventTopics collection, and this is stored on the RootWorkItem. Any other WorkItem using the
syntax workItem.EventTopics gets the same collection returned.

Thus the first WorkItem in the call does not affect the scope of the EventSubscriptions called at
all.

Invoking onto the user interface thread

If you are familiar with .NET events you will know that one problem with them is that they can
be fired on threads other than the user interface thread but may need to access user interface
components. Threads that are not on the user interface thread should not interact with
Microsoft‟s GUI components as these are not thread-safe. As a result with .NET eventing it is
quite common to „invoke‟ back onto the user interface thread in an event handler as the first
thing you do:

private void RunIt()


{
if (((ISynchronizeInvoke)this).InvokeRequired)
this.Invoke(new MethodInvoker(RunIt));
else
this.label1.Text = "Hello";
}

Don‟t worry if you don‟t recognize and understand this syntax: just accept that we may need to
get code running back on the user interface thread in certain circumstances, and that this is the
way we do it.

Clearly CAB events can suffer from the same problem. Once again we have a very neat solution
to this, however. We simply add a parameter to our EventSubscription attribute as below:
P a g e | 50

[EventSubscription("MyEvent", ThreadOption.UserInterface)]
public void MyEventHandler(object sender, EventArgs e)
{
MessageBox.Show("Hello from the CAB event handler");
}

This has the effect of invoking the code onto the user interface thread when the event is fired and
the code is called. It‟s somewhat easier than the .NET code in the previous example.

The ThreadOption Enumeration

There are two other values in the ThreadOption enumeration that we can use here (other than
ThreadOption.UserInterface as above):

ThreadOption.Publisher: forces the code to run on the same thread as the one the
EventTopic was fired on. This is the default if we don‟t specify a ThreadOption on our
EventSubscription.
ThreadOption.Background: forces the code to run asynchronously on a background
thread. This means the code in the EventSubscription does not block the thread in the
class the calls „Fire‟. With normal .NET events we would normally have to explicitly
start a second thread to get this behaviour, so again the syntax is much simpler.

AddSubscription/RemoveSubscription

The syntax shown above for setting up a subscription to an EventTopic using the
EventSubscription attribute is very clean. However, there will be times when we want to
dynamically add or remove subscriptions in code rather than using attributes. This is analogous
to the use of the „+=‟ and „-=‟ syntax for hooking up our usual .NET events to event handlers.

To support this EventTopic has AddSubscription and RemoveSubscription methods. Obviously


we use AddSubscription to add an EventSubscription to an EventTopic, as below:

RootWorkItem.EventTopics["MyEvent"].AddSubscription(subscriber,
"MyEventHandler", workItem1, ThreadOption.UserInterface);

This should be fairly self-explanatory: we are setting up an EventSubscription for the method
MyEventHandler in our subscription object. We are setting up this subscription in workItem1,
and when the event handler is called it will run on the user interface thread.

Similarly we use RemoveSubscription to remove an EventSubscription from an EventTopic:

eventTopic.RemoveSubscription(subscriber, "MyEventHandler");

Here we simply need to identify the object and the event handler name that we are trying to
remove.
P a g e | 51

We are only permitted to have one subscription to a given event handler on a given object. This
is why RemoveSubscription only needs the two parameters to uniquely identify the subscription
to be removed. If we try to add a subscription that already exists then the CAB won‟t throw an
exception, nor will it add a second subscription. Similarly we can try to remove a subscription
that doesn‟t exist and the CAB won‟t throw an exception (but won‟t actually do anything of
course).

An example that demonstrates AddSubscription and RemoveSubscription is available.

Note that in the CAB if we want to prevent our EventSubscriptions from running when an event
is fired we don‟t have to remove them entirely. The EventTopic has an Enabled property that can
be used. There are more details on this later in this article.

AddPublication/RemovePublication

The AddPublication method of an EventTopic is used to add .NET events as „Publications‟ into a
CAB EventTopic. What this means is that we can fire a .NET event and have CAB
EventSubscriptions run without the need to set up .NET event handlers directly ourselves, or to
explicitly call the Fire method of the EventTopic. Similarly we have a RemovePublication event
to disable this behaviour.

AddPublication: what is a ‘Publication’?

The „Publication‟ nomenclature is a little confusing. As we have seen the CAB eventing
mechanism uses „Subscriptions‟ to an EventTopic, which are methods that run when the
associated EventTopic is fired.

However, in general the CAB eventing mechanism doesn‟t use „Publications‟. The Subscriptions
will run without an explicit „Publication‟ being set up at all: we can just Fire the EventTopic
when we need to.

The method containing the Fire event code can be thought of as a „Publication‟. However, if we
look at the PublicationCount of an EventTopic after it has been fired directly with the „Fire‟
method we see that it is zero: normally we don‟t need a Publication for a CAB event to work.

A code example that shows this is available. It also shows how to use the ContainsSubscription
method of an EventTopic (which is straightforward).

With the AddPublication method we ARE explicitly creating a Publication, and in the example
below the PublicationCount will be one when an EventTopic is fired. But this is only for the
special case where we want to hook .NET events up to CAB event subscriptions.

AddPublication: code example

A code example of how to use AddPublication is available. In this example we have a button on
the Shell form that fires our CAB event, but there is NO .NET event handler set up for the click
P a g e | 52

event of that button. Instead at when the application starts up we hook up the EventTopic to the
button directly:

RootWorkItem.EventTopics["MyEvent"].AddPublication(Shell.cabEventFirerButton,
"Click", RootWorkItem, PublicationScope.Global);

Here Shell.cabEventFirerButton is the button on the Shell form, and obviously „Click‟ is the
name of the .NET event that we want to be a Publication in our MyEvent EventTopic. Once this
code has been run if we click the button the EventTopic will fire and any associated
EventSubscriptions will run. We don‟t need to explicitly call the Fire event of the EventTopic.

In the section „Parameters of the Fire Method‟ we saw that when we call the „Fire‟ method we
can specify the scope that the CAB will use to search for EventSubscriptions. If we use
AddPublication as shown here we are not calling the „Fire‟ method directly. Instead we can
specify the scope parameters in the AddPublication call: they are the final two parameters to the
call as shown above. These are a WorkItem and a member of the PublicationScope enum as
before, and work in the same way.

Issues with AddPublication

The AddPublication syntax is a very powerful way of hooking up .NET events to CAB
EventSubscriptions. However, it needs to be used with care. Developers expect there to be a
.NET event handler for a .NET event, and it can be very confusing if code is running as a result
of an AddPublication call.

For example, in the code above if you were trying to work out what happens when you click the
button you could easily think there‟s no code going to run at all. There‟s no easy way to find out
that the click event is a CAB publication and what the associated EventTopic is.

As a result my feeling is that direct use of AddPublication as shown in the example above should
be used sparingly. It‟s clearer to hook up the .NET event handler and then call the „Fire‟ event of
your EventTopic directly in the handler.

EventTopic Enabled Property

The EventTopic class has an „Enabled‟ property. By default this is set to true, meaning that when
the EventTopic is fired all the associated EventSubscriptions will run. However, we can simply
set this property to false to disable all the EventSubscriptions of the EventTopic.

Once again this can be useful and there‟s no easy way of doing it with traditional .NET eventing.

An example showing this is available. This modifies the example above used to demonstrate
changing PublicationScope. The example is set up to have multiple EventSubscriptions to one
EventTopic. All of these normally get called when a button is clicked and the EventTopic is
fired.
P a g e | 53

The example uses a checkbox. When the checkbox is checked the EventTopic is enabled and
firing the EventTopic runs all the EventSubscriptions, when it is cleared the EventTopic is
disabled and the EventSubscriptions do not run. This is achieved with the code below in the
CheckedChanged event of the checkbox:

private void eventsEnabledCheckbox_CheckedChanged(object sender,


EventArgs e)
{
rootWorkItem.EventTopics["MyEvent"].Enabled =
eventsEnabledCheckbox.Checked;
}

Conclusion

Events in the CAB are syntactically cleaner and are easier to use than normal .NET events, and
can give us greater control over the scope of what runs when they are fired.
P a g e | 54

13. Introduction to UI Extension sites

Introduction

Part 12 of this series of articles went into some detail on events in the Composite Application
Block, and concluded our discussions of commands and events.

As we‟ve already discussed in this series of articles, the Composite Application Block (CAB) is
intended as a means of creating smart client applications that are composed of several
independent „modules‟. We‟ve also seen that the CAB has a number of other features to make
development easier in general, in particular a dependency injection framework.

However, when we think of a „smart client‟ we usually think of a well-designed and powerful
user interface. The CAB introduces a number of new classes to aid in the design and
implementation of such user interfaces.

So far this series of articles has not really discussed user interfaces at all, and certainly hasn‟t
covered any of the user interface elements of the CAB. The next few articles will remedy this.

UIExtensionSites

This article and the next will discuss one of the CAB user interface classes, the UIExtensionSite.
A UIExtensionSite is a user interface element of the shell (the containing window) for a
composite application. It might be a ToolStrip, a MenuStrip or a StatusBar, but could be any
shared user interface element. The idea of the UIExtensionSite class is to allow each individual
module to talk to these elements of the shell in a decoupled way.

In this article we‟ll start with a basic example. In fact, we‟re going to base the example on an
earlier one, which will be recapped first.

Basic Example Starting Point – Recap of the BasicMDIApplication from Part 5

For this example we start with the code for the first example from part 5 of this series of articles,
„BasicMDIApplication‟. This contains three projects, none of which reference each other.
However, each project contains one form, and when we run the application two of the forms
appear as MDI children of the third. The two MDI children are coloured red and blue
respectively.

This was done in a slightly contrived way (it‟s not the way you‟d do it in production code). In
our Shell project in method AfterShellCreated we added the Shell form itself to our
RootWorkItem‟s Items collection:

protected override void AfterShellCreated()


{
base.AfterShellCreated();
this.Shell.IsMdiContainer = true;
P a g e | 55

RootWorkItem.Items.Add(this.Shell, "Shell");
}

Then we accessed it from the same collection in each of the other projects. We did this in the
Load method of theModuleInit class in each project. There we set the MdiParent property of the
project‟s form to be the Shell form:

public override void Load()


{
base.Load();
Form shell = (Form)parentWorkItem.Items["Shell"];
Form1 form = new Form1();
form.MdiParent = shell;
form.Show();
}

Note that here we had access to the parentWorkItem of the project (which is the same as the
RootWorkItem). We got access to this through dependency injection.

The original code is available here.

Basic Example Extended

We‟ll extend this so that the Shell form has a ToolStrip with two buttons. One of these will bring
the red MDI child to the front, and one will bring the blue MDI child to the front. Remember that
there are no direct references between any of the projects, so it isn‟t immediately obvious how
we do this.

Furthermore, each individual project will set up its own ToolStrip button. So the ToolStrip itself
will be in the Shell project. The Red project will contain code to create the „Show Red Form‟
button and add it to the ToolStrip. Similarly the Blue project will contain code to create the
„ShowBlueForm‟ button and add it to the ToolStrip.

Basic Example – Code in the Shell Project

To do this we first add the ToolStrip to the Shell form using the visual designer. We‟ll call it
„shellToolStrip‟. To make life easy in this simple example we‟ll give it a scope of „Internal‟ (by
changing the „Modifiers‟ property).

Then we extend AfterShellCreated to register this ToolStrip as a UIExtensionSite:

protected override void AfterShellCreated()


{
base.AfterShellCreated();
this.Shell.IsMdiContainer = true;
RootWorkItem.Items.Add(this.Shell, "Shell");
RootWorkItem.UIExtensionSites.RegisterSite("ShellToolStrip",
this.Shell.shellToolStrip);
P a g e | 56

The RegisterSite method has the effect of adding the object passed in its second parameter (the
shellToolStrip) to the UIExtensionSites collection of the RootWorkItem. The UIExtensionSites
collection is indexed by name, and RegisterSite gives the object the name passed in the first
parameter (“ShellToolStrip”).

Basic Example – Code in the MDI Child Projects

As in the original example, we have access to the RootWorkItem in the individual projects
containing the MDI child forms. So we can retrieve a UIExtensionSite object from the
UIExtensionSites collection of that RootWorkItem. The UIExtensionSite object represents the
ToolStrip. UIExtensionSite has an Add method we can use to add a ToolStripButton to the
UIExtensionSite.

So in the ModuleInit classes (RedModuleInit and BlueModuleInit) of the appropriate MDI child
projects we create such a button. We give it an appropriate event handler for its Click event.
We‟re using standard .NET events here:

private Form1 form;


public override void Load()
{
// Code as before
base.Load();
Form shell = (Form)parentWorkItem.Items["Shell"];
form = new Form1();
form.MdiParent = shell;
form.Show();

// Create a new button, hook it up to an event handler,


// and add it to our ToolStrip by using the UIExtensionSite.
ToolStripButton toolStripButton = new ToolStripButton("Show Red
Screen");
toolStripButton.Click += new
System.EventHandler(toolStripButton_Click);
UIExtensionSite uiExtensionSite =
parentWorkItem.UIExtensionSites["ShellToolStrip"];
uiExtensionSite.Add<ToolStripButton>(toolStripButton);
}

void toolStripButton_Click(object sender, System.EventArgs e)


{
form.BringToFront();
}

That‟s all there is to this example. The only change to the above code for the Blue project is that
the ToolStripButton is initialized to have Text “Show Blue Button” rather than “Show Red
Button”.
P a g e | 57

Basic Example – Results

The code for this is available. If we run it we get a screen as below. Clicking “Show Blue
Screen” brings the blue child form to the front, clicking “Show Red Screen” brings the red child
form to the front.

As previously with this example, please note that this is not the way you would normally set up
an MDI application in the CAB (although it might well be the way you would set up a
ToolStrip). The example simplifies many aspects of the code in order to demonstrate the core
concepts.

Conclusion

In this article we‟ve created an application with three separate projects that don‟t reference each
other, but having a common ToolStrip in the Shell project with buttons contributed by the other
projects.

In part 14 we will examine how this is working in more detail, show how we can use
UIExtensionSites for other user interface elements, and discuss what value this is adding to the
development process.
P a g e | 58

14. More on UI Extension Sites

Introduction

Part 13 of this series of articles discussed UIExtensionSites, and gave a basic example of how
they work.

This article discusses UIExtensionSites in more detail, including a discussion of their use of the
Adapter design pattern.

Whilst most of this article is fairly straightforward, I should say now that I am very sceptical of
the value of UIExtensionSites and we have decided not to use them in our current project. I‟ll
discuss this below.

Additional Functionality of the UIExtensionSites

The basic example in part 13 showed how we can register a ToolStrip as a UIExtensionSite in a
WorkItem using the RegisterSite method. We can then access it from other modules via the
UIExtensionSites collection of the WorkItem.

In particular we can then add ToolStripButtons to it using the Add method of the
UIExtensionSite.

In addition to the Add method, a UIExtensionSite has a Remove method which, clearly, removes
an item that has been added to the UIExtensionSite.

A UIExtensionSite is really just a simple collection class behind the scenes (in fact it‟s a wrapper
around List<object>). Obviously in the case of a ToolStrip it‟s a collection of ToolStripButtons.

In addition to the Add and Remove methods, the UIExtensionSite class has some of the usual
public methods you‟d expect on a collection class: Count, Clear, Contains, and GetEnumerator
(which allows „foreach‟ to be used on the collection, of course).

Types that can be added to a UIExtensionSite

The only types that can be registered as UIExtensionSites without additional work are types that
contain ToolStripItems: that is, ToolStrips, MenuStrips and StatusStrips.

It is possible to set up other user interface items so that they can be used as UIExtensionSites. To
do this you need to write an adapter class for your user interface items. We‟ll examine this in
more detail below.

Restrictions of UIExtensionSites
P a g e | 59

So we have a means of adding a ToolStrip, MenuStrip or StatusStrip to a collection that can be


accessed from any module in a Composite Application Block project. We can then add or
remove ToolStripItems from the ToolStrip, MenuStrip or StatusStrip. We can clear them as well.

However, that‟s it. If we want to do anything more sophisticated we can‟t easily. For example, if
we have a menu item that can be checked we can‟t use these interfaces to find out if it‟s checked
or not. Equally, if we just want to hide a ToolStrip from code it can‟t be done easily.

You might think you could cast the UIExtensionSite back to its original type to get this
functionality. So to hide the ToolStrip you might cast the UIExtensionSite to ToolStrip and call
the Hide method. Unfortunately this isn‟t possible: there isn‟t a direct cast to the underlying type.
We‟ll examine the relationship between ToolStrip and UIExtensionSite in a little more detail
below.

Decoupling

So what is the UIExtensionSite giving us? I‟m sure the original idea was to decouple our
underlying user interface items (ToolStrips etc.) from the way individual modules would access
them. By having a generic UIExtensionSite with a generic interface we could plug in any user
interface element we wanted, and maybe even swap them around. So if we wanted to use a
different ToolStrip to Microsoft‟s we could do so: all we‟d really need to do would be to ensure
the methods in the interface (Add, Remove etc.) worked correctly.

However even this isn‟t possible with the current implementation of UIExtensionSite. If you
look back at the code in the basic example in part 13 we are explicitly creating a ToolStripButton
object in our client code:

ToolStripButton toolStripButton = new ToolStripButton("Show Red


Screen");
toolStripButton.Click += new
System.EventHandler(toolStripButton_Click);
UIExtensionSite uiExtensionSite =
parentWorkItem.UIExtensionSites["ShellToolStrip"];
uiExtensionSite.Add<ToolStripButton>(toolStripButton);

In this code we have decoupling in the sense that we are handling a generic UIExtensionSite
object rather than a specific ToolStrip object. However we are still tightly coupled to Microsoft‟s
ToolStrip since we‟re creating the ToolStripButton. If we wanted to swap out the ToolStrip and
replace it with a different one we‟d have to change all this code.

As I mentioned in the introduction, I am struggling to understand what UIExtensionSites are


giving us: they make it difficult to access core functionality of our ToolStrips etc. without giving
us proper decoupling.
P a g e | 60

How is the Basic Example Working?

In the example in part 13 we added a ToolStrip to the UIExtensionSites collection of the


RootWorkItem. We then retrieved the same object from the same collection. However, when we
retrieved the object it had type UIExtensionSite. This meant that we then called the Add method
of UIExtensionSite to add buttons to the ToolStrip.

You may be wondering how we managed to do this. UIExtensionSite is a class, and clearly
ToolStrip doesn‟t inherit it. How are we calling Add on UIExtensionSite and getting
ToolStripButtons added to a ToolStrip class? The answer to this is that we are using an adapter
pattern, as we shall see in more detail below.

Using Other User Interface Elements as UIExtensionSites

As mentioned above we can use other user interface elements than just ToolStrips, MenuStrips
and StatusStrips as UIExtensionSites. However, we have to do a little more work to get this
going. In fact, we have to write an adapter class for our user interface element. This tells the
CAB what to do when the Add or Remove methods are called on the associated UIExtensionSite.

Before we discuss how to do this we‟ll quickly recap the Adapter pattern.

The Adapter Design Pattern

The adapter is a pattern that we use when we want a class to implement a standard interface but
don‟t want to (or can‟t) change the actual code of the class. In the case of our UIExtensionSites
our user interface elements (e.g. ToolStrips) will have methods for adding and removing
individual items (e.g. ToolStripButtons). However we want to be able to use a generic „Add‟
method on a UIExtensionSite object to add ToolStripButtons. We clearly can‟t change the
ToolStrip class to implement this, so we use an adapter.

The book „Design Patterns: Elements of Reusable Object-Oriented Software‟ (the „Gang of Four‟
book) says the intent of the Adapter pattern is to:

“Convert the interface of a class into another interface clients expect. Adapter lets classes work
together that couldn‟t otherwise because of incompatible interfaces.”

The Adapter class diagram is below:


P a g e | 61

The idea here is that we have some class Adaptee that has a „SpecificRequest‟ method that the
client wants to call. However, the client code uses an Adapter class to invoke the functionality,
calling the „Request‟ method. Adapter is an abstract base class: it‟s just defining an interface that
the client code will use.

Furthermore we can‟t, or don‟t want to, change the Adaptee class to actually inherit from
Adapter. So instead we write a ConcreteAdapter class. This inherits Adapter, and so has a
Request method. It also takes a reference to the Adaptee class (usually in its constructor) and
caches it in a data member. This means we can write a very simple implementation of the
Request method in our Adapter class that simply forwards the call to the SpecificRequest method
on the Adaptee object in the data member.

Now the client code can work with Adapter objects, calling the Request method, but still get the
functionality of the SpecificRequest method of the Adaptee.

Of course the Adapter class can do much more work than just forwarding method calls to
methods with different names. The Adaptee might need several calls to do the work we want
done in the call to Request on the interface, and the Adapter class can clearly deal with that as
well.

One consequence of the use of this pattern is that we can‟t cast our Adaptee class to Adapter
since it doesn‟t implement it directly. This explains why in our examples we can‟t cast our
UIExtensionSite (or the IUIElementAdapter data member it contains) back to our original
ToolStrip. As mentioned above this restricts quite severely what we can do with a
UIExtensionSite.

How this is Implemented in the CAB for UIExtensionSites

For UIExtensionSites in the Composite Application Block this pattern is made slightly more
complex. The Patterns and Practices group have separated out the interface implemented by our
Adapter base class into an actual C# interface called IUIElementAdapter which is then
implemented by our abstract base class
UIElementAdapter<TUIElement>. You don‟t need to worry about the details of this. All you
need to know is that to implement your own adapter you need to inherit from
UIElementAdapter<TUIElement> where TUIElement is the type of the objects that will be
added to or removed from the UIExtensionSite. Inheriting this class compels you to override the
abstract Add and Remove methods that it contains.

As you‟ve probably realized, the Composite Application Block already contains an adapter class
for ToolStrips, MenuStrips and StatusStrips. This is snappily called
„ToolStripItemCollectionUIAdapter‟and is in the CompositeUI.WinForms library.
P a g e | 62

Custom UIExtensionSite Example

This example will again be based on the Red and Blue form example used in part 13. This time
we will add a panel to the left side of the screen that display link labels. Our link labels will bring
the appropriate red or blue screen to the front:

The panel will be set up as a UIExtensionSite. It will therefore have an Add method that allows
you to add a LinkLabel into the panel, and similarly have a Remove method that allows you to
take one out.

The code for this example is available.

LinkLabelPanel User Control

To implement this the first thing we need is a user control to act as the panel for the LinkLabels.
This needs to have methods to add and remove labels. To set this up all we have to do is add a
UserControl to the Shell project, make its background white, and add methods to handle the
LinkLabels as below:

public partial class LinkLabelPanel : UserControl


{
public LinkLabelPanel()
P a g e | 63

{
InitializeComponent();
}

private const int labelSpacing = 22;


private int nextLabelTop = 10;
private const int left = 3;

public void AddLabel(LinkLabel label)


{
label.Location = new Point(left, nextLabelTop);
nextLabelTop += labelSpacing;
this.Controls.Add(label);
}

public void RemoveLabel(LinkLabel label)


{
this.Controls.Remove(label);
}
}

As you can see this keeps track of where the next LinkLabel should be positioned vertically in
data member nextLabelTop. We can add a LinkLabel to the panel by calling AddLabel, and this
adds it to the Controls collection and positions it appropriately.

Note that the Remove method isn‟t particularly sophisticated since it does no repositioning of
existing controls: it will just take the LinkLabel it is passed off the screen and leave a gap where
it previously was.

The Adapter

To be able to use this as a UIExtensionSite we need an adapter class that inherits


UIElementAdapter<LinkLabel> (since LinkLabel is the type that we are adding and removing
from the UIExtensionSite). This is a very simple adapter that just forwards the calls to the
underlying LinkLabelPanel. It gets a reference to this LinkLabelPanel passed in in its
constructor:

public class LinkLabelPanelUIAdapter : UIElementAdapter<LinkLabel>


{
LinkLabelPanel panel;
public LinkLabelPanelUIAdapter(LinkLabelPanel panel)
{
this.panel = panel;
}

protected override LinkLabel Add(LinkLabel uiElement)


{
panel.AddLabel(uiElement);
return uiElement;
}
P a g e | 64

protected override void Remove(LinkLabel uiElement)


{
panel.RemoveLabel(uiElement);
}
}

Using the LinkLabelPanel

We can now use the LinkLabelPanel in the same way as we did the ToolStrip in the example in
part 13.

Firstly we add the user control to our Shell form, dock it to the left, and make its Modifiers
property have value „Internal‟.

We then register the UIExtensionSite in method AfterShellCreated. One slight difference here is
that we need to tell the CAB which adapter it needs to use, and we do this by using a different
overload of RegisterSite:

protected override void AfterShellCreated()


{
base.AfterShellCreated();
this.Shell.IsMdiContainer = true;
RootWorkItem.Items.Add(this.Shell, "Shell");
RootWorkItem.UIExtensionSites.RegisterSite("LinkLabelPanel", new
LinkLabelPanelUIAdapter(this.Shell.linkLabelPanel1));
}

As mentioned above our adapter needs to have a reference to the LinkLabelPanel passed to it in
its constructor.

Now we can add LinkLabels to our UIExtensionSite from our individual Red and Blue module
projects. Again this is done in the same way as for the ToolStrip example in part 13. We create a
new LinkLabel, retrieve the UIExtensionSite that represents the LinkLabelPanel from the
UIExtensionSites collection, and use the Add method to add the LinkLabel to it. We set up the
Click event of the LinkLabel using .NET events, again analogously to what we did with the
Click event for our ToolStripButtons in part 13:

private Form1 form;


public override void Load()
{
// Code as before
base.Load();
Form shell = (Form)parentWorkItem.Items["Shell"];
form = new Form1();
form.MdiParent = shell;
form.Show();

LinkLabel label = new LinkLabel();


label.Text = "Show Red Screen";
P a g e | 65

label.Click += new System.EventHandler(label_Click);


UIExtensionSite uiExtensionSite =
parentWorkItem.UIExtensionSites["LinkLabelPanel"];
uiExtensionSite.Add<LinkLabel>(label);
}

void label_Click(object sender, System.EventArgs e)


{
form.BringToFront();
}

That‟s it: if we repeat the code immediately above in both the Red and the Blue projects our
example we will work as we desire.

Conclusion

UIExtensionSites allow us to access user interface elements in the shell of a Composite


Application Block project in a generic way. The CAB provides us with code (an adapter) to let
us use ToolStrips, MenuStrips and StatusStrips as UIExtensionSites. If we wish to use other user
interface elements as UIExtensionSites we can quite simply write our own adapter class.

However, UIExtensionSites are quite limited in the functionality they provide, restricting us to
just Add and Remove methods for elements of the UIExtensionSite. As a result we may need
some more powerful mechanism to provide the rich user interface support we require.
P a g e | 66

15. Introduction to Smart parts and Workspaces

Introduction

Part 14 of this series of articles discussed UIExtensionSites. This article continues our discussion
of user interface elements in the Composite Application Block by giving an introduction to
SmartParts, and a very brief introduction to Workspaces. Part 16 will expand on this discussion.
Workspaces and SmartParts are interlinked and to understand one you need some understanding
of the other.

Why do we need Workspaces and SmartParts?

We don‟t have to use any of the new user interface elements described in this article. We can
create a composite application as described in previous articles using just the existing Form
class, UserControl class and the various visual components found in the standard toolbox in
Visual Studio. Part 1 and part 5 of this series of articles showed how we can construct a very
basic multiple document interface (MDI) application comprising three independent modules.
Those articles didn‟t use any of the CAB user interface components.

Many introductory texts on the Composite Application block start with Workspaces and
SmartParts. This series of articles has left them until close to the end. This is because I
personally found SmartParts very confusing (and still do to a certain extent), and because we
don‟t need to use them to get the benefits of the Composite Application Block. Workspaces are
more useful, as we shall see.

SmartParts

„SmartParts‟ were first introduced in the original CAB code back in 2005. As mentioned above
the concept can be confusing. SmartParts are most easily thought of as user controls in a CAB
application. In fact they can be any visual element low-level element in your CAB user interface.
They can, for example, be child forms in an MDI application.

However, in almost every case you will come across SmartParts will be user controls (including
the normal children in CAB MDI applications).

Microsoft‟s CAB documentation defines a SmartPart as „a view of data (in the MVC pattern)
such as a control, a Windows Form, or a wizard page‟. This is slightly misleading as SmartParts
don‟t necessarily have to display any data, and don‟t have to be in an MVC pattern.

SmartParts Collections

In part 2 of this series of articles we saw that a WorkItem can be thought of as a „run-time
container of components‟ and that the WorkItem class has various collection classes associated
with it (e.g. Items, Services, WorkItems). One of these collection classes is the SmartParts
collection. As we shall see later in this article, another collection class on a WorkItem is the
Workspaces collection.
P a g e | 67

So perhaps a better definition of a SmartPart is as any object that is put into the SmartParts
collection in a WorkItem in the CAB.

However, even this definition is confused by the fact that the Workspaces collection itself has a
SmartParts collection. This means there are two SmartParts collections at different places in any
WorkItem. This article will call these „WorkItem SmartParts‟ and „Workspace SmartParts‟. The
two collections behave in different ways, which are discussed below. Before that we‟ll take a
quick look at what a Workspace actually is. This brief exposition will be expanded on in part 16.

Workspaces

Microsoft‟s CAB documentation defines Workspaces as:

“The components that encapsulate a particular visual layout of controls and SmartParts, such as
within tabbed pages.”

Workspaces are themselves controls that allow other controls to be laid out within them. In
particular they are designed to allow SmartParts to be laid out within them.

Several Workspace types are available in the Visual Studio toolbox and can just be dragged onto
our screens. In this sense they are like the existing layout controls in the .NET Framework (e.g.
the TabControl).

Where Workspaces differ from existing layout controls is in the fact that they are part of and
utilize the CAB dependency injection containers (Workitems). As with SmartParts, WorkItems
have a „Workspaces‟ collection which, obviously, contains all the Workspaces associated with
the WorkItem.

We can create a Workspace in our Workspaces collection in the usual way with the AddNew
keyword. However, we don‟t need to do this if we‟ve just dragged our Workspace onto a screen:
the ObjectBuilder will recognize it as a Workspace when it is created, and add it to the
appropriate collections.

Workspaces also interact with SmartParts in a standard way: they have a Show method that will
display a SmartPart, an ActiveSmartPart property that gets a reference to the active SmartPart in
the Workspace, and so on. These methods will be examined in more detail in part 16 of this
series of articles.

SmartParts Collections: WorkItem SmartParts

We look now at the SmartParts collections in more detail. To show the concepts involved there is
a code example available.

The SmartParts collection in a WorkItem is just a filter on the Items collection, filtering for any
Items where the underlying class is decorated with the attribute „SmartPart‟. If we have an object
whose class is decorated with the SmartPart attribute and add it directly to either the Items
P a g e | 68

collection or the SmartParts collection it will appear in both. However, if we try adding an object
NOT decorated with the attribute to the SmartParts collection it will get added to the Items
collection only.

The underlying type of our SmartPart doesn‟t matter for this . It can be any class at all. As long
as that class is decorated with „SmartPart‟ it will behave as described above. The intention is that
objects added to this collection be visual ones (user controls, forms etc.) but they don‟t have to
be.

Example of WorkItem SmartParts

This is illustrated in the code example. Here we have a user control, UserControl1, that is
decorated with the SmartPart attribute:

[SmartPart]
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
}

In the AfterShellCreated method we add this to the SmartParts collection of the RootWorkItem:

RootWorkItem.SmartParts.AddNew<UserControl1>();

We then examine what effect that has on the various collection classes on the RootWorkItem.
We can see that the UserControl1 object is in both the SmartParts collection and the Items
collection as we would expect (see below for the results output).

Similarly we define a plain old .NET class and also decorate that with the SmartPart attribute:

[SmartPart]
internal class TestClass {}

We then just add that to the Items collection of the RootWorkItem in AfterShellCreated:

RootWorkItem.Items.AddNew<TestClass>();

If we now look at the RootWorkItem collection classes we see that the TestClass object is in
both the SmartParts collection and the Items collection in exactly the same way as the
UserControl instance above. It is a „SmartPart‟ even though it has no visual element.

The full output of the relevant collections from this example is shown below under „Output from
SmartParts Example‟.
P a g e | 69

SmartParts Collections: Workspace SmartParts

As discussed above, the second SmartParts collection is on a Workspace. An object gets added to
this collection if we call the Show method on the Workspace with the object as the parameter.

For the Workspace SmartParts collection it doesn‟t matter whether the object‟s class is
decorated with the „SmartPart‟ attribute or not: it gets added to the Workspace SmartParts
collection when the Show method of the Workspace is called regardless.

Note that the Show method doesn’t add the object into the Items collection of the WorkItem, nor
does it add the object into the WorkItem SmartParts collection.

We‟ll examine how Workspaces work, and how they interact with SmartParts, in more detail in
part 16 of this series of articles. In particular we‟ll look at why the Show method is a useful one,
and we‟ll examine how SmartPartInfo classes work and why we need them. For now you can
just accept that this second collection exists and can be useful.

Issues with Workspace SmartParts

One issue here is that objects can only be added to the SmartParts collection of a Workspace if
they inherit System.Windows.Forms.Control at some level. That is, in this case our SmartParts
are forced to be visual controls.

Also you can‟t add SmartParts directly to the SmartParts collection of a Workspace. The only
way to add an object to this collection is to use the Show method of the Workspace (I think).
Note that they don‟t get removed from this collection just because you call Show with a different
SmartPart.

You were warned that this is confusing.

Example of Workspace SmartParts

The code example discussed above has been extended to show how Workspace SmartParts work.
We have added a DeckWorkspace (one of the more common Workspace classes) to our Shell
form simply by dragging it from the Toolbox. We‟ve also added another user control class to the
project, UserControl2.

We then display the user control in the Workspace by calling the Show method:

this.Shell.deckWorkspace1.Show(new UserControl2());

This has the effect of adding UserControl2 to the SmartParts collection of the Workspace.
However, UserControl2 is NOT added to the Items collection of the WorkItem, nor to the
SmartParts collection of the WorkItem.
P a g e | 70

In the example above we defined a plain old .NET class and added it to the WorkItem‟s
SmartParts collection. We can‟t do this with the Workspace‟s SmartParts collection because this
collection will only accept objects that inherit from Control at some level.

One thing to note here is that UserControl2 is decorated with the SmartPart attribute, but this
makes no difference at all to the example. We can remove it and the example will work in the
same way. This is because this attribute is not relevant for the SmartParts collection on a
Workspace.

Output from SmartParts Example

The SmartParts example uses some simple looping code to output the collections created to the
Output window. The results of this are shown below. As we can see, UserControl1 and TestClass
(discussed in the section „Example of WorkItem SmartParts‟ above) appear in the Items
collection, and in the SmartParts collection at RootWorkItem level. However, UserControl2
(from the section „Example of Workspace SmartParts‟) appears ONLY in the SmartParts
collection on the Workspace. This is what we‟d expect as discussed above.

ITEMS:
[d506f65b-e818-4379-b15a-5e53bfe7777f, Microsoft.Practices.CompositeUI.State]
[f4d17dcd-13cc-4d61-b24b-0b3cd03c88a8, Shell.Form1, Text: Form1]
[deckWorkspace1, Microsoft.Practices.CompositeUI.WinForms.DeckWorkspace]
[1d141251-3436-4a8a-8bd3-1e63ceca3d9e, Shell.UserControl1]
[632482f5-aaa3-490b-b800-3575bea33a06, Shell.TestClass]
SMARTPARTS:
[1d141251-3436-4a8a-8bd3-1e63ceca3d9e, Shell.UserControl1]
[632482f5-aaa3-490b-b800-3575bea33a06, Shell.TestClass]
WORKSPACES:
[deckWorkspace1, Microsoft.Practices.CompositeUI.WinForms.DeckWorkspace]
SMARTPARTS:
Shell.UserControl2

The SmartPart Attribute

Another source of confusion with SmartParts is what exactly the SmartPart attribute does.
Several texts mention that it doesn‟t seem to make much difference whether it‟s there or not, and
this is true to an extent with the Workspace SmartParts collection.

In fact there are (at least) two places where the SmartPart attribute makes a difference:

1. As we‟ve already seen any object decorated with the SmartPart attribute that is added to
either the Items or the SmartParts collection of a WorkItem will effectively be added to
both collections. Any object without the SmartPart attribute added to either collection
will end up in the Items collection only. Remember that the SmartParts collection of a
WorkItem is really just a filter on the Items collection for any objects that have the
SmartPart attribute.
2. The SmartPart attribute also makes a difference if we add a Control to the Controls
collection of the Shell, or to the Controls collection of a Control on the Shell, when the
Shell is being initialized (in its constructor). In this case the ObjectBuilder recognizes that
P a g e | 71

we have a WorkItem SmartPart. It adds the SmartPart to the Items collection of the
WorkItem and hence to the SmartParts collection (since it has the SmartPart attribute).

This is still confusing, but the behaviour in 2 is there so that if you drag a User Control with the
SmartPart attribute onto the Shell from the Toolbox then it will get added to the SmartParts
collection of the root WorkItem at start up.

Example of Effects of SmartPart Attribute on User Controls Dragged on to the Shell Form

Some example code showing this is available. This has a user control with the SmartPart
attribute applied (SmartPartUserControl) and a user control with no SmartPart attribute
(NormalUserControl). Both of these have been dragged onto the Shell form (Form1).

Additionally in the constructor of the Shell form we manually instantiate a SmartPartUserControl


and add it to the Form‟s Controls collection:

public partial class Form1 : Form


{
public Form1()
{
InitializeComponent();
SmartPartUserControl smartPartUserControl = new
SmartPartUserControl();
smartPartUserControl.Name = "Manually instantiated user control";
this.Controls.Add(smartPartUserControl);
}
}

That‟s all the code that‟s been added. Once again the code dumps the various relevant WorkItem
collections in AfterShellCreated by using simple loops outputting to the Output window:

ITEMS:
[fa70dbe9-0c30-443e-9fe6-a13e353994e0, Microsoft.Practices.CompositeUI.State]
[d67d7177-cf63-4b4f-9447-ef2fd1e8271b, Shell.Form1, Text: Form1]
[userControl11, Shell.SmartPartUserControl]
[deckWorkspace1, Microsoft.Practices.CompositeUI.WinForms.DeckWorkspace]
[Manually instantiated user control, Shell.SmartPartUserControl]
SMARTPARTS:
[userControl11, Shell.SmartPartUserControl]
[Manually instantiated user control, Shell.SmartPartUserControl]
WORKSPACES:
[deckWorkspace1, Microsoft.Practices.CompositeUI.WinForms.DeckWorkspace]
SMARTPARTS:

As we can see, both SmartPartUserControls have been added to both the Items and WorkItem
SmartParts collections, whilst the NormalUserControl does not appear (although we can see it on
the Shell fine: it just hasn‟t been added to these collections). This is what we‟d expect from the
discussions above.

Summary of the SmartParts Collections and their Intention


P a g e | 72

The intention of the Workspace SmartParts is to give us (and the CAB Framework) a collection
of SmartParts that have been shown in a Workspace but not closed. These can be re-activated
(effectively brought to the front). We can show Controls that are not marked with the SmartPart
attribute in a Workspace (and hence arguably aren‟t really SmartParts). However this collection
needs to track everything that has been shown, and so it all ends up in this collection.

The intention of the WorkItem SmartParts is to give us a collection of SmartParts that we as


developers can control and use. Here we do want everything in the collection to have the
SmartPart attribute: this is what distinguishes SmartParts from ordinary Items as far as this
collection is concerned.

Workspace SmartParts have to be Controls (i.e. inherit from System.Windows.Forms.Control at


some level). WorkItem SmartParts can be any object.

My personal opinion is that it would have been less confusing if the CAB developers had given
the SmartParts collection on the Workspace a different name: „ViewsShown‟ or something
similar might have been better.

Conclusion

This article gave a brief introduction to SmartParts and showed why they can be confusing. It
also gave an even briefer introduction to Workspaces. Part 16 of this series of articles will
examine Workspaces in more detail, and expand on how we can use SmartParts in our code. It
will also look at the SmartPartInfo class.
P a g e | 73

16. More detail on WorkSpaces and SmartParts

Introduction

Part 15 of this series of articles explained SmartParts in the CAB, and gave a very brief
introduction to Workspaces. This article will continue with the same topics. In particular we will
look in more detail at Workspaces.

Workspaces Recap

Part 15 explained the SmartParts can be most easily thought of as user controls or views in a
composite application block application.

Part 15 also explained that Workspaces are just controls that allow other controls (SmartParts) to
be laid out within them, and differ from other container controls in that they interact with other
objects in the CAB in a predefined way. In particular there is a Workspaces collection on any
WorkItem, and they have a Show method that shows a SmartPart.

User Interface Design for Business Applications

In an earlier blog posting on user interface design I discussed some of the possible user interface
designs for applications that have to display multiple different screens of data. A common design
for these applications is to have a tabbed client area for the screens, together with a tree-based
window manager of some kind. An alternative is an Outlook-style interface, again possibly with
a tree window manager, but dispensing with tabs at the top of the screen. Clearly both of these
designs are very similar: we click on a tab or double-click in a tree and our screen gets displayed
in a predefined part of the screen.

One thing to notice with both of these designs is that after we have displayed a client screen for
the first time we won‟t usually close it again. When other screens are displayed our first screen
will stay in memory. It will retain the state it was displaying the last time the user interacted with
it. When the user requests to see the screen again it will just be brought to the front.

So we have a collection of objects (our screens) with persistent state whilst the application is
running. We may create all of these screens at start-up. However more usually we‟ll create a
screen the first time the user requests it, and then redisplay it the second time it is requested (a
sort of lazy initialization). Note that at any given time many of the screens in the collection may
not actually be displayed at all.

Building User Interfaces for Business Applications

Of course it is easy enough to create an application of this kind using Windows Forms standard
controls. However, there‟s some infrastructure code that we are going to have to write. We need:

some means of caching our screens collection


a way of allowing new screens to be added to the screens collection
P a g e | 74

a method of displaying a screen when it is requested for the first time


a method of redisplaying the appropriate screen in response to the appropriate request

We‟ll also want to make sure we control the scope of our screens carefully so that they can‟t be
accessed from anywhere in the code. As we all know, global singletons (or global variables of
any kind) are a bad thing.

The good news is that Workspaces and SmartParts do all this for us. What‟s more they do it in a
very simple way.

Workspaces – the IWorkspace Interface

All Workspaces implement the IWorkspace interface. This is the interface we are meant to use to
interact with our Workspaces: usually we don‟t need any more functionality than this interface
provides as we shall see.

The IWorkspace interface has a number of useful methods. In general these behave as explained
below, although each type of Workspace is free to implement them in its own way:

void Show(object smartPart)

When this method is called, if the SmartPart passed as a parameter has not previously been
shown in this Workspace it will be loaded and then activated. If it has already been shown and
not been closed (i.e. if it is in the Workspace‟s SmartParts collection) it will just be activated.
Usually „activated‟ means brought to the front and made into the ActiveSmartPart.

void Activate(object smartPart)

If the object is in the Workspace‟s SmartParts collection it will be activated as described above.
If it‟s not in that collection then an ArgumentException will be thrown.

void Hide(object smartPart)

Hides the SmartPart (sends it to the back usually), but leaves it in the Workspace‟s SmartParts
collection. The next control in the Workspace will usually be activated (made into the
ActiveSmartPart). What „next‟ means here varies by Workspace.

void Close(object smartPart)

Hides the SmartPart and also removes it from the SmartParts collection. The next control in the
Workspace will usually be activated.

IWorkspace also has a property ActiveSmartPart, which returns the active SmartPart if there is
one. As discussed in part 15 Workspaces have a SmartParts collection, and the IWorkspace
interface has a SmartParts property that lets us access this (it returns a
ReadOnlyCollection<object>).
P a g e | 75

IWorkspace also has events SmartPartActivated and SmartPartClosing. You can probably guess
when these get fired.

There are also some methods to deal with SmartPartInfo on IWorkspace. I‟ll discuss
SmartPartInfo below.

Workspaces – Aside on how the Supporting Classes Work

The core functionality of IWorkspace is encapsulated in a class called, appropriately,


Workspace. This is an abstract base class that all Workspaces are expected to inherit from. It
implements IWorkspace so the individual Workspace classes don‟t have to (since they inherit the
interface from Workspace).

The base class gives basic implementations of the members of IWorkspace, and also handles
things like caching the active smart part, tracking the SmartParts collection, and raising the right
events at the right time.
Whilst the way the supporting classes work is quite interesting, you don‟t need to know it in any
detail to use the Workspace classes. The exception to this is if you want to write your own
custom Workspace class, in which case you will need to get to grips with them in more detail.
Writing your own custom Workspaces is beyond the scope of these articles for now.

Further Aside on Multiple Inheritance in C#

The Workspace classes also demonstrate a method of achieving a kind of multiple inheritance in
C#. This is done by composition, using a class called WorkspaceComposer and an interface
called IComposableWorkspace. It‟s needed because certain Workspace classes (e.g.
TabWorkspace) already inherit a Control class to give their basic functionality (in the case of
TabWorkspace this is TabControl). As we know, in .NET a class can‟t directly inherit more than
one other class.

It is not my intention in these articles to actually discuss the underlying code in the Composite
Application Block in any detail. The aim of these articles is to let you use the CAB as a black
box component. But the WorkspaceComposer is particularly interesting since it shows us a
pattern for achieving multiple inheritance (albeit messily) in C#. If you are interested the code is
in the Microsoft.Practice.CompositeUI.SmartParts namespace in the
Microsoft.Practices.CompositeUI component.

SmartPartInfo

As we have seen the normal Show method on the IWorkspace interface only lets you pass the
SmartPart you want to show as a parameter. There may be other information that the CAB
framework will need to know to show your SmartPart correctly. For example, in a
TabWorkspace you need to provide the text for a new tab somehow. In a ZoneWorkspace you
need to tell the CAB which particular zone the SmartPart will be displayed in.

This problem is solved by passing an additional object to the Show method:


P a g e | 76

void Show(object smartPart, ISmartPartInfo smartPartInfo)

This additional object implements the interface ISmartPartInfo, which has Title and Description
properties. It‟s the Title property that‟s used to set the tab page title in the TabWorkspace.

The smartPartInfo object can contain any additional information we require. For example, for
ZoneWorkspaces it contains the name of the zone in which the SmartPart will be displayed.

The IWorkspace interface also has a method to directly apply the information in a SmartPartInfo
object to a SmartPart that has already been displayed:

void ApplySmartPartInfo(object smartPart, ISmartPartInfo smartPartInfo)

In a ZoneWorkspace this can be used to change the zone where a SmartPart is shown in, for
example. The next article in this series will give some examples of this.

Conclusion

This article has discussed some of the theory behind Workspaces, and shown the basic interfaces.
Part 17 in this series of articles will discuss the various types of Workspace that are available in
the CAB, and give some code examples of how to use them.
P a g e | 77

17. Workspace Types

Introduction

Part 16 of this series of articles explained in general terms why Workspaces are useful. It also
examined the methods that are available on a Workspace via the IWorkspace interface.

There are five Workspace types provided with the Composite Application Block framework:
DeckWorkspace, ZoneWorkspace, TabWorkspace, MdiWorkspace and WindowWorkspace.
This article looks in a little more detail at these various Workspace types and associated
SmartPartInfo types, and gives some code examples.

The ToolBox

Some Workspaces can be added to the Visual Studio toolbox as shown below. To do this you (as
usual) right-click and select „Choose Items…‟. Then click the „Browse…‟ button, and browse to
your Microsoft.Practices.CompositeUI.WinForms.dll library. If you click „OK‟ to this the
Workspaces shown should be added:

DeckWorkspace

The DeckWorkspace is the first of the Workspace types provided with the CAB that we shall
look at.
P a g e | 78

This is „deck‟ as in „deck of cards‟. When we show a SmartPart in a DeckWorkspace it fills the
area of the Workspace completely. If we show another SmartPart it replaces the original
SmartPart in the view completely. However, the old SmartPart is still there in the deck,
immediately behind the original SmartPart. If we add a third SmartPart it gets displayed at the
front of the deck, but the other two SmartParts are still there in order. If you close the third
SmartPart the second one will get displayed.

A code example of use of a DeckWorkspace is available. The shell form for this CAB
application has a DeckWorkspace on it. The project also contains two SmartParts, with red and
blue backgrounds. A series of buttons allow the user to call methods on the DeckWorkspace,
providing either the red or the blue SmartPart as an argument. The methods available are the
IWorkspace methods discussed in part 16: Show, Hide, Activate, Close.

This behaves as described in part 16. If we try to Activate, Close or Hide a SmartPart that hasn‟t
been Shown we get an exception. However if we Show the red SmartPart, then Show the blue
SmartPart, then Activate the red SmartPart the red SmartPart that was originally shown gets
shown again.

As shown above, the form also has a „Details‟ button. This shows the current ActiveSmartPart,
and the Items and Workspaces collections on the RootWorkItem. As a result it will show you
which SmartParts are loaded at any given time.

To use a DeckWorkspace you can simply drag one onto a form and start coding. There is no
specific SmartPartInfo class for the DeckWorkspace .

The DeckWorkspace is a useful type if you are building an Outlook-style interface. It can act as
the main display area in the application, and gives us the behaviour we desire (which was
outlined in part 16).
P a g e | 79

ZoneWorkspace

The ZoneWorkspace allows the user to define „zones‟ or areas within the Workspace where
SmartParts can be shown. As mentioned briefly in part 16 a SmartPartInfo object can be used to
define which zone a SmartPart will be shown in .

The easiest way to set up a ZoneWorkspace is firstly to drag one onto your form or user control
from the ToolBox. Then drag ordinary Windows Forms panels onto the ZoneWorkspace and
position them to define your zones. If you look in their properties you will see that these panels
have a ZoneName property where you should give your zones sensible names.

To show a SmartPart in a specific zone you need to tell it the zone via a SmartPartInfo object.
The easiest way to do this is to drag a ZoneSmartPartInfo item from the Toolbox shown above
onto your form or user control. You can make your ZoneSmartPartInfo reference a specific zone
by setting ITS ZoneName property to the ZoneName of the zone. You can then show SmartParts
in the zone by calling the Show method and passing the ZoneSmartPartInfo object as the second
parameter.

A code example of this is available. Once again this has two SmartParts, red and blue. It also has
two zones, left and right, as shown. Further it has two visual ZoneSmartPartInfo objects as
discussed above, one of which references the left zone and one of which references the right
zone. Which one of these is used when you click on the buttons is controlled by the radio buttons
shown below.

The buttons are as above, apart from the Apply buttons. The Apply buttons call
ApplySmartPartInfo on the ZoneWorkspace with the appropriate ZoneSmartPartInfo object
depending on which of the radio buttons is selected. They can thus be used to change which zone
a SmartPart is displayed in: if the red SmartPart is shown in the left zone (as shown below) we
can check the „Right zone‟ radio button and hit „Apply‟ for the red SmartPart, which will move it
to the right zone.
P a g e | 80

One thing to note about the ZoneWorkspace is that calling Show with a SmartPart does not
necessarily bring that SmartPart to the front. The Show method adds the SmartPart to the
appropriate collections, gives the SmartPart the focus and make the SmartPart into the
ActiveSmartPart. However in spite of this the SmartPart can still be hiding behind another
SmartPart.

For this reason DeckWorkspaces are often put into zones of ZoneWorkspaces, since a SmartPart
will be brought to the front when Show is called on a DeckWorkspace.

TabWorkspace

TabWorkspace has the standard Windows Forms TabControl as a base class, and acts like a CAB
version of that control. Every SmartPart that you add to the TabWorkspace gets shown in its own
tab.

There‟s a TabSmartPartInfo class we can use to set details on our SmartParts and tabs. This has a
Title property which can be used to set the title of the TabPage the SmartPart is being displayed
in. It also has a Position property. This can be set to TabPosition.Beginning or TabPosition.End,
and affects where the new tab appears in relation to existing tabs.

There‟s a code example that shows this, with the same buttons and red and blue SmartParts as in
the previous examples. This has no tabs showing at start up. When we click the Show button for
a SmartPart it calls the Show method for the TabWorkspace, passing the appropriate SmartPart
as a parameter.

The Show method creates a new tab with the SmartPart displayed on it.
P a g e | 81

In addition the example has visual TabSmartPartInfo components that are passed to the Show
methods, one for the red SmartPart and one for the blue. These set the titles on the tab pages, and
control where they are added.

This example also has „Apply‟ buttons that let us change the titles of the tab pages from a value
entered in a TextBox. The buttons do this by setting the Title property on the appropriate
TabSmartPartInfo and then calling the ApplySmartPartInfo method.

The SmartPartInfo you give to the Show method implements ISmartPartInfo and has no
additional members.

MdiWorkspace

The MdiWorkspace allows each SmartPart to be displayed in a separate child window inside a
parent Form. This allows us to build MDI applications using the Composite Application Block.

One thing to note about the MdiWorkspace is that, as with other Workspaces, our child
SmartParts have to be User Controls. We can‟t display child Forms inside an MdiWorkspace
with the code as it stands. This is in spite of the fact that our children look and behave like
Forms: they have title bars and maximize and minimize buttons, for example.

MdiWorkspaces can use the WindowSmartPartInfo type to give additional information about
SmartParts that are being displayed. As usual, this has a Title property. It also has properties to
determine whether our MDI child is modal, whether it displays minimize, maximize and/or
control boxes, and its location.

Once again a code example is available, and this behaves in the same way as the examples
above. This includes allowing us to change the titles by entering some text in a TextBox and
clicking „Apply‟, which calls ApplySmartPartInfo as for the TabWorkspace above.
P a g e | 82

WindowWorkspace

A WindowWorkspace lets us display our SmartParts in floating windows, each one in a separate
window. Once again it uses the WindowSmartPartInfo type to give additional information about
SmartParts that are being displayed.

A code example is available. This is extremely similar to the MdiWorkspace example above,
except that obviously it deals with a WindowWorkspace and not an MdiWorkspace.
P a g e | 83

18. Introduction to Smart Client Software Factory

Introduction

So far in this series of articles the focus has been on the core functionality of the Composite
Application Block (CAB). No mention has been made of the Smart Client Software Factory
(SCSF), in spite of the fact that the series is entitled „An Introduction to the Composite
Application Block and the Smart Client Software Factory‟.

This article and the ones that follow will remedy that. They will discuss what the Smart Client
Software Factory is, how it relates to the Composite Application Block, and how to use it.

Versions of the Composite Application Block and Smart Client Software Factory

The first version of the Composite Application Block was released in December 2005. This had
all of the features that have been described in this series of articles so far. As was mentioned in
part 1 of this series, the Composite Application Block on its own is quite difficult to understand
and learn how to use. Furthermore, documentation and support in the initial version were
somewhat lacking: many developers complained that they couldn‟t understand how to use the
new framework.

The Patterns and Practices team released a follow-up version in June 2006, and another in May
2007. However, they did not attempt to change the core Composite Application Block code.
Instead they provided additional documentation and examples, as well as a way of automatically
generating code for various useful patterns using the Composite Application Block. We‟ll
examine this in a little more detail below.

The idea behind these SCSF releases was to make it easier for developers both to learn and to use
the Composite Application Block software (and other application blocks). However, as we shall
see, the SCSF introduces new code and patterns on top of the CAB‟s already complex structures,
and the documentation could still be clearer. In many ways the Patterns and Practices team have
added to the confusion with these releases rather than clarifying the situation.

Software Factories

The last two releases were branded as the „Smart Client Software Factory‟. A „software factory‟
is one of the latest computer industry buzzwords.

The idea behind software factories is that current software development practices depend on
highly-skilled developers, who are similar to craftsmen in a pre-industrial age. The argument is
that the need for highly-skilled craftsmen is the reason that many software projects fail: there are
too few really good craftsmen, and they are usually hand-crafting from scratch in every new
project. We need to „industrialize‟ the software development process. Software should be created
using „software factories‟.
P a g e | 84

Like many computer industry buzzwords, what a „software factory‟ is in practice is a little
unclear. It tends to vary depending on the author, but in general a software factory should
provide a means of producing code in a standard way. This may mean reusing and customizing
existing code, simply following a set of guidance practices, or generating code automatically
based on a model, which may be visual. It may mean a combination of all of these techniques.
The phrase is also often used to describe model-driven development, possibly using domain-
specific languages.

Smart Client Software Factory

Microsoft‟s „software factory‟ is slightly simpler than some of the usual definitions described
above. The „Smart Client Software Factory‟ comprises a small set of code generators plus some
documentation and examples. The code generators are quite straightforward, producing code to
set patterns (there‟s no model to be maintained here).

The paragraph below is from the SCSF documentation:

„The software factory provides a set of proven and integrated practices that are exposed through
patterns, How-to topics, QuickStarts, a reference implementation, a Visual Studio Guidance
Automation Toolkit package, and architecture documentation. The software factory guides
projects through the development of smart client applications based on the architecture of the
Composite User Interface Application Block.‟

The Visual Studio Guidance Automation Toolkit Package

The Smart Client Software Factory includes a „Visual Studio Guidance Automation Toolkit
Package‟. This is an add-in to Visual Studio that automates certain software development tasks
relating to the CAB. Some of these are added to the right-click context menu in Solution
Explorer.

Probably the most useful Guidance Package, however, is the one that generates a new Smart
Client Application project. This is also a good place to start when investigating what the Smart
Client Software Factory can do.

This Guidance Package is available if you request a new project in the usual way inside Visual
Studio after the SCSF has been installed. The New Project window has a project type of
„Guidance Package‟ available. Underneath that you can choose a new „Smart Client Application
(C#)‟:
P a g e | 85

If you select this option the Guidance Package will show a screen that allows you to set some
properties of your solution. In particular you need to tell the Package where the Composite
Application Block libaries are, and to set some options. These include whether you want a
separate module for layout of the Shell (in general you won‟t want this). The Guidance Package
will then set up a Smart Client solution as below:
P a g e | 86

The SmartClientDevelopmentSolution

This is a base solution for a smart client project using the Composite Application Block. It gives
your code some basic structure. It also gives you a lot of code on top of the Composite
Application Block code itself: the various projects contain about 3,000 lines of code in total.
P a g e | 87

So we have even more code to try to understand if we are to use the resulting project effectively.

As you can see we are given four basic projects:

1. Shell

This is the start-up project for the solution. It is very similar to the start-up projects in the sample
applications we‟ve already seen in this series of articles: it has a start-up class (ShellApplication)
which (indirectly) inherits from FormShellApplication. It has a form, ShellForm, which is the
containing window for the application. It has a ProfileCatalog which will contain the composite
application modules to be loaded.

If you compare this the Naïve Application sample code from part 1 of this series of articles you
will see the similarities.

However, there are subtle differences as well, mainly in the form of extra code constructs. For
example, ShellApplication actually inherits from a class called „SmartClientApplication‟ which
in turn inherits from FormShellApplication. The SmartClientApplication class simply sets up
some SCSF services.

Additionally the ProfileCatalog now allows us to specify dependencies. We also have a


Constants folder with a series of class files in it. We‟ll examine these extra code constructs in
later articles.

2. Infrastructure.Interface

The remaining Infrastructure projects are intended to provide common functionality for all of the
composite applications we add into our solution. However, we don‟t want to directly reference
the projects that contain the code. Instead we want to hide the code behind interfaces in a
separate library and reference the interface library. Infrastructure.Interface is this interface
library. It mainly contains interfaces, with some simple classes.

3. Infrastructure.Library

The Infrastructure.Library project contains the bulk of the new code that this SCSF solution
gives us. In fact it contains about 2000 lines of code, including such things as the Action Catalog,
and support for loading modules using sources other than ProfileCatalog.xml.

4. Infrastructure.Module

Infrastructure.Module is an empty module project. It is intended that any code that we as


developers want to add to the infrastructure section of our solution will go in here. It is a CAB
module, which we have seen before, and it contains a ModuleInit class as we‟d expect (see part 1
of this series of articles). However, it also contains a ModuleController class, which inherits
WorkItemController. This will be discussed further in the next article.
P a g e | 88

19. Business Modules and Interfaces in the SCSF Smart Client Solution

Introduction

Part 18 gave a brief introduction to the Smart Client Software Factory. This article continues that
discussion by looking at business modules, and also examining how the various modules in a
Smart Client solution are expected to interact.

Recap on the Smart Client Application

In part 18 we saw that a „Guidance Automation‟ package in the Smart Client Software Factory
lets you create a base solution for a smart client program. It sets up four projects, three of which
are infrastructure projects.

One of the projects is an empty „Infrastructure.Module‟ project. Infrastructure.Module is a CAB


module as described earlier in this series of articles: it isn‟t directly referenced by the other
projects in the solution but can be used to write infrastructural code for the solution without any
tight-coupling with the rest of the solution. We‟ll examine this in a little more detail below.

Business Modules

It isn‟t intended that we put business logic into the Infrastructure projects discussed above.
Instead we are meant to create „business modules‟.

To create a business module we use another of the Guidance Automation packages: we right-
click the solution in Solution Explorer, select Smart Client Factory/Add Business Module (C#),
click „OK‟ in the „Add New Project‟ window and then click „Finish‟ in the „Add Business
Module‟ window.

This gives us two new projects in the solution with default names Module1 and
Interface.Module1 as below:
P a g e | 89

Once again here Module1 is a Composite Application Block module, and is not referenced by
any other project in the solution. However, Module1.dll IS added to the ProfileCatalog (which is
in Shell). This means that the Load method of a class inheriting ModuleInit in Module1 will get
called by the CAB at start up, as described in part 1 of this series of articles. The class with the
Load method in Module1 is called „Module‟. We‟ll look at what the Load method is doing in the
next article in this series.

Note here that the Module and ModuleController classes are identical to those in
Infrastructure.Module. Note also that there‟s really no code at all in Module1.Interface: there are
just some empty classes in a folder called Constants.
P a g e | 90

Business Module Interaction with the Rest of the Smart Client Project

As discussed in part 1 of this series, a „module‟ is a standalone project to be used in a composite


user interface. So our business module here is intended to be a slice of business functionality that
can potentially be developed independently of the other modules in the application. Because the
business module isn‟t directly referenced by other modules a separate development team could
potentially work on it and change it. It can then in theory be plugged in to the containing
framework without the need for code changes in the framework. The other project‟s libraries
might not even need to be recompiled since they don‟t actually reference the business module
directly.

Clearly in practice it‟s likely that the business module will have to interact with the rest of the
Smart Client solution on some level. There will be a need for:

1. The business module to use the infrastructure components: for example it might need to
put a toolstrip into the Shell form.
2. Other components in the Smart Client solution to use some of the business module
functionality. As a simple example we might have a business module that deals with
customers and a back-end customer database. It might have screens to show customer
data and allow updates. Another business module might want to display these screens in
response to a request: an Orders module might allow a double-click on a customer name
to show the customer.

We want to achieve the interaction described above in a way that‟s as loosely-coupled as


possible, so that we can change the system easily. To do this we make sure that all interaction is
through the Interface projects.

We now examine each of these possible scenarios in more detail:

1. The Business Module Using Infrastructure Components

For this scenario in our example solution Module1 references Infrastructure.Interface directly. It
is set up to do this by default when you add the business module to the solution. Note that
Infrastructure.Interface is intended to (mainly) contain .NET interfaces: it is not meant to contain
large amounts of code.

Note that Module1 does not reference Infrastructure.Module or Infrastructure.Library directly,


nor should it under any circumstances. These projects may well be under the control of a
separate development team from our business module team, and they may need to be updated
independently of the business modules. So we reference the interface project, and that handles
our interaction with the Infrastructure libraries.

This seems to be a concept that developers working on these projects have difficulty with: almost
every member of my development team at work has added one of these libraries to a business
module at some stage.
P a g e | 91

I think the confusion arises because it‟s not necessarily obvious how we do this. If my module
just references an interface how can I actually call any functionality using just the interface? The
answer is that we are once again using the dependency inversion and dependency injection
concepts described in part 3 and part 4 of this series of articles.

An example here may help.

Example

We‟ll use the WorkspaceLocator service that the SCSF adds into the Infrastructure.Library
component when we create a Smart Client solution. The WorkspaceLocator service lets you find
the Workspace a SmartPart is being displayed in, although this isn‟t relevant for this discussion:
all we‟re interested in is how to invoke the service from a business module.

There‟s a class called WorkspaceLocator that actually does the work in


SmartClientDevelopmentSolution.Infrastructure.Library.Services. There‟s also an interface in
Infrastructure.Interface as below:

namespace SmartClientDevelopmentSolution.Infrastructure.Interface.Services
{
public interface IWorkspaceLocatorService
{
IWorkspace FindContainingWorkspace(WorkItem workItem, object
smartPart);
}
}

Note that Infrastructure.Library references Infrastructure.Interface and so WorkspaceLocator can


implement this interface. Note also that our business module, Module1, also references
Infrastructure.Interface but NOT Infrastructure.Library. So it can‟t see the WorkspaceLocator
class directly and thus can‟t call FindContainingWorkspace on it directly. So how do we use the
service?

The answer is that this is the standard CAB dependency inversion pattern using WorkItem
containers to access objects.

At start up the solution creates an instance of the WorkspaceLocator service and adds it into the
Services collection of the root WorkItem, referencing it by the type of the interface:

RootWorkItem.Services.AddNew<WorkspaceLocatorService,
IWorkspaceLocatorService>();

This actually happens in the new SmartClientApplication class mentioned in part 18, but all we
really need to know is that the service will be available on the root WorkItem.

Now, in our module we know we can get a reference to the root WorkItem in our new module by
dependency injection in a class:
P a g e | 92

private WorkItem _rootWorkItem;

[InjectionConstructor]
public Module([ServiceDependency] WorkItem rootWorkItem)
{
_rootWorkItem = rootWorkItem;
}

Our module also knows about the IWorkspaceLocator interface since it references
Infrastructure.Interface. So it can retrieve the WorkspaceLocator service object from the root
WorkItem using the interface, and can then call the FindContainingWorkspace method on that
object:

IWorkspaceLocatorService locator =
_rootWorkItem.Services.Get<IWorkspaceLocatorService>();
IWorkspace wks = locator.FindContainingWorkspace(_rootWorkItem,
control);
MessageBox.Show("Workspace located: " + wks.ToString());

In summary, as long as our module knows the interface to the functionality it needs, and knows
how to retrieve an object that implements that interface from a WorkItem collection of some
kind, it doesn‟t need to have direct access to the underlying class to use the object. This was
explained in more detail in earlier articles in this series.

2. Other Components Using the Business Module Functionality

For other components to use our business module functionality we are expected to work out what
functionality our business module should expose to the rest of the solution. We should then
define interfaces that allow access to that functionality and put them into our Module1.Interface
component.

Other components in the solution can then reference Module1.Interface and call the
functionality. Note that to allow them to do this we need to ensure that the correct objects are
available in a WorkItem, as described above. Once again other components should NOT
reference Module1. We can then change Module1 without impacting the other components.

We may of course need to change the interfaces. In this case it may be sensible to retain the old
version of the interface component itself so not all other components have to upgrade, and to add
a new version with the changed interfaces in as well. The old interface can then be disabled when
everyone has upgraded.

Conclusion

This article has examined modules in a Smart Client solution, and discussed how they should
interact.
P a g e | 93

20. SCSF Business Modules: Start Up and the ControlledWorkItem

Introduction

Part 19 of this series of articles discussed business modules in a Smart Client solution generated
using the Smart Client Software Factory. This article continues that discussion.

The Load Method of a Business Module

As discussed in the previous article, a business module has a class called „Module‟ which
inherits from class ModuleInit. We saw in part 1 of this series of articles that this means the Load
method in that class will get called at start up, provided the module has been added to the
ProfileCatalog file.

The Load method of Module generated by the Smart Client Software Factory is as below:

public override void Load()


{
base.Load();

ControlledWorkItem<ModuleController> workItem =
_rootWorkItem.WorkItems.AddNew<ControlledWorkItem<ModuleController>>();
workItem.Controller.Run();
}

As we can see, it‟s creating a ControlledWorkItem class instance and adding it to the WorkItems
collection of the root WorkItem. It‟s then calling the Run method on the Controller property of
this WorkItem.

ControlledWorkItem

ControlledWorkItem is a class that inherits directly from WorkItem. So a ControlledWorkItem is


a WorkItem. The ControlledWorkItem also adds additional functionality to the WorkItem, and,
crucially, it is a sealed class (which means we can‟t inherit from it).

The idea here is that each business module should have a ControlledWorkItem as a root for its
functionality. This is what we are creating in the Load method. In the overall WorkItem
hierarchy each business module ControlledWorkItem is immediately below the root WorkItem
for the entire solution.

Inheriting WorkItem to add Functionality

The ControlledWorkItem has been created to clarify the situation with regard to adding code to
WorkItems. When we start using the CAB we quickly find that we need our WorkItems to be
P a g e | 94

extended in various ways. They are intended to control business use cases, after all. For example
we may want specific services instantiated at start up and added to the Services collection. Doing
this in the WorkItem itself may seem like a sensible thing to do. Clearly the main WorkItem
class is a CAB framework class, but we can inherit from it to give it this additional behaviour.

The reference implementations of both the CAB and the SCSF do this: each WorkItem inherits
from the base WorkItem class and extend it to give the use case functionality. If you look at the
CustomerWorkItem in the Bank Teller Reference Implementation you‟ll see this.

Why Inheriting from WorkItem has been Deprecated

The difficulty with this is that our WorkItem class is acting as both a container for all the various
WorkItem collections, as we have discussed before, AND as a place where all the code for a
business use case goes.

This breaks the Single Responsibility principle, which is that every class should have just one
responsibility in a system to avoid confusion.

As a result the Patterns and Practices team have decided it‟s not ideal to have developers inherit
from WorkItem and add functionality to the derived class. Instead a second class is created to
contain the new code, and that class is associated with the WorkItem class by composition.

How ControlledWorkItem Addresses the Problem

This is what the ControlledWorkItem is doing. The ControlledWorkItem class itself inherits
from WorkItem, but also has a member variable that references another class. The type of this
class is generic (so the developer provides it), and the class is instantiated when the
ControlledWorkItem is created.

So in the line of code below we are creating the ControlledWorkItem and adding it to the root
WorkItem‟s WorkItems collection. However we are also telling the ControlledWorkItem that its
member class should be of type ModuleController, and that class will get instantiated and set up
as the member variable.

ControlledWorkItem<ModuleController> workItem =
_rootWorkItem.WorkItems.AddNew<ControlledWorkItem<ModuleController>>();

We are not expected to inherit from ControlledWorkItem itself. In fact we can‟t because it is
sealed: the Patterns and Practices team have done this deliberately to indicate that the pattern has
changed. Instead we add our additional functionality for the WorkItem to the ModuleController
class.

ModuleController

We can access the ModuleController instance from the ControlledWorkItem using the Controller
property. We can then call a Run method on that class. This is the standard pattern that is
P a g e | 95

generated by the Guidance Automation Package: note that the final line in the Load method
above is:

workItem.Controller.Run();

So we can add start up code for the WorkItem into the ModuleController class in the Run
routine.

The SCSF gives us a default ModuleController whenever we set up a Module, as we have seen.
This has a default Run method. There isn‟t any code that actually does anything in this method,
but four empty methods are set up in ModuleController to indicate to us the sort of things we
should be doing:

public class ModuleController : WorkItemController


{
public override void Run()
{
AddServices();
ExtendMenu();
ExtendToolStrip();
AddViews();
}
...

There are also comments in these routines to describe what we should be doing inthem. To see
this in more detail look in any of the ModuleController classes in the sample code.

WorkItemController Class

Note also above that our default ModuleController inherits from a class called
WorkItemController, which is an abstract base class intended to be used just of these controllers.
Inheriting from this ensures that we have a Run method in our derived class as there is an
abstract function of this name in the base class.

The base WorkItemController also gets a reference to the associated WorkItem using our usual
dependency injection pattern. This can be accessed via the WorkItem property on the
WorkItemController class.

Finally the WorkItemController class has two overloaded ShowViewInWorkspace methods,


which can create and show a SmartPart in a named Workspace in the WorkItem.

Obviously we don‟t have to make our ModuleController inherit from WorkItemController.


However, if we don‟t this base class functionality will not be available.

Conclusion

This article has discussed the standard patterns generated by the Smart Client Software Factory
for starting up business (and other) modules.
P a g e | 96

21. Foundational Modules and Names as Constants

Introduction

Part 19 and part 20 of this series of articles looked at business modules in the Smart Client
Software Factory.

This article looks at foundational modules briefly, and also discusses the pattern for handling
names in the SCSF.

Foundational Modules

In part 18 of this series of articles we saw how we can use one of the Guidance Automation
Packages to add a business module to our solution. There‟s also a Guidance Automation package
that lets us add a „foundational module‟ to our solution. This is on the same submenu as the „Add
Business Module (C#)‟ option we saw above. So to add a foundational module to our solution
right-click the solution folder in Solution Explorer, select Smart Client Factory/Add
Foundational Module (C#) and then click through the two setup screens.

A foundational module is identical to a business module except that it does not have a root
WorkItem. This is because it is intended to contain supporting functionality rather than core
business functionality for our solution. It is not expected that we will create business objects and
add them to the various WorkItem collections.

So we are expected to create fairly generic services and supporting code in foundational
modules, rather than business code. Of course we could do this in the Infrastructure projects
mentioned in part 18, but a foundational module allows us to separate out supporting code into
its own CAB module.

Note that we can create an interface component, „Module.Interface‟, for our foundational module
in exactly the same way as for a business module. This allows other components in the solution
to use the module‟s functionality without referencing it directly, as described above.

Constants Folders

In our examples above we have seen several Constants folders being set up. The main Smart
Client solution has a Constants folder in both the Infrastructure.Interface component and the
Shell component. Both the foundational modules and the business modules have Constants
folders in both their main Module components and their Module.Interface components.

The Constants folders all contain four classes: CommandNames, EventTopicNames,


UIExtensionSiteNames, and WorkspaceNames. In the Constants folders mentioned above most
of these are empty by default, although Infrastructure.Interface has some constants set up in its
classes.
P a g e | 97

The important thing to notice here is that the individual classes with the same name are arranged
in an inheritance hierarchy. So if we have a business module in our Smart Client solution (as in
the code example we have already seen) then CommandNames in the Module itself inherits from
CommandNames in Module.Interface, which in turn inherits from CommandNames in
Infrastructure.Interface. CommandNames in Shell also inherits from Infrastructure.Interface.

The reason these classes exist is to allow us to use standard constants throughout our solution for
names, rather than having to use strings. The inheritance hierarchy lets us define these constants
at the correct level in the hierarchy, but then to use any of them very simply by just accessing the
class at the level the code is at.

The reason we don‟t want to use strings in our code as names is they are prone to error in entry
(since we can‟t use intellisense) and can‟t be checked by the compiler at compile-time: if we
enter a string name wrongly we will get a run-time error. If we use constants to represent these
strings we avoid both of these problems.

This will be clearer in an example:

We might call a Workspace on our Shell form “LeftWorkspace” when we add it to the
Workspaces collection of the root WorkItem. Elsewhere in the code we may want to retrieve that
workspace and interact with it, for example to call the Workspace‟s Show method to display a
SmartPart. Normally to do this the syntax would be, for example:

_rootWorkItem.Workspaces["LeftWorkspace"].Show(control);

The obvious difficulty with this is that we are just entering the name “LeftWorkspace” as a
string, which is prone to error and the compiler can‟t check.

So we add the code below to the WorkspaceNames class in Infrastructure.Interface. We add it to


the Infrastructure.Interface component because the Workspace is being defined in the
Infrastructure part of the solution, but we want it to be available outside of that:

public const string LeftWorkspace = "LeftWorkspace";

Now suppose we want to use this Workspace name in code in a business module. The
WorkspaceNames class in the business module inherits from the WorkspaceNames class in
Infrastructure.Interface, and hence the constant is available in that class. All we need do is
reference that class to access any Workspace name. So we just import the appropriate
namespace:

using SmartClientDevelopmentSolution.Module1.Constants;

And then we can do:

_rootWorkItem.Workspaces[WorkspaceNames.LeftWorkspace].Show(control);
P a g e | 98

Now intellisense is available when we enter the „LeftWorkspace‟ name, and the compiler can
check that what we have entered is correct.

Note that if we have a Workspace name defined just for the module (say „LocalWorkspace‟) we
can still just do WorkspaceNames.LocalWorkspace to access it.

So these Constants folders provide us with an easy way of using named constants for items in the
WorkItem hierarchy throughout our code.
P a g e | 99

22. Model – View – Controller

An Apology, and Topics Still To Be Covered

Let me start by apologizing to all the CAB/SCSF fans (?) out there who have been asking me to
continue the series of posts. I know it‟s been a while since I wrote about the CAB/SCSF (I got
diverted by FpML as you can see). However the series of articles is not yet finished and I will be
sporadically posting on the topics many of you have been asking about. If there‟s interest I may
look at how to use some of the other application blocks with the CAB as well.

If there are specific things you would like to see covered please leave a comment.

Having said that, our CAB project is live and working well, and we are moving onto other issues,
so my enthusiasm for spending my Saturday mornings writing about CAB/SCSF has waned
somewhat.

Introduction

Part 21 of this series of articles briefly discussed foundational modules and the way constants are
handled in an SCSF project.

Part 23 of this series of articles will examine another Smart Client Software Factory Guidance
Automation pattern, the Model-View-Presenter.

By way of preparation for part 23, this article discusses the problems with putting code directly
behind screens in smart client applications, and a traditional solution to this, which is Model-
View-Controller.

The Basic Problem

When writing user interface code it‟s quite easy to put too much logic in the class that draws a
form or user control.

In badly-designed .Net applications, for example, it‟s not uncommon to see classes behind user
controls of several thousand lines of code (excluding the automatically generated code). We may
have code that handles events, updates the data on the screen, caches and refreshes data, updates
the state of user interface controls based on the data or user input, colors parts of the screen
based on the data, binds data to controls in complex ways and so on.

With all this code in one class it can be difficult to work out what is going on. The code becomes
hard to maintain.

Clearly if we have a lot of code doing different things in a class we are violating the single
responsibility principle. We should be looking to refactor in such a way that we have a number
of classes, each with a clear role and tidy interfaces into the other classes.
P a g e | 100

The difficulty with this is that it isn‟t necessarily easy to see how to break up this sort of code in
a logical way. There are a number of user interface patterns that address this. The granddaddy of
them all is Model-View-Controller (MVC), although as we shall see this is not a pattern you are
likely to see in a .Net application, at least in its original pure form.

Where to Cache the Data

It‟s arguable that the main problem Model-View-Controller solves is that of data being cached
directly behind a screen and not elsewhere in the application. Again this is a common problem in
poorly written smart client applications.

Suppose we have a screen that displays data that has been retrieved into a series of textboxes
directly from a middle-tier service. This data is loaded into the textboxes the first time it is
displayed, retained in the textboxes but not actually stored in any variables anywhere. There may
be a „refresh‟ button that lets us reload the data from the service. However, the values in the
textboxes will not automatically update if there‟s a change server-side.

Suppose we now want to add another screen that uses that data in some calculations. Where does
the second screen get the data from? If it goes back to middle-tier service the data may be out of
sync with the data displayed in the screen. Should it go to the screen itself?

Model-View-Controller (MVC)

The traditional solution to this problem is to use the Model-View-Controller pattern (MVC).

MVC dictates that we have three classes for user interface display:

1. A Model class contains the data to be displayed. This can be a simple data cache,
although it may be a full domain model (classes containing data plus associated business
functionality).
2. A View class that contains the screen code. This would be a user control or form in .Net.
3. A Controller class that provides the glue between the Model and the View. This class is a
little more difficult to understand than the other two. The idea is that the Controller
handles all user input, which means events raised in response to user actions (e.g.
clicking a button, changing a value in a textbox etc.). It then updates the Model as
necessary.

Note that the Controller does not update the View. It updates the Model. If necessary the Model
will then raise an event saying that it has changed. The View will subscribe to this event and
redraw itself, getting the new data directly from the Model. Note that this is the Observer design
pattern: the View(s) observe the Model.

In its purest form the View class should ONLY contain code that draws to the screen: it
shouldn‟t contain any event handling code for user events, all of which should be in the
Controller. This isn‟t the usual pattern with a .Net user control of course, where your event
handlers are normally in the code behind the user control (the View). It‟s possible to set up the
P a g e | 101

event handlers actually in the Controller, or to just immediately call the Controller from the View
in the event handler.

Class Interaction in Model-View-Controller

These classes should have references to each other as shown in the diagram below:

The solid arrows above represent references between classes through which direct method calls
can be made.

The View class will have a reference to the Model to allow it to directly request the data it needs
to display (A).

The Controller will have a reference to the Model because it will need to manipulate it in
response to user actions (B). The Controller also has a reference to the View because it may need
to retrieve values that have been changed in order to manipulate the Model in an appropriate way
(C).

Note however that the Controller will not update the View directly. The View itself will go to
the Model to actually get the data.

The dotted lines above represent an indirect relationship where events can be raised from one
class into the other. So the Model may raise events when its data changes, which the View will
sink and update any display depending on that data (D).

Note that the Model has no direct reference to the other two classes: it is independent of any
Views or Controllers.

Use Case Examples

It can be difficult to understand exactly how this fits together when we see it for the first time. In
particular what the Controller does can be confusing.
P a g e | 102

To clarify this here is a use case example:

A user interacts with a screen displaying data (which is the View). Suppose that they
change some base data and hit an Update button. Further suppose that they expect some
derived data on the screen to change as a result of this action.
The click event for the Update button gets raised in the Controller. A parameter to the
event may be the data that needs to be saved (otherwise the Controller can go back to the
View to get it). The Controller takes the changed data and updates the Model for the
changes. This will include updating any derived data.
The Model raises an event that it has changed.
The View will sink the event and redraw itself based on the new data. This means that the
correct derived data will now be displayed.
The system waits for further user input when the cycle above will be repeated.

Solving the Data Caching Problem

MVC gives a solution to the data cache problem outlined above. We have separated the data for
our screen into a Model class. Any other screen that needs to display the same data can access
the same Model class (using its own Controller). The textboxes on the screens are effectively just
views of this data whenever they are displayed.

As a result if the data changes it should only need to be changed in the one place (the Model) for
the individual screens to be able to use it. What‟s more, because the Model raises an event when
the data changes, ALL we need do is change the data in the Model and all the screens will
automatically update. If we change a value in a textbox on one screen it should update on any
other screens via the process described in „Use Case Examples‟ above.

Note that this means that one Model can be associated with multiple Views and Controllers.
However, it is usual to have a one-to-one mapping between Views and Controllers: each View
will have its own unique Controller class.

‘Pure’ Model-View-Controller

The Model-View-Controller pattern described in this article is one that could be used with
modern programming languages such as .Net. The description here is what is usually meant by
„MVC‟ these days. However, MVC as described here differs slightly from the original pure
MVC design.

MVC originated with early Smalltalk which was a very different language from modern user
interface languages like .Net or Java. For a detailed look at the history of MVC (and of MVP)
see Martin Fowler‟s article „GUI Architectures‟.

In the original Smalltalk design every single control (textbox, button, etc.) would have its OWN
View and Controller class, and the screen they were on would have a top-level View and
Controller that would handle putting them all together. This was because Smalltalk didn‟t have
P a g e | 103

draggable user interface controls in the way we do today, so writing a user interface was a
somewhat different proposition.

Clearly we could do this in a modern programming language such as .Net, but it would arguably
make our code less clear rather than clearer.

Active and Passive Model-View-Controller

MVC as described here is „active‟ MVC. This means that, as we have seen, if the Model changes
all Views will be updated automatically via the eventing mechanism.

It is also possible to set up „passive‟ MVC. This is a slightly simpler pattern where the Model
does not raise an event when it changes, and consequently the View cannot update itself
„automatically‟. Instead the View is updated when the user next requests it (by pressing a
„Refresh‟ button for instance). At this time the View will go to the Model and get the new data.

Advantages of Model-View-Controller

MVC obviously has the advantage that for complex screen logic we get clearer code, which
should be easier to maintain. In theory this pattern also makes it easier for us to replace the user
interface itself, since only screen logic is in the screen.

MVC also provides an easy way of allowing multiple views of the same data to always be
synchronized (via the event mechanism).

Disadvantages of Model-View-Controller

Of course, there‟s one obvious argument against using MVC for every single screen in a system:
it‟s a fairly complex pattern, and for very simple screens may simply mean we create three
classes where we only need one. Also you clearly have to learn the pattern to be able to use it
effectively, which is an overhead.

MVC also suffers from the same problem that all eventing mechanisms have: it can be hard to
debug. When the Model fires an event saying it has changed it may not be immediately obvious
where this event is being sunk, and finding out in order to debug the code may be tricky.

However, the biggest problem with MVC is that it doesn‟t actually solve all of the issues
involved in the original problem described in this article. There are multiple reasons why we
might have too much code behind our screens, and for some of these it‟s not clear how MVC
helps us. For this we may need a slightly different pattern, which might be the Model-View-
Presenter pattern the SCSF gives us.

This will be discussed at greater length in part 23 of this series of articles.


P a g e | 104

23. Model – View – Presenter

Introduction

Part 22 of this series of articles looked at the Model-View-Controller pattern and discussed how
it is one way of structuring a user interface to avoid having too much code behind a screen.

This article will examine some of the shortcomings of Model-View-Controller, and describe an
alternative, which is Model-View-Presenter.

Part 24 of this series of articles will then briefly examine some variations on the basic Model-
View-Presenter pattern described here, and look at the advantages and disadvantages of the
pattern.

Part 25 of this series of articles will look at the support that CAB/SCSF gives us for the Model-
View-Presenter pattern.

Model-View-Controller Problems

There are a couple of user interface scenarios that are difficult to handle with the Model-View-
Controller pattern. The first of these is the one that is most widely cited as a problem with
Model-View-Controller, but in my opinion the second is the more difficult case to deal with, in
spite of the fact that it‟s hardly an unusual scenario:

1. Elements of our screen display depend on complex business logic

The canonical example here is coloring the background of a field in varying colors depending on
the output from some business rule.

For example suppose we are showing daily sales figures for a business. We might want to color
the background of a sales figure green if that figure is more than 10% above the average daily
sales figure for the quarter, and color it red if it‟s more than 15% below the average. Otherwise
we leave the background white.

Model-View-Controller struggles with this scenario. Clearly it involves calculations involving


business logic (averaging the sales figures for the quarter). In the Model-View-Controller pattern
the business logic should go in the Model class. However, the only place we can sensibly put the
coloring logic is in the View when it refreshes itself. We‟ll come back to this below.

Note that we want to be able to enter the daily sales figure and have the background color
change appropriately depending on the new value.

2. Elements of our screen display depend on what the user has selected in other screen
components in a complex way
P a g e | 105

This could be as simple as a Save button being enabled only if the user has actually changed
something on the screen (and being disabled again if the user changes the screen back to its
original values).

Again the only place we can logically put this sort of logic in the Model-View-Controller pattern
is in the View when it refreshes itself.

Whilst these problems are slightly different they can both be thought of as complex view logic
surrounding the state of the user interface.

Why is Putting View Logic in the View a Problem?

In both of the examples above there probably isn‟t all that much code relating to our view logic,
and maybe putting it in the View in a Model-View-Controller pattern will be fine. However, with
complicated screens this „view logic‟ can run to many hundreds of lines of code. We don‟t really
want this code in our View, which we want to just be simple screen drawing code. Part of the
idea of splitting out the View, after all, is that it becomes so simple we can easily replace it if we
want to change our screen technology.

Another problem with having this logic in the View is that the event model may get quite
complex. In my example it‟s possible that a change in a sales figure that we‟re not actually
displaying could affect the background color of the textbox. Remember that we are comparing
the textbox contents to the average daily sales. If the average daily sales change sufficiently we
may need to raise an event to force a color change.

There‟s another reason why developers prefer to get this „view logic‟ out of the actual View
class. It can be hard to automatically unit test a View class. Screen widgets often don‟t lend
themselves to unit testing. If the view logic is in another class it may be easier to unit test it.

Aside on Unit Testing in User Interfaces

I think the difficulties of unit testing user interfaces in Microsoft world are hugely exaggerated.
Most Microsoft controls will let you do programmatically almost anything you can do with a
mouse and keyboard. So, for example, we have a PerformClick method on a button, and settable
SelectedIndex and SelectedItem properties on a ListBox. We can instantiate our screen in the test
and interact with it programmatically in the same way we would if we were clicking on things.
We have extensive unit tests that work this way in our current project.

It‟s true that interactions between controls can be difficult to test (e.g. drag-drop operations).
Also third-party (non-Microsoft) controls often don‟t expose mouse and keyboard actions in the
same way. However, in general you can usually unit test a user interface fairly extensively
without recourse to restructuring your code as outlined in this article.
P a g e | 106

The Presenter in Model-View-Presenter

The first thing to understand about Model-View-Presenter is that it is very similar to Model-
View-Controller, only with the Controller replaced with a Presenter (predictably).

The idea of the Presenter is that it can update the View directly. This isn‟t permitted for a
Controller in Model-View-Controller. This means we can put our complex „view logic‟
described above into the Presenter and take it out of the View. Clearly we couldn‟t do this with
the Controller in Model-View-Controller since it had no easy way of updating the View with the
results of the view logic: the View updated itself from the Model and the Controller was not
involved.

Note that the Presenter, as with the Controller in Model-View-Controller, handles user events
raised from the View as well. This means the View only contains screen drawing logic, which is
what we want.

So a Presenter is able to „present‟ data: it can directly update the View. On the other hand a
Controller only controls: it takes user input and updates the Model as appropriate. Note that the
Presenter is doing some controlling as well since it handles user events.

Diagram of Model-View-Presenter

Diagrammatically this looks as below:

As you can see, we again have three classes that interact. As with Model-View-Controller the
Model class contains the data to be displayed, and the View class contains the code that actually
draws the screen. We have already discussed the Presenter.

As with Model-View-Controller we can have multiple Presenter/View pairs of classes interacting


with the same Model (with a change entered on one screen updating other screens showing the
same data).
P a g e | 107

Class Interaction (active Model-View-Presenter with an active View)

When a user interacts with the View an event will be raised. This will be passed immediately to
the Presenter (A). The Presenter will update the Model as appropriate (B): it may go back to the
View to get the data it needs (F). The Model may at this stage raise an event that gets sunk in the
View (C), leading to the View updating itself from the Model (D).

So far everything is the same as in active Model-View-Controller (except with the Controller
replaced with the Presenter).

The difference is that when the Model is updated by the Presenter it may raise an event that also
gets sunk back in the Presenter itself (E). The Presenter may then apply the complex view logic
to work out what needs to be displayed before updating the View (F).

So in this version of Model-View-Presenter the View can update itself directly from the Model
in simple cases where there is no view logic. When some view logic is needed the Presenter
intervenes. It handles that logic and updates the View directly.

Interface on the View (F)

Another point to note here is that the Presenter accesses and updates the View through a clearly-
defined interface on the View (F in the diagram). This has two effects. Firstly we can replace the
View more easily with another screen technology since we know exactly what methods need to
be exposed (those in the interface). Secondly this makes automated unit testing simpler. We can
test the Presenter without needing screen elements directly by mocking the interface on the View
in another class.
P a g e | 108

24. Model – View – Presenter

Introduction

Part 23 of this series of articles described the basic Model-View-Presenter pattern (MVP).

This article examines the Model-View-Presenter pattern in more detail. It describes some
variations on the basic pattern, and looks at the advantages and disadvantages of using the
pattern.

Part 25 of this series of articles will examine how the Model-View-Controller pattern is
implemented in the Smart Client Software Factory (SCSF).

Can the View Update Itself? Active View versus Passive View

The version of Model-View-Presenter described in part 23 has an „active View‟. This means that
the View can update itself directly from the Model (arrows C and D on the diagram in the
article). As described in part 23, the View can also be updated by the Presenter.

An alternative to this is what Martin Fowler calls the „passive View‟. Here the View cannot
update itself directly from the Model. The only way the View can be updated is via the
Presenter. This is the pattern that the Microsoft SCSF documentation describes as Model-View-
Presenter.

Diagrammatically this looks as below. It‟s identical to the diagram in part 23 except that there
are no arrows between the Model and the View:

The passive View design leads to more code in the Presenter and more code in general as the
View now has to expose everything that can be updated on its interface, and the Presenter has to
P a g e | 109

be coded to update it appropriately. However, this is arguably a less complicated design than the
original active View in part 23.

Does the View Update Automatically? Active Model-View-Presenter versus Passive Model-
View-Presenter

As with Model-View-Controller we have a distinction between an „active‟ and a „passive‟ design


overall (see the section „Active and Passive MVC‟ in part 22). Model-View-Presenter as
described above in part 23 is „active‟ Model-View-Presenter. This means that if the Model
changes all Views will be updated automatically via the eventing mechanism. These events may
be sunk in the Presenter or the View.

It is also possible to set up „passive‟ Model-View-Presenter. This is a slightly simpler pattern


where the Model does not raise an event when it changes. This means the View is not updated
„automatically‟. Instead the View is updated when the user next requests it (by pressing a
„Refresh‟ button for instance). At this time either the View or the Presenter will go to the Model
to get the new data.

Advantages of Model-View-Presenter

As with Model-View-Controller, Model-View-Presenter has the advantage that it clarifies the


structure of our user interface code and can make it easier to maintain. Not only do we have our
data taken out of the View and put into the Model, but also almost all complex screen logic will
now reside in the Presenter.

This solves the problems with more traditional user interface designs as described in the last few
articles. However, it comes at the cost of some complexity.

Since we now have almost no code in our View apart from screen drawing code Model-View-
Presenter also makes it theoretically much easier to replace user interface components (user
controls, whole screens, or even the whole user interface (Windows Forms to WPF for
example)).

In addition unit testing the user interface becomes much easier as we can test the logic by just
testing the Presenter. However see part 23 for some comments on whether this is strictly
necessary.

Disadvantages of Model-View-Presenter

The disadvantages of Model-View-Presenter are similar to the disadvantages of Model-View-


Controller as described in part 22:

The pattern is complex and may be unnecessary for simple screens.


The pattern is one more thing to learn for busy developers: there‟s some overhead.
It can be hard to debug events being fired in active Model-View-Presenter.
P a g e | 110

The „Passive View‟ version of Model-View-Presenter can lead to a certain amount of


boilerplate code having to be written to get the interface into the View to work.

My personal view is that even if you think this is a useful pattern (and it is) you shouldn‟t use it
indiscriminately on every screen in your application. You should use it where you have
reasonably complex logic which will benefit from splitting the user interface classes in this way.

User Events and View Logic Combined in the Presenter

One thing that seems a bit odd with Model-View-Presenter is that we have factored both the
responses to user input events and what I‟m calling the „complex view logic‟ into our Presenter.
At first glance these seem to be slightly different things: perhaps we should have separate classes
for each? Perhaps we need a Presenter and a Controller?

One reason for not doing this is that our user interface is getting very complicated if we have
both Presenter and Controller.

Also, in the passive version of Model-View-Presenter we may want the user event itself to call
the complex view logic and to directly update the View. This means that the code to handle the
user event also needs to contain the view logic. It can‟t do this if we have separate classes for the
two pieces of functionality. In this case it makes more sense if we only have one class.

However, splitting the Presenter into two classes may be a valid pattern in active Model-View-
Presenter. Here the Model will be updated in response to a user event by the Presenter. The
Model will then raise an event to the Presenters telling them to update the View for complex
view logic. The user event and complex view logic are thus separate in the Presenter and could
be split into separate classes. We would probably only want to do this in very complex screens.

Model-View-Controller and Model-View-Presenter Confusion

As Martin Fowler points out, there‟s a lot of confusion over what Model-View-Controller is. As
already discussed, this arises because it doesn‟t really apply to modern user interface
programming languages in its purest Smalltalk form.

Equally there seems to be a lot of confusion over what Model-View-Presenter is. Martin Fowler
currently calls the basic MVP pattern that I describe in part 23 „Supervising Controller‟. He calls
the amended version presented in this article „Passive View‟ (as does this article).

I‟m not quite sure why Mr Fowler calls the basic Model-View-Presenter pattern „Supervising
Controller‟ and not „Supervising Presenter‟. It seems to me that the key difference between
Model-View-Controller and Model-View-Presenter is that the Presenter in Model-View-
Presenter can update the View directly. This is not permitted in Model-View-Controller; here the
View updates itself from the Model. In the „Supervising Controller‟ the Presenter/Controller can
update the View directly.
P a g e | 111

Having said that I‟m not sure that Mr Fowler would recognize the pattern described in part 22 as
Model-View-Controller: this is closer to Model-View-Presenter as he describes it. As I mention
in part 22 the pattern described is not „pure‟ Model-View-Controller because the user events are
initially sunk in the View (which is normal with modern UI widgets) and because there‟s only
one Controller and View per screen, rather than one per widget as in pure Model-View-
Controller.

Finally note that I have adopted the „Passive View‟ nomenclature in this article. However
personally I think calling this pattern „Passive View‟ adds to the confusion surrounding Model-
View-Presenter. We already have the concept of active/passive Model-View-Controller and
Model-View-Presenter as a whole, „active‟ being the case where all Views get updated
automatically on a change in the Model, „passive‟ being where they have to update themselves.
This is easily confused with an active/passive View distinction. Here an „active‟ View is one that
can update itself from the Model, whether automatically or not.
P a g e | 112

25. Model – View – Presenter using the Smart Client Software Factory

Introduction

Part 23 and part 24 of this series of articles described the Model-View-Presenter pattern.

This article explains how the Smart Client Software Factory supports this pattern by generating
appropriate classes.

Guidance Automation Packages in the Smart Client Software Factory

We saw how we could use the Smart Client Application Guidance Automation Package to set up
a Smart Client Application in part 18. We can also set up a Model-View-Presenter pattern in a
Smart Client application using another of the Guidance Automation Packages.

This will only work in an existing Smart Client Application.

Running the Model-View-Presenter Package

To use the Guidance Automation Package we right-click in Solution Explorer on a project or


folder where we want to run the package. It is intended that we do this in the Views folder in a
business module. On the right-click menu we select „Smart Client Factory/Add View (with
presenter)‟. We get a configuration screen that lets us name our view, and also lets us put the
classes that get created into a folder. For the purposes of this example we name our view „Test‟,
and check the checkbox that says we do want to create a folder for the view.

When we click „Finish‟ we get three classes and a TestView folder as below:
P a g e | 113

Classes Created

1. TestView
This is (obviously) our View class. It is intended that this contain the auto-generated code
to display the View. As discussed in the previous articles any complex view logic will not
go into this class, but will go into the Presenter.
2. TestViewPresenter
This is our Presenter class. As discussed in previous articles this should contain logic to
deal with user events. It should also contain any complex view logic, and should directly
update the View with the results of an view logic calculations. It has access to the View
class via an interface.
3. ITestView
This is the interface that the View implements. The Presenter can only update the View
through this interface.

Diagram

In terms of the diagrams shown in parts 23 and 24 this looks as below. Remember that we may
or may not have arrows between the Model and the View depending on whether we are using the
active View or passive View version of Model-View-Presenter:

Where’s the Model?

The Guidance Automation package does not set up a Model class for us. As we have seen, the
Model has no direct references to a View/Presenter pair (it raises events), and there may be
multiple View/Presenter pairs for one Model. Further the Model would not usually be in the
same folder, or even in the same component, as our View and Presenter.

For these reasons we are expected to set up our Model classes separately by hand.

Note that the Presenter (and the View as well if we are using the active View pattern) will have a
direct reference to the Model. We will have to add these references manually.
P a g e | 114

Active and Passive View: a Quick Recap

Remember that in Model-View-Presenter the Presenter updates the View via an interface. We
can set this up so only the Presenter is allowed to update the View. This is the „passive View‟
pattern. We can also set this up so that the Presenter can update the View in complex cases, but
the View can also update itself (in response to an event or user request) in simple cases. This is
the „active View‟ pattern.

Active and Passive View: Which Should We Use?

The pattern described in the SCSF documentation is the passive View: the documentation
implies that all updates to the View should be done by the Presenter.

However there is nothing to stop us using the active View pattern with the classes generated by
the Guidance Automation Package. We can add code to update the View wherever we like. In
fact I would recommend using active View in simple cases: passive View should only be used
where we are putting too much logic into the View class.

Should We Use Model-View-Presenter for Every Screen? A Personal View

Let me also reiterate a point made in part 24. It‟s easy to get obsessive about the use of patterns
and use them everywhere without thinking. My personal opinion is that we should only use the
full Model-View-Presenter pattern where we have a complex screen that will benefit from the
separation of the View and Presenter classes. For very basic screens the pattern is really too
complex to give us benefit. In simple cases I think it is fine to put event handling and screen
update logic directly behind the screen.

Note that I don‟t think this applies to the use of the Model. We should always separate out the
business logic from our screens into separate classes (this is what Martin Fowler calls „Separated
Presentation‟). However, we frequently have screens that don‟t show any business logic or
business data, so we may not need a Model class either.

For example an About screen that just shows the system name and version won‟t need separate
View and Presenter classes, and probably won‟t need anything in a Model class either.

Equally a screen that shows a read-only grid of currencies used in a trading system probably
doesn‟t need separate View and Presenter classes. In this case the currencies themselves should
be in a Model class so that other screens can access them.

Implementation Details: What We’d Expect

If we examine the diagram above, we expect the Presenter to have a data member with type of
our ITestView interface that it will use to access the View. We expect the View to implement the
ITestView interface to allow this. We further expect the View to have a direct reference to the
Presenter class (a data member), which it will use to invoke code relating to user events. We‟d
P a g e | 115

probably expect both the View and the Presenter classes to be created the first time the View is
needed.

Implementation Details: the Base Presenter Class

The actual details of the implementation of the Presenter are a little unusual.

If we look at the code generated by the Guidance Automation Package we see that the
TestViewPresenter above has been given its core functionality by inheriting from an abstract
Presenter<TView> class. Remember that the generic „TView‟ simply lets us provide a type
whenever we use the Presenter class. Here we inherit from Presenter, and provide the type when
we inherit:

public partial class TestViewPresenter : Presenter<ITestView>


{

This allows the base Presenter class to have a data member of type ITestView (which is what we
expect), rather than it being directly in the TestViewPresenter class. Note that the base Presenter
is in the Infrastructure.Interface project (which is one of the reasons why we have to use this
pattern in a Smart Client application).

The base Presenter class exposes our ITestView data member publicly, contains a reference to
our WorkItem, and has disposal code and a CloseView method. It also has virtual OnViewReady
and OnViewSet methods. These get called when you‟d expect from the name and let us respond
at the appropriate times by overriding the methods in our TestViewPresenter class.

All the above functionality in the base Presenter class means that the derived TestViewPresenter
class is basically empty when it is created. It is up to us to put logic in there to handle user events
and complex view logic.

The TestView class is a normal user control. It implements ITestView and contains a reference
to the TestViewPresenter as we‟d expect. It also calls OnViewReady as appropriate (in the
OnLoad event of the user control). Again other than this TestView is also basically empty.

Das könnte Ihnen auch gefallen