Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#5.0

SVG Tile Based Dashboard in C# to Control Model Railroad

4.75/5 (8 votes)
1 Sep 2014CPOL5 min read 30.8K   1.6K  
Flexible SVG tile based dashboard in C#

Introduction

I have built a flexible user interface which allows the user to shape the user interface according to physical process and to represent the real process. In this way, the user immediately sees what the effect of a control action is.

In this sample application, a signal tower to control model trains is used as an example. By replacing the SVG (Scalable Vector graphics) in the resource files, this application can easily be modified to control a chemical process flow for an example.

Editmode: Building the visualisation:

Image 1

After building the visualisation, it can be controlled in Control Mode.

Image 2

And to show the status of a tile, click the occupation test in the menu, each tile will show it's occupied:

Image 3

Of course, this should be triggered by the process/hardware.

Background

The main objective of this article is not software design primarily, but more focused on the concept and architectural design. Many designers will fall in the pitfall and start with a design based on the graph theory. And what this design tries to show is that a UI control itself is not bound to other controls like in the physical world, but only by the graphical representation (location on the screen) and therefore the graph theory is not needed. This reduces the complexity of UI design. Of course, the model (outside of this articles scope) still contains the relational knowledge and uses the graph theory.

Using the Code

Two main patterns are used throughout the complete application:

  • MVP, Model View Presenter pattern to loosely couple UI with the other layers (and please notice that this sample only contains the view part)
  • Proxy pattern to let the Layout and AddTile class access the tile library via the MainApp.

And two events are used:

  • ControlStateChange, to notify the view (tile representation) about an external state change or to notify the external hardware about a state change triggered by a user (tile clicked).
    (switch is thrown or straight / valve is open or closed)
  • TrackStateChange, to notify the view about an external state change. (track is free or occupied / water pipe is empty or flooded)

To identify the events, two types of IDs are used throughout the application (all layers):

  1. ControlIDs
  2. TrackIDs

Examples:

ControlID: “CI10” will be translated to IODevice x, register 8 and bit 6. If the user clicks on the tile, an event will be sent to the IO Service to toggle the IO bit. Likewise, if an external event toggles the IO bit, the IO Service will notify the View about this event and the view will update the Tile.

TrackIDs can’t be triggered by a user but only by the IO Service. The IO Service will notify the View whether a track is occupied or free and the view will update the Tile.

The complete application looks like this:

Image 4

The scope of the sample application looks like this:

Image 5

The view part of this application contains the following classes:

MainApp

This is the main application and acts as a boiler plate for user actions (menu actions), shows/hides panels and translates application strings by using two resource files (Dutch and English).

TileProperties

This is a user control which allows the user to change 3 properties from a control:

  • Logical name (e.g., Junction 21)
  • ControlID, a hardware id to relate a bi-directional hardware event with a tile
  • TrackID, a hardware id to relate an input hardware event (track is occupied) with a tile

The IO service layer will use both IDs to address certain hardware (logical to physical translation) and handle hardware events by notifying the view (which updates the tile on its turn).

AddTile

This is a user control which allows the user to select a tile from a library. In this sample application, two kinds of tiles are supported in this sample:

  1. Tracks
  2. Signals

Signals only support control ids (run/stop, red/green) and Tracks support control ids (left/right, open/close) and track ids (Occupied/Free, Flooded/dry).

Layout

This class is derived from a panel and handles the CRUD actions related to tiles and the movement/placement of tiles on a canvas (Mouse handling, single/multiselect).

And this class is the major interface with the MVP pattern. In the full application, this class creates the presenter and model. Also loading from the model is supported by this class.

Tile

The Tile class is the graphical representation of a tile (the physical tile is handled by the model). Based on its state, it will show the related bitmap in the right orientation.

SVG Tile Library

To support a flexible interface and to make it possible to quickly extend and change the functionality, a SVG parser has been created. This parser reads SVG images related to a tile from a resource XML file (library) and delivers the file as a bitmap set.

Example:

A simple switch (left/right) has 4 states (bitmaps):

  1. Left (control state) and free (trackstate)
  2. Left (control state) and occupied (trackstate)
  3. right (control state) and free (trackstate)
  4. right (control state) and occupied (trackstate)

The Tilefactory class discloses the resources files as libraries and supplies the following (ITilefactory):

C#
List<String> GetCategoryList();
List<String> GetAvailableTiles(String Category);
Dictionary<int, Bitmap> GetBitmap(String Category, String TileName, Color BackgroundColor);
  • GetCategoryList: This function delivers a string per resource file. In this case: “Tracks” and “Signals
  • GetAvailableTiles: This function delivers a string per tile depending on the category: “buffer”, ”curve” , ”straight”, etc. when track is selected as category.
  • GetBitmap: This function delivers a set of bitmaps as described above and uses the category and tilename as selector and Backgroundcolor as color for the background.

To deliver these bitmaps, the following classes are used:

  • SVGItem (abstract base class)
  • SVGPath
  • SVGRect
  • SVGCircle

Each derived class used a SVG string from the SVG XML files.

So SVG Path is created when a SVG file contains the “Path” line. Then this class will be able to parse this line and draw it in a bitmap. Currently, only Path (relative and absolute), Rect and Circle are supported. And the rotation translation is only supported for Rect. (It can easily be ported to the other types.)

Points of Interest

I needed a lightweight SVG parser and have built one myself. I do know some libraries are available, but since I wanted to learn from this application, I decided to build one myself. It currently supports only a limited set of SVG functionality, but it fitted my needs.

History

  • 2nd September, 2014: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)