Pizza Splitter: Source Code
June 27, 2012Today I am showing the source code of my PizzaSplitter app for Windows Phone.
It is a simple, straight forward app that saves no settings and has a StackPanel based layout.
Download PizzaSplitter.WP Solution
This solution requires Telerik RadControls for Windows Phone. You can download a trial here.
First page is MainPage.xaml:
<phone:PhoneApplicationPage x:Class="PizzaSplitter.WP.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:telerikInput="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True" xmlns:my="clr-namespace:Microsoft.Advertising.Mobile.UI;assembly=Microsoft.Advertising.Mobile.UI"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <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="PIZZA SPLITTER" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="slice divider" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel Height="80" Orientation="Horizontal"> <TextBlock Text="Number Of People" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Width="250" /> <telerikInput:RadNumericUpDown Name="NumberOfPeopleRadNumericUpDown" Value="5" Width="195" Margin="10,0,0,0" FontSize="36" BorderThickness="0" Style="{StaticResource RadNumericUpDownStyle1}"/> </StackPanel> <StackPanel Height="80" Orientation="Horizontal"> <TextBlock Text="Number Of Pizzas" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Width="250"/> <telerikInput:RadNumericUpDown Name="NumberOfPizzasRadNumericUpDown" Value="3" Width="195" Margin="10,0,0,0" FontSize="36" TextOptions.TextHintingMode="Animated" BorderThickness="0" Style="{StaticResource RadNumericUpDownStyle1}"/> </StackPanel> <StackPanel Height="80" Orientation="Horizontal"> <TextBlock Text="Slices Per Pizza" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Width="250"/> <telerikInput:RadNumericUpDown Name="SlicesPerPizzaRadNumericUpDown" Value="8" Width="195" Margin="10,0,0,0" FontSize="36" TextOptions.TextHintingMode="Animated" BorderThickness="0" Style="{StaticResource RadNumericUpDownStyle1}"/> </StackPanel> <Button Content="Calculate Split" Margin="10,15,10,10" Height="72" HorizontalAlignment="Left" Name="CalculateSplitButton" VerticalAlignment="Top" Width="440" Click="CalculateSplitButtonClick" /> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Height="125" Width="200" Margin="10,10,5,10"> <TextBlock Name="SlicesPerPersonTextBlock" Text="4" FontSize="60" TextAlignment="Center" Foreground="Green"/> <TextBlock Text="Slices Per Person" FontSize="24" TextAlignment="Center" /> </StackPanel> <StackPanel Height="125" Width="200" Margin="5,10,10,10"> <TextBlock Name="RemainingSlicesTextBlock" Text="4" FontSize="60" TextAlignment="Center" Foreground="Red"/> <TextBlock Text="Remaining Slices" FontSize="24" TextAlignment="Center" /> </StackPanel> </StackPanel> <my:AdControl Height="80" Name="adControl1" Width="480" Margin="-15,10,0,0"> <my:AdControl.ApplicationId>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</my:AdControl.ApplicationId> <my:AdControl.AdUnitId>xxxxxxxx</my:AdControl.AdUnitId> </my:AdControl> </StackPanel> </Grid> </phone:PhoneApplicationPage>
You may have noticed the custom StaticResource ‘RadNumericUpDownStyle1’ applied to the Telerik RadNumericUpDown. I needed to remove the border on the increase and decrease buttons. This entailed opening the solution in Expression Blend and creating a custom style on the control. I used this doc page. After saving in Blend, I reopened the solution on Visual Studio and it was available to be applied to the other instances of this control. I’m sure I could have done this in Blend, but I was a bit out of my element so I opted to go back to VS2010 and just code it. There are 3 styles. One each for the up and down buttons and the third for the whole control. This third one uses the first two. Blend puts the custom style in the App.xaml file:
<Application 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:sys="clr-namespace:System;assembly=mscorlib" xmlns:telerikInput="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input" x:Class="PizzaSplitter.WP.App" > <!--Application Resources--> <Application.Resources> <Style x:Key="NumericUpDownRepeatButtonStyle" TargetType="Button"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/> <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/> <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/> <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/> <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/> </Style> <Style x:Key="IncreaseButtonStyle" BasedOn="{StaticResource NumericUpDownRepeatButtonStyle}" TargetType="Button"> <Setter Property="BorderThickness" Value="1, 0, 0, 0"/> <Setter Property="BorderBrush" Value="{StaticResource PhoneSubtleBrush}"/> <Setter Property="Padding" Value="25, 25, 25, 25"/> <Setter Property="VerticalAlignment" Value="Stretch"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ButtonBase"> <Grid Background="Transparent"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastBackgroundBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastForegroundBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{TemplateBinding Margin}"> <ContentControl x:Name="ContentContainer" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"> <Grid> <Rectangle Fill="{Binding Foreground, ElementName=ContentContainer}" Height="5" Width="17"/> <Rectangle Fill="{Binding Foreground, ElementName=ContentContainer}" Height="17" Width="5"/> </Grid> </ContentControl> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="DecreaseButtonStyle" BasedOn="{StaticResource NumericUpDownRepeatButtonStyle}" TargetType="Button"> <Setter Property="BorderThickness" Value="1, 0, 0, 0"/> <Setter Property="Padding" Value="25, 25, 25, 25"/> <Setter Property="BorderBrush" Value="{StaticResource PhoneSubtleBrush}"/> <Setter Property="VerticalAlignment" Value="Stretch"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ButtonBase"> <Grid Background="Transparent"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastBackgroundBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastForegroundBrush}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{TemplateBinding Margin}"> <ContentControl x:Name="ContentContainer" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"> <Grid> <Rectangle Fill="{Binding Foreground, ElementName=ContentContainer}" Height="5" Width="17"/> </Grid> </ContentControl> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="RadNumericUpDownStyle1" TargetType="telerikInput:RadNumericUpDown"> <Setter Property="IncreaseButtonStyle" Value="{StaticResource IncreaseButtonStyle}"/> <Setter Property="DecreaseButtonStyle" Value="{StaticResource DecreaseButtonStyle}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="BorderBrush" Value="{StaticResource PhoneSubtleBrush}"/> <Setter Property="Margin" Value="{StaticResource PhoneHorizontalMargin}"/> <Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Padding" Value="5"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="telerikInput:RadNumericUpDown"> <Border x:Name="LayoutRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> </Grid.RowDefinitions> <Grid Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" HorizontalAlignment="Left" Text="{TemplateBinding Header}" VerticalAlignment="Center"/> <TextBlock x:Name="PART_ValueTextBlock" Grid.Column="1" FontFamily="Segoe WP Semibold" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5, 0, 5, 0" Text="{TemplateBinding ValueString}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> <TextBlock Grid.Column="2" HorizontalAlignment="Right" Text="{TemplateBinding Suffix}" VerticalAlignment="Center"/> </Grid> <Button x:Name="PART_DecreaseButton" Grid.Column="1" BorderThickness="0"/> <Button x:Name="PART_IncreaseButton" Grid.Column="2" BorderThickness="0"/> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Application.Resources> <Application.ApplicationLifetimeObjects> <!--Required object that handles lifetime events for the application--> <shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated"/> </Application.ApplicationLifetimeObjects> </Application>
The code behind file (MainPage.xaml.cs) contains most of the business logic for the application.
using System; using System.Globalization; using System.Windows; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using Microsoft.Phone.Tasks; namespace PizzaSplitter.WP { public partial class MainPage : PhoneApplicationPage { private PizzaMath pm; public MainPage() { InitializeComponent(); ApplicationBar = new ApplicationBar(); ApplicationBar.IsMenuEnabled = true; ApplicationBar.IsVisible = true; ApplicationBar.Opacity = 1.0; ApplicationBar.Mode = ApplicationBarMode.Minimized; var helpItem = new ApplicationBarIconButton(new Uri("/Images/appbar.questionmark.rest.png", UriKind.Relative)); var rateItem = new ApplicationBarIconButton(new Uri("/Images/appbar.favs.rest.png", UriKind.Relative)); helpItem.Text = "help"; rateItem.Text = "rate"; helpItem.Click += HelpClick; rateItem.Click += RateItemOnClick; ApplicationBar.Buttons.Add(helpItem); ApplicationBar.Buttons.Add(rateItem); NumberOfPeopleRadNumericUpDown.Value = 3; NumberOfPizzasRadNumericUpDown.Value = 2; SlicesPerPizzaRadNumericUpDown.Value = 8; SlicesPerPersonTextBlock.Text = "0"; RemainingSlicesTextBlock.Text = "0"; } private void HelpClick(object sender, EventArgs eventArgs) { NavigationService.Navigate(new Uri("/Help.xaml", UriKind.Relative)); } private void RateItemOnClick(object sender, EventArgs eventArgs) { MarketplaceReviewTask rate = new MarketplaceReviewTask(); rate.Show(); } private void CalculateSplitButtonClick(object sender, RoutedEventArgs e) { pm = new PizzaMath( (int)NumberOfPeopleRadNumericUpDown.Value, (int)NumberOfPizzasRadNumericUpDown.Value, (int)SlicesPerPizzaRadNumericUpDown.Value); if (pm.Calculate()) { SlicesPerPersonTextBlock.Text = pm.SlicesPerPerson.ToString(CultureInfo.InvariantCulture); RemainingSlicesTextBlock.Text = pm.SlicesRemaining.ToString(CultureInfo.InvariantCulture); } } } }
And finally, the PizzaMath class:
using System; namespace PizzaSplitter.WP { public class PizzaMath { public int NumberOfPeople { get; private set; } public int NumberOfPizzas { get; private set; } public int SlicesPerPizza { get; private set; } public int SlicesPerPerson { get; private set; } public int SlicesRemaining { get; private set; } public PizzaMath(int numberOfPeople, int numberOfPizzas, int slicesPerPizza) { NumberOfPeople = numberOfPeople; NumberOfPizzas = numberOfPizzas; SlicesPerPizza = slicesPerPizza; SlicesPerPerson = 0; SlicesRemaining = 0; } public bool Calculate() { try { SlicesRemaining = (NumberOfPizzas * SlicesPerPizza) % NumberOfPeople; SlicesPerPerson = (((NumberOfPizzas * SlicesPerPizza) - SlicesPerPerson) / NumberOfPeople); return true; } catch (Exception) { return false; } } } }
Comments are closed.