如何从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 ?
}
}
}
谢谢!
答案 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());