Home > ASP.NET WebAPI, C#, WinRT > How to create a slideshow of images for the Windows 8.1 Lock screen

How to create a slideshow of images for the Windows 8.1 Lock screen

10/12/2013

The new LockScreen.RequestSetImageFeedAsync method that is available in Windows 8.1 allows to set a remote RSS feed as source for the Lock Screen slideshow.

The RSS must have the following structure:

<?xml version="1.0" ?>
<rss version="2.0">
<channel>
	<title>Bing Images RSS feed</title>
	<link>http://mypersonalsite.azurewebsites.net/api/wallpapers</link>
	<description>Bing Images for Windows 8.1 Lock Screen</description>
	<pubDate>Sat, 07 Dec 2013 19:39:04 GMT</pubDate>
	<lastBuildDate>Sat, 07 Dec 2013 19:39:04 GMT</lastBuildDate>
	<item>
		<title>A billabong in Wooleen Station, Western Australia</title>
		<link>http://www.bing.com/az/hprichbg/rb/WooleenStation.jpg</link>
		<description>A billabong in Wooleen Station, Western Australia</description>
		<enclosure url="http://www.bing.com/az/hprichbg/rb/WooleenStation.jpg" 
                type="image/jpg" />
		<pubDate>Fri, 06 Dec 2013 00:00:00 GMT</pubDate>
	</item>
	<item>
		<!-- ... -->
	</item>
</channel>
</rss>

Images must be in JPEG or PNG format. We can easily defines a WebAPI that provides an RSS with this structure. The following example creates the feed with the last Bing images:

public class WallpapersController : ApiController
{
    private static readonly Uri BASE_URI = new Uri("http://www.bing.com");

    public async Task<HttpResponseMessage> Get(string market = null)
    {
        var response = Request.CreateResponse();

        try
        {
            using (var client = new HttpClient())
            {
                var content = await client.GetStringAsync(
                    "http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=8");

                var feed = new SyndicationFeed("Bing Images RSS feed", 
                    "Bing Images for Windows 8.1 Lock Screen", Request.RequestUri);
                
                feed.ElementExtensions.Add(
                    "pubDate", string.Empty, DateTimeOffset.UtcNow.ToString("r"));

                feed.LastUpdatedTime = DateTimeOffset.UtcNow;
                var items = new List<SyndicationItem>();
                feed.Items = items;

                var xml = XDocument.Parse(content);
                foreach (var image in xml.Descendants("image"))
                {
                    var description = image.Element("copyrightsource") != null ? 
                        image.Element("copyrightsource").Value : null;
                    
                    var item = new SyndicationItem(image.Element("copyright").Value, 
                        description, new Uri(BASE_URI, image.Element("url").Value));
                    
                    item.PublishDate = 
                        DateTimeOffset.ParseExact(image.Element("startdate").Value, 
                        "yyyyMMdd",
                        CultureInfo.InvariantCulture);
                    
                    item.ElementExtensions.Add(
                        new XElement("enclosure", 
                            new XAttribute("url", item.Links[0].Uri),
                            new XAttribute("type", "image/jpeg")));

                    items.Add(item);
                }

                using (var ms = new MemoryStream())
                {
                    using (var writer = XmlWriter.Create(ms))
                    {
                        feed.SaveAsRss20(writer);
                        writer.Flush();
                        var buffer = ms.ToArray();
                        var output = Encoding.UTF8.GetString(buffer, 0, buffer.Length);

                        response = Request.CreateResponse();
                        response.Content = 
                            new StringContent(output, Encoding.UTF8, 
                                "application/rss+xml");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            response = 
                Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
        }

        return response;
    }
}

Note that, in order to use the SyndicationFeed and SyndicationItem classes, we must add a reference to the System.ServiceModel.dll assembly.

Now we can create a Windows Store app that calls the RequestSetImageFeedAsync method:

var result = await LockScreen.RequestSetImageFeedAsync(
    new Uri("http://mypersonalsite.azurewebsites.net/api/wallpapers"));

if (result == SetImageFeedResult.Success)
{
    // The image feed was set was successfull.
}
else if (result == SetImageFeedResult.ChangeDisabled)
{
    // The feed was not set because the lock screen image slide show 
    // is disabled by group policy.
}
else if (result == SetImageFeedResult.UserCanceled)
{
    // The operation was canceled by the user.
}

When executing the method at line 1, Windows will show a message to confirm the operation. If we decide to continue, the feed will be automatically saved, and the app will be listed in the PC and devices | Lock screen section of the PC Settings app. Note that, in some cases, to correctly show the images, we must turn off the switch Only show the pictures that will fit best on my screen (the screenshot below is taken from the Italian version of Windows 8.1):

Windows 8.1 Lock screen settings

Usually, we must wait at least one minute before the feed images will start to be used. After this, the RSS will be regularly updated, so that our slideshow wil always show the most recent Bing images.

The feed will be available as long as our app is installed in the system. If we want to stop the slideshow from our app, we need to call the LockScreen.TryRemoveImageFeed.

Categories: ASP.NET WebAPI, C#, WinRT
%d bloggers like this: