0
votes

How can I make the background agent execution to wait before all ImageOpened() events are fired (3 in this case) in order to update secondary live tile with custom images?

Edit 1:

In the OnInvoke() method of the ScheduledAgent I am calling my own create tile data function implemented in a shared library which in turn subscribes to 3 ImageOpened() events as I am trying to create custom images for all live tile templates i.e. small, medium and wide.

Since these being asynchronous events I have no way to check if all the events have completed successfully so that I can call NotifyComplete() to notify the background agent that its job is now done. So sometimes the tile gets updated while most of the times it doesn't. Also I am using the same function to update the live tiles every time the app is launched so there is no problem with its implementation. I have also tried to take care of all the memory limitations with the ScheduledAgent by disposing Bitmaps and calling GC.Collect() forcefully.

Please help in any possible way to fix this problem.

1
I'm having the same problem... did you manage to do this?Cabuxa.Mapache
Yes I managed to fix the issue by using manual reset events that made the scheduled agent wait until all the images were rendered. All the ImageOpened events fired a completion event that made sure that the image has been decoded properly. Let's say that you are changing both the medium and wide tiles. Dispatch a completion event signalling the completion of the ImageOpened event for both the medium and wide tile images. Now you'll update the secondary tiles only when both the events are set.Shikhar
I'll probably post some code samples as soon as I get time but this will atleast guide you in the right direction.Shikhar
Thank you very much, i'll wait for it...Cabuxa.Mapache

1 Answers

1
votes

Add a new class that lets you create custom events -

public class SaveImageCompleteEventArgs : EventArgs
{
    public bool Success { get; set; }
    public Exception Exception { get; set; }
    public string ImageFileName { get; set; }

    public SaveImageCompleteEventArgs(bool success, string fileName)
    {
        Success = success;
        ImageFileName = fileName;
    }
}

Initialize the events and required variables in the file you are updating the custom live tile from -

public static int countTile = 3;
public event EventHandler<SaveImageCompleteEventArgs> SaveMediumImageComplete;
public event EventHandler<SaveImageCompleteEventArgs> SaveWideImageComplete;
public event EventHandler<SaveImageCompleteEventArgs> SaveSmallImageComplete;
public event EventHandler<SaveImageCompleteEventArgs> SaveAllImagesComplete;

Fire the completion event in the ImageOpened() event handlers for all the tiles and check if the SaveAllImagesComplete event needs to be fired-

public void OnBackgroundBmpOpenedMedium(object sender, RoutedEventArgs e)
{
    if (SaveMediumImageComplete != null)
    {
        countTile -= 1;
        CheckIfAllImagesOpened();
        SaveMediumImageComplete(this, new SaveImageCompleteEventArgs(true, mediumTileImageUriIronMan));
    }
}

private void CheckIfAllImagesOpened()
{
    if (countTile == 0)
    {
        if (SaveAllImagesComplete != null)
        {
            var args1 = new SaveImageCompleteEventArgs(true, "");
            SaveAllImagesComplete(this, args1);
        }
    }
}

In the ScheduledAgent file -

public static ManualResetEvent evt;
public bool IsPaused { get { return !evt.WaitOne(0); } }

In the OnInvoke() function -

evt = new ManualResetEvent(false);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
    //Initialize secondary tile here

    if (secondaryTile != null)
    {
        /* 
        obj is a object of a helper file that contains all the  
        functions responsible for updating the custom live tile

        Call the function that is responsible for initializing all the  
        tile image bitmpas and that subscribes to the ImageOpened events 
        */

        obj.SaveMediumImageComplete += async (s, args) =>
        {
            if (!IsPaused)
                evt.Set();
        };
        obj.SaveWideImageComplete += async (s, args) =>
        {
            if (!IsPaused)
                evt.Set();
        };
        obj.SaveSmallImageComplete += async (s, args) =>
        {
            if (!IsPaused)
                evt.Set();
        };
        obj.SaveAllImagesComplete += async (s, args) =>
        {
            try
            {
                if (args.Success)
                    obj.UpdateTileIcon();
            }
            catch (Exception) { }
            finally
            {
                if (!IsPaused)
                    evt.Set();
            }
        };
    }
});
evt.WaitOne();
NotifyComplete();