如何实现 Windows Phone 8 的后台代理

network | | 访问(61)

创建可使用计划任务的应用

以下步骤带您完成创建可使用计划任务注册后台代理的简单应用。

创建可使用计划任务的应用的步骤

在 Visual Studio 中创建新的 Windows Phone 应用 项目。此模板在“Windows Phone”类别中。

接下来,向解决方案中添加一个计划任务项目。从“文件”菜单中,选择“添加->新项目…”。在“添加新项目”对话框中,选择“Windows Phone 计划任务代理”。保留默认名称 ScheduledTaskAgent1,然后单击“确定”。

下一步,在您的前台应用项目中,您需要添加对该代理项目的引用。在“解决方案资源管理器”中,单击您的前台应用项目以将其选中。接下来,从“项目”菜单中,选择“添加引用...”。在“添加引用”对话框中,选择“项目”标签。选择代理项目 ScheduledTaskAgent1,然后单击“确定”。

更新应用清单文件以注册后台代理。在“解决方案资源管理器”的“属性”下,右击 WMAppManifest.xml 文件,然后单击“查看代码”。在“任务”元素中的 DefaultTask 元素下面,添加 ExtendedTask 元素,如以下代码所示。Specifier 属性必须具有ScheduledTaskAgent 值。在前面的步骤中,您向项目添加了为计划的任务代理指定的名称时,其他属性应反映该名称。

<Tasks> 
  <DefaultTask Name="_default" NavigationPage="MainPage.xaml" /> 
  <ExtendedTask Name="BackgroundTask"> 
    <BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="ScheduledTaskAgent1" Source="ScheduledTaskAgent1" Type="ScheduledTaskAgent1.ScheduledAgent" /> 
  </ExtendedTask> 
</Tasks>

ScheduledTaskAgent1 中 ScheduledAgent.cs 的代码

using System.Diagnostics;
using System.Windows;
using Microsoft.Phone.Scheduler;
using Microsoft.Phone.Shell;
using System;

namespace ScheduledTaskAgent1
{
    public class ScheduledAgent : ScheduledTaskAgent
    {
        /// <remarks>
        /// ScheduledAgent 构造函数,初始化 UnhandledException 处理程序
        /// </remarks>
        static ScheduledAgent()
        {
            // 订阅托管的异常处理程序
            Deployment.Current.Dispatcher.BeginInvoke(delegate
            {
                Application.Current.UnhandledException += UnhandledException;
            });
        }

        /// 出现未处理的异常时执行的代码
        private static void UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (Debugger.IsAttached)
            {
                // 出现未处理的异常;强行进入调试器
                Debugger.Break();
            }
        }

        /// <summary>
        /// 运行计划任务的代理
        /// </summary>
        /// <param name="task">
        /// 调用的任务
        /// </param>
        /// <remarks>
        /// 调用定期或资源密集型任务时调用此方法
        /// </remarks>
        protected override void OnInvoke(ScheduledTask task)
        {
            //TODO: 添加代码来执行你的后台任务
            string toastMessage = "";

            // 如果你的应用程序使用PeriodicTask和ResourceIntensiveTask
            // 在这里你可以扩展您的应用程序代码。否则,你不需要。
            if (task is PeriodicTask)
            {
                // 执行周期性任务的行为。
                toastMessage = "周期性任务运行。";
            }
            else
            {
                // 执行资源密集型任务的行为。
                toastMessage = "资源密集型任务运行。";
            }

            // 启动一个土司表明代理正在运行。
            // 面包将不会显示,如果前台应用程序正在运行。
            ShellToast toast = new ShellToast();
            toast.Title = "Background Agent Sample";
            toast.Content = toastMessage;
            toast.Show();

            // 在一分钟再次启动代理。

            ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));


            // 叫NotifyComplete让系统知道代理工作完成。
            NotifyComplete();
        }
    }
}

主程序中 MainPage 的代码

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Scheduler;

namespace PhoneApp1
{
    public partial class MainPage : PhoneApplicationPage
    {

        PeriodicTask periodicTask;
        ResourceIntensiveTask resourceIntensiveTask;

        string periodicTaskName = "PeriodicAgent";
        string resourceIntensiveTaskName = "ResourceIntensiveAgent";
        public bool agentsAreEnabled = true;
        bool ignoreCheckBoxEvents = false;

        // 构造函数
        public MainPage()
        {
            InitializeComponent();
        }

        private void RemoveAgent(string name)
        {
            try
            {
                ScheduledActionService.Remove(name);
            }
            catch (Exception)
            {
            }
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            ignoreCheckBoxEvents = true;

            periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;

            if (periodicTask != null)
            {
                PeriodicStackPanel.DataContext = periodicTask;
            }

            resourceIntensiveTask = ScheduledActionService.Find(resourceIntensiveTaskName) as ResourceIntensiveTask;
            if (resourceIntensiveTask != null)
            {
                ResourceIntensiveStackPanel.DataContext = resourceIntensiveTask;
            }

            ignoreCheckBoxEvents = false;

        }

