Archive for the ‘CAB’ Category

CAB comes with a default implementation for handling state called the State bag. However, it’s not a particularly good implementation. Part of the problem with the CAB state bag is that it’s not strongly typed; it’s basically a glorified Dictionary. When you retrieve an object from the State bag you do this:

Employee employee = (Employee)State["SomeKey"];

Since I started using CAB, I’ve avoided using the CAB State bag. I remember a hallway chat with Brad Wilson during last year’s Patterns & Practices Summit, where Brad basically said, “Yeah, we wish we would have had time to remove the State bag from CAB before it shipped, but the schedule didn’t allow it.” Brad’s advice was to roll our own State service if we wanted to handle state.

For a while, our shop functioned without a State service and without relying on the State bag. One solution we initially tried was to dump objects into the WorkItem’s Item collection. This is not much better than the State bag, but it does have the advantage of being typed. However, it makes unit testing a pain because now your Presenter class is dependent on having a WorkItem injected into it for unit testing purposes. I don’t like those sorts of dependencies when I unit test – I like to test classes in bare isolation with mocks.

A second solution we used was to simply hold on to objects via private member variables in Presenter classes:

public class SomeViewPresenter : Presenter
{
   private Employee _employee;
   private IPayrollService _payrollService; 

   [InjectionConstructor]
   public SomeViewPresenter([ServiceDependency] IPayrollService payrollService)
   {
      _payrollService = payrollService;
   }

   [EventSubscription(EventTopicNames.LoadEmployee, ThreadOption.UserInterface)]
   public void LoadEmployee(object sender, EventArgs e)
   {
      _employee = _payrollService.GetEmployee(e.Data);
   }
}

This is simple, but creates its own pain during testing. When you use private member variables to hold on to references to objects, you have to ensure that whatever method in your Presenter is responsible for fetching the business object from its source (like LoadEmployee) must be called prior to calling the method you’re really interested during testing, because you have to be able to load the private variable with an actual object. This is awkward, to say the least. Not to mention that it precludes us from doing any sort of sophisticated state management, like undo/reset.

For testing purposes, wouldn’t it be better if we could just call the method we’re really interested in testing, and not have to initialize or load the Presenter? And isn’t maintaining model state outside the scope of the Presenter anyway? It’s job is coordination, not state management.

To solve these problems I gravitated toward the creation of an IStateService and an ApplicationClosingEventHandler delegate. The interface and delegate are listed below:

public delegate bool ApplicationClosingEventHandler(IList unsavedChangesNotification);

public interface IStateService
{
   void SetState(string key, object obj);
   T GetState(string key);
   T Undo(string key);
   bool Remove(string key);
   bool ContainsKey(string key);
   bool HasUnsavedChanges();
   IList UnsavedChangesNotifications { get;}

   event ApplicationClosingEventHandler ApplicationClosing;
}

The implementation is as follows:

public class StateService : IStateService
{
   protected IDictionary _state = new Dictionary();
   protected IList _unsavedChangesNotifications;

   public virtual void SetState(string key, object obj)
   {
      if (_state.ContainsKey(key))
      {
         throw new ArgumentException("An item with the same key has already been added to the StateService.");
      }
      else
      {
         using (MemoryStream buffer = new MemoryStream())
         {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(buffer, obj);
            Memento memento = new Memento(obj, buffer.ToArray());
             _state.Add(key, memento);
         }
      }
   }

   public virtual T GetState(string key)
   {
      return (T)_state[key].Item;
   }

   public virtual bool ContainsKey(string key)
   {
      return _state.ContainsKey(key);
   }

   public virtual bool Remove(string key)
   {
      return _state.Remove(key);
   }

   public virtual T Undo(string key)
   {
      T obj;

      using (MemoryStream buffer = new MemoryStream(_state[key].ByteArray))
      {
         buffer.Position = 0;
         BinaryFormatter formatter = new BinaryFormatter();
         obj = (T)formatter.Deserialize(buffer);
      }

       _state[key].Item = obj;
      return obj;
   }

