Archive for the ‘CAB’ Category

Fresh on the heals of the CAB debate comes Acropolis.

Ayende has posted about it, as have a few other people. Here’s my take (in homage to Dream Theater, who released a new album this week, this post will be broken down into multiple movements).

Part I: Annoyance

Initially I was annoyed. Only slightly, but still annoyed. After all, as Ayende points out here, Frameworks require a higher adoption cost. We’ve invested in CAB; it would be annoying if Microsoft came out with something that competed against it.

But then I read Glenn Block’s excellent post about Acropolis. Acropolis is a WPF Framework. We’re not developing for WPF, we’re developing for WinForms. This doesn’t affect us (although I still feel a twinge of pain for the folks who have invested in a WPF adapter for CAB).

And by “affect us” I mean: we don’t have to feel an annoying itch in the back of our heads that causes us to sit down and research the technology to determine if it’s worthwhile for us to switch to it, or continue down our current path. This is perhaps the most annoying thing about what we do as developers: we invest in technology to solve our problems, and no sooner do we feel like we finally have the reigns of a giant dragon firmly in our grasp, the monster under our control, then it rears up, throws us off and spews fire, turning us into an ashen corpse. We’re bombarded with new widgets, gizmos, gadgets and things every day. Like Rocky says, it’s a bit overwhelming at times, especially when what you’re really trying to do every day is address business concerns.

Part II: Indifference

My second reaction after reading the Acropolis descriptions and blog posts was: I don’t really care.

Like Ayende, I don’t have a fondness for tools that mask XML as a programming language.

Sidebar.Start()
Several years ago someone asked me what I thought of this “XML thing”. It was in conjunction with another question, which was, “How would you make the web experience more like a desktop experience?” My answer to the latter question was, “I’d rewrite browsers so they interpret real code (not just Javascript) so that we programmers can actually write useful apps with a browser as our application shell.” Then XML landed along with XAML and instantly we all saw that the opposite was happening: desktops were going to be more like browsers, and we’d all end up writing markup. I wanted to puke. Such is life. Sidebar.End()

I read on some blog comments that people already see Acropolis as an attempt at a .NET RAD tool. I’m not sure if that’s an accurate or fair comparison (I simply don’t know enough about it yet), but to me it seems a lot more like trying to VisualBasic-ize .NET and application development.

One of the most popular questions that aspiring programmers ask is always, “What language should I learn first?” And my answer to that is almost always, “Anything except VB”. I just feel like it hides too many details, and as a beginner you have to learn the details first. You’ve got to know what’s going on underneath the hood before you can be a racing crew chief. My concern with Acropolis is that it’s attempting to create a cookie-cutter solution to something that can’t be solved with cookie cutters. Are application developers going to end up making bad choices because of a tool that allows them to drag and drop an enterprise application?

Part III: Intrigue

On the one hand, I like the idea of evolving tools. I said as much last week. I like the idea of something like Acropolis, because maybe it’s a step in the evolutionary chain. Maybe it’s one tiny step closer toward Star Trek, where I can start worrying about more high level concerns.

I imagine a future where developers don’t have to spend their time writing skeletal code or wiring up events; where we can just tell the computer “hey, when the user clicks this button I expect X, Y and Z to happen.” And under the covers I expect proven patterns, practices and programming constructs to handle the code in a way that developer could instantly understand if they were to open up the guts to it and look. Just like I can look at a coworker’s code and know what’s going on, I’d expect to be able to look at any code generated by an abstraction layer and understand what’s going on.

But am I going to understand the XML spaghetti that Acropolis spits out? Hell, every time I run across an XML feed from Google instead of an actual web page I hit the back button as fast as if the offending image were capable of giving me rabies.

I just really don’t like writing code without code. It seems like there’s a whole mess of problems that could crop up. At least with a real programming language I have one degree of security: the compiler. At least there’s one checkpoint it has to get through; one test it has to pass before it gets to my unit tests.

Part IV: Acceptance

Acropolis is here; what does it do for me? The only thing I’m really concerned about is our current project, and as such the only thing I really care about is CAB. Does Acropolis affect us in any way? No.

As Glenn Block said, there are no plans for any more SCSF released. There’s no more new CAB. But that doesn’t really bother me for two reasons:

  1. CAB is pretty stable. It’s two year’s old. We feel like we have a pretty good grasp on it; we’ve invested the time and effort; we’re married to it. CAB might not be the best wife – she might frown when we watch too many sports events, or pitch a fit when we forget to take out the garbage – but she’s good enough.
  2. Glenn and Co. started the SCSF Contrib site, so people who are married to CAB, like us, can contribute to the CAB and extend it. If the CAB is important to people then it should continue to see people downloading it, using it, asking questions about it and extending it.

There’s nothing really missing from the CAB from our perspective. It’s a Framework that does what we need it to do. Anything it doesn’t do we can accomplish through other means (and as previously debated, some folks feel it does too much already). We can extend it where we need to; we can get stuff done. So not seeing any more updates from SCSF doesn’t bother me at all. I’m fine with that.

