【问题标题】:How do I host WPF content in MFC Applications?如何在 MFC 应用程序中托管 WPF 内容?
【发布时间】:2010-10-24 05:12:43
【问题描述】:

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

有一个MSDN Walkthrough 可以让你大部分时间到达那里,但是我在其他地方找到了几个关键部分。例如,演练告诉您将 [System::STAThreadAttribute] 行放在 _tWinMain() 定义之前,但如果您正在实现标准 MFC 应用程序,则源代码中没有 _tWinMain()。

如果这里有任何不清楚的地方,请随时提出问题,我会编辑答案以使事情更清楚。

【问题讨论】:

    标签: wpf mfc wpf-controls


    【解决方案1】:

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

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

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

    在解决方案资源管理器中右键单击项目并选择“参考”。单击“添加新引用”。在 .NET 选项卡下,添加 WindowsBase、PresentationCore、PresentationFramework 和 System。确保在添加任何引用后重建全部,以便它们被拾取。

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

    WPF 要求在主 UI 线程上设置 STAThreadAttribute。通过转到项目的配置属性进行设置。在 Linker->Advanced 下有一个名为“CLR Thread Attribute”的选项。将此设置为“STA 线程属性”。

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

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

    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();

    源对象和关联的 WPF 内容将一直存在,直到您调用 ::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 的包装模板来完成工作。

    给对话框类添加成员变量:

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

    然后在第 5 步的代码中添加以下行:

    m_webBrowser = browser;
    

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

    【讨论】:

    • source->SizeToContent = System::Windows::SizeToContent::WidthAndHeight;这就是我所缺少的! +1
    • 一条额外的信息,如果你不设置 StaThreadModel,它会在 MFC 深处非常神秘地崩溃。并且您需要在主可执行应用程序上设置线程模型。如果您和我一样,想要在另一个 DLL 中替换对话框,那么如果您在未包含的 DLL 上设置 CLR 线程属性,它将不会有帮助。对其他人来说可能很明显,但对我来说却不是。
    猜你喜欢
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 2010-09-09
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    相关资源
    最近更新 更多