Click here to Skip to main content
15,885,366 members
Articles / Web Development / ASP.NET

Dockable CAB Workspaces

Rate me:
Please Sign up or sign in to vote.
3.89/5 (26 votes)
11 Mar 2006CPOL5 min read 119K   1.4K   69   25
Custom Workspaces for the CompositeUI Application Block using DivElements SandDock controls

Prerequisites

The code covered in this article uses a proprietary control suite from DivElements. You must purchase a license to use the DivElements product or download a 30-day evaluation copy to run the code. You can download SandDock at http://www.divelements.com/.

Introduction

The CompositeUI Application Block (CAB) is the latest offering from Microsoft to aid developers in creating extensible, modular, pluggable applications. If you’re not familiar with CAB, I strongly suggest you stop reading this article and cruise over to MSDN and read through some of the documentation available there. There are also a number of hands on labs that will help you understand what the CAB is all about.

There are a lot of features offered by this application block. I have spent the last three weeks looking over it and am just barely beginning to put the pieces together. The portion of the block covered in this article is Workspaces. The graphics below show my DockableWindowWorkspace and TabbedDocumentWorkspace in action.

[Docking Hints]

[Side By Side]

Workspaces for Dummies

I don't claim to fully understand the concepts behind the CompositeUI Application Block, but here is my sixty second summary of what Workspaces are and how you use them. The Workspace acts as a container for the SmartPart views exposed by your WorkItems. The CAB comes with several built in Workspaces for showing SmartParts in Windows, TabControls, Zones, and Decks. The WindowWorkspace shows each SmartPart in its own Window. The TabWorkspace shows each SmartPart in its own TabPage. If you are wondering what a SmartPart and WorkItem are, that is a pretty good sign you need to go through the CAB hands on labs before reading the rest of this article.

The design of the application block allows a developer to change a Workspace without breaking the application. This leads to the concept of a "shell" application. The shell application provides one or more Workspaces and allows dynamically loaded modules to display WorkItems in those Workspaces. The shell application can be modified to completely change the way a user interacts with WorkItems. I will be demonstrating this concept by modifying one of the hands on lab samples to use my custom Workspaces.

Microsoft has made it fairly painless and straight forward to create custom Workspaces. One of the hands on labs walks you through creating a custom Workspace using a TreeView control. My custom workspaces were created based on the WindowWorkspace included in the CAB source download.

Workspace Design

Both the DockableWindowWorkspace and the TabbedDocumentWorkspace must be constructed with an existing SandDockManager. Those of you who have used the SandDock controls from DivElements will be familiar with the SandDockManager. The SandDock controls allow you to create an interface similar to that provided by Visual Studio, complete with pinnable/collapsible windows that can be rearranged by the user. See the screen shots below for an example of such a UI.

[Sidebar on Left]

[Sidebar Collapsed]

The SandDockManager is a component that must be added to your shell application form. The code below from BankShellForm.cs shows the creation of the custom Workspaces, passing the SandDockManager previously added to the form.

C#
[InjectionConstructor]
public BankShellForm(WorkItem workItem, 
                     IWorkItemTypeCatalogService workItemTypeCatalog)
  : this()
{
  this.workItem = workItem;
  this.workItemTypeCatalog = workItemTypeCatalog;

  /// ADDED
  this.sideBarWorkspace = new DockableWindowWorkspace(this.sandDockManager);
  this.contentWorkspace = new TabbedDocumentWorkspace(this.sandDockManager);
  this.workItem.Workspaces.Add(sideBarWorkspace, "sideBarWorkspace");
  this.workItem.Workspaces.Add(contentWorkspace, "contentWorkspace");
  ///
}

Internally, the SandDockManager does most of the work for us; the custom Workspaces are just wrappers around the SandDockManager that implement the IWorkspace interface.

IWorkspace exposes methods for showing, hiding, activating, and closing SmartParts. The custom Workspaces simply show, hide, activate, and close either a DockableWindow or a TabbedDocument associated with the SmartPart.

Persisting Layouts

