我很难在ServicedComponent中托管WPF应用程序。我有一个WPF库,我需要从本机代码中使用它。为了实现这个目标,我创建了一个outproc COM +组件,将所有WPF调用放入其中,并从本机代码中调用此组件,如下所示:
// Managed
[ComVisible(true)]
public class HpPcKeyboardSrv : ServicedComponent, ISrv
{
...
}
// Native
CComPtr<ISrv> spISrv;
hr = spISrv.CoCreateInstance(__uuidof(MySrv), nullptr, CLSCTX_SERVER);
ATLVERIFY(SUCCEEDED(hr));
hr = spISrv->WPFCommand();
ATLVERIFY(SUCCEEDED(hr));
它作为原型完美无缺,但当我添加实际的WPF功能时,一切都开始分崩离析。
由于臭名昭着的WPF异常"The calling thread must be STA, because many UI components require this"
,我无法在COM + ServicedComponent中创建WPF窗口。其中一个解决方案是使用Dispatcher。问题是WPF调度员Dispatcher.CurrentDispatcher
没有调用BeginInvoke()
中的函数:
public void WPFCommand()
{
Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate
{
System.Threading.ApartmentState aptStateLocal = Thread.CurrentThread.GetApartmentState();
Debug.WriteLine("Spawned thread apartment: {0}", aptStateLocal);
_Window = new Window();
});
}
另一种选择是使用Application.Current.Dispatcher
。这种方法的问题在于,在此调用中Application.Current
为空,因此没有Dispatcher可用。
行。接下来要尝试的是在STA模型中产生威胁,如下所示:
public void WPFCommand()
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
{
Thread thread = new Thread(() =>
{
System.Threading.ApartmentState aptState = Thread.CurrentThread.GetApartmentState();
Debug.WriteLine("Spawned thread apartment: {0}", aptState); // <- Still MTA
// !!! If _Window is the member of the class, the thread will be MTA
// !!! otherwise STA
_Window = new Window();
System.Windows.Threading.Dispatcher.Run();
});
Debug.WriteLine("Thread apartment state1: {0}", thread.GetApartmentState());
thread.SetApartmentState(ApartmentState.STA); // <- even though set as STA
Debug.WriteLine("Thread apartment state2: {0}", thread.GetApartmentState());
thread.IsBackground = true;
thread.Start();
thread.Join();
}
}
此代码有部分帮助。由于已经设置为STA模型的产生线程无论如何都会在MTA中被调用,如果_Window是类成员(如果不是,那么它是STA),因此new Window()
抛出相同的#34;必须是STA&#34;异常。
此时我完全卡住了。如何在ServicedComponent中实际创建WPF元素?或者我如何在本机代码和WPF之间进行交互?任何想法都表示赞赏。
更新:奇怪的是,赋值(_Window = new Window())会影响线程模型。如果_Window是该类的成员,则treading模型仍然是MTA。如果它是局部变量,则线程模型将更改为MTA。似乎_Window应该以其他方式作为班级成员分配。
答案 0 :(得分:1)
我可能正在寻找解决方案或完全偏离轨道 -
http://drwpf.com/blog/2007/10/05/managing-application-resources-when-wpf-is-hosted/
基本上,上述方法加载所有资源字典并创建WPF环境。请检查&#34;管理代码中的资源字典集合并在元素级别合并它们#34;。
所以,在此之后,你可以从WPFCommand调用你的窗口,而不必担心STA \ MTA。