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

2022-01-12 00:00:00 wpf mfc wpf-controls

我将在这里回答我自己的问题,因为我花了几个小时将这些拼凑起来,并想分享我的发现,希望我能拯救别人的挖掘.

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++.这是通过转到项目的配置属性来完成的.在 General 下有一个选项Common Language Runtime support".将此设置为公共语言运行时支持/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.通过转到项目的配置属性进行设置.在 Linker->Advanced 下有一个名为CLR Thread Attribute"的选项.将此设置为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();

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

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.

相关文章