The SandDock controls support the concept of persisting their layout between instances of the application. This means that if your savvy users decide to take time rearranging their Workspace windows and tabs to their liking, the SandDockManager will create an XML file that can be saved to the users' disk and loaded the next time they launch the application. The code below from BankShell.cs is a quick and dirty implementation that saves/loads the SandDock layout to a file called SandDockLayout.txt located in the same directory as the application executable.

C#
/// ADDED
private string _ReadLayout()
{
  using (FileStream fs = System.IO.File.Open("SandDockLayout.txt",
    FileMode.OpenOrCreate, FileAccess.Read))
  {
    using (StreamReader sr = new StreamReader(fs))
    {
      return sr.ReadToEnd();
    }
  }
}

private void _WriteLayout(string layout)
{
  using( FileStream fs = System.IO.File.Open("SandDockLayout.txt",
    FileMode.Create, FileAccess.Write))
  {
    using (StreamWriter sw = new StreamWriter(fs))
    {
      sw.Write(layout);
    }
  }
}

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
  base.OnClosing(e);
  if (!e.Cancel)
  {
    _WriteLayout(this.sandDockManager.GetLayout());
  }
}
///

protected override void OnLoad(EventArgs e)
{
  //. . .

  /// ADDED
  string layout = _ReadLayout();
  if (!String.IsNullOrEmpty(layout))
  {
    try
    {
      this.sandDockManager.SetLayout(layout);
    }
    catch { }
  }
  ///
}

This is a great feature to take advantage of but may prove difficult for WorkItems that are loaded dynamically. To help you implement this feature in your applications, I created the IDockableSmartPart interface that you can use to mark your SmartParts that will persists their layout.

IDockableSmartPart

Implementers simply define a Guid for their SmartPart that will be used by the SandDockManager to identify the location and layout of the SmartPart between uses of the applications. See the example code below from SideBarView.cs:

C#
public partial class SideBarView : UserControl, IDockableSmartPart
{
  private static readonly Guid dspGuid = 
    new Guid("{B69E82F9-5FA2-4309-8FC0-0F421D12F0EB}");
  
  //. . .
  
  Guid IDockableSmartPart.Guid
  {
    get { return dspGuid; }
  }
}

You can test the BankTeller application by running the application, moving the SideBarView to the right side of the screen, close the application, then re-open the application. The SideBarView should be displayed on the right side of the screen now. Wherever you put the SideBarView, it should be remembered and reloaded in the correct location each time.

[Sidebar on Left]

[Sidebar on Right]

You can use the built in State and IStatePersistanceProviders for your WorkItems to remember their Guids between uses, and pass those Guids to your IDockableSmartParts so they will be loaded and arranged properly by the custom Workspaces.

Unit Testing

I pilfered the unit tests for the TabWorkspace and WindowWorkspace that come with the CompositeUI Application Block source code and modified them to suit my needs. If you have nUnit installed on your machine, you can run the GUI interface on the WCPierce.Practices.CompositeUI.WinForms.Test assembly and see all of the pretty green lights. I added very little to the existing tests so I would say the DockableWindowWorkspace and TabbedDocumentWorkspace have about 90% of their features covered by the unit tests.

(UPDATED: alexsantos posted the code to correct this problem. Use the download link above for the new code). One problem I ran into with the TabbedDocumentWorkspace was properly setting focus to sibling tabs when an existing tab was closed. Those of you with greater experience using the SandDock controls may be able to solve this. If anyone comes up with a valid solution, please let me know and I will incorporate it into the Workspaces.

Conclusion

I do want to make it perfectly clear that the code download does not include a dockable/pinnable windowing framework. That amazing functionality is provided by the SandDock controls from DivElements. The code download does include a nice little wrapper that, when coupled with the amazing work done by the Microsoft Patterns & Practices team, will allow you to create highly dynamic and customizable applications in a modular fashion.

