我有一个C#(FFx 3.5)应用程序,它将DLL作为插件加载。这些插件加载在单独的AppDomain中(出于很多原因,这种架构无法更改)。这一切都很好。
我现在要求显示其中一个插件的Dialog。请记住,我无法将对话框表单返回到主应用程序并将其显示在那里(当前基础结构不支持它)。
失败1
在我的DLL中,我创建了一个名为Show的表单。对话框轮廓显示但没有绘制,它不响应鼠标事件。我认为这是因为DLL在一个单独的AppDomain中,并且应用程序的消息泵无论如何都无法将消息发送到新表单。
失败2
在我的DLL中,我创建了一个Form并调用了ShowDialog,所有权利都应该为对话框创建一个内部消息泵。对话框显示并响应点击(万岁),但似乎主应用程序不再正在处理或调度Windows消息,因为它退出绘画并且不再响应鼠标事件。由于某些原因,现在似乎主应用程序的消息泵没有调度。
失败3
在我的DLL中,我创建了一个Form并调用了Application.Run。这肯定会创建一个完整的第二个消息泵。我得到了与失败2相同的行为 - 对话行为,但调用应用没有。
有关这里究竟发生了什么以及如何从其他AppDomain的DLL显示对话框并让调用者和被调用者仍然响应并正确绘制的任何想法?
答案 0 :(得分:4)
尝试使用appdomain1的主窗体的BeginInvoke和一个显示appdomain2表单的委托。所以在伪代码中:
Appdomain1:
AppDomain2.DoSomething(myMainForm);
AppDomain2:
DoSomething(Form parent)
{
Form foolishForm = new Form();
parent.BeginInvoke(new Action( delegate { foolishForm.Show(); } ));
}
代码可能并不完美,但它证明了这一概念。
顺便说一下,如果因为远程操作而传递表格时遇到问题,您可以:
public class Container<T> : MarshalByRefObject
{
private T _value;
public T Value { get { return _value; } set { _value = value; } }
public Container() { }
public Container(T value) { Value = value; }
public static implicit operator T(Container<T> container)
{
return container.Value;
}
}
那将包含你扔的对象。
答案 1 :(得分:1)
我们有一个非常类似的架构应用程序,可以加载DLL文件和插件。每个DLL文件都加载在一个单独的application domain中,该文件是在一个单独的线程上创建的。除非我们定期致电System.Windows.Forms.Application.DoEvents()
,否则我们会以不会出现的形式提供第三方控件。
伪代码:
<In new thread>
<Application domain created. Start called inside new application domain.>
<Start loads new DLL file, calls init function in DLL file>
<Start loops, calling DoEvents until the DLL file exits>
<Application domain unloaded>
<Thread exits>
这解决了我们所有的GUI问题。
答案 2 :(得分:1)
我之前使用的一件事是实现DomainManager。可以自定义各种application domain安全性/绑定/上下文来处理复杂或鸡蛋类型问题,以便将数据抽取到您想要的位置;)
我通常使用native.exe完成此操作,通过COM接口引导CLR(psudo代码,但顺序和方法名称正确;):
CorBindToRuntimeEx()
SetHostControl()
GetCLRControl()
SetAppDomainManagerType("yourdomainmanger","info")
// Domain manager set before starting runtime
Start()
HostControl -- GetDomainManagerForDefaultDomain()
DomainManager -- Run()
您的域管理员可以是任何CLR类库,因此他们的本地C不是那么多。
旁注,如果你在WPF;我真的很喜欢使用“Microsoft.DwayneNeed.Controls”方法。你可能在相同的 UI控件中使用自己的Dispatcher泵来分离线程(不需要求助于全新的Window())。
使用这种方法的独特之处在于,即使主UI线程被阻塞/忙碌(一些繁重的操作,扫描文件系统等等),这些其他线程也可以在没有任何打嗝的情况下绘制/更新其UIElement