The other thing is this: we’re currently running Windows XP on all our workstations. There’s no imminent upgrade where I work and I suspect this is the situation for a lot of businesses. If all our workstations were Vista then maybe I’d have some research to do and a decision to make, but I don’t.

Part V: Closure

Acropolis might end up being a great Framework with some really neat tools to implement it with. Then again it might be XML Hell. I don’t know. But I’ll say this: I don’t think anyone currently using the CAB should feel one bit bad about this. If you’ve invested in the CAB and feel like it’s giving you what you need, then keep using it. That’s what we’re doing.

If/When Vista becomes the primary desktop in our environment and we feel the need to start developing in WPF, then we’ll do what we always do: research the available options, ask people’s opinions, and make a decision. But for us that time hasn’t come.



Source code can be downloaded here

One of the common problems that people run into when developing CAB applications is how to handle a “global” ToolStrip commands or EventBroker events, and have only the active view respond to that command/event. There have been a myriad of solutions presented on the CAB message boards over time, but none of them have solved the problem very well. Until recently, our shop had not been forced to addressed this problem. Then it hit us in the face as well when we wanted to put an “Undo” button on the ToolStrip and have the active view respond. Faced with this problem we set about solving it. Here’s our solution, and I think it’s pretty slick.

There’s two core elements to this problem:

  • Tracking the active view when it changes
  • Querying for the Active View against the current view when responding to an event or command

To solve the first part of the problem requires a couple of things:

  • A service to track the “active view”
  • A way to make each view unique, so that it can be tracked in the first place.

Making Views Unique

This is the key part to the solution. We have our views inherit from a base View class. This view class implements an interface called IView. The IView interface exposes one property: A Guid. This is the heart and soul of solving this problem.


public interface IView
{
    Guid Guid { get;}
}

The implementation of the View is very simple. The constructor just creates a new Guid when the view is created.


private Guid _guid;

public View()
{
    InitializeComponent();

    _guid = Guid.NewGuid();
}

public Guid Guid
{
    get { return _guid; }
}

Tracking The Active View

Each view now has a unique identifier. The next step is to create a service to track the active view:


public interface IUIService
{
    void SetActiveView(object view);

    bool IsActiveView(object view);
}

The service implementation is listed here:


public class UIService : IUIService
{
    private Guid _activeViewGuid = new Guid();

    public void SetActiveView(object view)
    {
        if (view is IView)
        {
            IView eView = (IView)view;
            _activeViewGuid = eView.Guid;
        }
    }

    public bool IsActiveView(object view)
    {
        if (view is IView)
        {
            IView eView = (IView)view;
            if (eView.Guid == _activeViewGuid)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
}

Activating The View

With a tracking service and a unique Guid you finally have a way to identify views. The next step is to set the active view when it is displayed in a Workspace.

What you have to do here is wire-up a Workspace’s SmartPartActivated event. Somewhere in your code you’re going to have a view that contains a DockWorkspace, or a TabWorkspace, or some other workspace. In the sample application I use a TabWorkspace because this seems to be a common workspace that prompts this problem for users.


public EmployeeTabWorkspaceView()
{
    InitializeComponent();
    EmployeeTabWorkspace.TabPages.Clear();
    EmployeeTabWorkspace.SmartPartActivated += new
    EventHandler(
    EmployeeTabWorkspace_SmartPartActivated);
}

void EmployeeTabWorkspace_SmartPartActivated(object sender,
WorkspaceEventArgs e)
{
    _presenter.SetActiveView(e.SmartPart);
}

When the Workspace shows a view this event is fired. We delegate the call to the Presenter but you don’t have to do it this way; you could inject the UIService into this view and handle it directly.

The Presenter then sets the active view via the service:


private IUIService _uiService; 

public EmployeeTabWorkspaceViewPresenter(
[ServiceDependency] IUIService uiService)
{
    _uiService = uiService;
}

public void SetActiveView(object smartPart)
{
    _uiService.SetActiveView(smartPart);
}

Every time the TabWorkspace activates a view or has a new view added to it, this event wil fire and the UIService will set it as the active view.

We’re almost done.

Answering The Call

The final step is to answer the question: How do we utilize the Guid and the UIService to handle a command or event?

In the EmployeeViewPresenter of the sample application I have two ToolStripItems: Print and Undo.



Pressing the Print button causes an employee’s name to be printed in a ListView. Pressing the Undo button causes the ListView to Clear() itself. There is only one of each button on the ToolStrip, but there are three copies of the same EmployeeView and Presenter listening for these Commands.

To determine which view should respond to the call they each query the UIService to determine if their view is the active view.


[CommandHandler(CommandNames.Print)]
public void Print(object sender, EventArgs e)
{
    if (_uiService.IsActiveView(View))
        View.PrintEmployeeName(_employeeName);
}

Only the active view’s Guid will match, and thus only the proper presenter’s code will execute. That’s it; that’s all there is to it. Enjoy!

Download the source code here. Note: this code was built with the latest version of ObjectBuilder, v 1.0.51206.0. If you want to alter or recompile the code you may run into problems if you don’t have the latest version.