Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating CycleTile with remote images

I have seen a number of examples showing the CycleTile in action, but these have all used local images. Is it possible to set these images once the app is first run and point the CycleTile to the remote images? Or if I do need to save these to the phone first, how can I get the CycleTile to reference them?

like image 627
totiDev Avatar asked Jan 03 '13 23:01

totiDev


2 Answers

CycleTileTemplate & CycleTileData only support local URIs and don't support remote web URIs. Meaning that you can only set the source of a cycle image from files installed from the XAP or from files in IsoStore.

In order to support remote images in CycleTileData, you'll need to download the images in a periodic background agent, save them to IsoStore and then update the CycleTileData with those images. Push notifications won't work here since the images need to be local and neither will ShellTileSchedule.

Make sure to save the images to IsoStore under the "/Shared/ShellContent" and set their URIs as "isostore:/Shared/Shellcontent/myImage.png" or they won't be accessible to the start screen tiles.

Let's see an example of that. First we start off by writing up a parallelized threaded algorithm that launches 9 download threads, waits for the results and then updates tiles:

private IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
        var threadFinishEvents = new List<WaitHandle>();

        DownloadImages(threadFinishEvents);

        new Thread(()=>
        {
            Mutex.WaitAll(threadFinishEvents.ToArray());

            UpdateTiles();

            isoStore.Dispose();
        }).Start();
}

Next, we'll download the 9 images into IsoStore "/Shared/ShellContent". We'll take special note to add the new threading flags for each web download, and set the flag as done once the file is in IsoStore.

private void DownloadImages(List<WaitHandle> threadFinishEvents)
{
    for (int i = 0; i < 9; i++)
    {
        var localI = i;

        var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
        threadFinishEvents.Add(threadFinish);

        var request = WebRequest.CreateHttp("http://www.justinangel.net/storage/691x336.png");
        request.BeginGetResponse(ir =>
        {
            var result = request.EndGetResponse(ir);
            using (var isoStoreFile = isoStore.OpenFile("shared/shellcontent/myImage" + localI + ".png",
                                                        FileMode.Create,
                                                        FileAccess.ReadWrite))
            using (var response = result.GetResponseStream())
            {
                var dataBuffer = new byte[1024];
                while (response.Read(dataBuffer, 0, dataBuffer.Length) > 0)
                {
                    isoStoreFile.Write(dataBuffer, 0, dataBuffer.Length);
                }
            }

            threadFinish.Set();
        }, null);
    }
}

Finally, we'll update the live tile to use the new images in IsoStore.

private void UpdateTiles()
{
    ShellTile.ActiveTiles
        .First()
        .Update(new CycleTileData()
        {
            Title = "Cyclical",
            CycleImages = new Uri[]
            {
                new Uri("isostore:/Shared/ShellContent/myImage0.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage1.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage2.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage3.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage4.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage5.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage6.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage7.png", UriKind.Absolute), 
                new Uri("isostore:/Shared/ShellContent/myImage8.png", UriKind.Absolute), 
            }
        });
}

There's a couple of interesting things to consider:

  1. Periodic background agents only have 25 seconds to complete their operation, so it might make sense to add timer thresehold when activating Mutex.WaitAll and have it fail gracefully.
  2. Downloading 9 images in 25 seconds might not work at all under some network conditions so it might be best to optimize for that. You can either use less images, or update only a few images every 30 minutes.
  3. Updating the CycleTileData to the same file URIs won't trigger an update of the tile (AFAIK). So you'll need better filenames then myImage0, but rather have unique file names for the images.
like image 54
JustinAngel Avatar answered Sep 28 '22 02:09

JustinAngel


For CycleTile, the images have to be local. You could set up a periodic task to refresh the images though, then store those images in the shared/shellcontent special folder in local/isolated storage (e.g., ms-appdata:///local/shared/shellcontent/image01.png)

Session 7 of the Windows Phone 8 Jumpstart is a good reference for this - specifically about 25:30 in.

like image 31
Jim O'Neil Avatar answered Sep 28 '22 03:09

Jim O'Neil