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.
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.
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!
I want the timings to be displayed as below:
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.
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.
At this point we are ready for create the new visualization that we need for our feature
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.
The new <Grid /> now introduces the new display. Notice the following carefully:
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:
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:
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.
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.
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.
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.
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:
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
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
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.
Notice, since the event name is a text box, you can simply type in it to change the default name – as shown below
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.
Next, I change the TextBox XAML definition to include the newly defined style
With that, when I run the application, the TextBox looks a lot nicer!
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!
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
Finally I test to see that portrait mode works well and it does!
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.