65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Phone 7 的秒表应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (14投票s)

2012年2月11日

Ms-PL

5分钟阅读

viewsIcon

73333

downloadIcon

3005

Windows Phone 7 的秒表应用程序。

Description: Stop watch

引言

几周前,我想使用秒表来测量完成 400 米跑所需的时间。我查看了 Windows Phone 上所有已安装的应用程序,但找不到可用的。在 Windows 市场快速搜索一下,我发现 Windows 市场上有许多免费的秒表应用程序,这促使我决定自己写一个。

这个应用程序是一个非常基础的秒表。一旦用户按下开始按钮,它就会启动秒表。计时器会一直运行,直到用户按下停止按钮。在秒表运行时,用户可以添加圈数。该应用程序还有一些其他基本功能,例如:

  1. 关闭屏幕自动锁定。此功能很重要,因为为了节省电池,通常手机屏幕在不活动几秒钟后会自动关闭。
  2. 在离开应用程序时保存计时器值。这是为了在用户不小心离开秒表应用程序而未停止计时器时保存值。

所需软件

没有这些软件,此应用程序将无法编译。

基本设计

Visual Studio 为 Windows Phone 开发提供了许多不同的模板,如下所示:

Description: VS2010PhoneDevOptions.png

在开始我的设计选择之前,我将简要介绍其中一些模板。

最基本的模板是 Windows Phone Application。用户会看到一个可滚动屏幕。用户可以通过按下某个按钮跳转到下一个屏幕。屏幕可以垂直滚动,但不能水平滚动。开发者可以添加应用程序栏,为用户提供更改设置或选择不同菜单等选项。

Pivot 应用程序以标签格式呈现数据。这可能是 Windows Phone 开发中最常见的格式,因为用户可以通过水平滑动查看/点击其他标签。请查看 Marketplace 应用程序以获取此模板的示例。Pivot 模板的优点是开发者可以添加应用程序栏。

Panorama 应用程序与 Pivot 应用程序非常相似,但它们没有应用程序栏。基本上,这种应用程序就像一个大画布,用户通过水平滑动来查看其他可用选项。应用程序标题会跨越多个屏幕,每个部分比整个手机屏幕窄,以便用户可以看到下一个可用部分。整个屏幕是环绕的,因此从最后一个选项滑动,屏幕将移至第一个选项。

为了开发此应用程序,我选择了 Windows Phone Panorama Application。选择此模板主要是基于我喜欢这种应用程序的外观,而且我的应用程序不需要应用程序栏,因为我可以在其中一个部分中提供所有用户选项。

为了显示经过的时间,我开发了一个新的控件,TimeSpanControl。最初,我使用了一个简单的文本块,并且每次经过的时间改变时都会更新这个文本块。这种方法的问题是文本更新不流畅。它看起来像旧的 Windows 桌面画图应用程序,文本在更新时会闪烁。

为了保存/从手机读取数据,我创建了一个通用类,PersistSettings。该类基于 www.silverlight.net 网站上关于 Silverlight 隔离存储的文章。该类在每次使用变量(附加到此类)时自动保存数据。当用户返回此应用程序时(使用 OnNavigatedTo 事件处理程序),设置会从隔离存储中加载。

该应用程序使用一个计时器来计算经过的时间。

整个应用程序分为 3 个部分:计时器、设置和关于。计时器部分显示经过的时间、用户控制的圈数和重置按钮。设置部分包含一些设置,例如关闭屏幕锁定功能以及重置计时器值的警告消息。关于部分主要是关于应用程序的信息,例如版本等。

Using the Code

如上所述,此应用程序有三个 panorama 项目:timersettingsabout。每个部分都使用一个带有各种行(可能还有列)的网格。

 <controls:Panorama x:Name="StopWatch" Title="stop watch" Foreground="White" 
  FontFamily="Calibri" FontSize="18">

<!--Panorama item one-->
<controls:PanoramaItem x:Name="ElapedTimer" Foreground="White" FontSize="16" Header="Timer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
...
...
<!--Panorama item two-->
...

为了使用 Windows Phone 工具包,我在 XAML 文件中添加了命名空间,如下所示(在文件顶部):

 xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"<br>  

要使用包含的 namespace,只需像下面一样添加前缀即可:

 <toolkit:ToggleSwitch x:Name="ResetWarning"
    Header="Reset warning"<br>                        IsChecked="True"
                        Checked="ResetWarning_Checked" 
                        Unchecked="ResetWarning_Unchecked" Content="Yes" 
                        Grid.Row="1"/><local:timespancontrol fontsize="40" 
                        fontfamily="Segoe WP Bold" horizontalalignment="Center" 
                        digitwidth="28" grid.columnspan="4" grid.row="0" 
                        x:name="TotalTimeDisplay"><local:timespancontrol 
                        x:name="TotalTimeDisplay" grid.row="0" grid.columnspan="4" 
                        digitwidth="28" horizontalalignment="Center" 
                        fontfamily="Segoe WP Bold" fontsize="40" />

