patterncsharpMinor
Cancellable UI loader
Viewed 0 times
cancellableloaderstackoverflow
Problem
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 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 => page;
protected bool Mode => 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(() => AutoLoad(value, items))).Start();
}
public async Task 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 = () =>
{
if (entry.Token
```
abstract class PageLoader 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 => page;
protected bool Mode => 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(() => AutoLoad(value, items))).Start();
}
public async Task 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 = () =>
{
if (entry.Token
Solution
You should be using a
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
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.Code Snippets
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;Context
StackExchange Code Review Q#118577, answer score: 6
Revisions (0)
No revisions yet.