【问题标题】:Task Does not Update UI in WPF任务不更新 WPF 中的 UI
【发布时间】:2011-11-01 12:01:13
【问题描述】:

我写了这段代码:

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 显示它的值

为什么这段代码不起作用?

【问题讨论】:

  • 您的视图模型是否实现了INotifyPropertyChanged 接口?
  • 您仍然需要告诉 XAML 该属性已更改。
  • 请多描述一下我...
  • @ChrisF:我在这里没有看到缺少的 INPC。 OP 直接设置 txttest.Text 。不需要 PropertyChanged 事件。我错了吗?
  • @HCL - 啊 - 我明白你的意思了。我上面的 cmets 是错误的 - 我误解了正在更新的属性。

标签: c# wpf multithreading task


【解决方案1】:

ContinueWith 创建一个在目标任务完成时异步执行的延续。即它只会在您的 SumRootN 操作完成后更新结果。

【讨论】:

    【解决方案2】:

    我从未使用过 TaskScheduler,因此我无法直接反馈问题所在。但是从你的问题描述来看,我很确定问题是 UI 线程被阻塞了。只要您的代码没有终止,UI 就不会更新。

    对于耗时的操作,请使用BackgroundWorker 进行操作。但是请注意,您不能直接从异步中设置控件的值。使用 Dispatcher 将您的命令路由到 UI 线程或使用 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();  
    

    【讨论】:

    • 但我在 winforms 中使用了类似的代码,它可以工作。使用 1`var ui = TaskScheduler.FromCurrentSynchronizationContext(); ' 用于同步线程。为什么这不起作用?
    【解决方案3】:

    对此有一些故障排除提示...您可能必须先回答这些问题...

    1. 您的代码实际位于何处?在 Button_click() 调用中?
    2. 当您在代码TaskScheduler.FromCurrentSynchronizationContext(); 上放置断点时,您会看到什么样的SynchronizationContext 对象? Dispatcher 类型?还是其他类型?
    3. 是否有使用 TPL 的特定原因?不能使用BackgroundWorkerDispatcher 对吗?

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 2014-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多