在非UI线程中创建控件

Tom*_*ens 7 .net controls multithreading winforms

我有一种插件模型,其中各种复杂的用户控件存储在DLL中,并在运行时加载和实例化使用

Activator.CreateInstanceFrom(dllpath, classname).
Run Code Online (Sandbox Code Playgroud)

由于我正在加载其中的一些,我想在后台执行它,通过创建一个新线程来执行加载来保持我的UI响应.然后,控件将作为主窗体的父级,并在需要时显示.

这似乎工作正常 - 直到我尝试在其中一个用户控件上的任何嵌套控件上设置任何属性,例如在按钮的事件处理程序中,这会引发交叉线程异常.我确实通过每次访问属性时检查InvokeRequired都可以避免这种情况,但是在为用户控件编写代码时我宁愿不必担心(特别是因为还有其他人编写这些代码也可能并不总是记得).

所以我的问题是,是否有任何安全的方法来做我正在尝试的事情,或者我应该如何最好地在后台加载这些控件?或者它基本上是不可能的,我是否必须坚持主线程来创建控件?

我希望我提供的信息足以使我的情况清楚; 如果没有,我很乐意详细说明并提供代码示例.

Rem*_*anu 3

可以在后台加载 DLL 并创建控件对象,但必须将控件添加到主线程中的窗体中,并且所有用户交互以及控件属性的任何编程更改(在创建之后)都必须发生在主线程中。正如您可能已经知道的那样,根本没有办法解决这个问题。现在,除非这些 DLL 的加载和控件创建需要很长时间,否则我认为没有理由在单独的后台线程中执行此操作。

如果控件执行的某些操作阻塞了 UI,并且您希望它们在后台发生,则情况不同,您最好单独考虑每个操作,并创建显式方法在 UI 线程和后台线程之间进行通信。

尝试做一个通用的万能框架,在 UI 线程模式和后台模式下工作相同,并且简单地检查 InvokeRequired 有时会导致性能更差(因为所有线程都在 Invoke 中被阻止),甚至导致(未检测到的)死锁一旦应用程序达到合理的复杂性。此外,在 BeginInvoke 中异步执行所有更新(不单独考虑每个方法)可能会导致数据一致性问题(即,由于线程之间的调用顺序颠倒,控件可能会及时更新自身状态)