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.