   public virtual event ApplicationClosingEventHandler ApplicationClosing;

   public virtual bool HasUnsavedChanges()
   {
      _unsavedChangesNotifications = new List();
      bool hasUnsavedChanges = false;

      if (ApplicationClosing != null)
      {
         foreach (ApplicationClosingEventHandler handler in ApplicationClosing.GetInvocationList())
         {
            bool result = handler.Invoke(_unsavedChangesNotifications);

            if (result)
               hasUnsavedChanges = true;
          }
      }

      return hasUnsavedChanges;
   }

   public virtual IList UnsavedChangesNotifications
   {
      get { return _unsavedChangesNotifications; }
   }
}

The StateService has two main parts: state management and gathering unsaved changes notification. The first part, the state management, works similar to the Memento pattern you’d find in GoF. There’s a SetState, GetState and Undo (Reset), which will place your object back into the state it was in when you last called SetState. This is not n-level undo: it’s just 1-level undo because that’s all we need right now. But you could tweak it to support n-level undo pretty easy I think.

The StateService achieves the 1-level undo by taking a “snapshot” of the object when SetState is called. It then serializes the object to a binary stream and stores it, along with a reference to the actual object, in a “memento” class (not a true Memento pattern as you would see in GoF because we don’t ask objects to provide their own mementos, but the idea is similar). Of course, since it uses serialization it expects your objects to be Serializable. If you didn’t want that, you’d have to provide a different implementation. But since most objects that require state management are probably serializable already, this seems a logical fit.

The second part of the StateService is gathering unsaved change notification. Now, you may wonder: why do we need the delegate when we could just iterate through the list of objects we’re already holding in the StateService, and if they inherit from some base class (which ours do) then we could just cast them to the base class and check a “dirty” flag and know if there were objects in an unsaved state. But we added the delegate because we wanted interested classes (Presenters/Controllers) in our application to be able to return a message telling the user where those unsaved changes are located within the UI, so the user can quickly find them and make the necessary saves. You might think this is overkill or unnecessary, but you haven’t had to write code for our users :)

Thus, the StateService publishes an ApplicationClosing event which interested controllers/presenters in the UI layer can subscribe to. When the user goes to shut down the application we listen for that event (at the Shell level) and ask the StateService if it has any unsaved changes. The StateService queries all it’s listeners and if there are any unsaved changes then we can halt the application from closing and throw up a MessageBox with the list of messages from the event handler.

So why all the fuss with the service? The advantage here is that the StateService can easily be mocked via a tool like RhinoMocks. State management now becomes the responsibility of the StateService, and not the Presenter. We’re able to separate those concerns, which helps us focus on testing the real responsibilities of the Presenter, which is typically coordination between the model and the view.

It’s not the most awesome solution, I’m sure, but it serves our needs. And since this is a topic that continues to crop up in CAB circles, I thought I’d post our way of doing things.

One of the cool things about being a software developer is the chance to learn something new every day, even if it’s something small. I always get a little rush when I discover something I didn’t previously know.

The other day I was refactoring some code and ran up against an interesting bug. A WorkItem that I had created for a Use Case was responsible for creating several views in a DockWorkspace, and then exposing that view to another other WorkItem that wanted to create and use it, so that it could be shown in a WindowWorkspace, for example.

But a WindowWorkspace can be a tricky bugger; if the user clicks the Close button (“X”) in the upper right hand corner, the Form closes and disposes of the view.

Well… sometimes.

The WorkItem I created was wired-up to the view’s Disposing event to see when it was being disposed. Because when the view was disposed, the WorkItem was then in an invalid state – it’s fairly useless without the view – and in that case, I simply wanted the WorkItem to terminate, because it meant the user had clicked the “X” and closed that particular Use Case.

This WorkItem was used in two locations. In one location the WorkItem was created and it’s main view shown in a WindowWorkspace. When the user clicked the “X” button to close the Form, the WorkItem caught the Disposing event and Terminated correctly. The user could then re-open that WorkItem.

