Adding Some Life

The previous installment in the Building FitNet series explained how to connect a view-model with a view, using a modular and extensible architecture. In this episode, I explain how interactivity can be added to the user interface.

The simplest interactive UI control is a button. You click on it, and it executes some action. Buttons in Windows Forms worked the same way. But WPF takes the button and turns the knob up to 11. Buttons in WPF can take on literally any appearance that you can dream of. Building the user interface using XAML is already so much better than using the Designer or literal code statements. Features such as data binding are added bonus and allow for more dynamism in the user interface. You can bind the appearance of a Button instance to a view-model that reacts to the state of the application and literally make things dance.

The change in architecture also extends to the use of the event handlers. The built-in System.Windows.Controls.Button class has a property called Command, which can be bound to the view-model of the instance. The Command property is of type System.Windows.Input.ICommand. Any class that implements this interface can be attached to this property.

This sounds a bit counterintuitive at first. Why have a special type, when a simple function can suffice?

And the answer is separation of concerns. A command decouples the object that invokes the command from the object that executes the command.

The ICommand interface also provides additional properties that make it easy to control the state of the button with a bit of additional code.

public class RelayCommand : ICommand
{
    public RelayCommand(Action execute, Func<bool> canExecute)
    {
        …
        _execute = execute;
        _canExecute = canExecute;
    }
 
    event EventHandler ICommand.CanExecuteChanged
    {
        // Event dispatched event when the state of the CanExecute property changes
        …
    }
 
    bool ICommand.CanExecute(object parameter)
     {
         return null == _canExecute ? true : _canExecute();
     }
 
    void ICommand.Execute(object parameter)
     {
         _execute();
     }
}

The Command property of the button is assigned an instance of RelayCommand. This class constructor takes two parameters – an Action delegate called execute and a Func<bool> delegate called canExecute. The Action is called when the command is to be executed, whereas the Func<bool> determines if the command can be executed at all or not.

This is useful for performing runtime checks on the validity of input. The CanExecute delegate is triggered automatically by the framework periodically, which keeps the state of the button updated at all times.

The Command object should be made available through the view-model so that the button can be bound to it.

public class CalculatorViewModel
{
    public CalculatorViewModel()
    {
        TryCalculateCommand = new RelayCommand(TryCalcuate, CanTryCalculate);
    }
 
    public ICommand TryCalculateCommand
     {
         get;
         private set;
     }
 
    private void TryCalcuate()
    {
    }
 
    private bool CanTryCalculate()
     {
         // Validate the input fields and return a boolean
     }
}

That’s it! All that’s left is to bind the Command property of the Button instance to the TryCalculateCommand property in the view-model.

<Button Content="Calculate" Command="{Binding TryCalculateCommand}"/>

Collectively, these minor improvements in paradigm make WPF a much nicer framework to use over its predecessors.

In With the New

It turns out that there is a much better way to manipulate the user interface in WPF which is based on view-models. I cover this aspect in this episode of Building FitNet.

The System.Windows.Application class is the core of a WPF program. An instance of this class remains in memory for as long as the application is running. In order for the application to do something useful, programmers must extend this class and customise its behaviour to the needs of their own application. By convention, the primary application window is also instantiated by this class in the OnStartup event handler.

private ShellViewModel _shellViewModel;

override public void OnStartup(StartupEventArgs e)
{
  base.OnStartup(e);
  _shellViewModel = new ShellViewModel();

  var window = new Shell();
  window.DataContext = _shellViewModel;
  window.Show();
}

An instance of the ShellViewModel class is assigned as the view-model for the application window through its DataContext property. When the properties in the view-model instance change, it dispatches a PropertyChanged event along with the name of the changed property. Corresponding event handlers in the window object then query the view-model for the new state and update the appearance of the display. The ShellViewModel class must implement the System.ComponentModel.INotifyPropertyChanged interface for this behaviour.

The following example illustrates this by changing the title of the application window.

public class ShellViewModel
{
  …
  public string Title
  {
   get
   {
     return _title;
   }

   set
   {
      _title = value;
     var e = new PropertyChangedEventArgs("Title");
     PropertyChanged(this, e);
    }
  }
}

Specific properties of the view are bound to their corresponding counterparts in the view-model. In this example, the Title property of the Window class is bound to its namesake in the view-model.

