Skip to content

C# 多线程 11-更多信息 03-在通用 Windows 平台应用中使用 BackgroundTask

🏷️ 《C# 多线程》

实现方式

  1. 新建 C# => Windows 通常 => 空 App 项目

  2. 打开 Package.appxmanifest 文件。在 Declarations(声明)标签中,添加 Background Tasks(后台任务)到 Supported Declarations(支持的声明)。

    Properties(属性中),选择 System event(系统事件)和 Timer(计时器),并将Entry point(入口点)设置为 YourNamespace.TileSchedulerTask

    YourNamespace是你的命名空间。

示例代码

页面

xml
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel Margin="50">
        <TextBlock Name="Clock"
                    Text="HH:mm"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Style="{StaticResource HeaderTextBlockStyle}"></TextBlock>
    </StackPanel>
</Grid>

后台代码

csharp
/// <summary>
/// 可用于自身或导航至 Frame 内部的空白页。
/// </summary>
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        string language = GlobalizationPreferences.Languages.First();
        _cultureInfo = new CultureInfo(language);

        _timer = new DispatcherTimer();
        _timer.Interval = TimeSpan.FromSeconds(1);
        _timer.Tick += (sender, e) => UpdateClockText();
    }

    private const string TASK_NAME_USERPRESENT = "TileSchedulerTask_UserPresent";
    private const string TASK_NAME_TIMER = "TileSchedulerTask_Timer";

    private readonly CultureInfo _cultureInfo;
    private readonly DispatcherTimer _timer;

    private void UpdateClockText()
    {
        Clock.Text = DateTime.Now.ToString(_cultureInfo.DateTimeFormat.FullDateTimePattern);
    }

    private static async void CreateClockTask()
    {
        BackgroundAccessStatus result = await BackgroundExecutionManager.RequestAccessAsync();
        if (result == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity
            || result == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity)
        {
            TileSchedulerTask.CreateSchedule();

            EnsureUserPresentTask();
            EnsureTimerTask();
        }
    }

    private static void EnsureTimerTask()
    {
        foreach (var task in BackgroundTaskRegistration.AllTasks)
        {
            if (task.Value.Name == TASK_NAME_TIMER)
            {
                return;
            }

            var builder = new BackgroundTaskBuilder();
            builder.Name = TASK_NAME_TIMER;
            builder.TaskEntryPoint = (typeof(TileSchedulerTask)).FullName;
            builder.SetTrigger(new TimeTrigger(180, false));
            builder.Register();
        }
    }

    private static void EnsureUserPresentTask()
    {
        foreach (var task in BackgroundTaskRegistration.AllTasks)
        {
            if (task.Value.Name == TASK_NAME_USERPRESENT)
            {
                return;
            }

            var builder = new BackgroundTaskBuilder();
            builder.Name = TASK_NAME_USERPRESENT;
            builder.TaskEntryPoint = (typeof(TileSchedulerTask)).FullName;
            builder.SetTrigger(new SystemTrigger(SystemTriggerType.UserPresent, false));
            builder.Register();
        }
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        _timer.Start();
        UpdateClockText();
        CreateClockTask();
    }
}

public class TileSchedulerTask : IBackgroundTask
{
    public void Run(IBackgroundTaskInstance taskInstance)
    {
        var deferral = taskInstance.GetDeferral();
        CreateSchedule();
        deferral.Complete();
    }

    public static void CreateSchedule()
    {
        var tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
        var plannedUpdated = tileUpdater.GetScheduledTileNotifications();

        DateTime now = DateTime.Now;
        DateTime planTill = now.AddHours(4);

        DateTime updateTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0).AddMinutes(1);
        if (plannedUpdated.Count > 0)
        {
            updateTime = plannedUpdated
                .Select(x => x.DeliveryTime.DateTime)
                .Union(new[] { updateTime })
                .Max();
        }
        XmlDocument documentNow = GetTilenotificationXML(now);

        tileUpdater.Update(new TileNotification(documentNow)
        {
            ExpirationTime = now.AddMinutes(1)
        });

        for (var startPlanning = updateTime; startPlanning < planTill; startPlanning = startPlanning.AddMinutes(1))
        {
            Debug.WriteLine(startPlanning);
            Debug.WriteLine(planTill);

            try
            {
                XmlDocument document = GetTilenotificationXML(startPlanning);

                var scheduleNotification = new ScheduledTileNotification(document, new DateTimeOffset(startPlanning))
                {
                    ExpirationTime = startPlanning.AddMinutes(1)
                };

                tileUpdater.AddToSchedule(scheduleNotification);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
            }
        }
    }

    private static XmlDocument GetTilenotificationXML(DateTime dateTime)
    {
        string language = GlobalizationPreferences.Languages.First();
        var cultureInfo = new CultureInfo(language);

        string shortDate = dateTime.ToString(cultureInfo.DateTimeFormat.ShortDatePattern);
        string longDate = dateTime.ToString(cultureInfo.DateTimeFormat.LongDatePattern);

        var document = XElement.Parse(string.Format(@"<tile>
<visual>
    <binding template=""TileSquareText02"">
        <text id=""1"">{0}</text>
        <text id=""2"">{1}</text>
    </binding>
    <binding template=""TileWideText01"">
        <text id=""1"">{0}</text>
        <text id=""2"">{1}</text>
        <text id=""3""></text>
        <text id=""4""></text>
    </binding>
</visual>
</tile>", shortDate, longDate));

        return document.ToXmlDocument();
    }

}

public static class DocumentExtensions
{
        public static XmlDocument ToXmlDocument(this XElement xDocument)
    {
        var xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(xDocument.ToString());
        return xmlDocument;
    }
}