Monday, November 24, 2008

Microsoft's OfficeUI Ribbon: Application template

I've been working with the recently released Ribbon control from Microsoft's Office UI group. There are several cookie-cutter setup steps to get an application ribbon aware. In order to facilitate setting up a new application, I made a Visual Studio 2008 template that creates a blank application containing a ribbon bar with some empty controls.

Here is the template file. Copy this zip file to My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#. When Visual Studio is started, the New project dialog displayed when File | New | Project... will have a new Ribbon Application option under My Templates. Select this to create a skeleton ribbon application.

When the application is created, an error will be displayed indicating the ribbon control library cannot be found. This is because this library needs to be acquired directly from Microsoft. To get it you need to go to the OfficeUI web site. (Here are the how-to-get instructions.)

Once the library is downloaded and installed on your computer, go to the new ribbon application's References, remove RibbonControlsLibrary and then add it in again, pointing to the location on your computer.

The skeleton application contains a Close option on the application menu to stop the application. There is a single tab with a single group containing a single button. Finally, there is a single button on the quick access toolbar. These all can be used as templates to easily add more.

More information on creating Visual Studio templates can be found on the MSDN site. (Thanks to paranoid ferret for the pointers on to how to create templates.)

Friday, November 14, 2008

How much of the implementation can be hidden by interfaces?

Short answer: All of it.

Consider this example:
unit uSomeManager;
interface
type
    ISomeManager = interface
    ...
    end;
function SomeManager: ISomeManager;
implementation
type
    TSomeManager = class(TInterfacedObject, ISomeManager)
    ...
    end;
var
    gSomeManager: ISomeManager;
function SomeManager: ISomeManager;
begin
    if not Assigned(gSomeManager) then
       gSomeManager := TSomeManager.Create;
    result := gSomeManager;
end;
Notice what is in the interface part of the unit. There are two things: the interface that is being defined and a global function which returns something implementing that interface. There is no class information  whatsoever. The entire implementation of this interface, including the class declaration, is in the implementation section of the unit. This prohibits others from using this class in any other way. They can't extend it, override it or instantiate another copy of it. If they want a different implementation of this interface, they have to completely re-implement it.

Whether or not this is a Good Thing is another discussion, but it does make it very clear to the user that it is intended to only have one instance of this. I find it works well for places where you might want to use a singleton, without the low-level messiness normally associated with them in Delphi.

Thursday, November 6, 2008

Splash screens are evil! 8 ways to improve them.

Ok, perhaps evil is too strong a word, but ideally splash screens should not be needed. They represent a failure on the part of the development team to make an application that can load fast enough that the user isn't left wondering what happened when they double click its icon. The best case is to make the program load fast enough that it's not needed. As a developer, I realize minimizing application start-up time can be a really hard problem, possibly hard enough that it's not worth the resources to invest in this area of optimization.

Faced with this reality, here are some guidelines, splash screen etiquette if you will, to make it less obnoxious. These are things I've come up with as a user of many different software packages over the years within the context of having done a fair bit of reading in the area of user interaction and experience. I find it interesting that after a bit of searching on the topic, both on the web and in some dead-tree resources, I have found many people talking about splash screens' visual design but no one describing their functionality.

1. Not centered: that's where I'm working!

I typically have a minimum of three applications open. Quite frequently I have two or three times that number. When I start an application, the odds are I have something else I'm working on, and want to continue working on, while the new application is starting. The center of the screen is where my focus is normally going to be for those other applications. Therefore, the center of the screen is the worst place the splash screen can go. It's going to be right in the way of my doing anything else.

2. Not modal: I'm trying to do something else.

The splash screen should should not be system modal. I am working on something else while the new application tries to get going. There is no reason to think the splash screen is more important than what I'm working on. The splash screen should not ever cover up my current work.

3. Not focused: I'm not typing to you.

The starting application should not grab focus unless no other application has it. If another application has focus, it should maintain it. If I'm typing, I'm not typing into the not yet started application, I'm typing to the existing application. (Microsoft Office Outlook team, do you hear me?!?)

4. Not too big: you're not that important.

All the splash screen needs to do is tell me it's working. To do this it just needs a small, unobtrusive animation. I'm willing to give splash screens 5% of my screen. If it can't let me know it's there in a 300 x 300 pixel box, the designers need to rethink what they're trying to do. Ideally, I should be able to size it to the dimensions I want, including minimized.

5. Not fixed: I want that space.

Even when it's not centered, I should still be able to move it where I want it so it's out of the way. No matter where the designers set it by default, there is always going to be the case where, for someone, that location is in the way. Make the silly thing movable, like any other window on my system.

6. Not default: remember what I've told you.

After I've told you where and how big, remember it! Next time I start the application, odds are my system is going to be about the same configuration. I've gone through the hassle of moving it and sizing it; I shouldn't have to do it again tomorrow.

7. Not a non-task: be on the task bar.

The splash screen should cause a button to appear on the task bar; preferably the same button that will be used by the main form when it finally appears. This way, one of the sizes I can give it (see #4 above) is minimized. This allows me to know the application is starting without it having to take any of my precious screen space.

8. Not needed: delay initialization.

Finally, the ideal is to not need a splash screen at all. Consider making the main form visible immediately with things disabled. As modules are loaded and initialized, then build the form and enable the various areas for the user.