与使用任何用户控件完全相同。

通常,Microsoft.Phone namespace 提供了许多有用的功能来控制手机,如上所示。要执行与手机相关的任务,如发送电子邮件、启动相机或在 MarketPlace 中搜索特定内容,请使用 Microsoft.Phone.Tasks namespace

例如,要打开/关闭空闲时间屏幕锁定,只需使用 IdleDetectionMode enum,如下所示:

private void UserIdleModeOnOff_Checked(object sender, RoutedEventArgs e)
{
    this.UserIdleModeOnOff.Content = "Yes";
    try
    {
        Microsoft.Phone.Shell.PhoneApplicationService.Current.ApplicationIdleDetectionMode =
        Microsoft.Phone.Shell.IdleDetectionMode.Disabled;
    }
    catch (InvalidOperationException ex)
    {
        
    }
}

Persist Settings Class (持久化设置类)

此类使用键/值对来保存或从隔离存储中检索数据。这是一个通用类,可用于保存任何类型的基本数据,如整数、字符串等。要使用此类,只需像这样使用:

  PersistSettings<int> currentLap = new PersistSettings<int> ("LapCount", 0);

其中 LapCount 是我们要保存的值。要使用 LapCount,只需像 LapCount.Value 一样使用。Value 属性以非常简单的方式实现:

        public T Value
        {
            get
            {
                // Try to get the value from Isolated Storage
                if (!IsolatedStorageSettings.ApplicationSettings.TryGetValue(
                        this.name, out this.value))
                {
                    // Value is not set so set it for future use
                    IsolatedStorageSettings.ApplicationSettings[this.name] = this.initialValue;
                }

                return this.value;
            }

            set
            {
                // Save the value to Isolated Storage
                IsolatedStorageSettings.ApplicationSettings[this.name] = value;
                this.value = value;
            }
        }

Time Span Control (时间跨度控件)

时间跨度控件是一个用户控件,可在定义的宽度内显示经过的时间字符串。如果经过的时间文本不适合定义的宽度,文本将被截断。此控件有趣之处在于它具有固定宽度,因此文本不会闪烁,如下所示:

public partial class TimeSpanControl : UserControl
{
        int digitWidth;
        TimeSpan time;

        public TimeSpanControl()
    {
        // Required to initialize variables
        InitializeComponent();

            // In design mode, show something other than an empty text box
            if (DesignerProperties.IsInDesignTool)
                this.LayoutRoot.Children.Add(new TextBlock { Text = "00:00:00.0" });
        }

        public int DigitWidth
        {
            get { return this.digitWidth; }
            set
            {
                this.digitWidth = value;
                this.Time = this.time;
            }
        }

        public TimeSpan Time
        {
            get { return this.time; }
            set
            {
                this.LayoutRoot.Children.Clear();

                // Hours
                string hoursString = value.Hours.ToString();
                ConcatenateTime((value.Hours / 10).ToString());
                ConcatenateTime((value.Hours % 10).ToString());

                this.LayoutRoot.Children.Add(new TextBlock { Text = ":" });

                // Support two digits of minutes digits
                string minutesString = value.Minutes.ToString();
                ConcatenateTime((value.Minutes / 10).ToString());
                ConcatenateTime((value.Minutes % 10).ToString());

                this.LayoutRoot.Children.Add(new TextBlock { Text = ":" });

                // Two digits for Seconds
                ConcatenateTime((value.Seconds / 10).ToString());
                ConcatenateTime((value.Seconds % 10).ToString());

                // Add the decimal separator
                this.LayoutRoot.Children.Add(new TextBlock
                {
                    Text = System.Globalization.CultureInfo.CurrentUICulture.
                           NumberFormat.NumberDecimalSeparator
                });

                // milliseconds display
                ConcatenateTime((value.Milliseconds / 100).ToString());

                this.time = value;
            }
        }

        void ConcatenateTime(string timeValue)
        {
            TextBlock textBlock = new TextBlock
            {
                Text = timeValue,
                Width = this.DigitWidth,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            this.LayoutRoot.Children.Add(textBlock);
        }
}

历史

  • 2012 年 2 月:初始版本
  • 2012 年 2 月 13 日:更新以添加已完成圈数和时间的历史记录
© . All rights reserved.