locked
Explanation on Windows.UI.Xaml.Media.XamlRenderingBackgroundTask RRS feed

  • Question

  • This class have been mentioned numerous time in Build 14' as the new way of generating live tiles. But apart from the (limited) msdn documentation, there's been no documentation/sample/code/explanation of sorts.

    Maybe someone could shed some light on this?

    Thanks.

    Saturday, April 19, 2014 3:49 PM

Answers

  • This is used for background tasks which need to use the XAML rendering engine, for example: to generate images for the Live Tile.

    The following sample uses this API: http://code.msdn.microsoft.com/wpapps/Updating-a-tile-from-a-e0e492df


    Eric Fleck, Windows Store and Windows Phone Developer Support If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.

    • Marked as answer by Frankie Foo Thursday, May 8, 2014 5:42 PM
    Tuesday, April 22, 2014 5:05 PM
  • We recommend against writing this type of background task in managed code because memory restrictions are too tight and it is more likely to crash due to out of memory resulting in a bad user experience.

    If you really want to take that chance I have pasted below the code from a proof-of-concept I threw together (...based on the C++ sample.)

    1. Add a project to your solution using the "Windows Runtime Component (Windows Phone)" template.

    2. replace the code in class1.cs with the following:

    using System;
    using System.Threading.Tasks;
    using Windows.ApplicationModel.Background;
    using Windows.Storage.Streams;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Markup;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Imaging;
    using Windows.Graphics.Imaging;
    using Windows.UI.Notifications;
    using Windows.Data.Xml.Dom;
    
    namespace BackgroundTask
    {
        public sealed class AppTileUpdater : XamlRenderingBackgroundTask
        {
            protected override void OnRun(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
            {
                BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
                System.Diagnostics.Debug.WriteLine("OnRun called!");
                UpdateTileAsync(_deferral);
            }
    
            private async Task<string> ReadFile()
            {
                var folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
                var file = await folder.GetFileAsync("customTile.xml");
                string szCustomTileXML = await Windows.Storage.FileIO.ReadTextAsync(file);
                return szCustomTileXML;
            }
            private async void UpdateTileAsync(BackgroundTaskDeferral deferral)
            {
                
                var folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
                var file = await folder.GetFileAsync("customTile.xml");
                string szCustomTileXML = await Windows.Storage.FileIO.ReadTextAsync(file);
    
                Border tile = XamlReader.Load(szCustomTileXML) as Border;
    
                if (null != tile)
                {
                    tile.Background = new SolidColorBrush(Windows.UI.Colors.Orange);
                    Grid grid = tile.Child as Grid;
                    TextBlock text = grid.FindName("Timestamp") as TextBlock;
                    text.Text = DateTime.Now.ToString("hh:mm:ss");
                    text = grid.FindName("TimeZone") as TextBlock;
                    text.Text = TimeZoneInfo.Local.DisplayName;
    
                    Image logo = grid.FindName("LogoImage") as Image;
                    var img = new BitmapImage() { CreateOptions = BitmapCreateOptions.None };
                    img.UriSource = new Uri("ms-appx:///Assets/acorn.png");
    
                    RenderTargetBitmap rtb = new RenderTargetBitmap();
                    await rtb.RenderAsync(tile, 150, 150);
                    IBuffer pixels = await rtb.GetPixelsAsync();
                    DataReader dReader = Windows.Storage.Streams.DataReader.FromBuffer(pixels);
                    byte[] data = new byte[pixels.Length];
                    dReader.ReadBytes(data);
    
                    var outputFile = await Windows.ApplicationModel.Package.Current.InstalledLocation.CreateFileAsync("UpdatedLiveTile.png", Windows.Storage.CreationCollisionOption.ReplaceExisting);
                    var outputStream = await outputFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
                    BitmapEncoder enc = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, outputStream);
                    enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)rtb.PixelWidth, (uint)rtb.PixelHeight, 96,96, data);
                    await enc.FlushAsync();                
                }
                var TileMgr = TileUpdateManager.CreateTileUpdaterForApplication();
                TileMgr.Clear();
                var tileTemplate = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Image);
                var tileImageAttributes = tileTemplate.GetElementsByTagName("image");
                XmlElement tmp = tileImageAttributes[0] as XmlElement;
                tmp.SetAttribute("src", "UpdatedLiveTile.png");
                var notification = new TileNotification(tileTemplate);
                TileMgr.Update(notification);
                deferral.Complete();
            }
    
            public void Run(IBackgroundTaskInstance taskInstance)
            {
                System.Diagnostics.Debug.WriteLine("Run called!");
                OnRun(taskInstance);
            }
        }
    }

    note, the referenced resources: acorn.png and customTile.xml should be included in the main app project.

    The rest is more or less like the instructions from the C++ sample.


    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.


    • Proposed as answer by T. Partl Friday, May 2, 2014 10:58 PM
    • Marked as answer by Frankie Foo Thursday, May 8, 2014 5:42 PM
    • Edited by Eric Fleck Thursday, August 14, 2014 2:17 PM fix code
    Friday, May 2, 2014 8:13 PM

