windows-phone-8bitmapimagewriteablebitmapbackground-agentssecondary-live-tile

WP8 - How can I make the background agent execution to wait before all ImageOpened events are fired to update live tile with custom images?


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.


Solution

  • 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();