Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Creating a Utility Framework

In this article I demonstrate how you can take advantage of a light application framework when creating simple utilities.  Instead of working on lower-level plumbing, just create the code for whatever tool you need, and this framework can get you working faster.

Introduction

When you write small utilities, there's a certain amount of tedious repetitive work to get it up and going. Creating the main window, the tray icon (including the icon and context menu), and other common tasks just get in the way. In this article, I've created a reusable utility framework and will show you how to make use of it.

To run this code, you'll need to use Visual Studio 2008 SP1, Express Edition or higher. If you haven't downloaded it yet, go to http://www.microsoft.com/express. You can either use Visual Basic or Visual C# to work with the main project or create add-ins for this project.

A Framework?

So what did I actually create for this article? We all know that using base classes is a great way to tie together closely-related objects. As a very practical example, a base window or control class lets you add functionality to something that already exists without reinventing the wheel, so to speak. Windows exposes a number of code execution models such as services, console apps, Sidebar gadgets, Windows forms, WPF, COM, and more. Each of these provides a certain amount of functionality that you don't need to worry about, such as start/stop hooks for services, or the system message loop for Windows forms and WPF.

Having built a good number of small utilities over the years, I've definitely realized that I'm copying or rewriting too much code. What a waste! Since I always create a notification icon (shows up by the system clock), and I like to hide to tray on minimize, and remember window settings, I implement these in each project. I probably should have created a project template in Visual Studio as a shortcut, but this has a disadvantage. If I added a cool new feature to my framework, I'd need to recompile and rework the older apps to take advantage of it

The better solution was to create a “base application.” This would actually be its own application that exposes a notification icon and menu, and a main window. If you move the window, the location is saved. Individual utilities can then be added as plugins. I originally envisioned a framework able to host multiple applications, but that creates some interesting design challenges with visual apps. In the end, I settled on a reusable application which can host a single utility.

A Common User Interface

I decided to write this in WPF since it affords so many great options for layout and interactivity. I still write some Winforms code, but WPF is just an incredible way to build your application declaratively (not that XAML is required…) and it enables a nice clean code layout. If you are really tied to Windows Forms, you can always use the WindowsFormsHost control to expose it.

The basic application isn't very complicated. It lets you set the application name which it uses in the tray menu and in the main window title. You can also set whether it minimizes to tray or not. If not, the close button will actually kill the application. Minimize always minimizes as normal.

Finally, the main window shows both the preferences UI. Most small utility apps don't really have a UI other than settings. You can always show dialogs and windows, but if all you have is a few settings, you can just create a UserControl to contain them and the application will host it.

As an example, I created a utility add-in. It looks like some sort of file watching utility. It's not actually functional – it's just a collection of controls in a UserControl. This is paired up with the application name, icon, and more.

Figure 1 : Main Window

Figure 1 : Main Application Window

Modularity

So I mentioned before that one of my motivations with this project was to allow me to update the framework without needing to recompile the utilities themselves. To be clear, this won't be possible 100% of the time, but as long as I leave the public interfaces alone, it should work well. So here's the cool implementation: Managed Extensibility Framework, or MEF.

MEF allows you to build extensibility into your applications with little effort. Build your interfaces or contracts, and as long as plugins use that contract, code can be compiled into separate assemblies with no dependencies. When the application starts up, you tell it where to find extensions and it takes care of loading them. The contract for addins (IWpfService) is defined as:

Visual C#

public interface IWpfService
{
    // Gets the custom control to display in the host preferences dialog.
    UserControl OptionsUserControl { get; }

    string Name { get; }
    System.Drawing.Icon TrayIcon { get; }
    string Description { get; }
    string Author { get; }
    Version Version { get; }
    Uri AuthorUri { get; }
    bool HideOnClose { get; }
    string Status { get; set; }

    void Initialize();
    void Start();
    void Stop();

    event EventHandler StatusUpdated;
}

Visual Basic

Public Interface IWpfService
    ' Gets the custom control to display in the host preferences dialog.
    ReadOnly Property OptionsUserControl() As UserControl

    ReadOnly Property Name() As String
    ReadOnly Property TrayIcon() As System.Drawing.Icon
    ReadOnly Property Description() As String
    ReadOnly Property Author() As String
    ReadOnly Property Version() As Version
    ReadOnly Property AuthorUri() As Uri
    ReadOnly Property HideOnClose() As Boolean
    Property Status() As String

    Sub Initialize()
    Sub Start()
    Sub [Stop]()

    Event StatusUpdated As EventHandler

End Interface

The UserControl reference is a composite control with any necessary user interface elements for configuring the application. This could be a file dialog, checkboxes for options, buttons to start or stop processing threads, or whatever makes sense. The base application (the host) then provides access to them based on user request. The Name, TrayIcon, Description, and other such properties are used to generate information such as found in an About dialog. The methods are used by the host to control the lifecycle, similar to a Windows service. The Initialize() method is called on startup, followed by Start(). Stop() is called at shutdown/close. The hosted utility doesn't need to worry about many of the general application logic – just specific units of work.

