我正在Visual Studio中开发基于C#+ WPF的App,并且给出的建议仅在MainWindow线程上运行System.Drawing相关方法(例如,使用SynchronizationContext)。我与System.Drawing一起使用的一些任务包括:创建位图图像,在其他图像对象和位图对象之间转换,使用图形在位图上绘制并保存它们。但是,由于该线程占用了图像操作,因此从GUI窗口冻结中可以注意到许多操作。这会影响用户体验,并且是增加项目复杂性的问题。那么,使用其他线程来执行System.Drawing工作是否有问题?谢谢。
正如评论已经指出的那样,System.Drawing命名空间以WinForms为目标,并且仅包含其呈现平台特定的GDI +对象。这些对象不是线程安全的。因此,应避免在多线程上下文中处理它们,因为副作用是不可预测的。
由于WPF不使用GDI +,因此它具有与System.Drawing命名空间等效的类(例如FontFamily
,Image
,Brush
,ColorConverter
)。它们大多数位于System.Windows.Media命名空间。
在WPF中,线程亲和性由DispatcherObject
强制执行。由于DispatcherObject
与DispatcherObject
相关联,并且Dispatcher
对象与线程相关联,我们也可以说调度程序相关性。
所有WPF UI对象,即从Dispatcher
派生的对象,也从Dispatcher
继承。 UIElement
只能在创建它们的线程上访问实现,否则会引发异常:
调用线程无法访问此对象,因为其他线程拥有它。
这也禁止在线程之间传递DispatcherObject
实例,除非这种类型另外从DispatcherObject
派生,例如DispatcherObject
或Freezable
。一旦这些对象处于冻结状态,就可以在线程之间传输它们,因为它们现在已从Freezable
分离出来,因此解除了调度程序的亲和力。
这意味着您可以在后台线程上创建图像数据,例如Brush
,通过调用ImageSource
将其冻结,然后将其传递回UI线程以使用Dispatcher
控件进行渲染。