Don’t make your Application lifetime events async void!

So just to rephrase: Don’t make your Application lifetime events async void!

Yes, I learned the hard way. Yes I’ve read, and know, about the: Never make a void async. But if you want write an event-handler you’ve got no choice. But beware, sometimes things look to be working okay, but actually don’t.

Alright, back to where all my trouble started. Every Windows Phone App developer knows about the Application Lifetime events that are automatically subscribed to in the App.xaml.cs. You’ve probably added code to at least one of the following event-handlers.

Application_Launching: Occurs when the application is being launched

Application_Closing: Occurs when the application is exiting

Application_Activated: Occurs when the application is being made active after previously being put into a dormant state or tombstoned.

Application_Deactivated: Occurs when the application is being deactivated. You have 10 seconds to complete your work, though it’s recommended to aim for completing the work within 2 seconds.

No await in those event handlers!

Alright, I’m just writing code. I need to perform the last small SQLite query to save some state. Hmm, that’s done in the Closing method. I’m writing the code, oh yeah, the SQLite query is an asynchronous operation. I write await, hmm, mark the method as async void. Hmm, shouldn’t do that, should I? It’s an event-handler, true, but don’t forget you’ve done it before, and the code does execute. Okay move on and test later. I’ll be honest, I forgot to test, but I got some strange issues that I had difficulty with solving.

What I found out, that as soon as the word await was hit in the event-handler, the thread was given back to the application, which kind of signaled the app, I’m ready to terminate. Ouch! The actual never executed, that was painful! Just note, after save the settings in the SQLite database, I did the closing of all open connections. This closing never happened either, which in itself caused strange situations with trying to execute queries on closed connections when the app resumed.

Okay I learned the hard way, don’t use await in the above mentioned event-handlers, better don’t use it in any event-handler.

But I need that API call, which happens to be async

So I started looking for a way to call a Task synchronously. Yes I found a way on StackOverflow that works very well. So I could change my code like this, which indeed does result in nice code I think.

private void Application_Closing(object sender, ClosingEventArgs e)
{
    Debug.WriteLine("BEGIN - ApplicationClosing");
    AsyncHelpers.RunSync(() => ApplicationClosingAsync(sender, e));
    Debug.WriteLine("END - ApplicationClosing");
}

private async Task ApplicationClosingAsync(object sender, ClosingEventArgs e)
{
    try
    {
        ApplicationSettings settings = await ApplicationSettings.LoadSettings();
        settings.LastAppRun = DateTime.Now;
        await ApplicationSettings.SaveSettings(settings);
        ViewModelLocator.Cleanup();
        SQLiteConnectionPool.Shared.ApplicationSuspended();
    }
    catch (Exception exception)
    {
        //swallow exceptions that occur at this moment.
    }
}

 

All the code that was originally in the Application_Closing event handler is now moved to the ApplicationClosingAsync method, which indeed is an async method which returns a Task. The method contains multiple await statements, the keyword that shouldn’t be in de event handler itself. I added the Debug information for testing purpose, so you can see everything get’s called. The magic is in the AsyncHelper method which I copied from the StackOverflow site, so please place the credits in the right place. I’ve shown the code for Application_Closing, but it works for the other event-handlers as well.

UPDATE 1: According to Oren Novotny this feature also exists in the Nito.AsyncEx NuGet Package. Pick the one you like best, but at least test your code.

public static class AsyncHelpers
{
    /// <summary>
    /// Execute's an async Task method which has a void return value synchronously
    /// </summary>
    /// <param name="task">Task method to execute</param>
    public static void RunSync(Func<Task> task)
    {
        var oldContext = SynchronizationContext.Current;
        var synch = new ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(synch);
        synch.Post(async _ =>
        {
            try
            {
                await task();
            }
            catch (Exception e)
            {
                synch.InnerException = e;
                throw;
            }
            finally
            {
                synch.EndMessageLoop();
            }
        }, null);
        synch.BeginMessageLoop();

        SynchronizationContext.SetSynchronizationContext(oldContext);
    }

    /// <summary>
    /// Execute's an async Task<T> method which has a T return type synchronously
    /// </summary>
    /// <typeparam name="T">Return Type</typeparam>
    /// <param name="task">Task<T> method to execute</param>
    /// <returns></returns>
    public static T RunSync<T>(Func<Task<T>> task)
    {
        var oldContext = SynchronizationContext.Current;
        var synch = new ExclusiveSynchronizationContext();
        SynchronizationContext.SetSynchronizationContext(synch);
        T ret = default(T);
        synch.Post(async _ =>
        {
            try
            {
                ret = await task();
            }
            catch (Exception e)
            {
                synch.InnerException = e;
                throw;
            }
            finally
            {
                synch.EndMessageLoop();
            }
        }, null);
        synch.BeginMessageLoop();
        SynchronizationContext.SetSynchronizationContext(oldContext);
        return ret;
    }

    private class ExclusiveSynchronizationContext : SynchronizationContext
    {
        private bool done;
        public Exception InnerException { get; set; }
        readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
        readonly Queue<Tuple<SendOrPostCallback, object>> items =
            new Queue<Tuple<SendOrPostCallback, object>>();

