Szymon Kobalczyk's Blog

A Developer's Notebook

  Home  |   Contact  |   Syndication    |   Login
  85 Posts | 5 Stories | 175 Comments | 380 Trackbacks

News

View Szymon Kobalczyk's profile on LinkedIn

Twitter












Article Categories

Archives

Post Categories

Image Galleries

Blogs I Read

Tools I Use

It's been over a week since my last post on Composite UI App Block, but don't start thinking I have given up on it already. I still want to finish the PetShop sample and at the same time to cover all important parts of CAB on this blog.

Last time I have covered some basics on using Commands and UI Elements and demonstrated how I implemented commands in my sample application. But as I said before, out of the box CAB only has UIElementAdapters for ToolStrips and MenuStrips. Just to get started I put all my commands on the main menu, but the original PetShop was a web app so this were all links. So it got me thinking what it takes to implement my own UIElementAdapter. For most people support for menus and toolstrip could be enough, but some of us use third-party controls or wants to invoke commands from other controls like trees, or Outlook style navigation bars. I think knowing how to extend CAB to handle such situation can be helpful.

(On the other hand, I heard on ARCast that Infragistics committed to release CAB wrappers for their controls so those of you who use NetAdvantage don't need to read any further).

First thing was to create the control that will display my links and fire events when one is clicked. For this I have extended the standard LinkLabel adding collection of my own LinkListItems. These items are similar to a menu items having Text, Enabled, and Visible properties, and a Click event. The control automatically updates itself based on these settings. Under the hood it constructs a single line from the texts of all visible items inserting bars ( | ) as separators, and it positions a LinkArea on each enabled item. Then upon receiving LinkClicked event it propagates it back to corresponding item and fires its Click event. It took ~200 lines of code but there is nothing fancy so I won't bore you with it here.

Now having the control ready I need to plug it into the CAB framework. There are three additional elements that I need to provide: IUIElementAdapter, IUIElementAdapterFactory, and CommandAdapter.

As explained in last post, UIElement adapter is responsible for properly showing items of given UIElement type. This interface has only two methods: Add and Remove that are called each time items are added or removed from extension site. In my case these methods simply add or remove items from the LinkList items collection:

public class LinkListUIAdapter : UIElementAdapter
{
    LinkList linkList;

    public LinkListUIAdapter(LinkList linkList)
    {
        Guard.ArgumentNotNull(linkList, "linkList");
        this.linkList = linkList;
    }

    protected override LinkListItem Add(LinkListItem uiElement)
    {
        if (linkList == null)
            throw new InvalidOperationException();

        linkList.Items.Add(uiElement);
        return uiElement;
    }

    protected override void Remove(LinkListItem uiElement)
    {
        if (uiElement.Owner != null)
            uiElement.Owner.Items.Remove(uiElement);
    }
}

The role of IUIElementAdapterFactory is to provide appropriate UIElementAdapter instances for given UIElement's type. The Supports method should indicate if particular factory supports the given UI Elements type, and then GetAdapter methods should create adapter for that UI Element.

public class LinkListItemAdapterFactory : IUIElementAdapterFactory
{
    public IUIElementAdapter GetAdapter(object uiElement)
    {
        if (uiElement is LinkList)
            return new LinkListUIAdapter((LinkList)uiElement);

        throw new ArgumentException("uiElement");
    }

    public bool Supports(object uiElement)
    {
        return (uiElement is LinkList);
    }
}

If we want to be able to attach command to the UI Elements we also need to provide a CommandAdapter. It's purpose is to provide logic that is needed for UIElement to invoke a Command, and also to synchronize changes to Command with the UI Element. Luckily for me the first part is handled by the base class EventCommandAdapter, so I only had to make sure that changes to Command status will be applied to the corresponding link:

public class LinkListItemCommandAdapter : EventCommandAdapter
{
    public LinkListItemCommandAdapter()
        : base()
    { }

    public LinkListItemCommandAdapter(LinkListItem item, string eventName)
        : base(item, eventName)
    { }

    protected override void OnCommandChanged(Command command)
    {
        base.OnCommandChanged(command);

        foreach (KeyValuePairstring>> pair in Invokers)
        {
            pair.Key.Enabled = (command.Status == CommandStatus.Enabled);
            pair.Key.Visible = (command.Status != CommandStatus.Unavailable);
        }
    }
}

Having all these three pieces we can now register them in CAB. It should be done in the AfterShellCreated method of the ShellApplication class:

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

    ICommandAdapterMapService mapService = 
        RootWorkItem.Services.Get();
    mapService.Register(typeof(LinkListItem), typeof(LinkListItemCommandAdapter));

    IUIElementAdapterFactoryCatalog catalog = 
        RootWorkItem.Services.Get();
    catalog.RegisterFactory(new LinkListItemAdapterFactory());
}
Finally we have all set up and we are ready to use the new UI Elements. But the best thing it was, that the only change I had to make was to replace references to ToolStripMenuItem with my own LinkListItems like this:
  LinkListItem signInItem = new LinkListItem("SIGN IN");
  UIExtensionSites["NavigationBar"].Add(signInItem);
  Commands["SignIn"].AddInvoker(signInItem, "Click");