In another location, similar code (so it seemed) was doing the same job: creating the WorKItem and showing its view in a WindowWorkspace. But when the user clicked the “X” to close the Form, the view didn’t get Disposed and the WorkItem didn’t Terminate. When the user when to re-open that WorkItem the application would throw an exception because it already existed in the WorkItem collection hierarchy. This was unexpected.

I scratched my head for a few minutes trying to figure out why these two pieces of code that seemed to be using this WorkItem identically were functioning differently. It turned out that in one case, when the WorkItem’s view was shown, it was shown in the WindowWorkspace in a Modal fashion. In the other case, it was shown in a non-modal fashion. Both cases had very good reasons for showing them the way they did, so we couldn’t simply make them both the same. Plus, I wanted to know why I was seeing this behavior…

Upon further digging I found this on MSDN:

When a form is closed, it is disposed, releasing all resources associated with the form. If you cancel this event, the form remains opened.

That is the behavior I expected, and indeed verified with the first case. But then there’s this neat little note:

When a form is displayed as a modal dialog box, clicking the Close button (the button with an X at the upper-right corner of the form) causes the form to be hidden and the DialogResult property to be set to DialogResult.Cancel.

The Form is not Disposed…

Now, obviously this makes perfect sense. When you’re working with traditional Windows Forms you’re used to this behavior because you typically fetch a DialogResult back, and a Disposed object can’t send back a DialogResult. But when you get your mind attuned to the way CAB does things, sometimes, well, you forget :)

Intro to CAB

When Acropolis was announced, quite a few people I chatted with in e-mail and on message boards seemed to want to move away from CAB because they were afraid it would no longer be “maintained” or built upon. Fortunately, the SCSF Contrib Project has been busy steadily adding code and features to CAB. I haven’t had a chance to blog about much of the additions lately (or contribute myself, even though I have plans to add my UIService and WizardWorkspace to the code base), but I have taken notice of a few cool blog posts.

For starters, Rich Newman has put together a pretty darn nice looking Intro to CAB. It is one of the best point-by-point introductions to the CAB framework that I have seen (if a bit lengthy). Rich does a nice job of separating out some of the patterns and ideas (Command, Dependency Injection) from the way CAB implements them. So, if you’re new to the concepts as well as the framework (which many developers are) then you get to digest both the theory and the implementation as separate chunks, which I think is very valuable if you’re trying to learn this stuff for the first time. I highly recommend his site for people new to CAB.

ActionCatalog

The other really cool thing I saw in the last week or so is Bil Simser’s post on Taming the ActionCatalog in SCSF. The ActionCatalog has been a point of confusion for many developers. Here, though, Bil makes everything very clear with a concise explanation and some great code samples. It becomes really easy to see how one would go about utilizing this service to perform role-based UI configuration in a much less intrusive way.

I know for myself, I can’t wait to make use of what Bil outlines. In the application I’m currently working on, we have to do some role-based, permission-based UI configuration. But up to now, because of the limited amount of configuration we’ve had to do, we’ve done it the quick-and-dirty way. The ActionCatalog looks a lot better from where I stand.

So there’s some CAB updates to sink your teeth into.

Savij just blogged about a problem he had with tabbing through a CAB application and invoking logic on a control that was not being shown. This is a problem we ran into as well. He posts his solution here.

Our solution is quite different, so I thought I’d post it as well.

What we do is hook into the SmartPartActivated event for our workspaces. Our intention is to turn off the TabStop for all Controls, and then turn it on for the ActiveSmartPart, as well as set the Focus:

 private void EmployeeEditDeckWorkspace_SmartPartActivated(object sender, WorkspaceEventArgs e)
{
   Utility.FocusWorkspaceView(EmployeeEditDeckWorkspace);
}

The utility is a static class with a method that looks like so:

