DooDoo
DooDoo

Reputation: 13437

Task Does not Update UI in WPF

I wrote this code:

public double SumRootN(int root)
{
    double result = 0;
    for (int i = 1; i < 10000000; i++)
    {
        tokenSource.Token.ThrowIfCancellationRequested();
        result += Math.Exp(Math.Log(i) / root);
    }
    return result;
}

private void btnclick_Click(object sender, RoutedEventArgs e)
{
    tokenSource = new CancellationTokenSource();
    txttest.Text = "";

    var watch = Stopwatch.StartNew();
    List<Task> tasks = new List<Task>();
    var ui = TaskScheduler.FromCurrentSynchronizationContext();
    for (int i = 2; i < 20; i++)
    {
        int j = i;
        var compute = Task.Factory.StartNew(() =>
        {
            return SumRootN(j);
        }, tokenSource.Token);

        tasks.Add(compute);

        var displayResults = compute.ContinueWith(
                                resultTask =>
                                   txttest.Text
                                    += "root " + j.ToString() + " " +
                                        compute.Result.ToString() +
                                        Environment.NewLine,
                                CancellationToken.None,
                                TaskContinuationOptions.OnlyOnRanToCompletion,
                                ui);             
    }      
}

It works in WPF but when I wrote this code this way;

tokenSource = new CancellationTokenSource();
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
var ui = TaskScheduler.FromCurrentSynchronizationContext();

Report 
   += ((Microsoft.Office.Interop.Excel.Range)_sheet.Cells[row, "B"]).Value2;

var compute = Task.Factory.StartNew(() =>
             {
                return Report;                             
             }, tokenSource.Token);

            tasks.Add(compute);

            var displayResults
                = compute.ContinueWith(resultTask =>
                     txtReport.Text 
                        += compute.Result.ToString() +
                           Environment.NewLine,
                     CancellationToken.None,
                     TaskContinuationOptions.OnlyOnRanToCompletion,
                     ui);

It does not work, whereas txtReport.Text has correct values, but it does not show in the middle of operation but when operation ends txtReport show it's values

Why does this code not work?

Upvotes: 1

Views: 1510

Answers (3)

Vinit Sankhe
Vinit Sankhe

Reputation: 19885

There are a few troubleshooting tips for this... You may have to answer these questions first...

  1. Where is your code actually located? In Button_click() call?
  2. When you put brekapoint on your code TaskScheduler.FromCurrentSynchronizationContext(); what kind of SynchronizationContext object do you see? Dispatcher type? Or some other type?
  3. Is there a specific reason to use TPL? Cant you use BackgroundWorker and Dispatcher pair?

Upvotes: 1

s_nair
s_nair

Reputation: 812

ContinueWith creates a continuation that executes asynchronously when the target Task completes. I.e it will only update the result once your SumRootN operation complete.

Upvotes: 1

HCL
HCL

Reputation: 36765

I never worked with TaskScheduler, therefore I can not give you a direct feedback whats wrong. But from your problem description, I'm quite shure that the problem is that the UI-thread is blocked. As long as your code has not terminated, the UI will not be updated.

For time time consuming operations, do them with a BackgroundWorker. However take care that you can not set values of your controls from within the asynchronous directly. Either use the Dispatcher to route your command to the UI-thread or use the ProgressChanged-event.

The following code shows you how to use the BackgroundWorker:

BackgroundWorker bgWorker = new BackgroundWorker() { WorkerReportsProgress=true};  
bgWorker.DoWork += (s, e) => {      
    // Do here your calculations
    // Use bgWorker.ReportProgress(); to report the current progress  
};  
bgWorker.ProgressChanged+=(s,e)=>{      
    // Here you will be informed about progress and here it is save to set the labels value. 
};  
bgWorker.RunWorkerCompleted += (s, e) => {      
// Here you will be informed if the job is done. 
};  
bgWorker.RunWorkerAsync();  

Upvotes: 1

Related Questions