        public override void Send(SendOrPostCallback d, object state)
        {
            throw new NotSupportedException("We cannot send to our same thread");
        }

        public override void Post(SendOrPostCallback d, object state)
        {
            lock (items)
            {
                items.Enqueue(Tuple.Create(d, state));
            }
            workItemsWaiting.Set();
        }

        public void EndMessageLoop()
        {
            Post(_ => done = true, null);
        }

        public void BeginMessageLoop()
        {
            while (!done)
            {
                Tuple<SendOrPostCallback, object> task = null;
                lock (items)
                {
                    if (items.Count > 0)
                    {
                        task = items.Dequeue();
                    }
                }
                if (task != null)
                {
                    task.Item1(task.Item2);
                    if (InnerException != null) // the method threw an exeption
                    {
                        throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
                    }
                }
                else
                {
                    workItemsWaiting.WaitOne();
                }
            }
        }

        public override SynchronizationContext CreateCopy()
        {
            return this;
        }
    }
}

Make the ListPicker or RadListPicker behave in a ScrollViewer

I’ve seen a lot of applications that have a page in there that just doesn’t behave the way it should. Either there’s a textbox that’s placed in a not so brilliant way, where a lot of controls are covered by the onscreen keyboard and there’s not a nice way to close the keyboard (tapping somewhere on the screen is not a nice way, is it?). The same goes for ListPickers, when they are placed in a ScrollViewer at the bottom of the screen chances are that you’re only seeing one item once you open de ListPicker, the rest is at the bottom of the screen.

A picture is worth a thousand words, so here the situation of the ListPicker I’m explaining, closed (no trouble) and opened where the user hardly sees that there are options at all.

closed

opened wrong

 

 

 

 

 

 

 

 

Of course I want to fix this. And I even know I fixed this before, but I had to think hard in which app I fixed this problem. I found the code but in the old app I was making use of the ListPicker from the Windows Phone Toolkit and now I’m making use of the RadListPicker by Telerik. Though besides that I didn’t find anyone blogging about this before. That’s why I’m writing this. The code I show in here could have been written by someone else, but I can’t remember.

ListPicker from the Windows Phone Toolkit solution

The original ListPicker can react to the GotFocus event to then bind to the SizeChanged event in which the actual logic for making the control visible in the scrollviewer is called. The magic piece is shown in the end, it’s shared by both solutions. The magic is in line 8 of course.

NewTracksToDownloadPicker.GotFocus += PickerGotFocus;

private void PickerGotFocus(object sender, RoutedEventArgs eventArgs)
{
    var picker = sender as ListPicker;
    if (picker != null)
    {
        picker.SizeChanged += (s, e) => picker.EnsureVisibleInScrollViewer();
    }
}

RadListPicker by Telerik solution

The RadListPicker by Telerik doesn’t fire the GotFocus event at the same time, so I had to pick and try to correct event to listen to. I found out that the StateChanged event works best for me.

NewTracksToDownloadPicker.StateChanged += PickerStateChanged;

private void PickerStateChanged(object sender, ListPickerStateChangedEventArgs listPickerStateChangedEventArgs)
{
    var picker = sender as RadListPicker;
    if (picker != null)
    {
        picker.SizeChanged += (s, e) => picker.EnsureVisibleInScrollViewer();
    }
}

 

So now it’s time for some magic!

No not really, but the code can be quite handy for other situations as well when you want to be sure a control is completely visible inside a ScrollViewer.

The magic consists of two parts, finding the parent ScrollViewer of the Control you want to make visible. With all kinds of nesting, it could be difficult to tell how many levels are there. So with the help of the VisualTreeHelper and a little bit of recursion you get this pieces of code.

public static T FindParentOf<T>(this UIElement element) where T : UIElement
{
    var found = FindParentOf(element, typeof(T)) as T;
    return found;
}

public static DependencyObject FindParentOf(DependencyObject element, Type type)
{
    if (type.IsInstanceOfType(element))
        return element;
    DependencyObject parent = VisualTreeHelper.GetParent(element);
    if (parent == null)
        return null;
    return FindParentOf(parent, type);
}

 

So that piece of magic is gone. Next is the actual making sure that the control is visible in the ScrollViewer. A little bit of measuring and making the ScrollViewer to scroll to the measured position. What magic were you talking about?

public static void EnsureVisible(this ScrollViewer scroller, UIElement element)
{
    scroller.UpdateLayout();

    double maxScrollPos = scroller.ExtentHeight - scroller.ViewportHeight;
    double scrollPos =
        scroller.VerticalOffset -
        scroller.TransformToVisual(element).Transform(new Point(0, 0)).Y;

    if (scrollPos > maxScrollPos) scrollPos = maxScrollPos;
    else if (scrollPos < 0) scrollPos = 0;

    scroller.ScrollToVerticalOffset(scrollPos);
}

public static void EnsureVisibleInScrollViewer(this UIElement element)
{
    var scrollViewer = element.FindParentOf<ScrollViewer>();
    if (scrollViewer != null)
        scrollViewer.EnsureVisible(element);
}

 

Yes, I know you want to see the end result. Have fun with it!

opened correctly