PunchClock: Source Code
May 19, 2012Here is the source code for my first Windows Phone application. It has a few thing I would do differently now but I can admit this baby is a bit ugly. 🙂
Download PunchClock.WP7 Solution
This solution requires Telerik RadControls for Windows Phone. You can download a trial here.
First page is MainPage.xaml:
 <phone:PhoneApplicationPage
   x:Class="PunchClock.WP7.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:my="clr-namespace:Microsoft.Advertising.Mobile.UI;assembly=Microsoft.Advertising.Mobile.UI"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">
   <!--LayoutRoot is the root grid where all page content is placed-->
   <Grid x:Name="LayoutRoot">
       <Grid.Background>
           <ImageBrush ImageSource="/Images/background.png">
             <ImageBrush.Stretch>Fill</ImageBrush.Stretch>
               <ImageBrush.Opacity>0.3</ImageBrush.Opacity>
           </ImageBrush>
       </Grid.Background>
 <Grid.RowDefinitions>
           <RowDefinition Height="Auto"/>
           <RowDefinition Height="*"/>
       </Grid.RowDefinitions>
       <!--TitlePanel contains the name of the application and page title-->
       <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
           <TextBlock x:Name="ApplicationTitle" Text="PUNCHCLOCK" Style="{StaticResource PhoneTextNormalStyle}"/>
           <TextBlock x:Name="PageTitle" Text="send email" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
       </StackPanel>
       <!--ContentPanel - place additional content here-->
       <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
           <StackPanel VerticalAlignment="Top" Name="ButtonsStackPanel" Width="420" Height="391" Margin="18,0">
               <Button Content="Start Day" Height="93" Name="DayStartButton" Width="374" Click="DayStartButton_Click" />
               <Button Content="Start Lunch" Height="93" Name="LunchStartButton" Width="374" Click="LunchStartButton_Click" />
               <Button Content="End Lunch" Height="93" Name="LunchEndButton" Width="374" Click="LunchEndButton_Click" />
               <Button Content="End Day" Height="93" Name="DayEndButton" Width="374" Click="DayEndButton_Click" />
           </StackPanel>
       </Grid>
       <my:AdControl Height="86" HorizontalAlignment="Left" Margin="0,444,0,0" VerticalAlignment="Top" Width="480" Grid.Row="1">
           <my:AdControl.Name>mainPageAdControl</my:AdControl.Name>
           <my:AdControl.ApplicationId>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</my:AdControl.ApplicationId>
           <my:AdControl.AdUnitId>XXXXXXXX</my:AdControl.AdUnitId>
           <my:AdControl.IsAutoRefreshEnabled>true</my:AdControl.IsAutoRefreshEnabled>
       </my:AdControl>
   </Grid>