<Window … Title="{Binding Path=Title}">
  …
</Window>

Therefore, when the title changes on the view-model, the change gets reflected on the view. The key here is assigning an instance of the ShellViewModel to the DataContext property, which establishes the bindings between the view and the view-model.

This concept is key to understanding and implementing properly architected WPF applications.

Binding On-Screen Views

This concept of binding a view to data can be extended to any type. Primitive types are rendered as strings. For complex types, programmers can build composite views made up of several different fundamental UI elements such as labels, text fields and buttons. Properties in the view-model are bound to these controls.

In order to render the content in the window, the application must instantiate ContentControl, which is shipped along with WPF. This class has a property called Content, which can be bound to any property in the view-model.

<ContentControl Content="{Binding Title}"/>

The output of the program written so far is shown below.

A string binding between a view-model and a view

When the value of Title in the view-model changes, the text rendered inside the ContentControl instance is updated to reflect the new text.

Building Compound User Interfaces

The third part of the equation is assigning a data template to the view, which describes the visual structure of an object. A data template is a window resource.

<Window…>
  <Window.Resources>
    <DataTemplate DataType="{Type system:String}">
      <TextBlock Text="{Binding StringFormat={}The application name is &#x2014; {0}}"/>
    <DataTemplate>
  </Window.Resources>
  …
</Window>

This modifies the appearance of the ContentControl instance. Instead of rendering plain text with just the name of the application, the output is decorated with some additional text and special characters, and looks like this.

An annotated string binding between a view-model and a view

The Big Picture

Essentially, the outcome of what appears on the screen is now split into three classes – a view-model, a view, and a data template that specifies which determines which view to use to render a view-model.

It’s a small step from here to building complete user interfaces using this style of programming.

This is done by having a custom view-model class for the window as shown above, then adding another view-model to it as a public, bindable property called SelectedView.

public class ShellViewModel
{
  …
  private Object _selectedView;

  public Object SelectedView
  {
    get
    {
      return _selectedView;
    }

    set
    {
      if (value == _selectedView)
      {
        return;
      }

      _selectedView = value;
      OnPropertyChanged(nameof(SelectedView));
    }
  }
}

It is preferred that SelectedView be a custom type instead of System.Object. A different view-model is required for each view that the application needs to render. For example, if the application requires tabs for a calories consumed calculator and a speed calculator, then two view-models must be made for each of these tabs. Having a common base class between them ensures type-safety when switching between the two view-models.

A custom renderer is also required for each view. Renderers are typically built on top of the UserControl class. The declarative syntax of XAML makes it very easy to build a user interface with any kind of layout.

The example below shows a SpeedCalculatorView that computes the value of speed based on the time taken and distance covered.

<UserControl …>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="150"/>
      <ColumnDefinition Width="250"/>
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Column="0" Grid.Row="0" Text="Time"/>
    <TextBlock Grid.Column="0" Grid.Row="1" Text="Distance"/>
    <TextBlock Grid.Column="0" Grid.Row="2" Text="Speed"/>

    <TextBox Grid.Column="1" Grid.Row="0" Text="{Binding Time}"/>
    <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Distance}"/>
    <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Speed}"/>
  </Grid>
</UserControl>

The window resources contains a DataTemplate declaration to associate the SpeedCalculatorView with the SpeedCalculatorViewModel. The user interface is changed by setting the value of SelectedView in ShellViewModel to an instance of SpeedCalculatorViewModel.

In the next part, I will cover how to add interactivity to this application.

Out With the Old

In the previous post I described the rationale and the approach to building a custom fitness tracker for the desktop. The application was to be built using the Windows Presentation Foundation. As far as execution goes, I had a lot to learn about the correct way to use WPF. The first commit of the application followed so many WinForms paradigms that it made zero sense to involve the overhead of WPF.

FitNet Desktop screenshot

This is what the XAML that implements the above screen looked like.

<TabControl>
     <TabItem Header="Summary">
         <fit:Summary/>
     </TabItem>
     <TabItem Header="Reports">
         <Label>Reports View</Label>
     </TabItem>
     <TabItem Header="Tracking">
         <Label>Tracking View</Label>
     </TabItem>
</TabControl>

