如何在MFC应用程序中托管WPF内容?

问题描述:

我将在这里回答我自己的问题,因为我花了几个小时将这些问题拼凑在一起,并希望分享我的发现,以期希望我能节省其他人的挖掘工作.

I'm going to answer my own question here because I spent a few hours piecing this together and wanted to share what I found in the hope that I will save someone else the digging.

有一个 MSDN演练可为您提供大部分帮助在那里,但是我在其他地方找到了几个关键要素.例如,演练告诉您将[System :: STAThreadAttribute]行放在_tWinMain()定义之前,但是如果要实现标准的MFC应用程序,则源代码中没有_tWinMain().

There is an MSDN Walkthrough that gets you most of the way there, but there are a couple of key pieces that I found elsewhere. For example, the walkthrough tells you to place the line [System::STAThreadAttribute] before the _tWinMain() definition but if you're implementing a standard MFC application then you don't have _tWinMain() in your source code.

如果此处不清楚,请随时提出问题,我将编辑答案以使内容更清楚.

If anything here is unclear, feel free to ask questions and I will edit the answer to make things more clear.

步骤1:配置MFC应用程序以使用CLR支持进行编译

实现本机C ++和托管.NET代码之间互操作性的最佳方法是将应用程序编译为托管C ++,而不是本机C ++.这可以通过转到项目的配置属性"来完成.在常规下,有一个选项公共语言运行时支持".将此设置为公共语言运行时支持/clr".

The best way to achieve interoperability between native C++ and managed .NET code is to compile the application as managed C++ rather than native C++. This is done by going to the Configuration Properties of the project. Under General there is an option "Common Language Runtime support". Set this to "Common Language Runtime Support /clr".

步骤2:将WPF程序集添加到项目中

在解决方案资源管理器中的项目上单击鼠标右键,然后选择参考".点击添加新参考".在.NET选项卡下,添加WindowsBase,PresentationCore,PresentationFramework和System.请确保在添加任何引用后重新构建所有内容,以使它们能够被拾取.

Right-click on the project in the Solution Explorer and choose "References". Click "Add New Reference". Under the .NET tab, add WindowsBase, PresentationCore, PresentationFramework, and System. Make sure you Rebuild All after adding any references in order for them to get picked up.

第3步:在MFC应用程序上设置STAThreadAttribute

WPF要求在主UI线程上设置STAThreadAttribute.通过转到项目的配置属性"进行设置.在链接器->高级下,有一个名为"CLR线程属性"的选项.将此设置为"STA线程属性".

WPF requires that STAThreadAttribute be set on the main UI thread. Set this by going to Configuration Properties of the project. Under Linker->Advanced there is an option called "CLR Thread Attribute". Set this to "STA threading attribute".

第4步:创建一个HwndSource实例以包装WPF组件

System :: Windows :: Interop :: HwndSource是一个.NET类,用于处理MFC和.NET组件之间的交互.使用以下语法创建一个:

System::Windows::Interop::HwndSource is a .NET class that handles the interaction between MFC and .NET components. Create one using the following syntax:

System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew     System::Windows::Interop::HwndSourceParameters("MyWindowName");
sourceParams->PositionX = x;
sourceParams->PositionY = y;
sourceParams->ParentWindow = System::IntPtr(hWndParent);
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;

System::Windows::Interop::HwndSource^ source = gcnew System::Windows::Interop::HwndSource(*sourceParams);
source->SizeToContent = System::Windows::SizeToContent::WidthAndHeight;

将HWND成员变量添加到对话框类,然后像这样分配它: m_hWnd =(HWND)source-> Handle.ToPointer();

Add an HWND member variable to the dialog class and then assign it like this: m_hWnd = (HWND) source->Handle.ToPointer();

在调用:: DestroyWindow(m_hWnd)之前,源对象和关联的WPF内容将一直存在.

The source object and the associated WPF content will remain in existence until you call ::DestroyWindow(m_hWnd).

第5步:将WPF控件添加到HwndSource包装器中

System::Windows::Controls::WebBrowser^ browser = gcnew System::Windows::Controls::WebBrowser();

browser->Height = height;
browser->Width = width;
source->RootVisual = browser;

步骤6:保留对WPF对象的引用

由于在退出创建函数后浏览器变量将超出范围,因此我们需要以某种方式保留对其的引用.托管对象不能是非托管对象的成员,但是您可以使用名为gcroot的包装器模板来完成工作.

Since the browser variable will go out of scope after we exit the function doing the creation, we need to somehow hold a reference to it. Managed objects cannot be members of unmanaged objects but you can use a wrapper template called gcroot to get the job done.

将成员变量添加到对话框类:

Add a member variable to the dialog class:

#include <vcclr.h>
gcroot<System::Windows::Controls::WebBrowser^> m_webBrowser;

然后将以下行添加到步骤5中的代码中:

Then add the following line to the code in Step 5:

m_webBrowser = browser;

现在,我们可以通过m_webBrowser访问WPF组件上的属性和方法.

Now we can access properties and methods on the WPF component through m_webBrowser.