</phone:PhoneApplicationPage>
The code behind file (MainPage.xaml.cs) contains most of the business logic for the application.
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PunchClock.WP7.Business;
using Telerik.Windows.Controls;
namespace PunchClock.WP7
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
RadDiagnostics radDiagnostics = new RadDiagnostics();
radDiagnostics.EmailTo = "support@adambenoit.com";
radDiagnostics.ApplicationName = "PunchClock WP7";
radDiagnostics.ApplicationVersion = "1.0";
radDiagnostics.ExceptionOccurred += new EventHandler<ExceptionOccurredEventArgs>(RadDiagnostics_ExceptionOccurred);
radDiagnostics.IncludeScreenshot = true;
radDiagnostics.Init();
// Add an Application Bar
ApplicationBar = new ApplicationBar();
ApplicationBar.IsMenuEnabled = true;
ApplicationBar.IsVisible = true;
ApplicationBar.Opacity = 1.0;
ApplicationBarIconButton settingButton = new ApplicationBarIconButton(new Uri("/Images/appbar.feature.settings.rest.png", UriKind.Relative));
settingButton.Text = "settings";
settingButton.Click += new EventHandler(settingButton_Click);
ApplicationBarIconButton helpButton = new ApplicationBarIconButton(new Uri("/Images/appbar.questionmark.rest.png", UriKind.Relative));
helpButton.Text = "help";
helpButton.Click += new EventHandler(helpButton_Click);
ApplicationBar.Buttons.Add(settingButton);
ApplicationBar.Buttons.Add(helpButton);
}
void settingButton_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/Views/Settings.xaml", UriKind.Relative));
}
void helpButton_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/Views/Help.xaml", UriKind.Relative));
}
private void RadDiagnostics_ExceptionOccurred(object sender, ExceptionOccurredEventArgs e)
{
//e.Cancel = true; setting Cancel to true will prevent the message box from displaying.
}
private void DayStartButton_Click(object sender, RoutedEventArgs e)
{
SendEmail email = new SendEmail(PunchTypes.DayStart);
}
private void LunchStartButton_Click(object sender, RoutedEventArgs e)
{
SendEmail email = new SendEmail(PunchTypes.LunchStart);
}
private void LunchEndButton_Click(object sender, RoutedEventArgs e)
{
SendEmail email = new SendEmail(PunchTypes.LunchEnd);
}
private void DayEndButton_Click(object sender, RoutedEventArgs e)
{
SendEmail email = new SendEmail(PunchTypes.DayEnd);
}
}
}
The second page is the Settings.xaml:
 <phone:PhoneApplicationPage
   x:Class="PunchClock.WP7.Views.Settings"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   xmlns:local="clr-namespace:PunchClock.WP7.Business" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
       <local:AppSettings x:Key="appSettings"></local:AppSettings>
   </phone:PhoneApplicationPage.Resources>
   <!--LayoutRoot is the root grid where all page content is placed-->
   <Grid x:Name="LayoutRoot" Background="Transparent">
       <!--Pivot Control-->
       <controls:Pivot Title="PUNCHCLOCK">
           <!--Pivot item one-->
           <controls:PivotItem Header="Addresses">
               <Grid>
                   <StackPanel VerticalAlignment="Top" Name="addressesStackPanel" Width="420" Height="408">
                       <TextBlock Text="Email To" Name="toEmailLabelTextBlock" FontSize="24" Foreground="{StaticResource PhoneAccentBrush}" />
                       <TextBlock Text="" Name="toNameTextBlock" FontSize="28" Foreground="{StaticResource PhoneForegroundBrush}" />
                       <TextBlock Text="" Name="toEmailTextBlock" FontSize="32" Foreground="{StaticResource PhoneForegroundBrush}" />
                       <Button Content="Select a contact" Height="71" Name="selectContactButton" Width="282" Click="selectContactButton_Click" />
                   </StackPanel>
               </Grid>
           </controls:PivotItem>
           <!--Pivot item two-->
           <controls:PivotItem Header="Subjects">
               <Grid>
                   <StackPanel VerticalAlignment="Top" Name="subjectsStackPanel" Width="420" Height="408">
                       <TextBlock Text="Start Day" Name="dayStartLabelTextBlock" FontSize="24" Foreground="{StaticResource PhoneAccentBrush}" />
                       <TextBox HorizontalAlignment="Left" Name="dayStartTextBox" Width="420" />
                       <TextBlock Text="Start Lunch" Name="lunchStartLabelTextBlock" FontSize="24" Foreground="{StaticResource PhoneAccentBrush}" />
                       <TextBox HorizontalAlignment="Left" Name="lunchStartTextBox" Width="420" />
                       <TextBlock Text="End Lunch" Name="lunchEndLabelTextBlock" FontSize="24" Foreground="{StaticResource PhoneAccentBrush}" />
                       <TextBox HorizontalAlignment="Left" Name="lunchEndTextBox" Width="420" />
                       <TextBlock Text="End Day" Name="dayEndLabelTextBlock" FontSize="24" Foreground="{StaticResource PhoneAccentBrush}" />
                       <TextBox HorizontalAlignment="Left" Name="dayEndTextBox" Width="420" />
                   </StackPanel>
               </Grid>
           </controls:PivotItem>
       </controls:Pivot>
   </Grid>
