
Introduction
Few weeks back, I wanted to use a stop watch to measure the time it takes to
complate a 400 meter lap. I looked all
the installed app in my Windows phone but couldn't find one available. A
quick search on Windows market place and I found plenty of stop watch
application on Windows market place for free which encouraged me to write one
for myself.
This application is a very basic stop watch. It starts the stop watch once a
user presses start button. The timer continues until user presses stop button.
While stop watch is on, user can add laps. The application also has some other
basic features like
1. turning off the idle time screen out. This
feature was important as, to save battery, usually phone screen automatically turns off if
inactive for few seconds.
2. Saving timer values if moved away from the application. This is to save
the values if user moves away from stop watch application accidently without
stopping the timer.
This application is posted on Windows Phone app market. Check it here.
Required software
Silverlight for Windows Phone
toolkit
Windows Phone Developer Tools
Visual Studio 2010
Without these softwares, this application will not
compile.
Basic design
Visual Studio provides many different templates for Windows Phone
development as shown below.

Before I start my design choices, I will present a basic understanding of
few of these templates.
The most basic template is Windows Phone Application. User is presented with
a scrollable screen. User can move to next screen by pushing on some button.
The screen can be scrollable vertically but not horizontally. A developer can
add application bar to give user choices like change settings or selection of
different menu.
Pivot application presents data in a tab format. This might be the most
common format for Windows phone development as user can swipe horizontally to
see/tap other tabs. Check the Marketplace application for a sample of this
template. The nice thing about the pivot template is that a developer can add
an application bar.
Panaroma applications are very similar to pivot
application but they don't have any application bar. Basically this type of
application acts like a large canvas and user swipes horizontally to see other
available options. The application title stretches to multiple screens and each
section is narrower than the entire phone width so that the next available
section is visible to user. The entire screens is
wrapped around so that swiping from last option, the screen will move to first
option.
To develop this application, I have chosen Windows Phone Panaroma
Application. The choice is mainly based on the fact that I liked the look of
this type of application and in my application, I don't need an application bar
as I can give all the user choices in one of the sections itself.
To show elapsed time, I developed a new control, TimeSpanControl.
Initially I used a simple text block and was updating this text block everytime elapsed time chaged.
The problem with this approach was that the update of the text was not smooth.
It looked like an old Windows desktop paint application where the text used to
flicker during update.
To save data to/from phone, I created a generic class, PersistSettings.
This class is based on an article on isolated storage in Silverlight on the www.silverlight.net
web-site. This class automatically saves the data everytime
a variable (attached to this class) is used. When user comes back to this
application (using OnNavigatedTo event handler), the
settings load from the isolated storage.
The application uses a timer to calculate the elapsed time.
The entire application is divided into 3 sections: timer, settings and
about. The timer section displays the elapsed time,
user controlled lap count and reset buttons. The settings section has few
settings like turning off the screen lock feature and a warning message for
reset timer values. The about section is basically about the application like
the version etc.
Using the code
As mentioned above that this application has three pararoma
items: timer , settings and about. Each section
uses a grid with various rows (and possibly columns).
<controls:Panorama x:Name="StopWatch" Title="stop watch" Foreground="White" FontFamily="Calibri" FontSize="18">
<!---->
<controls:PanoramaItem x:Name="ElapedTimer" Foreground="White" FontSize="16" Header="Timer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
...
...
<!---->
...
To use the Windows phone toolkit, I added the namespace in
the Xaml file as shown below (on top of the file):
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"<br>
To use an included namespace,
just prefix the name as shown below:
<toolkit:ToggleSwitch x:Name="ResetWarning"
Header="Reset warning"<br> IsChecked="True"
Checked="ResetWarning_Checked"
Unchecked="ResetWarning_Unchecked" Content="Yes"
Grid.Row="1"/><local:timespancontrol fontsize="40" fontfamily="Segoe WP Bold" horizontalalignment="Center" digitwidth="28" grid.columnspan="4" grid.row="0" x:name="TotalTimeDisplay"><local:timespancontrol x:name="TotalTimeDisplay" grid.row="0" grid.columnspan="4" digitwidth="28" horizontalalignment="Center" fontfamily="Segoe WP Bold" fontsize="40" />
The exact same way any user controls can be used.
Usually Microsoft.Phone namespace provides many useful features to control
phones like shown above. To perform phone related tasks like sending an email,
start camera or search a particular content in the MarketPlace, use the
Microsoft.Phone.Tasks namespace.
As an example, to turn on/off the idle time screen lock, just use the
IdleDetectionMode enum as shown below:
private void UserIdleModeOnOff_Checked(object sender, RoutedEventArgs e)
{
this.UserIdleModeOnOff.Content = "Yes";
try
{
Microsoft.Phone.Shell.PhoneApplicationService.Current.ApplicationIdleDetectionMode =
Microsoft.Phone.Shell.IdleDetectionMode.Disabled;
}
catch (InvalidOperationException ex)
{
}
}
Persist settings class
This class uses a key/value pair to save or retrieve data from isolated
storage. This is a generic class and can be used to save any kind of basic data
like integer, string etc. To use this class just use it as:
PersistSettings<int> currentLap = new PersistSettings<int> ("LapCount", 0);
where LapCount is the value we want to save. To use the LalCount, just use as
LapCount.Value. The Value property is implemented in a very simple way:
public T Value
{
get
{
if (!IsolatedStorageSettings.ApplicationSettings.TryGetValue(
this.name, out this.value))
{
IsolatedStorageSettings.ApplicationSettings[this.name] = this.initialValue;
}
return this.value;
}
set
{
IsolatedStorageSettings.ApplicationSettings[this.name] = value;
this.value = value;
}
}
Time span control
The time span control is a user control which displays the elapsed time
string within a defined width. If the elapsed time text won't fit within the
defined width, the text will cut off. The interesting part of this control is
that it has a fixed width and hence the text doesn't flicker as shown below:
public partial class TimeSpanControl : UserControl
{
int digitWidth;
TimeSpan time;
public TimeSpanControl()
{
InitializeComponent();
if (DesignerProperties.IsInDesignTool)
this.LayoutRoot.Children.Add(new TextBlock { Text = "00:00:00.0" });
}
public int DigitWidth
{
get { return this.digitWidth; }
set
{
this.digitWidth = value;
this.Time = this.time;
}
}
public TimeSpan Time
{
get { return this.time; }
set
{
this.LayoutRoot.Children.Clear();
string hoursString = value.Hours.ToString();
ConcatenateTime((value.Hours / 10).ToString());
ConcatenateTime((value.Hours % 10).ToString());
this.LayoutRoot.Children.Add(new TextBlock { Text = ":" });
string minutesString = value.Minutes.ToString();
ConcatenateTime((value.Minutes / 10).ToString());
ConcatenateTime((value.Minutes % 10).ToString());
this.LayoutRoot.Children.Add(new TextBlock { Text = ":" });
ConcatenateTime((value.Seconds / 10).ToString());
ConcatenateTime((value.Seconds % 10).ToString());
this.LayoutRoot.Children.Add(new TextBlock
{
Text = System.Globalization.CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalSeparator
});
ConcatenateTime((value.Milliseconds / 100).ToString());
this.time = value;
}
}
void ConcatenateTime(string timeValue)
{
TextBlock textBlock = new TextBlock
{
Text = timeValue,
Width = this.DigitWidth,
HorizontalAlignment = HorizontalAlignment.Center
};
this.LayoutRoot.Children.Add(textBlock);
}
}
History
First version: Feb 2012
Updated on Feb 13, 2012 to add history of completed lap and time.