Thursday, 19 April 2012

Binding in Windows Presentation Foundation (WPF)

What is this post all about?

Any programmer, novice or professional, who has wanted to pick up WPF and thought "hey, I know a few programming languages already. How hard could learning a new one be?" has found themselves rapidly and painfully disillusioned.

There is nothing inherently difficult about the concept of WPF. There are essentially 2 components; XAML and your preferred .NET language out of C# or VB.NET. XAML is a glorified version of XML, but tuned towards application programming. It is used to control the aspects of the application related to display and behaviour, whereas the traditional programming language is for aspects related to data and business logic.

Why is XAML difficult?

WPF is firmly grounded in the concept of MVC (Model-View-Controller) or MVVM (Model-View-ViewModel), depending on which book you read. The idea is that the view does not 'own' any data. Your model owns data, and it is your controller's / view model's job to handle user interaction and to marshal data in and out in a way that suits the application's usage. "If the view cannot own any data," I hear you ask, "how does it display anything to the user?" Good question. Through data binding.

Tell me more about binding...

Ok, since you asked so nicely. Binding is the act of linking a property's value to another property. Depending on how it is set up, a change in one property causes an event to fire which causes the other property to automatically update. If you have a binding between the text in some text box and a string property in your model, when the user navigates away from the text box after typing something, a property changed event gets fired, causing an update of the value in the model.

How does binding work? Literally the only way to answer is by magic. There are so many ways to bind data that it really comes down to horses for courses. You could define a resource in your window that points to the data model and bind the property to that. You could set the DataContext of some control and bind to that. There are more ways than I care to go into now.

The most confusing thing is when you bind a control that displays a collection of items to a collection in a data model. The control somehow just knows that it has to display each item next to each other, or on top of each other, etc. depending on the type of control. For example, you could bind a dropdown box to a List<String> property and it will allow you to select one of the items from that collection. It gets even more confusing when you bind a property of some other control to a property in that collection control. When you select a different item, the bound property also changes.

You're confusing me :(

No doubt. I'm confusing myself if I'm perfectly honest. That is why I spent days writing an application so that I could illustrate what I am talking about with an example. It is a very rudimentary contacts list type application. You can scroll through a list of contacts, click on one, and it will show you more details about the contact in question. You can download the compiled application here;

http://dl.dropbox.com/u/21044234/ContactsLayout.exe

And if you are feeling brave, you can get the source code here;

http://dl.dropbox.com/u/21044234/ContactsLayout.zip

It is built in Visual Studio 2010 Express. You will notice from the source code that, apart from the model data setup, it contains absolutely no source code. The entire application, from the user interaction through to the data presentation, is written in XAML and bound to the data model. It illustrates many of the powerful ways that WPF can be used to write pretty and interactive applications, which is what I like about it.

Sunday, 18 March 2012

Synchronised and Padded Iterators

Synchronised and Padded Iterators

What are they and why use them?

An iterator is something that can be used to loop over a collection of related items. For example, you could have a list of objects in an array which you would like to perform some operation on. An iterator allows you to get the value and step to the next item of interest.

Padded Iterators

Usually, you would only be interested in getting the values of objects in the array. Trying to dereference an index which does not point to an item in an array would result in a runtime error, such as an array out of bonds exception. However, there are cases where you might want to return some sort of value anyway, despite a value not existing in the array. An example would be where two arrays represent events in time, such as a sampled time series. You want to output these two time series aligned in time, such that you get
Time stamp - Value1 - Value2
However, what if these time series might not match up exactly, such that time series 1 has values where time series 2 does not, or vice versa? This is where padded iterators come in. They allow you to give a value at any index, whether one exists or not. You can specify what value to return if one does not exist.

Synchronised Iterators

Synchronised iterators are useful in situations where you would like to iterate over several lists of objects at once. In the example above, you want to get the value out for both time series for a specified time stamp and display them alongside each other. Then, you want to increment the time stamp of all lists being iterated over at once.

Source Code

Padded iterator code

class PaddedIterator
{
    public PaddedIterator(
        List<double> Values, DateTime DataStart, String PadVal)
    {
        _Values = Values;
        _DataStartDate = DataStart;
        _PadVal = PadVal;
        _Iterator = _Values.GetEnumerator();
    }

    public override string ToString()
    {
        if (this.CurrentDate >= _DataStartDate && _MoreData)
        {
            //return dereferenced iterator
            return _Iterator.Current.ToString();
        }
        else
        {
            // return padded value
            return _PadVal;
        }
    }

    public void MoveNext()
    {
        this.CurrentDate += this.Increment;
        if (this.CurrentDate >= _DataStartDate && _MoreData)
        {
            _MoreData = _Iterator.MoveNext();
        }
    }

    public DateTime CurrentDate {get;set;}

    public TimeSpan Increment {get;set;}

    private List<double> _Values;
    private List<double>.Enumerator _Iterator;
    private DateTime _DataStartDate;
    private String _PadVal;
    private bool _MoreData = true;
}

Explanation

In the above C# code, you would first construct a list of double values you would like to iterate over. Then, you construct a padded iterator with a representative start date of the first value and what you would like to give out if you ask for a data value that does not exist. Before using the iterator, you would set the CurrentDate and Increment properties. The CurrentDate is when the iterator starts giving values for, which would either be before or at the beginning of the data. In it's current form, it would not work to give it a CurrentDate that is within the data, as it always starts incrementing from the start of the data. The increment tells the iterator what value to add to the current date each time it is incremented.

Synchronised iterator code

class SynchronisedIterator
{
    public SynchronisedIterator(
        DateTime ReferenceDate, TimeSpan Increment, String PadVal)
    {
        this.Iterators = new List<PaddedIterator>();
        _EndDate = _CurrentDate = _ReferenceDate = ReferenceDate;
        _Increment = Increment;
        _PadVal = PadVal;
    }

    public List<PaddedIterator> Iterators {get;set;}

    public void AddIterator(List<double> Values, DateTime StartDate)
    {
        PaddedIterator Iterator =
            new PaddedIterator(Values, StartDate, _PadVal);
        Iterator.CurrentDate = _ReferenceDate;
        Iterator.Increment = _Increment;
        this.Iterators.Add(Iterator);

        //Recalculate end date to include new data
        int DataSpan = Values.Count * (int)_Increment.TotalDays;
        int OffsetDays = (int) (StartDate - _ReferenceDate).TotalDays;
        DateTime DataEndDate = _ReferenceDate +
            TimeSpan.FromDays(OffsetDays + DataSpan);
        if (DataEndDate > _EndDate) _EndDate = DataEndDate;
    }

    public override String ToString()
    {
        String Row = _CurrentDate.ToShortDateString();
        foreach (PaddedIterator It in this.Iterators)
        {
            Row += string.Format("\t{0}", It);
        }
        return Row;
    }

    public void NextRow()
    {
        _CurrentDate += _Increment;
        foreach (PaddedIterator iterator in this.Iterators)
        {
            iterator.MoveNext();
        }
    }

    public bool MoreData()
    {
        return (_CurrentDate < _EndDate);
    }

    private DateTime _ReferenceDate;
    private DateTime _CurrentDate;
    private DateTime _EndDate;
    private TimeSpan _Increment;
    private String _PadVal;
}

Explanation

In this example, the synchronised iterator holds a reference to a collection of padded iterators. The padded iterators know about the data that is being iterated over, and when to give a data value and when to give a padding value. The job of the synchronised iterator is to output a row of records with the date and the representative value of that date from all the padded iterators.
The synchronised iterator is given a reference start date which is the date that you would like to start returning values for. Then, the synchronised iterator will set up it's list of padded iterators with the current date as the reference start date. The end date is re-calculated for each padded iterator that is added.

Program code

class Program
{
    static void Main(string[] args)
    {
        List<double> myList = new List<double> { 10, 20, 30, 40, 50 };
        SynchronisedIterator synchronisedIterator =
            new SynchronisedIterator(new DateTime(2000, 1, 1),
                TimeSpan.FromDays(2), "None");

        synchronisedIterator.AddIterator(myList, new DateTime(2000, 1, 1));
        synchronisedIterator.AddIterator(myList, new DateTime(2000, 1, 15));
        synchronisedIterator.AddIterator(myList, new DateTime(2000, 1, 6));
        synchronisedIterator.AddIterator(myList, new DateTime(2000, 1, 3));
        synchronisedIterator.AddIterator(myList, new DateTime(2000, 1, 8));

        while (synchronisedIterator.MoreData())
        {
            Console.WriteLine(synchronisedIterator);
            synchronisedIterator.NextRow();
        }

        Console.ReadKey();
    }
}

Explanation

Because much of the complexity of how to iterate through the data, how to format the data, and whether to give values or to pad is hidden within the iterators, the actual program that constructs and uses these iterators can be quite simple.
In this example, I am creating a single list of double values which will be iterated over by several padded iterators. The synchronised iterator is constructed by telling it that it will start giving values from 1 Jan 2000, and that each value is 2 days apart. Whenever there is no value at a particular date, it will pad with the word "None". The actual padded iterators are added by calling AddIterator with the data and what date the data starts from.
Iterating over all the data is done with the while loop and just keeps churning out data until there is no more.

Result

Output of Program

Saturday, 11 February 2012

Creating a numeric left/right control

Why create a numeric left/right control?

A numeric up/down control, also called a spinbox, is used where properties of a form can be set over a continuous range between two extremes. This could be things like month of the year, where the month can only be an integer between 1 and 12.

In Windows Forms, this control looks like a text box with two tiny little arrows to increase or decrease the number.

NumericUpDown






It has several useful features when it has the focus. This includes being able to increase or decrease the numbers by pressing the up and down keys on the keyboard, or using the scroll wheel on the mouse to rapidly change it.

The problem is when it is being used to represent information that is horizontally aligned. Let's say you have a row of objects, and you want to use the spinbox to select which object is selected. Using up and down keys will confuse people. In my case, I needed to page through screens of time series data. A time series is a very long series of data, where the x-axis is time, and is almost always horizontally aligned. This is why I need the buttons to be pointing left and right.

What would be great is if the NumericUpDown control had a property you can toggle, which would just put the buttons on the left and right of the text box! This would save a lot of hastle. Unfortunately, as the name suggests, this is not possible. So I decided to create my own re-usable control that I can place on forms.

Creating a numeric left/right control

Create a new Visual C# project in Visual Studio. Then create a new user control.

Create new user control

I called the control NumericLeftRight. A grey canvas appears for you to create your control. Drop a NumericUpDown and two Button controls onto the canvas and arrange them either side of the NumericUpDown. Unfortunately, there is no way to turn off the up and down buttons on the NumericUpDown, so you will have to cover the up and down buttons with the right button. Change the text in the buttons to angle brackets to represent left and right operation.

Laying out the controls

Double click on the buttons to create click handers for them. In the click handlers, call the NumericUpDown.UpButton() and NumericUpDown.DownButton() methods. Also, expose the NumericUpDown control through a property. This is so that you can set the NumericUpDown control's settings , such as maximum and minimum, in the initialisation code for the form you drop it onto.

Click handlers and exposed NumericUpDown property

Compile your project and you are ready to add it to your form. Go back to the form designer and open the toolbox. You should see the user control for the NumericLeftRight available to drop onto the form.

The control appears in the toolbox

Drag the NumericLeftRight onto the form. Everything should be ready to go! Compile and launch the program and test that the buttons do increment and decrement the number in the NumericUpDown. In the properties window, the NumericUpDown property that I exposed can be seen in the Misc category at the bottom. You can expand it to see all the internal properties. However, you cannot set these properties here and have them applied at runtime. The designer does not apply these changes permanently for some reason. You need to go into the Form1.Designer.cs code directly and add the values to the properties manually.

Manually set the properties in the designer generated code
Hopefully, this should be everything you need to do in order to create a usable NumericLeftRight control. Compile and run, then spin away!

Using the form