</phone:PhoneApplicationPage>
Settings.xaml.cs
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;
using PunchClock.WP7.Business;
namespace PunchClock.WP7.Views
{
public partial class Settings : PhoneApplicationPage
{
public AppSettings settings = new AppSettings();
public Settings()
{
InitializeComponent();
// Add an Application Bar that has a 'done' confirmation button and
// a 'cancel' button
ApplicationBar = new ApplicationBar();
ApplicationBar.IsMenuEnabled = true;
ApplicationBar.IsVisible = true;
ApplicationBar.Opacity = 1.0;
ApplicationBarIconButton doneButton = new ApplicationBarIconButton(new Uri("/Images/appbar.check.rest.png", UriKind.Relative));
doneButton.Text = "done";
doneButton.Click += new EventHandler(doneButton_Click);
ApplicationBarIconButton cancelButton = new ApplicationBarIconButton(new Uri("/Images/appbar.Close.rest.png", UriKind.Relative));
cancelButton.Text = "cancel";
cancelButton.Click += new EventHandler(cancelButton_Click);
ApplicationBar.Buttons.Add(doneButton);
ApplicationBar.Buttons.Add(cancelButton);
toEmailTextBlock.Text = settings.ToEmailSetting;
toNameTextBlock.Text = settings.ToNameSetting;
dayStartTextBox.Text = settings.DayStartSetting;
lunchStartTextBox.Text = settings.LunchStartSetting;
lunchEndTextBox.Text = settings.LunchEndSetting;
dayEndTextBox.Text = settings.DayEndSetting;
}
void doneButton_Click(object sender, EventArgs e)
{
try
{
settings.ToEmailSetting = toEmailTextBlock.Text;
settings.ToNameSetting = toNameTextBlock.Text;
settings.DayStartSetting = dayStartTextBox.Text;
settings.LunchStartSetting = lunchStartTextBox.Text;
settings.LunchEndSetting = lunchEndTextBox.Text;
settings.DayEndSetting = dayEndTextBox.Text;
NavigationService.GoBack();
}
catch (Exception ex)
{
MessageBoxResult result =
MessageBox.Show(
"There was a problem Saving, please try again. If the problem continues, please report the problem by choosing 'Cancel' and saying yes to the next message..",
"Error", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.Cancel)
{
throw ex;
}
else if (result == MessageBoxResult.OK)
{
}
}
}
void cancelButton_Click(object sender, EventArgs e)
{
NavigationService.GoBack();
}
private void selectContactButton_Click(object sender, EventArgs e)
{
try
{
EmailAddressChooserTask emailAddressChooserTask = new EmailAddressChooserTask();
emailAddressChooserTask.Completed += new EventHandler<EmailResult>(emailAddressChooserTask_Completed);
emailAddressChooserTask.Show();
}
catch (Exception ex)
{
}
}
void emailAddressChooserTask_Completed(object sender, EmailResult e)
{
if (e.TaskResult == TaskResult.OK)
{
try
{
toNameTextBlock.Text = e.DisplayName;
toEmailTextBlock.Text = e.Email;
}
catch (Exception ex)
{
}
}
}
}
}
AppSettings.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.IsolatedStorage;
namespace PunchClock.WP7.Business
{
   public class AppSettings
   {
       // Our isolated storage settings
       IsolatedStorageSettings isolatedStore;
       // The isolated storage key names of our settings
       private const string ToEmailSettingKeyName = "ToEmail";
       private const string ToNameSettingKeyName = "ToName";
       private const string CcToSelfSettingKeyName = "CcToSelf";
       private const string DayStartSettingKeyName = "DayStartSubject";
       private const string LunchStartSettingKeyName = "LunchStartSubject";
       private const string LunchEndSettingKeyName = "LunchEndSubject";
       private const string DayEndSettingKeyName = "DayEndSubject";
       // The default value of our settings
       private const string ToEmailSettingDefault = "email@example.com";
       private const string ToNameSettingDefault = "Default User";
       private const bool CcToSelfSettingDefault = true;
       private const string DayStartSettingDefault = "Arrival Time";
       private const string LunchStartSettingDefault = "Off to lunch";
       private const string LunchEndSettingDefault = "Back From Lunch";
       private const string DayEndSettingDefault = "Home Time";
       /// <summary>
       /// Constructor that gets the application settings.
       /// </summary>
       public AppSettings()
       {
           try
           {
               // Get the settings for this application.
               isolatedStore = IsolatedStorageSettings.ApplicationSettings;
           }
           catch (Exception e)
           {
               Debug.WriteLine("Exception while using IsolatedStorageSettings: " + e.ToString());
           }
       }
       /// <summary>
       /// Update a setting value for our application. If the setting does not
       /// exist, then add the setting.
       /// </summary>
       /// <param name="Key"></param>
       /// <param name="value"></param>
       /// <returns></returns>
       public bool AddOrUpdateValue(string Key, Object value)
       {
           bool valueChanged = false;
           try
           {
               // if new value is different, set the new value.
               if (isolatedStore[Key] != value)
               {
                   isolatedStore[Key] = value;
                   valueChanged = true;
               }
           }
           catch (KeyNotFoundException)
           {
               isolatedStore.Add(Key, value);
               valueChanged = true;
           }
           catch (ArgumentException)
           {
               isolatedStore.Add(Key, value);
               valueChanged = true;
           }
           catch (Exception e)
           {
               Debug.WriteLine("Exception while using IsolatedStorageSettings: " + e.ToString());
           }
           return valueChanged;
       }
       /// <summary>
       /// Get the current value of the setting, or if it is not found, set the
       /// setting to the default setting.
       /// </summary>
       /// <typeparam name="valueType"></typeparam>
       /// <param name="Key"></param>
       /// <param name="defaultValue"></param>
       /// <returns></returns>
       public valueType GetValueOrDefault<valueType>(string Key, valueType defaultValue)
       {
           valueType value;
           try
           {
               value = (valueType)isolatedStore[Key];
           }
           catch (KeyNotFoundException)
           {
               value = defaultValue;
           }
           catch (ArgumentException)
           {
               value = defaultValue;
           }
           return value;
       }
       /// <summary>
       /// Save the settings.
       /// </summary>
       public void Save()
       {
           isolatedStore.Save();
       }
       /// <summary>
       /// Property to get and set a Username Setting Key.
       /// </summary>
       public string ToEmailSetting
       {
           get
           {
               return GetValueOrDefault<string>(ToEmailSettingKeyName, ToEmailSettingDefault);
           }
           set
           {
               AddOrUpdateValue(ToEmailSettingKeyName, value);
               Save();
           }
       }
       /// <summary>
       /// Property to get and set a Username Setting Key.
       /// </summary>
       public string ToNameSetting
       {
           get
           {
               return GetValueOrDefault<string>(ToNameSettingKeyName, ToNameSettingDefault);
           }
           set
           {
               AddOrUpdateValue(ToNameSettingKeyName, value);
               Save();
           }
       }
       /// <summary>
       /// Property to get and set a ListBox Setting Key.
       /// </summary>
       public string DayStartSetting
       {
           get
           {
               return GetValueOrDefault<string>(DayStartSettingKeyName, DayStartSettingDefault);
           }
           set
           {
               AddOrUpdateValue(DayStartSettingKeyName, value);
               Save();
           }
       }
       /// <summary>
       /// Property to get and set a ListBox Setting Key.
       /// </summary>
       public string LunchStartSetting
       {
           get
           {
               return GetValueOrDefault<string>(LunchStartSettingKeyName, LunchStartSettingDefault);
           }
           set
           {
               AddOrUpdateValue(LunchStartSettingKeyName, value);
               Save();
           }
       }
       /// <summary>
       /// Property to get and set a ListBox Setting Key.
       /// </summary>
       public string LunchEndSetting
       {
           get
           {
               return GetValueOrDefault<string>(LunchEndSettingKeyName, LunchEndSettingDefault);
           }
           set
           {
               AddOrUpdateValue(LunchEndSettingKeyName, value);
               Save();
           }
       }
       /// <summary>
       /// Property to get and set a ListBox Setting Key.
       /// </summary>
       public string DayEndSetting
       {
           get
           {
               return GetValueOrDefault<string>(DayEndSettingKeyName, DayEndSettingDefault);
           }
           set
           {
               AddOrUpdateValue(DayEndSettingKeyName, value);
               Save();
           }
       }
       /// <summary>
       /// Property to get and set a ListBox Setting Key.
       /// </summary>
       public bool CcToSelfSetting
       {
           get
           {
               return GetValueOrDefault<bool>(CcToSelfSettingKeyName, CcToSelfSettingDefault);
           }
           set
           {
               AddOrUpdateValue(CcToSelfSettingKeyName, value);
               Save();
           }
       }
   }
}
Here is the Help.xaml file.
<phone:PhoneApplicationPage
   x:Class="PunchClock.WP7.Views.Help"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait">
   <!--LayoutRoot is the root grid where all page content is placed-->
   <Grid x:Name="LayoutRoot" Background="Transparent">
       <!--Pivot Control-->
       <controls:Pivot Title="PunchClock">
           <!--Pivot item one-->
           <controls:PivotItem Header="about">
               <Grid>
                   <StackPanel VerticalAlignment="Top" Name="aboutStackPanel" Width="420" Height="612">
                       <TextBlock Height="400" Name="textBlock1" Text="PunchClock is an email based application for keeping track of when you arrive to work, take lunch and head home." FontSize="28" TextWrapping="Wrap" />
                   </StackPanel>
               </Grid>
           </controls:PivotItem>
           <!--Pivot item one-->
           <controls:PivotItem Header="configuration">
               <Grid>
                   <StackPanel VerticalAlignment="Top" Name="configurationStackPanel" Width="420" Height="612">
                       <TextBlock Height="45" Name="textBlock4" Text="1. Open application settings." FontSize="28" TextWrapping="Wrap"/>
                       <TextBlock Height="80" Name="textBlock5" Text="2. Select a recipient from your contacts." FontSize="28" TextWrapping="Wrap" />
                       <TextBlock Height="45" Name="textBlock6" Text="3. Update the email subject lines." FontSize="28" TextWrapping="Wrap" />
                       <TextBlock Height="45" Name="textBlock7" Text="4. Save the settings." FontSize="28" TextWrapping="Wrap"/>
                   </StackPanel>
               </Grid>
           </controls:PivotItem>
           <!--Pivot item one-->
           <controls:PivotItem Header="usage">
               <Grid>
                   <StackPanel VerticalAlignment="Top" Name="usageStackPanel" Width="420" Height="612">
                       <TextBlock Height="45" Name="textBlock8" Text="1. Open application settings." FontSize="28" TextWrapping="Wrap" />
                       <TextBlock Height="80" Name="textBlock9" Text="2. Select a recipient from your contacts." FontSize="28" TextWrapping="Wrap" />
                       <TextBlock Height="45" Name="textBlock10" Text="3. Update the email subject lines." FontSize="28" TextWrapping="Wrap" />
                       <TextBlock Height="45" Name="textBlock11" Text="4. Save the settings." FontSize="28" TextWrapping="Wrap"/>
                   </StackPanel>
               </Grid>
           </controls:PivotItem>
           <!--Pivot item one-->
           <controls:PivotItem Header="support">
               <Grid>
                   <StackPanel VerticalAlignment="Top" Name="supportStackPanel" Width="420" Height="612">
                       <TextBlock Height="80" Name="textBlock12" Text="1. Email support is available from support@adambenoit.com" FontSize="28" TextWrapping="Wrap" />
                       <TextBlock Height="80" Name="textBlock13" Text="2. Bug reports and suggestions are always welcome." FontSize="28" TextWrapping="Wrap" />
                   </StackPanel>
               </Grid>
           </controls:PivotItem>
       </controls:Pivot>
   </Grid>
