16

在 WinForms 中,几乎所有的 UI 都是线程特定的。您必须使用[STAThread]以便通用对话框工作,并且您不能(安全地)从创建它的线程以外的任何线程访问 UI 元素。据我所知,这是因为 Windows 就是这样工作的——窗口句柄是特定于线程的。

在 WPF 中,保留了这些相同的限制,因为最终它仍然构建在相同的 Windows API 之上,仍然是窗口句柄(尽管主要用于顶级窗口)等等。事实上,WPF 甚至使事情变得更加严格,因为你甚至不能跨线程访问位图之类的东西。

现在出现了 WinRT,这是一种访问 Windows 的全新方式——一种全新的、干净的状态。我们是否仍然坚持相同的旧线程限制(特别是:只能从创建它的线程操作 UI 控件),还是他们已经打开了它?

4

5 回答 5

9

希望它是相同的模型 - 但易于使用,至少在 C# 和 VB 中,新的异步处理允许您编写一个看起来同步的方法,当它需要等待时只使用“等待”在继续之前完成长时间运行的任务。

鉴于强调使异步代码更易于编写,MS 放弃同时要求单线程访问 UI 的效率是令人惊讶的。

于 2011-09-20T17:56:14.350 回答
5

线程模型是相同的。仍然存在单线程和多线程单元 (STA/MTA) 的概念,它必须通过调用RoInitialize来初始化。在名称、参数和错误返回方面,它的行为与 CoInitialize 非常相似。用户界面线程是单线程的,在此视频中于 36:00 确认。

于 2011-09-22T09:41:13.060 回答
2

HTML/CSS UI 模型本质上是单线程的(直到最近 Web Worker 的出现,JS 才支持线程)。Xaml 也是单线程的(因为开发人员很难将代码写入多线程 GUI)。

于 2011-09-21T13:30:39.423 回答
2

底层线程模型确实有一些关键的区别。当您的应用程序启动时,会创建一个 ASTA(应用程序 STA)来运行您的 UI 代码,正如我在演讲中展示的那样。此 ASTA 不允许重入 - 您在拨出电话时不会收到不相关的电话。这是与 STA 的显着区别。

您可以创建异步工作项 - 请参阅Windows.System.Threadpool命名空间。这些工作项线程会自动初始化为 MTA。正如 Larry 提到的,webworkers 是 JS 的等价概念。

您的 UI 组件是线程关联的。有关如何在 UI 线程上执行代码的信息,请参阅Windows.UI.Core.CoreDispatcher 类。您可以查看线程示例以获取一些示例代码,以从异步操作更新 UI。

于 2012-07-30T18:19:50.903 回答
1

事情在非常重要的方面有所不同。

虽然底层线程模型确实是相同的,但您的问题通常与逻辑并发如何与 UI 一起工作有关,而开发人员在 Windows 8 中看到的内容将是新的。

正如您提到的大多数对话框以前被阻止。对于 Metro 应用程序,许多 UI 组件不会全部阻塞。还记得 WinRT 是异步的吗?它也适用于 UI 组件。

例如,此 .NET 4 代码不一定会杀死您的硬盘,因为 UI 调用会阻塞 Show(C# 示例):

bool formatHardDrive = true;
if (MessageBox.Show("Format your harddrive?") == NO)
    formatHardDrive = false;
if (formatHardDrive == true)
    Format(); 

在 Windows 8 Metro 中,许多 UI 组件(如Windows.UI.Popups.MessageDialog)在默认情况下是异步的,因此在检索用户输入之前,Show 调用将立即(逻辑上)进入下一行代码。

当然,基于 await/promise 设计模式(Javascript 示例)有一个优雅的解决方案:

var md = Windows.UI.Popups.MessageDialog("Hello World!");
md.showAsync().then(function (command) { 
    console.log("pressed: " + command.label); });

关键是虽然线程模型没有改变,但当大多数人提到 UI 和线程时,他们正在考虑逻辑并发以及它如何影响编程模型。

总的来说,我认为异步范式转变是一件积极的事情。它需要稍微转变一下观点,但它与其他平台在客户端和服务器端的发展方式是一致的。

于 2012-01-25T18:47:26.573 回答