public static void FocusWorkspaceView(IWorkspace workspace)
{
   foreach(Control control in workspace.SmartParts)
      control.TabStop = false;

   Control smartPart = workspace.ActiveSmartPart as Control;
   smartPart.TabStop = true;
   smartPart.Focus();
}

I think static methods of this type are pretty ugly, but this is more of a short-term solution as well as a way to prevent ourselves from having to write repeating code. A more elegant solution, in my opinion, would be to put this code in the Workspaces themselves and recompile CAB for your solution.

At any rate, I thought I’d show there’s another way to solve this problem. After we hooked into the SmartPartActivated event for our workspaces our tabbing woes vanished.

People have been asking me for this code for a while, so it’s about time I put it up. There are two chunks of code: (a) A sample application to show how I use the service and (b) the UIService project by itself, in case you just want to reference the code in your project and get started.


Source code for the sample application: here


Source code for only UIService: here

Previously I discussed a method for solving the Active View Problem. The Cliff Notes version of the solution goes like this: Give every view a unique identifier, and then when you show that view, use some service to record the fact that is just got shown and is now the “active view”. Subsequent logic in your application can test to see if a particular view is the active view before executing certain code paths.

This is all very convenient for figuring out the active view, but a lot of people were in the dark about how this solution could help them manage the ToolStrip. That’s where the UIService/ToolStripService comes in.

The UIService I’ve implemented contains a sub-service called the ToolStripService. It’s job is to manage ToolStripGroups. ToolStripGroups are simply a way to configure a group of ToolStripButtons under one name. So you can write code like this to create a group and associated the commandHandlers with that group name:


_uiService.ToolStripService.Groups.Add("EmployeeGroup");
_uiService.ToolStripService.Groups["EmployeeGroup"].Commands.Add("SaveEmployee");
_uiService.ToolStripService.Groups["EmployeeGroup"].Commands.Add("UndoEmployeeChanges");

Once you have created all of the groups you wish, you can load them by simply calling the ToolStripService:


_uiService.ToolStripService.LoadGroup("EmployeeGroup");

The ToolStripService takes care of clearing the ToolStrip and loading the appropriate buttons based on the group you’ve previously created.

As far as creating the actual buttons goes, you can also make use of the ToolStripService to perform this function for you. I’ve included a ToolStripItemFactory which the ToolStripService makes use of to create ToolStripItems. If you want to adjust the way your buttons get created (borders, or any other visual aspect) just adjust the factory.

Creating a new ToolStripButton looks like this:



ToolStripItem item = _uiService.ToolStripService.Items.Add(CommandNames.SaveEmployee, "Save", Resources.SaveButton, "Save");
Commands[CommandNames.SaveEmployee].AddInvoker(item, "Click");

Note the second line: you still have to add the invoker to the WorkItem’s Commands collection.

There’s one other key thing you cannot forget to do: you must let the ToolStripService know about the UIExtensionSite otherwise you will get an exception when the service tries to clear the ToolStrip UIExtensionSite. Typically I do this in the ShellApplication class, in the AfterShellCreated override (after I’ve already added the UIService in the ShellApplication’s AddServices override):


protected override void AfterShellCreated()
{
   base.AfterShellCreated();

   RootWorkItem.UIExtensionSites.RegisterSite(UIExtensionSiteNames.MainMenu, Shell.MainMenuStrip);
   RootWorkItem.UIExtensionSites.RegisterSite(UIExtensionSiteNames.MainStatus, Shell.MainStatusStrip);
   RootWorkItem.UIExtensionSites.RegisterSite(UIExtensionSiteNames.MainToolbar, Shell.MainToolbarStrip);

   IUIService uiService = RootWorkItem.Services.Get();
   uiService.ToolStripService.ToolStrip = RootWorkItem.UIExtensionSites[UIExtensionSiteNames.MainToolbar];
}

As always, I hope this snippet of code helps folks out. Let me know if something doesn’t work, or if you find a better way to do something. I’m always excited to see what people are doing with CAB.