如何从TPL任务更新WPF控件?

时间:2011-10-11 13:21:12

标签: .net wpf parallel-processing task-parallel-library dispatcher

如何从TPL任务更新WPF控件?

很好所以我尝试了一些方案来使用Dispatcher,但无论如何它都会给出错误。我需要帮助的人!

private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        //Application.Current.Dispatcher.Invoke((Action)MyInit); 
        backgroundDBTask = Task.Factory.StartNew(() =>
            {
                DoSomething1();
            }, TaskCreationOptions.LongRunning);
        backgroundDBTask.ContinueWith((t) =>
        {
            // ... UI update work here ...
        },             
        TaskScheduler.FromCurrentSynchronizationContext());             
    }

    void DoSomething1()
    {
        // MyInit();
        int number = 0;
        while (true)
        {
            if (state)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Begin second task... {0}", number++);
               // mostCommonWords = GetMostCommonWords(words) + string.Format("   Begin second task... {0}", number++);

                textBox2.Text = (number++).ToString(); // Gives the error

                Dispatcher.BeginInvoke(); // How it should be ?
            }
        }
    }

谢谢!

2 个答案:

答案 0 :(得分:5)

您需要将完成工作的代表传递给BeginInvoke BeginInvoke将在UI线程上异步运行此委托。

例如:

Dispatcher.BeginInvoke(new Action(delegate {
    textBox2.Text = number.ToString(); 
}));

答案 1 :(得分:3)

我知道这里已经有了答案,Slaks给你的东西会修复它,因为它会使用Dispatcher线程,因此不会抛出accessing a control from a different thread的异常。

但是,我注意到了这一点。

 backgroundDBTask = Task.Factory.StartNew(() =>
        {
            DoSomething1();
        }, TaskCreationOptions.LongRunning);

有了这个

 backgroundDBTask.ContinueWith((t) =>
    {
        // ... UI update work here ...
    },             
    TaskScheduler.FromCurrentSynchronizationContext());   

您已经在评论更新用户界面的位置,并且还为其提供了SynchronizationContext。为什么还要尝试更新UI内的DoSomething1

除非您Task的目的是更新UI,否则无需使用ContinueWith。相反,只需传递SynchronizationContext即可,而无需明确调用Dispatcher.BeginInvoke

backgroundDBTask = Task.Factory.StartNew(() =>
        {
            DoSomething1();
        },
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext());