Задача не обновляет интерфейс в WPF - PullRequest
1 голос
/ 01 ноября 2011

Я написал этот код:

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);             
    }      
}

Он работает в WPF, но когда я написал этот код таким образом;

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);

Он не работает, тогда как txtReport.Text имеет правильныйзначения, но он не отображается в середине операции, но когда операция заканчивается txtReport показывают ее значения

Почему этот код не работает?

Ответы [ 3 ]

1 голос
/ 01 ноября 2011

ContinueWith создает продолжение, которое выполняется асинхронно после завершения целевой задачи.Т.е. он обновит результат только после того, как ваша SumRootN операция завершена.

1 голос
/ 01 ноября 2011

Для этого есть несколько советов по устранению неполадок ... Возможно, вам придется сначала ответить на эти вопросы ...

  1. Где фактически находится ваш код?В вызове Button_click ()?
  2. Когда вы ставите brekapoint на свой код TaskScheduler.FromCurrentSynchronizationContext();, какой объект SynchronizationContext вы видите?Dispatcher тип?Или какой-то другой тип?
  3. Есть ли конкретная причина использовать TPL?Не можете ли вы использовать BackgroundWorker и Dispatcher пары?
1 голос
/ 01 ноября 2011

Я никогда не работал с TaskScheduler, поэтому не могу дать вам прямой отзыв, что не так.Но из вашего описания проблемы я совершенно уверен, что проблема в том, что UI-поток заблокирован.Пока ваш код не завершен, пользовательский интерфейс не будет обновляться.

Для операций, отнимающих много времени, выполняйте их с помощью BackgroundWorker .Однако позаботьтесь о том, чтобы вы не могли устанавливать значения своих элементов управления непосредственно из асинхронного режима.Либо используйте Dispatcher для направления вашей команды в поток пользовательского интерфейса, либо используйте ProgressChanged -event.

В следующем коде показано, как использовать 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();  
...