Figure 2 : Showing About this Application

Figure 2 : Showing About this Application

The ExtensibleWpfApp project contains a base class called ApplicationWindow, which descends from Window. This can be used by any application that wants a simple tray menu, position and size saving, and minimize to tray. On top of that is the MainAppWindow class. This descends from ApplicationWindow and also implements IWpfHost. This takes care of creating a main window that displays the application metadata and settings. You're welcome to take either class as a base class, but then you wouldn't get the benefit of MEF extensibility.

During the instantiation of the MainAppWindow class it also initializes itself and its base class using properties from the add-in:

Visual C#

public MainAppWindow()
{
    InitializeComponent();

    Compose();

    // Settings menu item on or off, ShowApp menu item on or off, Wire up callbacks, etc.
    CurrentAddin.Start();

    this.ApplicationName = CurrentAddin.Name;
    this.HideOnClose = CurrentAddin.HideOnClose;

    // Sets a custom icon or leaves it as default
    if( CurrentAddin.TrayIcon != null )
    {
        this.TrayIcon = CurrentAddin.TrayIcon;
    }

    dockPanelAddinInfo.DataContext = CurrentAddin;

    Application.Current.Exit += new ExitEventHandler(CurrentApp_Exit);
    CurrentAddin.StatusUpdated += new EventHandler(CurrentAddin_StatusUpdated);
}

Visual Basic

Public Sub New()
    InitializeComponent()

    Compose()

    ' Settings menu item on or off, ShowApp menu item on or off, Wire up callbacks, etc.
    CurrentAddin.Start()

    Me.ApplicationName = CurrentAddin.Name
    Me.HideOnClose = CurrentAddin.HideOnClose

    ' Sets a custom icon or leaves it as default
    If CurrentAddin.TrayIcon IsNot Nothing Then
        Me.TrayIcon = CurrentAddin.TrayIcon
    End If

    dockPanelAddinInfo.DataContext = CurrentAddin

    AddHandler Application.Current.Exit, AddressOf CurrentApp_Exit
    AddHandler CurrentAddin.StatusUpdated, AddressOf CurrentAddin_StatusUpdated
End Sub

Notice how it has the concept of application name and a tray icon – something a standard application doesn't have. It's easy enough to add these things, but it can be tedious, and beginner programmers just have that much more to figure to get started.

Next Steps

Though the application is a good start, I see a need for more. The application could invoke add-in features on a timer with the framework prompting the user for the interval and handling that automatically. The concept of saving and cancelling settings changes should really be built into the framework. It might also be good for the add-in to have access to show/hide the window as needed. Hooking into the system Event Log or other logging and other tracing mechanisms could also be handled by the framework.

The key is to find common services that applications can use which also normally require some user configuration. If the framework can handle that automatically, it makes for less work for each utility.

Conclusion

First of all, this is only the first part of this article. Next time I'll dig into the MEF implementation and explain how an add-in works in better detail. I'll flesh out the sample add-in a bit as a point of reference and hopefully you'll see how you might benefit from it as well.

Building reusable application code can make a huge difference over time. Unfortunately it always takes longer the first time to do it right. Good code ends up being reused, but copy-and-paste reuse isn't as good as binary reuse (referencing an assembly/DLL), and that's still not as good as composition where new components bind to a framework at runtime. Frameworks like MEF, System.Addin, PRISM, and others make it much easier than it used to be to create extension points so code can fit in later. Used wisely this can lead to a more streamlined code base where you can rely on other contributors or communities to implement new features instead of coming to you each time. You can focus on creating a solid foundation and let people create niche or mainstream features as they see fit. You'll be happier and your users will love it too!

If you haven't already, download Visual Studio Express Edition today and get started.

About the Author

Arian Kulp

Arian Kulp is a software developer living in the Midwest.  He has been writing software since the fifth grade (though not always professionally).  Arian creates developer evangelism stuff, speaks at INETA and Code Camps, and loves to stay on the cutting edge of technology.  In his spare time, he enjoys nature, photography, and his family.

Tags:

Follow the Discussion

  • Marti KaljuveMarti Kaljuve

    Thanks for sharing! This came at a perfect time for me, since I just got offered a 3-day project at work where I need to create a simple single-purpose desktop utility. Smiley

  • charoncharon

    can it run on pro version? what difference between WPF and Windows application?

  • Clint RutkasClint I'm a "developer"

    @charon what do you mean by pro?  WPF is a rich windows application.  It uses XAML for building out the interface while a Windows Application is a more traditional style windows application.

  • DonDon

    Hello,

    Nice. Do you have a new version of the Utility Framework coming soon?

    Thanks.

  • Clint RutkasClint I'm a "developer"

    @Don, Coding4Fun has additional plans for this framework so you will be seeing updates to it.

  • Adem GashiAdem Gashi

    Thank you very much! Simple as right time right place.

    Best regard for the author.

  • rollsrolls

    Hi Aaron

    Great stuff any idea when your going to coplete your next steps with the project?

    Regards

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.