【问题标题】:Can't pass UI controls' values as parameters to method inside Task.Factory.StartNew无法将 UI 控件的值作为参数传递给 Task.Factory.StartNew 中的方法
【发布时间】:2018-03-12 00:36:25
【问题描述】:

我正在学习多线程,所以当我在玩 Task 类时,我注意到调用 Task.Factory.StartNew 方法时出现了一些奇怪的(对我来说)行为。我在 WPF 应用程序中做了一些示例,我只是尝试在单击按钮时从 Task 调用一个方法,而我所做的是:

Task.Factory.StartNew(() => OrderTickets(numberOfTicktes, cbMovieName.Text));

但是,OrderTickets 方法从未被调用过。然后我像这样更改了我的代码:

string movieName = cbMovies.Text;
Task.Factory.StartNew(() => OrderTickets(numberOfTicktes, movieName ));

在此更改之后,我的方法“OrderTickets”被按预期调用。我的问题是为什么我不能直接在 Task StartNew 方法内部使用 UI 控件的值,就像我尝试使用组合框一样?我猜,这是因为 UI 控件由 UI 线程持有,但不太确定。谁能向我解释这里到底发生了什么?你能指点我描述这个的微软文档吗?

【问题讨论】:

  • 我不确定,但Task.Factory.StartNew(() => OrderTickets(numberOfTicktes, cbMovieName.Text)) 这必须正常工作?
  • 这是个好问题。虽然您可以轻松地搜索其他 StackOverflow 问题/答案,即 WPF 不允许从控件上的 UI 线程以外的其他线程进行读取访问,并且 WPF 对此保持沉默,但我在 MSDN 上找不到任何信息。您能否重新表述您的问题,因此它要求提供指向 Microsoft 文档的链接?这会很有趣。
  • 顺便说一句,你可能想要to avoid StartNew
  • 否 - 来自其他线程的写访问没有例外(除非一个类像 ObservableCollection 一样严格禁止它)。这可以在 99.99% 的情况下工作,直到对于一个用户它不起作用,并且您重构一个应用程序以在任何地方使用 Dispatcher :)

标签: c# wpf multithreading task


【解决方案1】:

如果你的代码会说话,这就是你正在做的事情:

“我是主线程。嘿调度程序,你能使用池中的线程为我完成这项工作吗?”

() => OrderTickets(numberOfTicktes, cbMovieName.Text)

主线程现在是空闲的,稍后(或立即)一个池线程会接手这项工作并注意到这一点:

cbMovieName.Text

因此它尝试与cbMovieName 通信,但线程(在您的情况下为主线程或 UI 线程)介入并说:

“嘿池线程,你为什么不问我就试图与我的控件之一通信?走开!!!(当他翻白眼时)”

在池线程上抛出异常但没有冒泡。因此,在您看来,它似乎从未被调用,但上述所有事情都发生了。

在另一种情况下:

string movieName = cbMovies.Text;
() => OrderTickets(numberOfTicktes, movieName)

它将工作,因为池线程不需要任何 UI 控件。

【讨论】:

  • 感谢您的精彩解释!当你把它简单化的时候,它对于理解事物是如何工作的真的很有帮助。我的猜测是准确的,但不知道引擎盖下发生了什么。太棒了!
【解决方案2】:

这不是很明显,但问题是您遇到了 两个 问题 - 它们的交互方式有点令人困惑。

问题 1 - 您无法访问 UI thread 之外的控件。

问题 2 - StartNew 不像您期望的那样bubble up exceptionsContinueWith 可以帮助解决这个问题。

最终结果是 看起来在您看来调用失败而没有引发异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多