All the other code that handles commands and updates their status remains unchanged. And thats the real advantage of CAB!
posted on Sunday, February 05, 2006 7:54 PM

Feedback

# re: Understanding Composite UI Application Block, Part VI 2/7/2006 1:09 AM Alan
Szymon, I'm following your posts on this topic. I think you did a great job to flush out many aspects on the CAB. I'd like to continue my learning on the CAB together with your PetShop example. Thanks.

Alan

# re: Understanding Composite UI Application Block, Part VI 2/15/2006 6:42 PM Tomek
Hi Szymon...greetings from Katowice!

First, I appreciate your work here, well done!
I'm working with CAB in my company. I'm wondering about workitem approach.

I have edit user use case. Where is the place to load user's data?
- in UserWorkItem (in OnRunStarted)
or
- in workitem which call this use case (in WorkWithUser(int userId) method)?

In first case I have to give user id to the UserWorkItem somehow. In second case, if I will start this use case from many places in my application, I have to write loading user's data in all these places.

Another question for me is divide two use case: edit user and new user. One workitem or two different but very similar with redundant code. If only one workitem what do you thing about distinguish between these two use case when start workitem.

Thanks in advance for any ideas clears my problems up.

Tomek




# re: Understanding Composite UI Application Block, Part VI 2/20/2006 6:27 AM Szymon
Tomek,
Initially I had exactly the same problem. Now I understand that such logic should be placed in dedicated services (or service agents). In my sample (now available for download) I have services for Inventory, Account and Order operations.

The WorkItem is only intended to manage views and it's state should be used to synchronize data between views fullfilling particular use case.

I will elaborate more on this in my next blog.

# re: Understanding Composite UI Application Block, Part VI 2/25/2006 9:28 AM Tomek
Szymon, thanks a lot. Your explanation was very helpfull. Your solution of my problem sounds very nice and I'm going to solve my problem in similar way.

Tomek

# re: Understanding Composite UI Application Block, Part VI 7/7/2006 9:30 AM Litzi
Hint for Development.

Look at
„Smart Client Baseline Architecture Toolkit“:

http://msdn.microsoft.com/library/?url=/library/en-us/dnpag2/html/scbatlp.asp.


# re: Understanding Composite UI Application Block, Part VI 1/18/2007 12:47 AM Anup
I think your blog is highly informative. Thank you for taking the time to document your experiments. I have started doing the same off lately with my blog and I think your blog answers a lot of my questions.

Thanks and keep up the good work!

# CAB isn't so easy to learn... 3/9/2007 5:14 PM Guy Burstein's Blog
After spending a few hours trying to figure out the responsibilities of all the elements of CAB, I found

# re: Understanding Composite UI Application Block, Part VI 9/6/2007 5:29 PM Ila
I dont have EventCommandAdapter class, where do i find that??

Post Feedback

Title:
Name:
Email: (never displayed)
Url:
Comments: 
Please add 8 and 5 and type the answer here: