The IPLT20 cricket championship is currently in progress – this means there is a lot of cricket on Television. Usually a couple of games from 4pm to almost midnight! If you don’t have any other plans, these games are a great option to while away your evenings. I spend some time on the weekends watching these games. But I now have a happy solution to ensure watching the games doesn’t just become recreation but otherwise an unproductive use of time – I can continue to extend my Windows Phone Application and blog while I watch the games – woohoo!

It is time to add some new functionality and new concepts to the Chronometer application I have been building. I have posted a set of three blogs so far on it, with the first one being here.

The new functionality that I will add

In this post, I want to add the support of the “Save” functionality to the Stopwatch. If you remember, in the second post I had introduced the “Save” button in the Application Bar – however, I had not added any code for it. In this post I will add the following functionality.

  • The “Save” button will be enabled only when the Stopwatch is in paused state (disabled with the watch is running)
  • When you hit “Save” it will do the following:
  • “Copy” the time on the Stopwatch to a new line below the Stopwatch
  • Any existing lines will be pushed down one row
  • Each new line will have a default name, and the Stopwatch time against it
  • The name of the line should be editable 
  • The list of lines should be scrollable
  • The “Save” button should also reset the Stopwatch to “00:00:00:00”

 

Persistence and data binding too

It is important to mention here that, in the current release of the Windows Phone 7 only one application runs at a time. When you back out of your application, it gets suspended which is known as the “Tombstone” notion. While you get notifications of when the application gets tombstoned, but there is no guarantee that the application will be resumed from the same state when you go back to it. It may have gotten terminated (you would know that in the notification) and restarted. Hence it is important to take care of data persistence explicitly across tombstoning and restart.

I would like to save the list of timings displayed above from session to session.

For this, I will introduce the concept of persistence of the data in file, and I will also introduce the concept of data binding so that it makes it easy to associate and bind the data in the application screen to the file it is persisted in.

I am looking forward to learning a lot as I do this!

Creating the visualization of the area where timings are saved

I want the timings to be displayed as below:

<default timing name>     <hh1:mm1:ss1:ttt1>

<default timing name>     <hh2:mm2:ss1:ttt2>

……..

<default timing name>     <hhn:mmn:ssn:tttn>

While the name on each line starts with a default name (say “timing”), I want the name to be editable – so it needs to be TextBox. The actual value of the time however will be read-only (that value when save was hit) and hence it will be a TextBlock.

First, a basic education in data binding to a control

Let us first understand how data binding to a control works. There is already an excellent MSDN article here.  Please study the article, especially the following concepts that we will use in our application.

  • You have source and targets for binding, and a target is setup for binding using the “{Binding}” attribute value
  • There are two modes for binding – one way, and two way – via the BindingMode.OneWay (default) and BindingMode.TwoWay settings
  • The DataContext property of a framework or ui element allows it to participate in binding
  • The ObservableCollection<T> class that represents a dynamic data collection that provides notifications when items get added, removed, or when the entire list is refreshed
  • The INotifyPropertyChanged interface that notifies clients that a property value had changed
  • A DataTemplate that enables to customize how lists are displayed in a control, and ItemsControl.ItemTemplate that gets or sets the DataTemplate
  • The ItemsControl that can be used to represent a collection of items

At this point we are ready for create the new visualization that we need for our feature

The main content display XAML