</phone:PhoneApplicationPage>
Email.cs:
using System;
using System.Windows;
using Microsoft.Phone.Tasks;
namespace PunchClock.WP7.Business
{
   public class SendEmail
   {
       private readonly AppSettings _settings = new AppSettings();
       private readonly EmailComposeTask _emailComposeTask;
       public SendEmail(PunchTypes punchType)
       {
           try
           {
               _emailComposeTask = new EmailComposeTask();
               switch (punchType)
               {
                   case PunchTypes.DayStart:
                       _emailComposeTask.Subject = _settings.DayStartSetting;
                       break;
                   case PunchTypes.LunchStart:
                       _emailComposeTask.Subject = _settings.LunchStartSetting;
                       break;
                   case PunchTypes.LunchEnd:
                       _emailComposeTask.Subject = _settings.LunchEndSetting;
                       break;
                   case PunchTypes.DayEnd:
                       _emailComposeTask.Subject = _settings.DayEndSetting;
                       break;
               }
               _emailComposeTask.To = _settings.ToEmailSetting;
               _emailComposeTask.Show();
           }
           catch(Exception ex)
           {
               MessageBox.Show("Caught: " + ex.Message);
           }
       }
   }
   public enum PunchTypes
       {
           DayStart,
           LunchStart,
           LunchEnd,
           DayEnd
       }
}
Comments are closed.