Сегодня я показываю исходный код моего приложения 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; } } } }