I have created the design for the new content, and the XAML for that is shown below. You will notice that we have the “TimerDisplay” TextBlock at the top – this is the main display for the Stopwatch which we had introduced in the earlier posts – nothing has changed, I have however taken it out of the Grid which defines the new visualization that I will introduce now (and adjusted it’s margins to re-align it to where it was in the earlier posts.

image

The new <Grid /> now introduces the new display. Notice the following carefully:

  • For the make the entire Grid databound by marking DataContext=”{Binding}”.
  • The Grid essentially contains a ListBox “MainListBox”, and note the ItemSource property and it is bound to “inmemList” which will be an in memory list
  • The ListBox has a StackPanel which essentially stacks up a TextBox for the name of the timings, and the TextBlock to save the time
  • The “Text” property of the TextBox and TextBlock are set to data bound to EventName and timingsms variables.
  • Both of the above are set to TwoWay data binding

The data structure that will hold the list of timings in memory

As described earlier, the list of timings that the application will display is essentially a collection of tuples – with each tuple holding a string that represents the name of the event for which the Stopwatch was being used, and another string representing the timing value for that event.

We want to represent this as an ObservableCollection object with a class that holds the above tuple strings. This object will also fire the INotifyPropertyChanged event when any of the strings are changed. The data structure is simply the following:

image

image

image

image

Persisting the timings collection into a file

Now lets get to the code that saves the above data structure – the timings collection – into a file, which essentially will be our backing store

The code for this is pretty simple and almost self explanatory. Here it is:

image

image

image

Note, in the above code GetUserStoreForApplication essentially obtains a user-scoped isolated storage corresponding to the calling codes application identity. I will simply use a flat text file in the above storage for serializing and deserializing the timings collection data structure.

Here is the code which saves the data structure into a file, one line per timing tuple. It creates the file “acstopwatch.txt” if it is not already on the device, or opens it if it is there. The function is called with the collection. It then simply enumerates each element in the collection and writes out a line with the EventName and the timingsinms strings, separated by a comma.

image

The loading of the data structure from the file is likewise pretty simple. It opens the file, clears out the in-memory collection, reads one line at a time, and then splits the string at a comma to get the two texts stings that it creates a new Timing structure in the collection.

image

We will now do the initialization – where we will read the file, loading the in memory data structure, and set it as the data bound source for the MainListBox in our display that we created earlier in XAML. Note the last three lines in the code snipped below.

image

The application visibly looks no different yet

At this point we will build and run the application – and as expected, the application is visibly no different. The screen shot is shown below, and is really still where we had left off in the last blog. This is because while we aren’t really creating items in the MainListBox yet – that is the logic we now need to build into the play and save buttons. That comes up next.

image

Wiring in the new play/pause and save logic

First we add the save handler to the save button in the application bar. At this point I also take the opportunity to rename the handler for the play button to what I had in the previous post to the following:

image

The play_click logic keeps the save button disabled while the stopwatch is in play mode, and enables it when in the pause or stop mode

image

The save logic is pretty simple – it adds a new item to the timings collection, gives it a default name based on the number of items in the collection, and resets the Stopwatch

image

Now we see the new UI and the Stopwatch logic is in place

We are now ready to run the application. The screen below shows the Stopwatch running – see the save button displayed, then the pause mode where the save button is enabled, and on clicking the save notice the new line which shows up below the display.

imageimageimage

Notice, since the event name is a text box, you can simply type in it to change the default name – as shown below

imageimage

Improving the style of the TextBox

I don’t like the default look of the TextBox – the gray object – shown above. I would really like it to be like the TextBlock shown to the right. Perhaps there is a way to do this in the default designer –  but this can also be done easily be designers who use Expression Blend.

My colleague at work is very handy with Blend – and he has a style which matches what I want and I would use that. For the purpose of this blog I will simply show the XAML generated by Blend for the style in question – and perhaps explore Blend at another time.

I am only showing a part of the XAML for the style, as it is a lot of XAML code (please let me know if you need the full style). I am putting this in the App.XAML file.

image

Next, I change the TextBox XAML definition to include the newly defined style

image

With that, when I run the application, the TextBox looks a lot nicer!

image

Some final screen shots

We are done. Here are some final screen shots. The screen shows the state after a set of timings have been added, with some event names changed. The one on right shows that scrolling works just fine!

imageimage

Next we hit the back button to tombstone the application, and when we launch it again, we see that it has reloaded all of the saved timings showing that persistence is working just fine too

imageimage

Finally I test to see that portrait mode works well and it does!

image

That completes a few hours of coding this afternoon, and the cricket match is still on! I hope this blog is useful to someone out there who wants to add data binding and persistence to their application.

Cheers!