我正在 Visual Studio 中开发基于 C# + WPF 的应用程序,给出的建议是仅在 UI 线程上运行 System.Drawing 相关方法(例如使用 SynchronizationContext)。 我使用 System.Drawing 执行的一些任务包括:创建位图图像、在其他图像对象和位图对象之间进行转换、使用 Graphics 在位图上绘制并保存它们。 然而,由于图像操作占用了线程,因此可以从 GUI 窗口卡住中注意到许多操作。这会影响用户体验,并且会增加项目的复杂性。 那么,使用其他线程执行 System.Drawing 工作是否有问题?谢谢。
最佳答案
正如评论已经指出的,System.Drawing 命名空间以 WinForms 为目标,并且仅包含其渲染平台特定的 GDI+ 对象。这些对象不是线程安全的。因此,应避免在多线程上下文中处理它们,因为副作用是不可预测的。
由于 WPF 不使用 GDI+,因此它有自己的类,相当于 System.Drawing 命名空间(例如,FontFamily
、Image
,画笔
,ColorConverter
)。其中大部分位于System.Windows.Media命名空间中。
在 WPF 中,线程关联性由 DispatcherObject
强制执行。 。由于 DispatcherObject
与 Dispatcher
关联。并且 Dispatcher
对象与线程关联,我们也可以说调度程序亲和性。
所有 WPF UI 对象,即从 UIElement
派生的对象,也继承自 DispatcherObject
。 DispatcherObject
实现只能在创建它们的线程上访问(调度程序亲和性),否则会引发异常:
The calling thread cannot access this object because a different thread owns it.
这也禁止在线程之间传递 DispatcherObject
实例,除非此类型另外派生自 Freezable
例如,Brush
或 ImageSource
。
一旦这些对象处于卡住状态,它们就可以在线程之间传输,因为它们现在已与调度程序
分离,因此调度程序亲和性已被解除。
这意味着您可以在后台线程上创建图像数据,例如 System.Windows.Media.Imaging.BitmapSource
,通过调用 BitmapSource.Freeze()
卡住它并将其传回 UI 线程以使用 Image
控件进行渲染。
关于c# - System.Drawing 是否应该仅在 WPF 的 UI 线程(C#)上运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59794174/