在非UI线程创建控件(Creating controls in a non-UI thread)

2019-06-24 02:51发布

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

Activator.CreateInstanceFrom(dllpath, classname).

由于我装了不少的这些我想要做的背景下,保持我的UI响应,通过创建一个新的线程做加载。 然后,控制被父级的主要形式并在需要时显示。

这似乎很好地工作 - 直到我尝试设置对这些用户控件之一的任何嵌套控制,例如在一个按钮,它抛出一个错扣异常的事件处理程序的任何财产。 我不知道我可以通过检查InvokeRequired我每次访问属性时避免这种情况,但我宁愿没有编写用户控件的代码时,担心(尤其是因为有别人写的代码,这些位也可能谁没有永远记住)。

所以我的问题是,是否有任何安全的方式做我尝试,或我应该如何最好去在后台加载这些控件? 或者是基本上不可能和我要坚持主线程创建控件?

我希望我提供的信息足以让我的情况清楚; 如果不是我会很高兴来阐述,并提供代码示例。

Answer 1:

是细加载DLL和创建在后台控制的对象,但该控制已被添加到在主线程的形式,并且所有的用户交互以及控制特性的任何编程改变(它被创建之后)具有至发生在主线程。 我们根本没有办法解决这个,因为你可能已经知道。 现在,除非这些DLL和控制创造的负载需要年龄,我认为没有理由这样做在单独的后台线程。

如果由控件执行某些动作阻塞UI,并且希望他们在后台发生,这是一个不同的故事,你最好考虑在个人基础上的每个动作和创建明确的方法UI线程和后台线程之间进行通信。

试图做一个通用的一个一劳永逸的框架,它的工作原理相同的UI线程模式和后台模式,只是简单地检查有时表现越差 InvokeRequired结果(因为所有线程被阻塞在调用),甚至在(未检测)死锁一旦应用达到一个合理的复杂性。 也做的所有更新异步中的BeginInvoke,W / O单独考虑每个方法,可能会导致数据一致性问题(即控制可以更新自己的状态时间,由于螺纹之间的调用顺序的反转)。



Answer 2:

中的代码示例这个答案提供了解决这个问题的一种优雅的方式。

代码从回答引用:

public void UpdateTestBox(string newText)
{
    BeginInvoke((MethodInvoker) delegate {
        tb_output.Text = newText;
    });        
}

......虽然你的情况,你会想调用BeginInvoke上的控件本身:

public void UpdateTestBox(string newText)
{
    tb_output.BeginInvoke((MethodInvoker) delegate {
        tb_output.Text = newText;
    });        
}


Answer 3:

殊不知InvokeRequired机制的细节,我一直在尝试了一点,据我所知,你可以在一个线程中,只要它一直没有与父母(即添加到一些Control.Controls属性)设置大多数属性。

所以,你应该能够准备好您的控制,将它们存储在一个列表,并将它们连接到主界面中的调用方法。


编辑:我不认为它很重要,其线程创建的控制。 所以正常的规则应适用,即你可以只工作与对照形成主要的Windows线程。 而且我觉得标准是HandleCreated在,而不是与父母。 只要还没有发生的事情,你得到一点喘息。



文章来源: Creating controls in a non-UI thread