All replies

  • Hi Frankie,

    Look for more documentation as the preview comes closer to release.

    Jeff


    Jeff Sanders (MSFT)

    @jsandersrocks - Windows Store Developer Solutions @WSDevSol
    Getting Started With Windows Azure Mobile Services development? Click here
    Getting Started With Windows Phone or Store app development? Click here
    My Team Blog: Windows Store & Phone Developer Solutions
    My Blog: Http Client Protocol Issues (and other fun stuff I support)

    Monday, April 21, 2014 12:16 PM
  • This is used for background tasks which need to use the XAML rendering engine, for example: to generate images for the Live Tile.

    The following sample uses this API: http://code.msdn.microsoft.com/wpapps/Updating-a-tile-from-a-e0e492df


    Eric Fleck, Windows Store and Windows Phone Developer Support If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.

    • Marked as answer by Frankie Foo Thursday, May 8, 2014 5:42 PM
    Tuesday, April 22, 2014 5:05 PM
  • There is still no good explanation how to use it in a C#-background project

    • Edited by T. Partl Thursday, May 1, 2014 2:48 PM
    Wednesday, April 30, 2014 10:02 PM
  • In C# you would do basically the same thing the C++ app is doing, i.e. define a class which inherits from XamlRenderingBackgroundTask and override the OnRun event, ex:

        public sealed class AppTileUpdater : XamlRenderingBackgroundTask
        {
            protected override void OnRun(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
            {
                BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
                // your update code goes here...
                // call _deferral.Complete() once all async tasks have completed.
            }
    


    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.

    Thursday, May 1, 2014 6:28 PM
  • Every try to use a C#-background task (XamlRenderingBackgroundTask or not) results in an app crash as soon as the SystemTrigger (in my case "UserActive") is triggered. There isn't any exception or something, the both tasks (foreground & background) simply exit with code 0x01.

    Tested this in multiple projects and computers, any idea what I'm doing wrong? Isn't there any working sample project which uses XamlRenderingBackgroundTask in C#?


    • Edited by T. Partl Friday, May 2, 2014 7:37 PM
    Friday, May 2, 2014 7:35 PM
  • We recommend against writing this type of background task in managed code because memory restrictions are too tight and it is more likely to crash due to out of memory resulting in a bad user experience.

    If you really want to take that chance I have pasted below the code from a proof-of-concept I threw together (...based on the C++ sample.)

    1. Add a project to your solution using the "Windows Runtime Component (Windows Phone)" template.

    2. replace the code in class1.cs with the following:

    using System;
    using System.Threading.Tasks;
    using Windows.ApplicationModel.Background;
    using Windows.Storage.Streams;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Markup;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Imaging;
    using Windows.Graphics.Imaging;
    using Windows.UI.Notifications;
    using Windows.Data.Xml.Dom;
    
    namespace BackgroundTask
    {
        public sealed class AppTileUpdater : XamlRenderingBackgroundTask
        {
            protected override void OnRun(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
            {
                BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
                System.Diagnostics.Debug.WriteLine("OnRun called!");
                UpdateTileAsync(_deferral);
            }
    
            private async Task<string> ReadFile()
            {
                var folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
                var file = await folder.GetFileAsync("customTile.xml");
                string szCustomTileXML = await Windows.Storage.FileIO.ReadTextAsync(file);
                return szCustomTileXML;
            }
            private async void UpdateTileAsync(BackgroundTaskDeferral deferral)
            {
                
                var folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
                var file = await folder.GetFileAsync("customTile.xml");
                string szCustomTileXML = await Windows.Storage.FileIO.ReadTextAsync(file);
    
                Border tile = XamlReader.Load(szCustomTileXML) as Border;
    
                if (null != tile)
                {
                    tile.Background = new SolidColorBrush(Windows.UI.Colors.Orange);
                    Grid grid = tile.Child as Grid;
                    TextBlock text = grid.FindName("Timestamp") as TextBlock;
                    text.Text = DateTime.Now.ToString("hh:mm:ss");
                    text = grid.FindName("TimeZone") as TextBlock;
                    text.Text = TimeZoneInfo.Local.DisplayName;
    
                    Image logo = grid.FindName("LogoImage") as Image;
                    var img = new BitmapImage() { CreateOptions = BitmapCreateOptions.None };
                    img.UriSource = new Uri("ms-appx:///Assets/acorn.png");
    
                    RenderTargetBitmap rtb = new RenderTargetBitmap();
                    await rtb.RenderAsync(tile, 150, 150);
                    IBuffer pixels = await rtb.GetPixelsAsync();
                    DataReader dReader = Windows.Storage.Streams.DataReader.FromBuffer(pixels);
                    byte[] data = new byte[pixels.Length];
                    dReader.ReadBytes(data);
    
                    var outputFile = await Windows.ApplicationModel.Package.Current.InstalledLocation.CreateFileAsync("UpdatedLiveTile.png", Windows.Storage.CreationCollisionOption.ReplaceExisting);
                    var outputStream = await outputFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
                    BitmapEncoder enc = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, outputStream);
                    enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)rtb.PixelWidth, (uint)rtb.PixelHeight, 96,96, data);
                    await enc.FlushAsync();                
                }
                var TileMgr = TileUpdateManager.CreateTileUpdaterForApplication();
                TileMgr.Clear();
                var tileTemplate = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Image);
                var tileImageAttributes = tileTemplate.GetElementsByTagName("image");
                XmlElement tmp = tileImageAttributes[0] as XmlElement;
                tmp.SetAttribute("src", "UpdatedLiveTile.png");
                var notification = new TileNotification(tileTemplate);
                TileMgr.Update(notification);
                deferral.Complete();
            }
    
            public void Run(IBackgroundTaskInstance taskInstance)
            {
                System.Diagnostics.Debug.WriteLine("Run called!");
                OnRun(taskInstance);
            }
        }
    }

    note, the referenced resources: acorn.png and customTile.xml should be included in the main app project.

    The rest is more or less like the instructions from the C++ sample.


    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.


    • Proposed as answer by T. Partl Friday, May 2, 2014 10:58 PM
    • Marked as answer by Frankie Foo Thursday, May 8, 2014 5:42 PM
    • Edited by Eric Fleck Thursday, August 14, 2014 2:17 PM fix code
    Friday, May 2, 2014 8:13 PM
  • Thanks, that helped a lot.

    I think the main problem was that I didn't use the "Windows Runtime Component (Windows Phone)" -template as it wasn't visible at first glance. I will now test the background task in C# and then rewrite it in C++.

    I'd still have one little question: The background task now successfully does what he should do but he still exits with code 0x1. I call deferral.Complete() just like in the example. Is that a problem?


    • Edited by T. Partl Friday, May 2, 2014 9:26 PM
    Friday, May 2, 2014 9:26 PM
  • I'd still have one little question: The background task now successfully does what he should do but he still exits with code 0x1. I call deferral.Complete() just like in the example. Is that a problem?


    The same thing happens when I run the C++ sample ...but I'm not sure why.

    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.

    Friday, May 2, 2014 10:54 PM
  • Thanks for your C# sample.. But when I try to use it I get the following outcome:


    What is going on? I used the EXACT same C#, and customtile.xml!
    Friday, June 20, 2014 2:43 PM
  • this is my problem
    Sunday, June 22, 2014 5:18 PM
  • Thanks for your C# sample.. But when I try to use it I get the following outcome:


    What is going on? I used the EXACT same C#, and customtile.xml!
    Can anyone help with this?
    Tuesday, July 1, 2014 5:55 AM
  • Can you share your version of the project?

    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.

    Tuesday, July 1, 2014 9:35 PM
  • Can you share your version of the project?

    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.


    I have used the exact same config as the C++ sample, instead using not a C++ Background Agent but using the above C# code. XML and image are the same (direct copy). So.. basically it works (it does render SOMETHING :)), but not how it supposed to.
    Wednesday, July 2, 2014 7:29 PM
  • Any updates on this from Microsoft?

    I could go with the C++ implementation, but my current BT already uses C# classes. Is it possible to run a C# Background Task to fetch up data, and to let a C++ function render the tile and returning the Isolated Storage link???

    Kind regards,
    Niels
    Friday, July 18, 2014 9:55 AM
  • Eric, could you please fix line:

    enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, 150, 150, 96,96, data);

    It should be:

    enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)rtb.PixelWidth, (uint)rtb.PixelHeight, 96, 96, data);

    Otherwise resulting image can be broken.

    Thursday, August 14, 2014 9:31 AM
  • Thanks for the suggestion, I have updated the earlier code sample.


    Eric Fleck, Windows Store and Windows Phone Developer Support. If you would like to provide feedback or suggestions for future improvements to the Windows Phone SDK please go to http://wpdev.uservoice.com/ where you can post your suggestions and/or cast your votes for existing suggestions.

    Thursday, August 14, 2014 2:18 PM
  • This worked, and I have set up my project to render 2 Medium tiles (front / back) en 2 wide tiles (front / back). Unfortuntly, I do hit the memory limit so the tiles won't update (they will during debug, as the memorylimit is higher). This is my current setup:

    1. C# BT that receives data from an online API and then generates the tile, e.g.: string MediumTileUrl = await RenderTheMediumTile(CustomClass.Data);

    2. RenderTheMediumTile(CustomClass.Data dataInput) renders the tile as described, saves it and return an URL.


    Would it be possible to have the same C# background task, and move RenderTheMediumTile(CustomClass.Data) to a C++ object??? So it would be C# calling C++ to render the tile, and let C++ return the tile URI.

    If this is possible, how to achieve this? I'm not familiar with C++ at all.

    Kind regards,
    Niels

    Sunday, September 7, 2014 7:17 AM
  • Hi, I'm trying to use this to update everytime my music changes; please see my thread.

    http://social.msdn.microsoft.com/Forums/windowsapps/en-US/13fbb294-262d-4231-936b-361594e78257/update-livetile-from-backgroundmediaplayer-background-task?forum=wpdevelop

    For this reason I need to run on a Media event and not in OnRun(). It's inside my IBackgroundTask which I've implemented for xamkrenderingbackgroundtask as well. Problem is it won't let me create UI elements from these events?

    Anyway to trigger a separate background task with this tile updater in it from the background task implementing IBackgroundTask?

    • Proposed as answer by craig91 Sunday, September 21, 2014 4:13 AM
    Thursday, September 18, 2014 9:36 PM
  • OK. Major discovery!

    InstalledLocation is READ ONLY!!! This will work when deployed from Visual Studio, but once it's in the Store the tiles will not be generated. Please use:

      var outputFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(TileURI, Windows.Storage.CreationCollisionOption.ReplaceExisting);

    This will work!
    Monday, February 23, 2015 3:55 PM