Cancellable UI loader I'm playing with async/await, but I have yet to discover a standard method to safely cancel an intensive task. I have tested the following, and it works exactly as intended, though I remain unsure if a standard method exists.



abstract class PageLoader&lt;TPage, TElement&gt; where TPage : Page
{
    private TPage page;
    private Task loader;
    private volatile bool mode;
    private volatile int token;

    public PageLoader(TPage page)
    {
        if (page == null)
        {
            throw new ArgumentNullException("page");
        }

        this.page = page;
        this.mode = true;
    }

    protected TPage Page =&gt; page;
    protected bool Mode =&gt; mode;

    public void Load(TElement[] items)
    {
        if (!page.Dispatcher.HasThreadAccess)
        {
            throw new InvalidOperationException("The current thread is not authorized.");
        }

        if (loader != null)
        {
            throw new InvalidOperationException("The loader requires reset.");
        }

        if (items == null)
        {
            throw new ArgumentNullException("items");
        }

        int value = token;

        mode = true;
        (loader = new Task(() =&gt; AutoLoad(value, items))).Start();
    }

    public async Task&lt;bool&gt; Set(bool retainMode)
    {
        if (!page.Dispatcher.HasThreadAccess)
        {
            throw new InvalidOperationException("The current thread is not authorized.");
        }

        if (mode)
        {
            mode = false;

            if (loader != null)
            {
                await loader;
                loader = null;
                token++;
            }

            if (retainMode)
            {
                mode = true;
            }

            return true;
        }

        return false;
    }

    protected void Commit(Entry entry)
    {
        if (entry == null)
        {
            throw new ArgumentNullException("entry");
        }

        DispatchedHandler handler = () =&gt;
        {
            if (entry.Token == token)
            {
                AutoCommit(entry);
            }
        };

        var action = page.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, handler);
    }

    protected abstract void AutoLoad(int token, TElement[] items);
    protected abstract void AutoCommit(Entry entry);

    protected class Entry
    {
        public readonly int Token;
        public readonly TElement Element;
        public readonly object Data;

        public Entry(int token, TElement element, object data)
        {
            Token = token;
            Element = element;
            Data = data;
        }
    }
}


Tested with:



class GridViewLoader : PageLoader&lt;MainPage, int&gt;
{
    public GridViewLoader(MainPage page) : base(page) { }

    protected override void AutoLoad(int token, int[] items)
    {
        foreach (int item in items)
        {
            if (!Mode)
            {
                break;
            }

            // (Intensive process per item..)

            Commit(new Entry(token, item, null));
        }
    }

    protected override void AutoCommit(Entry entry)
    {
        GridViewItem item = new GridViewItem()
        {
            Content = entry.Element.ToString()
        };

        Page.gridView.Items.Add(item);
    }
}


Usage:

private GridViewLoader gridViewLoader;

private async void queryBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
    if (!await gridViewLoader.Set(false))
    {
        return;
    }

    gridView.Items.Clear();

    int[] selection;

    // (Do stuff..)
    selection = new int[] { 1, 2, 3 };

    if (selection != null)
    {
        gridViewLoader.Load(selection);
    }
}
You should be using a CancellationToken, which can be generated like:

CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;


Pass this token to the method you wish to potentially cancel and keep a reference outside the method.  Then, from the calling method you can check token.IsCancellationRequested at periodic intervals and return, or if you wish to throw, you can call token.ThrowIfCancellationRequested().  To signal a cancellation, you call source.Cancel(), which propagates through to the token and signals a cancellation request.  You can also set it up to automatically cancel after a certain amount of time when you create the CancellationTokenSource.