0

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.

Alex
  • 685
  • 3
  • 9
  • 20

2 Answers2

1

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.

Krzysztof Skowronek
  • 2,796
  • 1
  • 13
  • 29
  • Yep! This works perfectly. But, another question. May be you can answer on it. I have few tasks, that run the same function, but with different arguments. Can I use the same cts for every task run? – Alex Apr 04 '19 at 11:20
  • they can share the cancellation token and will be cancelled all at once – Krzysztof Skowronek Apr 04 '19 at 11:21
  • 1
    Nice! Thank you very much for explanations. Today you saved my life :) – Alex Apr 04 '19 at 11:22
1

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.

Mar Tin
  • 2,132
  • 1
  • 26
  • 46
  • 1
    Hi. Thank you for answer. I have decision already. But, I will place your answer into my code scratch book. May be I can apply your decision later. Anyway, thank you! – Alex Apr 04 '19 at 11:25