Сегодня я показываю исходный код моего приложения PizzaSplitter для Windows Phone.
Это простое и понятное приложение, которое не сохраняет настроек и имеет макет на основе StackPanel.
Загрузить решение PizzaSplitter.WP
Это решение требует Telerik RadControls для Windows Phone. Вы можете скачать пробную версию здесь.
Первая страница — 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>
Возможно, вы заметили пользовательский StaticResource RadNumericUpDownStyle1, примененный к Telerik RadNumericUpDown. Мне нужно было убрать границу на кнопках увеличения и уменьшения. Это повлекло за собой открытие решения в Expression Blend и создание собственного стиля в элементе управления. Я использовал эту страницу документа. После сохранения в Blend я снова открыл решение в Visual Studio, и оно стало доступно для применения к другим экземплярам этого элемента управления. Я уверен, что мог бы сделать это в Blend, но я был немного не в себе, поэтому решил вернуться к VS2010 и просто кодировать его. Есть 3 стиля. Один для кнопок «вверх» и «вниз» и третий для всего элемента управления. Этот третий использует первые два. Blend помещает пользовательский стиль в файл App.xaml:
<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>
Файл кода (MainPage.xaml.cs) содержит большую часть бизнес-логики для приложения.
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);
}
}
}
}
И, наконец, класс PizzaMath:
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;
}
}
}
}