Perfectly readable, but it would quickly devolve either into a big ball of mud with XML nodes nested several layers deep in a single file, or turn into a pile of nested classes inheriting unrelated behaviour from a few common base classes. Either case was unacceptable. But I didn’t know that yet.

The second mistake was borrowing a data-access implementation from a previous project which was based on a primitive architecture. The template pattern that this layer implemented was fine for a small number of data objects. But it becomes tedious to build a separate reader and writer sub-class and its associated ancillary classes for every aggregate data type (and FitNet requires quite a few of those). I needed something that was easier to extend when it came to data access.

FitNet Desktop Solution View

The third major flaw was having monolithic namespaces out of ignorance of the WPF architectural style, and not using its paradigms to the best benefit. This resulted in the application turning into three projects – a Desktop project as the primary executable, a Desktop.Lib library project as a massive collection of view classes, and a Persistence project which implemented the aforementioned half-functioning data access layer.

I went through this path for several weeks before finally realising my folly, by which time I had actually built quite a bit of useful functionality in the application. But it was getting unwieldy to make any modifications or add new functionality. It seemed like I was constantly fighting against the framework in order to get things done.

I had finally had enough of this struggle when I had to implement a flyout for modifying the list of exercises in the database. Adding yet another node to the already crowded main window file and more inline click event handlers in the backing CS file were a clear indicator that I was doing this wrong. There was no way this could scale up elegantly.

This is where I decided to take a step back and try to understand what the heck was going on.

Fortunately I stumbled upon XPence, an expense tracking application built on WPF by Siddhartha S. and hosted with an in-depth development tutorial on Code Project.

Hang on for the next part where I finally begin to turn this ship around to a more meaningful course.

Introducing FitNet

The recent surge in fitness-related technology innovations bodes well for the future of many people. And though the Cheeto-munching, Red Bull-guzzling stereotype for the technologists behind this progress still sticks, the truth is that more people, including programmers, are gaining awareness of their physical health and nutrition and changing lifestyles to seek improvement.

Latching on to this bandwagon came a surge of fitness tracking apps. FitNotes, StrongLifts 5×5, the Starting Strength App by legendary strength-training coach Mark Rippetoe, Strong App for iOS, and many more, provide ample choice to the enthusiast as well as advanced lifter. These apps cover various aspects, from simple tracking, to full blown programme design with progressions and periodisation. Some applications work online. Your data is stored on their server, and requires an internet connection to access and update. Others are offline, or a hybrid of both modes. Many are free and use ad revenue to sustain operations. Some of the fancier ones are paid. They all have their pros and cons.

Having used a small subset of them in the past few years, I have identified certain shortcomings between them.

Incompatible Storage

This is especially annoying because most of these applications use the same database engine – SQLite. But it’s impossible to move from one application to another without a lot of manual re-entry of data.

Now this is an understandable shortcoming. Database design is an engineering activity. People approach the same problem differently based on their skill levels and priorities. Copying databases between applications will never work directly. But the problem can be mitigated to a great extent by the industry agreeing to a common minimum format that they all support, which can be used to send data out of the application. Customers do not like being locked in.

Changing Platforms

Mobile phones change often. I have found myself switching between Blackberry to Android to iOS in a few short years. Fitness journeys last a lifetime. Phones last a few years, at best.

This is to some extent, a manifestation of point 1 above. If the common minimum format were to come together, changing platforms would become much easier. However, there’s another more subtle point. The one unchanged platform over all these years has been the desktop and the Windows operating system. People usually have access to at least one Windows computer. Even though Android has become the most popular operating system, the Windows desktop remains firmly lodged into place at workplaces, schools and homes. It’s still a very stable and dependable platform to target.

Privacy

It is possible to cast all these troubles away and switch to a web-based application. However, people are not always comfortable with storing sensitive personal information on a server that is not in their control. Not to mention the risk of the company going belly-up and taking their precious PR logs along with it.

This is a no-brainer. Put the data on the user’s own computer, where they do not have to worry about losing their privacy. Include an automated backup feature that saves the encrypted data on their cloud-storage service. The data remains reasonably safe from loss as well as from prying eyes. Again, a common minimum format can prove to be very useful in the worst case scenario of 100% loss of the physical computer itself.

These were real and personal pain-points I experienced first-hand. And being a programmer gave me the ability to actually work on a solution that addresses these problems.

