WPF Dashboard and Custom Panels


I’ve been toying around with creating a dashboard like display in WPF recently and figured there must be a million examples out there.

Some interesting and/or noteworthy ideas I came across:

The Telerik display was nice, but I wanted something free at the moment as I was working on a prototype idea. The TechEd demo was pretty close to what I was looking fro but I wanted a bit more “dynamic” functionality.

Using the work from the aforementioned links as inspiration, I set out to fill the missing gaps and learn a bit more about WPF in the process. Below is a list of the basic features I was shooting for:

  • Generic Management of “Dashboard Parts” that are defined, discovered and created dynamically
  • Support for single instance or multi-instanced parts
  • Drag and drop support of dashboard parts to the grid layout, as well as within the grid layout between “cells”
  • Automatic grid expansion when necessary
  • Ability to Maximize, Restore and Close parts
    The basic idea was to start with the dashboard editing and setup feature, which is what you see below. So here’s what I came up with:

 image

To see the auto expansion of the grid and drag and drop functionality in action, here’s a video:

    With my specific needs in mind I set about my work. My first attempt to was to try and subclass the Grid in WPF, but I quickly ran into the problem of sub-classing a component with existing public properties – these properties were available to be called instead of my specific functionality. Instead I wanted to make the management of the grid more prominent and explicit.

One option would have been to create a panel from the ground up that mimicked the behavior of a Grid only exposing the functionality I wanted. Instead I chose a simpler, albeit less elegant approach – the creation of a side component called GridManager.

The GridManager component takes care of all the “heavy” lifting – processing drag and drop messages, managing the grid layout and managing part lifetime and event handling.

Dashboard Parts

 

Part Interface

The parts for the dashboard are designed to operate in a plug-in style, where each one can be contained in one or more assemblies external to the main project. Each part needs to implement the following interface to be able to be loaded and recognized by the dashboard application.

    public interface DashboardPart
    {
        event EventHandler PartControlReadyForDisplay;

        System.Windows.Controls.UserControl PartControl { get; }
        string UniqueIdentifier { get; }               
        MyDBConnection DbConnection { get; set; }

        void Initialize();
        void Destroy();

        ObservableCollection<PartProperty> Properties { get; set; }
    }

  1.  
       
  2. The PartControlReadyForDisplay event allows parts to signal when they are ready to be displayed in the dashboard. This allows for a part to take as much time as needed to get ready for displaying. In the meantime, a “Loading…” placeholder is used with the parts place.

    Each part is required to have a unique identification – UniqueIdentifier, and can support being passed a database connection (if a data bound part). Additionally, the Properties collection allows any custom defined properties to be integrated into the part editing and setup via the “Properties Grid”.

    The parts lifetime is managed by the application itself and the expected chain of calls to a part are:

  3. Dashboard app creates an instance of the DashboardPart interface implementation defined in the parts catalog
  4. Dashboard app sets the DBConnection property (if needed and in use)
  5. Dashboard app calls Initialize() on the part
  6. Part finishes initialization and raises the PartControlReadyForDisplay event
  7. Dashboard app retrieves the PartControl property to get the parts visual instance and adds it to the grid
  8. When the part is no longer needed, Dashboard app calls Destroy() on the part

 

Part Definition

Currently the definition of parts is accomplished via a “parts catalog”. I decided on this approach because I wanted the definition of parts to be flexible as well as explicit.

An alternative mechanism would be to scan a “plugins” directory and load the appropriate plug-in dynamically if the proper interface was present. This can be fairly easily implemented.

<Parts>
  <Part>
    <Name>Project Status</Name>
    <Width>100</Width>
    <Height>100</Height>
    <Construction Assembly =”TestPart” Type=”TestPart.TestPart1″/>   
  </Part>
  <Part>
    <Name>Procedure Progress</Name>
    <Width>100</Width>
    <Height>100</Height>
    <Construction Assembly =”TestPart” Type=”TestPart.TestPart2″/>
    <Properties>
      <Property>
        <Name>Test Property</Name>
        <Value>This is my test property</Value>
      </Property>
    </Properties>
  </Part>
</Parts>

Conclusion

 

It’s amazing how easy and fast it can be to create visually pleasing and functional user interfaces in WPF with a minimum amount of effort. With a bit  more work, a dashboard of the caliber of the one shown in the Telerik demo application can be easily achieved.

There are a few more features left that I want to implement in the editing and setup portion of the dashboard, such as a more accurate visual of the parts when dragging / dropping and the ability to have a part span cells/rows. Both features should be pretty trivial to implement.

Note: Use of the Canvas was also tried although I deemed that it’s fairly static nature (fixed with and height) didn’t make it ideal for supporting an arbitrary number of parts.

As an aside, the styling was very easily accomplished with the WPF Themes CodePlex project.

Advertisements

11 thoughts on “WPF Dashboard and Custom Panels

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s