I greatly appreciate comments, ratings, feedback, etc. So if you found this article helpful, or you think it stinks, please let me know via the comments section below.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionPort to SCSF? Pin
mdulfer16-Sep-07 15:53
mdulfer16-Sep-07 15:53 
GeneralWel done Pin
Moim Hossain17-Jun-07 23:23
Moim Hossain17-Jun-07 23:23 
GeneralYou saved my life. Pin
Nigel Shaw25-Oct-06 11:57
Nigel Shaw25-Oct-06 11:57 
I have to produce exactly this for tomorrow. You saved my life man. Thanks!

Nigel

GeneralProblem with List Separator Pin
Boban Stojanovski13-Oct-06 4:47
Boban Stojanovski13-Oct-06 4:47 
GeneralRe: Problem with List Separator Pin
Boban Stojanovski16-Oct-06 1:37
Boban Stojanovski16-Oct-06 1:37 
GeneralTabbing dockable windows in side bar Pin
henning@moeller-mingers.de2-Sep-06 1:16
henning@moeller-mingers.de2-Sep-06 1:16 
GeneralHide Smartpart doesnt work [modified] Pin
Manjit Sooch6-Jul-06 5:45
Manjit Sooch6-Jul-06 5:45 
GeneralTabbedDocument and DockableWindow Workspace Close problem Pin
fewfewfewfgwew19-Apr-06 2:56
fewfewfewfgwew19-Apr-06 2:56 
AnswerRe: TabbedDocument and DockableWindow Workspace Close problem Pin
henning@moeller-mingers.de20-Jun-06 22:35
henning@moeller-mingers.de20-Jun-06 22:35 
GeneralRe: TabbedDocument and DockableWindow Workspace Close problem Pin
Bill Pierce6-Jul-06 7:55
Bill Pierce6-Jul-06 7:55 
GeneralRe: TabbedDocument and DockableWindow Workspace Close problem Pin
3choBoomer29-Nov-06 14:26
3choBoomer29-Nov-06 14:26 
GeneralRe: TabbedDocument and DockableWindow Workspace Close problem Pin
3choBoomer29-Nov-06 14:38
3choBoomer29-Nov-06 14:38 
QuestionThanks for anything on CompositUI... DockingPanel? Pin
kennster28-Mar-06 9:40
kennster28-Mar-06 9:40 
AnswerRe: Thanks for anything on CompositUI... DockingPanel? Pin
fewfewfewfgwew4-Apr-06 7:16
fewfewfewfgwew4-Apr-06 7:16 
GeneralRe: Thanks for anything on CompositUI... DockingPanel? Pin
kennster4-Apr-06 10:56
kennster4-Apr-06 10:56 
AnswerRe: Thanks for anything on CompositUI... DockingPanel? Pin
zhiyangxu26-Jul-07 17:09
zhiyangxu26-Jul-07 17:09 
AnswerRe: Thanks for anything on CompositUI... DockingPanel? Pin
zhiyangxu8-Nov-07 16:26
zhiyangxu8-Nov-07 16:26 
GeneralSmall casting fix in DockableWindowWorkspace Pin
nedz16-Mar-06 23:46
nedz16-Mar-06 23:46 
GeneralExcellent Work Pin
Orcrist11-Mar-06 8:11
Orcrist11-Mar-06 8:11 
GeneralChanges to pass all Nunit tests Pin
alexsantos9-Mar-06 15:13
alexsantos9-Mar-06 15:13 
GeneralRe: Changes to pass all Nunit tests Pin
Bill Pierce11-Mar-06 5:08
Bill Pierce11-Mar-06 5:08 
GeneralRe: Changes to pass all Nunit tests Pin
alexsantos12-Mar-06 14:22
alexsantos12-Mar-06 14:22 
GeneralGeneral Thoughts Pin
Orcrist15-Feb-06 6:54
Orcrist15-Feb-06 6:54 
GeneralPosting in wrong section Pin
Orcrist15-Feb-06 6:29
Orcrist15-Feb-06 6:29 
GeneralRe: Posting in wrong section Pin
Bill Pierce15-Feb-06 6:59
Bill Pierce15-Feb-06 6:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.