Introducing FitNet

The easiest replacement to these woes was a spreadsheet. Smack a new row for every workout, see real-time graph updates. It works as a log, but getting a report out of it is a chore. Besides, programming fancy reports into a spreadsheet eventually turns it into a prime feature for The Daily WTF. So that was out. Microsoft Access used to be a very good tool for this kind of tasks, but it still leaves out graphical reports. And the new monthly subscription model for Office 365 just isn’t for me.

Enter Windows Presentation Foundation.

I have been using Windows Forms since the longest time as the tool of choice for building desktop applications on Windows. It’s easy and it’s straightforward, and anybody who’s working with the previous Windows API feels perfectly at home with the new managed API that WinForms represents.

Windows Presentation Foundation is different. It is not just a wrapper around the Windows API. It’s a whole different framework which eschews the disparate development sub-frameworks from the Windows API in favour of a single well-integrated and extensible library. It also accounts for differing device capabilities in a more resilient fashion by abstracting away tasks like drawing objects relative to the device resolution and hardware accelerated graphics available out of the box without any extra effort. Finally, WPF brings a new type of resource – a XAML file – to be used as a declarative approach to building and programming user-interface elements rather than the procedural approach required by the Windows API.

This means that the following 50 lines of code –

WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

// Registering the Window Class
wc.cbSize        = sizeof(WNDCLASSEX);
wc.style         = 0;
wc.lpfnWndProc   = WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