        private void StartPeriodicAgent()
        {
            // 变量跟踪启用背景代理这款应用程序的状态。
            agentsAreEnabled = true;

            // 获得一段引用的任务,如果一个人的存在
            periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;

            // 如果任务已经存在和背景代理是启用的应用程序,您必须删除任务,然后再添加到更新时间表
            if (periodicTask != null)
            {
                RemoveAgent(periodicTaskName);
            }

            periodicTask = new PeriodicTask(periodicTaskName);

            // 描述需要周期性的代理。这是用户的字符串
            // 将在后台服务设备上的设置页面。
            periodicTask.Description = "这演示了一个周期性的任务。";

            //将调用添加在一个try块,以防用户禁用代理。
            try
            {
                ScheduledActionService.Add(periodicTask);
                PeriodicStackPanel.DataContext = periodicTask;

                // 如果启用了调试,在一分钟使用LaunchForTest启动代理。

                ScheduledActionService.LaunchForTest(periodicTaskName, TimeSpan.FromSeconds(60));

            }
            catch (InvalidOperationException exception)
            {
                if (exception.Message.Contains("BNS Error: 行动是禁用的"))
                {
                    MessageBox.Show("后台代理对于这个应用程序由用户已禁用。");
                    agentsAreEnabled = false;
                    PeriodicCheckBox.IsChecked = false;
                }

                if (exception.Message.Contains("BNS Error:最大数量ScheduledActions这种类型的已被添加。"))
                {
                    // 不需要用户操作。系统提示用户当周期性任务的硬限制。

                }
                PeriodicCheckBox.IsChecked = false;
            }
            catch (SchedulerServiceException)
            {
                // 不需要用户操作。
                PeriodicCheckBox.IsChecked = false;
            }
        }

        private void StartResourceIntensiveAgent()
        {
            // 变量跟踪启用背景代理这款应用程序的状态。
            agentsAreEnabled = true;

            resourceIntensiveTask = ScheduledActionService.Find(resourceIntensiveTaskName) as ResourceIntensiveTask;

            // 如果任务已经存在和背景代理是启用的应用程序,您必须删除任务,然后再添加到更新计划。
            if (resourceIntensiveTask != null)
            {
                RemoveAgent(resourceIntensiveTaskName);
            }

            resourceIntensiveTask = new ResourceIntensiveTask(resourceIntensiveTaskName);

            //描述需要周期性的代理。这是用户的字符串
            //将在后台服务设备上的设置页面。
            resourceIntensiveTask.Description = "这演示了一个资源密集型任务。";

            //调用添加在一个try块,以防用户禁用代理。
            try
            {
                ScheduledActionService.Add(resourceIntensiveTask);
                ResourceIntensiveStackPanel.DataContext = resourceIntensiveTask;

                //在一分钟使用LaunchForTest启动代理。
                ScheduledActionService.LaunchForTest(resourceIntensiveTaskName, TimeSpan.FromSeconds(60));

            }
            catch (InvalidOperationException exception)
            {
                if (exception.Message.Contains("BNS Error: 行动是禁用的"))
                {
                    MessageBox.Show("后台代理对于这个应用程序由用户已禁用。");
                    agentsAreEnabled = false;

                }
                ResourceIntensiveCheckBox.IsChecked = false;
            }
            catch (SchedulerServiceException)
            {
                // 不需要用户操作。
                ResourceIntensiveCheckBox.IsChecked = false;
            }


        }

        private void PeriodicCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            if (ignoreCheckBoxEvents)
                return;
            StartPeriodicAgent();
        }

        private void PeriodicCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            if (ignoreCheckBoxEvents)
                return;
            RemoveAgent(periodicTaskName);
        }

        private void ResourceIntensiveCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            if (ignoreCheckBoxEvents)
                return;
            StartResourceIntensiveAgent();
        }

        private void ResourceIntensiveCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            if (ignoreCheckBoxEvents)
                return;
            RemoveAgent(resourceIntensiveTaskName);
        }

    }
}

页面代码 MainPage.xaml

<phone:PhoneApplicationPage
    x:Class="PhoneApp1.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"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
                <StackPanel  Orientation="Vertical" Name="PeriodicStackPanel" Margin="0,0,0,40">
                    <TextBlock Text="定期代理" Style="{StaticResource PhoneTextTitle2Style}"/>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="名称: " Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="启用" VerticalAlignment="Center"  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <CheckBox Name="PeriodicCheckBox" IsChecked="{Binding IsEnabled}" Checked="PeriodicCheckBox_Checked" Unchecked="PeriodicCheckBox_Unchecked"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="计划: "  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding IsScheduled}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="最后安排时间: "  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding LastScheduledTime}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="过期时间: " Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding ExpirationTime}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="最后退出的原因: "  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding LastExitReason}" />
                    </StackPanel>
                </StackPanel>
                <StackPanel  Orientation="Vertical" Name="ResourceIntensiveStackPanel" Margin="0,0,0,40">
                    <TextBlock Text="资源密集型代理" Style="{StaticResource PhoneTextTitle2Style}"/>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="名称: " Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="启用" VerticalAlignment="Center"  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <CheckBox Name="ResourceIntensiveCheckBox" IsChecked="{Binding IsEnabled}" Checked="ResourceIntensiveCheckBox_Checked" Unchecked="ResourceIntensiveCheckBox_Unchecked"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="计划: "  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding IsScheduled}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="最后安排时间: "  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding LastScheduledTime}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="过期时间: " Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding ExpirationTime}" />
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="最后退出的原因: "  Style="{StaticResource PhoneTextAccentStyle}"/>
                        <TextBlock Text="{Binding LastExitReason}" />
                    </StackPanel>
                </StackPanel>
            </StackPanel>
        </Grid>

    </Grid>

</phone:PhoneApplicationPage>