如何将.NET中定义的一个Window Form控件作为一个MFC对话框调用?(From Msdn)

本文介绍如何使用MFC的CWinFormsDialog类来托管Windows窗体用户控件,并展示了如何实现双向交互,包括响应按钮点击事件及读取文本框内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MFC provides the template class tabindex="0" keywords="e3cec000-a578-448e-b06a-8af256312f61">CWinFormsDialog to allow you to host a Windows Forms user control ( tabindex="0" keywords="T:System.Windows.Forms.UserControl">UserControl) in a modal or modeless MFC dialog box. CWinFormsDialog is derived from the MFC class tabindex="0" keywords="ca64b77e-2cd2-47e3-8eff-c2645ad578f9">CDialog, so the dialog box can be launched as modal or modeless.

The process that CWinFormsDialog uses to host the user control is the similar to that described in Hosting a Windows Form User Control in an MFC Dialog Box. However, CWinFormsDialog manages the initialization and hosting of the user control so that it does not have to be programmed manually.

For a sample application that shows Windows Forms used with MFC, see text xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5">MFC and .

To create the MFC host application

  1. Create a new MFC Application project.

    On the File menu, select New, and then click Project. In the Visual C++ folder, select MFC Application.

    In the Name box, enter MFC03 and change the Solution setting to Add to Solution. Click OK.

    In the MFC Application Wizard, accept all the defaults, and then click Finish. This creates an MFC application with a Multiple Document Interface.

  2. Configure the project.

    In Solution Explorer, right-click the MFC03 project node, and select Properties from the context menu. The Property Pages dialog box appears.

    In the Property Pages dialog box, in the Configuration Properties tree control, select General, then in the Project Defaults section, set Common Language Runtime support to Common Language Runtime Support (/clr). Click OK.

  3. Add a reference to the .NET control.

    In Solution Explorer, right-click the MFC03 project node and select References. In the Property Page, click Add New Reference,select WindowsControlLibrary1 (under the Projects tab), and click OK. This adds a reference in the form of a tabindex="0" keywords="698f8603-457f-435a-baff-5ac9243d6ca1">/FU compiler option so that the program will compile; it also copies WindowsControlLibrary1.dll into the MFC03 project directory so that the program will run.

  4. Add #include <afxwinforms.h> to stdafx.h, at the end of the existing #include statements.

  5. Add a new class that subclasses CDialog.

    Right click on project name and add an MFC class (called CHostForWinForm) that subclasses CDialog. Since you do not need the dialog box resource, you can delete the resource ID (select the Resource View, expand the Dialog folder and delete IDD_HOSTFORWINFORM resource. Then, remove any references to the ID in code.).

  6. Replace CDialog in CHostForWinForm.h and CHostForWinForm.cpp files with CWinFormsDialog<WindowsControlLibrary1::UserControl1>.

  7. Call DoModal on the CHostForWinForm class.

    In MFC03.cpp, add #include "HostForWinForm.h".

    Before the return statement in the definition of CMFC03App::InitInstance, add:

    CHostForWinForm m_HostForWinForm;

    m_HostForWinForm.DoModal();

  8. Build and run the project.

    On the Build menu, click Build Solution.

    On the Debug menu, click Start without debugging.

    Next you will add code to monitor the state of a control on the Windows Forms from the MFC application.

  9. Add a handler for OnInitDialog.

    Display the Properties window (F4). In Class View, select CHostForWinForm. In the Properties window, select overrides and in the row for OnInitDialog, click in the left hand column and select < Add >. This adds the following line to CHostForWinForm.h:

     
    virtual BOOL OnInitDialog();
  10. Define OnInitDialog (in CHostForWinForm.cpp) as follows:

     
    BOOL CHostForWinForm::OnInitDialog() {
       CWinFormsDialog<WindowsControlLibrary1::UserControl1>::OnInitDialog();
       GetControl()->button1->Click += MAKE_DELEGATE(System::EventHandler, OnButton1);
       return TRUE;
    }
  11. Next add the OnButton1 handler. Add the following lines to the public section of the CHostForWinForm class in CHostForWinForm.h:

     
    virtual void OnButton1( System::Object^ sender, System::EventArgs^ e );
    
    BEGIN_DELEGATE_MAP( CHostForWinForm )
       EVENT_DELEGATE_ENTRY( OnButton1, System::Object^, System::EventArgs^ );
    END_DELEGATE_MAP()

    In CHostForWinForm.cpp, add this definition:

     
    void CHostForWinForm::OnButton1( System::Object^ sender, System::EventArgs^ e ) 
    {
       System::Windows::Forms::MessageBox::Show("test");
    }
  12. Build and run the project. When you click the button, which is on the Windows Form, code in the MFC application will run.

    Next you will add code to display from the MFC code the value in the text box on the Windows Form.

  13. In the public section of the CHostForWinForm class in CHostForWinForm.h, add the following declaration:

     
    CString m_sEditBoxOnWinForm;
  14. In the definition of DoDataExchange in CHostForWinForm.cpp, add the following three lines to the end of the function:

     
    if (pDX->m_bSaveAndValidate)
       m_sEditBoxOnWinForm = CString( GetControl()->textBox1->Text);
    else
       GetControl()->textBox1->Text = gcnew System::String(m_sEditBoxOnWinForm);
  15. In the definition of OnButton1 in CHostForWinForm.cpp, add the following three lines to the end of the function:

     
    this->UpdateData(TRUE);
    System::String ^ z = gcnew System::String(m_sEditBoxOnWinForm);
    System::Windows::Forms::MessageBox::Show(z);
  16. Build and run the project.

