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<TPage, TElement> where TPage : Page
{
private TPage page;
private volatile bool mode;
private volatile int token;

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

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

protected TPage Page => page;
protected bool Mode => mode;

{
{
throw new InvalidOperationException("The current thread is not authorized.");
}

{
throw new InvalidOperationException("The loader requires reset.");
}

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

int value = token;

mode = true;
}

{
{
throw new InvalidOperationException("The current thread is not authorized.");
}

if (mode)
{
mode = false;

{
token++;
}

if (retainMode)
{
mode = true;
}

return true;
}

return false;
}

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

DispatchedHandler handler = () =>
{
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 Entry(int token, TElement element, object data)
{
Token = token;
Element = element;
Data = data;
}
}
}


Tested with:

class GridViewLoader : PageLoader<MainPage, int>
{
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()
};

}
}


Usage:

private GridViewLoader gridViewLoader;

private async void queryBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
{
return;
}

gridView.Items.Clear();

int[] selection;

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

if (selection != null)
{
}
}

• To be clear, you're asking if there's a better way to do this, right? – Fund Monica's Lawsuit Feb 1 '16 at 23:45
• @QPaysTaxes - Not explicitly, but if there is a standard or better way, I'd sure like to know. I may have improvised a little because I do not know Windows Runtime very well. – Avenicci Feb 2 '16 at 0:16

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.

• I'm curious, what does CancellationToken offer besides helpful semantics? – Avenicci Feb 1 '16 at 21:52
• It is essentially a class that handles all the semantics of sharing the information so you just need to handle the actual cancelling and checking if it is canceled. – user34073 Feb 1 '16 at 21:53
• It could replace the mode flag. However, for a real-time UI loading task, dispatching is required to ensure that updates occur on the authorized thread. Any dispatch request is not certain to occur before any kind of cancellation. If they do not, then the results of distinct loading sessions may overlap. The code in OP solves this with an incrementing version named token. – Avenicci Feb 1 '16 at 22:36
• @Avenicci In this case, you can use separate tokens - one generated for each call. – user34073 Feb 2 '16 at 0:09
• @Avenicci instead of trying to shoehorn a CancelationToken into your current code, it would be best to start from scratch with a simple example that uses it. Might be the best way to break out of the "I already have this code" trap. Using the CancelationToken is the "right way" to do this when using async-await. – RubberDuck Feb 2 '16 at 10:33

• if (!page.Dispatcher.HasThreadAccess) use: page.Dispatcher.VerifyAccess(); instead, does the same thing but throws the framework exception.

• Without understanding what problem it solves I think the design is wrong.

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

// this can potentially be very expensive to do in a loop
// as it forces a layout on each item added
}


Why not do:

<ListView ItemsSource="{Binding Rows}">
<ListView.View>
<GridView>
...
</GridView>
</ListView.View>
</ListView>


And:

public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Row> _rows = new ObservableCollection<Row> ();

public ObservableCollection<Row> Rows
{
get { return _rows; }
set
{
if (Equals(value, _rows))
{
return;
}

_rows = value;
OnPropertyChanged();
}
}

{
var newRows = new ObservableCollection<Row>();
for (int i = 0; i < 1000; i++)
{
// pseudo code here
var item = FetchRow(i);

• Regarding cancellation: I agree with answer and comments that you should use CancellationToken. This is the idiomatic way of canceling tasks in .net.