Friday, 21 July 2017

Toasts 03 Background

So as we all know UWP apps just like there predecessors only run when they are in the foreground, this is to ensure performance of the device, preserve battery-life, etc... not sure what else that's why i put etc. Anyway we do have a way to run some logic in the background, now a caveat is that there is no guarantee that you're background task will ever fire, if the user has put their device into quite hours or the system is constrained for resources etc...

to start we have to add new winRT component project to our solution


so our solution explorer should look like

now that we have our two project ready let's open up the Class1.cs file in the newly added pc.background-taskExample project.

Now let's change it from Class1 to something a little more descriptive let's rename Class1 to LaunchToastBackgroundTask.

We are also going to implement the IBackgroundTask interface, which only implements one method; and it's Run, this is the method that will asynchronously fire. I mention Asynchronously because we're going to have to grab a deferral to keep our Background task from falling out of scope before we fire our code.

using Windows.ApplicationModel.Background;

namespace pc_backgroundTaskExample
{
    public sealed class LaunchToastBackgroundTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            var deferral = taskInstance.GetDeferral();

            //Our Logic goes here

            deferral.Complete();
        }
    }
}


Now let's create the logic to fire a toast notification from our background task

using Windows.ApplicationModel.Background;
using Windows.UI.Notifications;

namespace pc_backgroundTaskExample
{
    public sealed class LaunchToastBackgroundTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            var deferral = taskInstance.GetDeferral();

            var template = ToastTemplateType.ToastText02;
            var xmlDoc = ToastNotificationManager.GetTemplateContent(template);
            var xml = xmlDoc.GetXml();
            /*  <toast>
                    <visual>
                        <binding template="ToastText02">
                            <text id="1"></text>
                            <text id="2"></text>
                        </binding>
                    </visual>
                </toast>*/

            var textElements = xmlDoc.GetElementsByTagName("text");
            textElements[0].AppendChild(xmlDoc.CreateTextNode("Title text"));
            textElements[1].AppendChild(xmlDoc.CreateTextNode("body text"));

            var toast = new ToastNotification(xmlDoc);

            var notifier = ToastNotificationManager.CreateToastNotifier();
            notifier.Show(toast);

            deferral.Complete();
        }
    }
}


just as before

next let's move to our application, the first thing we have to do is enable background tasks in the app manifest.

once that's done let's go to our main application and write the logic of when to fire our background task.

using pc_backgroundTaskExample;
using System;
using System.Linq;
using Windows.ApplicationModel.Background;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace pc.toastExample
{
    public sealed partial class MainPage : Page
    {
        public MainPage() { this.InitializeComponent(); }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            var allowed = await BackgroundExecutionManager.RequestAccessAsync();

            switch (allowed)
            {
                case BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity:
                case BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity:
                    var existing = BackgroundTaskRegistration.AllTasks
                        .FirstOrDefault(t =>
                            t.Value.Name == nameof(LaunchToastBackgroundTask)).Value;

                    if (existing != null)
                        existing.Unregister(false);

                    var builder = new BackgroundTaskBuilder();
                    builder.Name = nameof(LaunchToastBackgroundTask);
                    builder.TaskEntryPoint = typeof(LaunchToastBackgroundTask).ToString();
                    builder.SetTrigger(new SystemTrigger(SystemTriggerType.InternetAvailable, false));

                    var taskRegistration = builder.Register();

                    break;
                case BackgroundAccessStatus.Denied:
                    //denied
                    break;
                case BackgroundAccessStatus.Unspecified:
                    //cancelled
                    break;
            }
        }
    }
}


now our background task will fire when our device receives an internet connection.