<think>在MFC中,一个窗口(或对话框)要访问另一个窗口(对话框)的控件,通常需要获取目标窗口的指针,然后通过该指针访问控件。以下是几种常见方法: ### 方法1:通过获取对话框指针直接访问 如果两个对话框(或窗口)都已经创建,并且你知道目标对话框的指针,可以直接使用该指针调用其成员函数。 **步骤:** 1. 在目标对话框类中提供公共成员函数来操作控件。 2.调用对话框中获取目标对话框的指针(例如通过父窗口、应用程序类或全局变量)。 3. 通过指针调用目标对话框的成员函数。 **示例:** 假设有两个对话框:`CPage1Dlg` 和 `CPage2Dlg`。在`CPage2Dlg`中有一个按钮`IDC_BUTTON1`,我们想在`CPage1Dlg`中模拟点击这个按钮。 **在`CPage2Dlg`类中:** ```cpp // Page2Dlg.h class CPage2Dlg : public CDialogEx { public: void ClickMyButton(); // 公共成员函数 // ... }; // Page2Dlg.cpp void CPage2Dlg::ClickMyButton() { CButton* pButton = (CButton*)GetDlgItem(IDC_BUTTON1); if (pButton) { // 发送按钮点击消息 pButton->SendMessage(BM_CLICK, 0, 0); } } ``` **在`CPage1Dlg`类中调用:** ```cpp // 假设m_pPage2Dlg是指向CPage2Dlg的指针(需要确保该指针有效) void CPage1Dlg::OnClickCallPage2Button() { if (m_pPage2Dlg != nullptr) { m_pPage2Dlg->ClickMyButton(); } } ``` ### 方法2:使用消息机制(SendMessage/PostMessage) 通过发送自定义消息来通知目标对话框执行操作。 **步骤:** 1. 在目标对话框定义消息处理函数。 2.调用方发送消息到目标对话框。 **示例:** **定义消息(通常在stdafx.h中):** ```cpp #define WM_USER_CLICK_BUTTON (WM_USER + 100) ``` **在`CPage2Dlg`中处理消息:** ```cpp // Page2Dlg.h class CPage2Dlg : public CDialogEx { protected: afx_msg LRESULT OnClickButton(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() }; // Page2Dlg.cpp BEGIN_MESSAGE_MAP(CPage2Dlg, CDialogEx) ON_MESSAGE(WM_USER_CLICK_BUTTON, &CPage2Dlg::OnClickButton) END_MESSAGE_MAP() LRESULT CPage2Dlg::OnClickButton(WPARAM wParam, LPARAM lParam) { // 调用按钮点击 ClickMyButton(); // 或者直接在这里写按钮点击的代码 return 0; } ``` **在`CPage1Dlg`中发送消息:** ```cpp void CPage1Dlg::OnClickCallPage2Button() { // 假设m_pPage2Dlg是有效的指针 if (m_pPage2Dlg && m_pPage2Dlg->GetSafeHwnd()) { m_pPage2Dlg->SendMessage(WM_USER_CLICK_BUTTON); } } ``` ### 方法3:通过应用程序类(App)中转 如果两个对话框都是应用程序中的主要窗口,可以在应用程序类中保存对话框的指针。 **步骤:** 1. 在应用程序类(如`CMyApp`)中添加成员变量保存对话框指针。 2.对话框创建时,将指针赋值给应用程序类。 3. 通过`AfxGetApp()`获取应用程序实例,再访问目标对话框。 **示例:** **在应用程序类中:** ```cpp // MyApp.h class CMyApp : public CWinApp { public: CPage1Dlg* m_pPage1Dlg; CPage2Dlg* m_pPage2Dlg; // ... }; ``` **在对话框创建时:** ```cpp // 在创建对话框的地方(如InitInstance中或对话框的OnInitDialog中) CMyApp* pApp = (CMyApp*)AfxGetApp(); pApp->m_pPage1Dlg = &page1Dlg; // 注意:要确保生命周期有效 pApp->m_pPage2Dlg = &page2Dlg; ``` **在`CPage1Dlg`中访问`CPage2Dlg`:** ```cpp void CPage1Dlg::OnClickCallPage2Button() { CMyApp* pApp = (CMyApp*)AfxGetApp(); if (pApp->m_pPage2Dlg != nullptr) { pApp->m_pPage2Dlg->ClickMyButton(); } } ``` ### 注意事项 1. **指针有效性**:确保访问的对话框指针有效(未被销毁)。 2. **线程安全**:如果涉及多线程,需要使用同步机制。 3. **封装性**:避免直接操作其他对话框控件,应该通过目标对话框提供的公共接口。 ### 完整示例(方法1的扩展) 以下是一个更完整的示例,展示如何在主对话框中操作另一个对话框的按钮: **主对话框(CPage1Dlg)头文件:** ```cpp class CPage1Dlg : public CDialogEx { public: CPage1Dlg(CWnd* pParent = nullptr); void SetPage2Dlg(CPage2Dlg* pDlg) { m_pPage2Dlg = pDlg; } protected: afx_msg void OnBnClickedButtonCallPage2(); CPage2Dlg* m_pPage2Dlg; // 指向Page2对话框的指针 }; ``` **主对话框实现:** ```cpp // 初始化时设置指针(假设在创建对话框后设置) void CPage1Dlg::OnBnClickedButtonCallPage2() { if (m_pPage2Dlg != nullptr) { m_pPage2Dlg->ClickMyButton(); } } ``` **子对话框(CPage2Dlg)实现:** ```cpp void CPage2Dlg::ClickMyButton() { // 模拟按钮点击 SendDlgItemMessage(IDC_BUTTON_ON_PAGE2, BM_CLICK, 0, 0); } ``` ### 总结 在MFC中跨对话框访问控件,核心是获取目标对话框的指针,然后通过该指针调用其公共方法。推荐使用方法1(直接调用公共方法)或方法2(消息机制),以保持较好的封装性。 §§相关问题§§: 1. MFC中如何获取应用程序类的指针? 2.MFC中如何安全地传递窗口指针? 3.定义消息在MFC中是如何定义和处理的? 4. 如何防止在MFC中访问已销毁的对话框指针?</think>在 MFC (Microsoft Foundation Classes) 中,在一个页面(对话框)中访问或操作另一个页面对话框控件,通常需要通过获取目标对话框的指针来实现。以下是几种常用的方法: ### 方法 1:通过父窗口获取对话框指针(推荐) 这是最安全且符合 MFC 设计模式的方法,适用于对话框有父子关系的情况。 ```cpp // 在调用对话框类中 (CallerDialog.cpp) #include "TargetDialog.h" // 包含目标对话框的头文件 void CCallerDialog::OnButtonClick() { // 1. 获取父窗口(通常是主框架窗口) CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd(); if (!pMainFrame) return; // 2. 通过父窗口获取目标对话框指针 CTargetDialog* pTargetDlg = (CTargetDialog*)pMainFrame->GetTargetDialog(); if (!pTargetDlg || !::IsWindow(pTargetDlg->m_hWnd)) return; // 3. 获取目标按钮控件并操作 CButton* pButton = (CButton*)pTargetDlg->GetDlgItem(IDC_TARGET_BUTTON); if (pButton) { pButton->EnableWindow(FALSE); // 禁用按钮 pButton->SetWindowText(_T("已禁用")); } } ``` **关键点解释:** 1. `AfxGetMainWnd()` 获取应用程序的主框架窗口指针 2. 需要在主框架类中提供访问目标对话框的方法(如 `GetTargetDialog()`) 3. `::IsWindow()` 检查窗口句柄是否有效,避免访问已销毁的窗口 4. `GetDlgItem()` 通过控件ID获取控件指针 ### 方法 2:使用全局变量(简单但需谨慎) 适用于简单场景,但要注意生命周期管理: ```cpp // 在目标对话框的实现文件中 CTargetDialog* g_pTargetDlg = nullptr; // 全局指针 BOOL CTargetDialog::OnInitDialog() { CDialog::OnInitDialog(); g_pTargetDlg = this; // 初始化时赋值 return TRUE; } void CTargetDialog::OnDestroy() { g_pTargetDlg = nullptr; // 销毁时置空 CDialog::OnDestroy(); } // 在调用对话框中使用 void CCallerDialog::OnButtonClick() { if (g_pTargetDlg && ::IsWindow(g_pTargetDlg->m_hWnd)) { CButton* pButton = (CButton*)g_pTargetDlg->GetDlgItem(IDC_TARGET_BUTTON); pButton->EnableWindow(FALSE); } } ``` ### 方法 3:使用应用程序类存储指针 更规范的全局访问方式: ```cpp // 在应用程序类中 (MyApp.h) class CMyApp : public CWinApp { public: CTargetDialog* m_pTargetDlg; // ... }; // 在目标对话框的初始化中 BOOL CTargetDialog::OnInitDialog() { CDialog::OnInitDialog(); ((CMyApp*)AfxGetApp())->m_pTargetDlg = this; return TRUE; } // 在调用对话框中使用 void CCallerDialog::OnButtonClick() { CMyApp* pApp = (CMyApp*)AfxGetApp(); if (pApp->m_pTargetDlg && ::IsWindow(pApp->m_pTargetDlg->m_hWnd)) { CButton* pButton = (CButton*)pApp->m_pTargetDlg->GetDlgItem(IDC_TARGET_BUTTON); pButton->SetCheck(BST_CHECKED); // 选中按钮 } } ``` ### 方法 4:通过自定义消息通信 最解耦的方式,使用 Windows 消息机制: ```cpp // 1. 定义定义消息 (在stdafx.h或公共头文件中) #define WM_USER_DISABLE_BUTTON (WM_USER + 100) // 2. 在目标对话框类中添加消息处理 BEGIN_MESSAGE_MAP(CTargetDialog, CDialog) ON_MESSAGE(WM_USER_DISABLE_BUTTON, OnDisableButton) END_MESSAGE_MAP() // 消息处理函数 LRESULT CTargetDialog::OnDisableButton(WPARAM wParam, LPARAM lParam) { CButton* pButton = (CButton*)GetDlgItem(IDC_TARGET_BUTTON); pButton->EnableWindow(FALSE); return 0; } // 3.调用方发送消息 void CCallerDialog::OnButtonClick() { CWnd* pTargetWnd = CWnd::FindWindow(NULL, _T("目标对话框标题")); if (pTargetWnd) { pTargetWnd->PostMessage(WM_USER_DISABLE_BUTTON); } } ``` ### 最佳实践建议: 1. **优先使用父子关系访问**:方法1是最符合MFC设计模式的 2. **检查窗口有效性**:始终使用 `::IsWindow()` 检查指针有效性 3. **避免直接访问**:尽量通过目标对话框的公共方法操作控件,而不是直接访问 4. **注意线程安全**:如果涉及多线程,需使用线程同步机制 5. **生命周期管理**:确保目标对话框存在时再访问 ### 常见错误及解决: 1. **访问违规错误**: - 原因:访问了已销毁的对话框 - 解决:添加有效性检查 `if (pDialog && ::IsWindow(pDialog->m_hWnd))` 2. **控件操作无效**: - 原因:可能在对话框未完全初始化时访问 - 解决:在 `OnInitDialog()` 之后操作 3. **未更新界面**: - 原因:操作后未刷新界面 - 解决:调用 `UpdateWindow()` 或 `RedrawWindow()`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值