if (!RegisterClassEx(&wc))
{
  MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

// Create the window
hwnd = CreateWindowEx(
  WS_EX_CLIENTEDGE,
  g_szClassName,
  "FitNet Desktop",
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
  NULL, NULL, hInstance, NULL);

if (NULL == hwnd)
{
  MessageBox(NULL, "Could not create application window.", "Error", MB_ICONEXCLAMATION | MB_OK);

  return 0;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Message loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
  TranslateMessage(&Msg);
  DispatchMessage(&Msg);
}

return Msg.wParam;

– can be distilled down to –

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="FitNet Desktop" Height="400" Width="300" />

Now it can be argued that the Windows Forms API also offers similar succinctness. But WPF takes this to a whole different level as I learned through the course of my project.

This series of articles is an ongoing log of my journey of building FitNet – a fitness tracker that meets my own needs.

WPF Game of Life

I was introduced to cellular automatons a good decade ago through books written by Peter Small. Back then, we were using Adobe (then Macromedia) Director as our primary development platform, where object-oriented programming was still a bit of a novelty. Small’s writings explained OOP using artificial life forms such as cellular automatons, with Conway’s Game of Life being an oft used concrete example. I was hooked and would spend hours running patterns on a simple implementation of the game that shipped with Windows Entertainment Pack.

But I never got around to implementing the application myself until now. The game has a fairly simple model that does not take much effort to build. This is handy when learning a new platform or language, leaves the programmer free to explore the features of the framework instead of spending cycles trying to nail down the business logic correctly using an unfamiliar language syntax.

Background

There are plenty of resources available online that describe, implement and demonstrate this game. The basic essence of the game is a two-dimensional array of cells and an endless loop that iterates over these cells to update their state depending upon some simple rules.

  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overcrowding.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

This implementation of the game also consists of the following features for convenience.

  1. Clicking on a cell toggles its state between being alive or dead.
  2. A Randomize button initializes the board by randomly setting the state of all cells to either alive or dead.
  3. A Stop button lets the user stop the cell update iterations in order to observe the arrangement of the board at any given time. This is useful for times when an interesting pattern appears on the screen that seeks further observation.
  4. A Next button complements the Stop button to let the user iterate to progressive generations of the board, one step at a time.

Implementation

This implementation is made up of the following classes.

MainWindow.xaml and MainWindow.xaml.cs

The application window is a XAML class called MainWindow.xaml, which defines the layout of the application. The layout is built around a DockPanel that divides the screen into two – a controller toolbar and the board view.

<DockPanel Name="layout">
    <ToolBar DockPanel.Dock="Top">
        <Button Content="Start" Name="btnStart" Height="23" Width="75" Margin="5" Click="toggleStart_Click" />
        <Button Content="Next" Name="btnNext" Height="23" Width="75" Margin="5" Click="nextIteration_Click" />
        <Button Content="Clear" Name="btnClear" Height="23" Width="75" Margin="5" Click="clear_Click" />
        <Button Content="Randomize" Name="btnRandomize" Height="23" Width="75" Margin="5" Click="randomize_Click" />
    </ToolBar>
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <life:BoardView x:Name="view" DockPanel.Dock="Top" Margin="10" Click="view_Click"></life:BoardView>
    </ScrollViewer>
</DockPanel>

The MainWindow class stores a reference to an instance of BoardModel as a private field. Buttons in the toolbar are wired to trigger event handlers in the MainWindow class, which in turn trigger public methods exposed by the model and view instances.

BoardModel.cs

The model class is where the business logic behind the application is implemented. It contains two arrays of bytes of identical length, which store the state of the board in the current iteration and the next iteration. It also initializes a timer that is used to iterate over the board state automatically. In addition, it exposes public methods to control the state of the board – Next(), Start(), Stop(), Clear() and Randomize().

The model instance dispatches an Update event every time the board changes. The window class listens for this event and passes on the contents of the new board cells to the Update() method of the view instance.

BoardView.cs

The view class inherits from System.Windows.FrameworkElement in order to take advantage of its built-in layout functionality. The board is drawn using low-level Visual elements. While it is easier to implement the cell drawing by using Drawings or Shapes, it also adds a lot of overhead for unnecessary features such as styles, data binding, automatic layout and input events. DrawingVisuals provide a much more performant way of drawing large numbers of objects on the screen.

private void DrawCells()
{
    if (null == this.values)
    {
        return;
    }

    using (DrawingContext dc = this.cells.RenderOpen())
    {
        int x = 0;
        int y = 0;
        Rect rect = new Rect(OUTLINE_WIDTH, OUTLINE_WIDTH, Constants.CELL_SIZE - OUTLINE_WIDTH, Constants.CELL_SIZE - OUTLINE_WIDTH);

        for (int i = 0; i &amp;lt; values.Length; i++)
        {
            x = (i % Constants.CELLS_X);
            y = (i / Constants.CELLS_X);
            rect.Location = new Point((x * Constants.CELL_SIZE) + OUTLINE_WIDTH, (y * Constants.CELL_SIZE) + OUTLINE_WIDTH);

            if (1 == values[i])
            {
                dc.DrawRectangle(Brushes.Red, null, rect);
            }
        }
    }
}

One must fetch a reference to a DrawingContext in order to draw content onto a DrawingVisual. This is done through the RenderOpen() method of the DrawingVisual. Since we are only drawing basic rectangles, we can use the in-built DrawRectangle() method of the DrawingContext class to draw this shape for us. Internally, this method still uses a GeometryDrawing and a subclass of the Geometry class, but abstracts away those details for convenience.

The drawing is displayed on the screen by adding the Visual instances to the visual tree of the BoardView class, which is done in its constructor.

public BoardView()
    : base()
{
    this.AddVisualChild(this.grid);
    this.AddLogicalChild(this.grid);

    this.AddVisualChild(this.cells);
    this.AddLogicalChild(this.cells);

    this.visuals = new DrawingVisual[] { this.grid, this.cells };

    this.drawGrid();
    this.drawCells();
}

Additionally, the BoardView class also overrides the VisualChildrenCount, GetVisualChild and MeasureOverride members of the FrameworkElement class.

protected override int VisualChildrenCount
{
    get
    {
        return this.visuals.Length;
    }
}

protected override Visual GetVisualChild(int index)
{
    if (index < 0 || index > this.visuals.Length)
    {
        throw new ArgumentOutOfRangeException("index");
    }

    return this.visuals[index];
}

protected override Size MeasureOverride(Size availableSize)
{
    return new Size(Constants.CELLS_X * Constants.CELL_SIZE, Constants.CELLS_Y * Constants.CELL_SIZE);
}

The BoardView class instance also dispatches an event when the user clicks on a cell on the board. This is in turn passed over to the model instance via the window, causing the model to toggle the state of the cell that was clicked.

ClickEventArgs.cs

An instance of this class is passed as a parameter along with the Click event is dispatched from the BoardView class. It exposes two parameters to identify the X and Y coordinates of the cell which was clicked upon, relative to the board.

The Visual Studio solution for this project can be downloaded from here as a ZIP archive.