Alex
Alex

Reputation: 715

Cancel Task running under User Control

In my project I have few User controls changed by navigation. One of controls runs Tasks. I do it like this:

public partial class uc_WorkingArea : UserControl
{
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken token;

    public uc_WorkingArea()
        {
            InitializeComponent();
            this.Unloaded += uc_WorkingArea_Unloaded;
            token = cts.Token;
            Task Printer1 = Task.Run(() => PrinterPooler(lst_PrinterStruct, 0), cts.Token);
        }


         private void uc_WorkingArea_Unloaded(object sender, RoutedEventArgs e)
        {
            cts.Cancel();
            if (token.CanBeCanceled)
            {
                MessageBox.Show("Can be canceled");
            }

            if (token.IsCancellationRequested)
            {
                MessageBox.Show("Canceled requested");
            }
            cts.Cancel();
            MessageBox.Show("Status: " + Printer1.Status.ToString());
        }
}

When I leave current user control and switching to another uc_WorkingArea_Unloaded executes. I see messages, that Task can be canceled and request to cancel accepted.

But, current status of Printer1 task still "IsRunning". So, If I return back to this user control, Task starts again and Application had two running similar tasks.

I tried run task under Factory, like this

Task Printer1 = Task.Factory.StartNew(() => PrinterPooler(lst_PrinterStruct, 0), cts.Token);

But without success. App still runs two similar tasks.

PrinterPooler method not async.

I can't understand where mistake was made. Your help guys needed.

Upvotes: 0

Views: 203

Answers (2)

Mar Tin
Mar Tin

Reputation: 2392

Regarding to this post How do I abort/cancel TPL Tasks?

You have to Implement your cancle condition by your self. For example:

public partial class uc_WorkingArea : UserControl
{
    public CancellationTokenSource cts = new CancellationTokenSource();
    public CancellationToken token;
    public Task Printer1;

    public uc_WorkingArea()
    {
        token = cts.Token;
        Printer1 = Task.Factory.StartNew(() =>
        {
            while (!token.IsCancellationRequested)
            {
                Console.WriteLine("run");
                Application.DoEvents();
            }
        }, token);
    }
}

Cancel Call:

    uc_WorkingArea gc = new uc_WorkingArea();

    for (int i = 0; i < 10; i++) //PASS SOME TIME
    {
        Application.DoEvents(); //CONSOLE SHOULD SPAM 'RUN' FROM TASK
        Thread.Sleep(1);
    }

    gc.cts.Cancel(); //CANCEL CALL, WHILE LOOP END
    if (gc.token.IsCancellationRequested)
    {
        Console.WriteLine("stop");
        MessageBox.Show("Canceled requested");

    }
    gc.cts.Dispose();
    gc.Printer1.Dispose();

Hope it helps.

Upvotes: 1

Krzysztof Skowronek
Krzysztof Skowronek

Reputation: 2936

You have to pass the token into the PrintPooler method, and there inside check if it should be cancelled.

for(int i = 0; i < 10000; i++)
{
   DoStuff();
   cancelToken.ThrowIfCancellationRequested(); // if tasks end with this exception, it knows the work has been cancelled
}

Canceling a Task does not stop the execution, it only gives signal to code inside that it should end and sets the task status to Cancelled/Faulted/RanToCompletion depending on how execution stops.

Note that you need to pass the same token to the Task and to the method that will throw it.

Upvotes: 1

Related Questions