MFC 8 (VC++ 2005) and Windows Forms


I know that some of you have managed to use some Windows Forms forms in your MFC applications via ActiveX Control hosting or just plain Win32 calls and hosting the CLR manually.
 
I’m sure you are suffering the accelerator/tab navigation issues, among others…


In VC++ 2005, we have fixed many of those issues! First, You’ll need to successfully compile for the .NET Runtime (/CLR) and link the DLL version of MFC. Once done, you can start using the CWinFormsControl and the CWinFormsView classes. You can now have some Windows Forms UI in your MFC application without the drawbacks I mentioned earlier!


What’s the main restriction? The UI surface has to be a Windows Form user control (i.e. derived from UserControl), not a form (i.e. derived from Form).


Let’s first look at how I included a Windows Form user control in an MFC dialog, next to MFC/Win32 controls. The user control is made of a linklabel and textbox:


public partial class UserControl1 : UserControl
{
   public UserControl1()
   {
      InitializeComponent();
   }
   public string LinkLabelText
   {
      set { this.linkLabel.Text = value; }
      get { return this.linkLabel.Text ; }
   }
   public string TextBoxText
   {
      set { this.textBox.Text = value; }
      get { return this.textBox.Text; }
   }
   public event LinkLabelLinkClickedEventHandler LinkClicked
   {
      add { this.linkLabel.LinkClicked += value; }
      remove { this.linkLabel.LinkClicked -= value; }
   }
}


The dialog in WindowsFormsInMFCDialog.rc contains a label as a place holder. It will get destroyed and replaced by the Windows Form user control. The position and style of the user control will be the “same” as the label one.



IDD_WINDOWSFORMSINMFCDIALOG_DIALOG DIALOGEX 0, 0, 320, 49
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION “WindowsFormsInMFCDialog”
FONT 8, “MS Shell Dlg”, 0, 0, 0x1
BEGIN
    DEFPUSHBUTTON   “OK”, IDOK, 263, 7, 50, 16
    PUSHBUTTON      “Cancel”, IDCANCEL, 263, 25, 50, 16
    LTEXT           “Label that serves as a placehoder for the Windows Forms user control …”, IDC_WINDOWS_FORMS_USER_CONTROL, 7, 7, 253, 33, WS_TABSTOP
END


Here is what I did in StdAfx.h:



#include <afxwinforms.h> // MFC Windows Forms support
using namespace Microsoft::VisualC::MFC ;
#if 0
// Instead of “#using”, let’s add the reference to the project, which translates to /FU compiler command line option.
#using
<C:\MyUserControlInCSharp\bin\Debug\MyUserControlInCSharp.dll>
#endif


In WindowsFormsInMFCDialogDlg.h:

class CWindowsFormsInMFCDialogDlg : public CDialog
{

   void OnLinkClicked( System::Object ^ sender, System::Windows::Forms::LinkLabelLinkClickedEventArgs ^ e ) ;

   // Required when using delegates (MAKE_DELEGATE)
   BEGIN_DELEGATE_MAP( CWindowsFormsInMFCDialogDlg )
      EVENT_DELEGATE_ENTRY( OnLinkClicked, System::Object ^, System::Windows::Forms::LinkLabelLinkClickedEventArgs  ^ )
   END_DELEGATE_MAP()



   // User Control wrapper.
   CWinFormsControl<MyUserControlInCSharp::UserControl1> m_WindowsFormsControl ;
} ;


In WindowsFormsInMFCDialogDlg.cpp:


void CWindowsFormsInMFCDialogDlg::DoDataExchange(CDataExchange* pDX)
{
   CDialog::DoDataExchange(pDX);
#if 0 // Instead of calling CWinFormsControl<MyUserControlInCSharp::UserControl1>::CreateManagedControl()
   DDX_ManagedControl(pDX, IDC_WINDOWS_FORMS_USER_CONTROL, m_WindowsFormsControl);
#endif
}

BOOL CWindowsFormsInMFCDialogDlg::OnInitDialog()
{

 
  // Let’s create the user control, initialize some of its properties
   // and setup up the delegate so that CWindowsFormsInMFCDialogDlg::OnLinkClicked
   // is called when the link is clicked.
   m_WindowsFormsControl.CreateManagedControl( 0, IDC_WINDOWS_FORMS_USER_CONTROL, this ) ;
   m_WindowsFormsControl->LinkLabelText = “The text of the link label” ;
   m_WindowsFormsControl->TextBoxText = “<Type your text here>” ;
   m_WindowsFormsControl->LinkClicked += MAKE_DELEGATE( System::Windows::Forms::LinkLabelLinkClickedEventHandler, OnLinkClicked ) ;

   return TRUE ;
}


// This method will be called when we click on that hyperlink inside the user control
void CWindowsFormsInMFCDialogDlg::OnLinkClicked( System::Object ^ sender, System::Windows::Forms::LinkLabelLinkClickedEventArgs  ^ )
{
  
// As I took some shortcuts, the sender is actually the link label inside the user control! 😉
   System::Windows::Forms::LinkLabel ^ linkLabel = safe_cast<System::Windows::Forms::LinkLabel ^>(sender) ;
   if ( linkLabel->Text == “Try Again” )
      linkLabel->Text = “Stop it!” ;
   else
      linkLabel->Text = “Try Again” ;
}


As I presented this topic during the C++ Accelerator Lab in South America, it would be my pleasure to share a couple more “examples” about how to use a Windows Forms user control, as the entire dialog and then as an MFC view.


Do you have any interest in this?

Comments (4)

  1. Thomas Prehn says:

    Hi! I’ve been following this guide, and I successfully developed a MFC dialog application, in which I replace a

    placeholder static with a c# usercontrol from a dll library.

    Everything seems to work with a CDialog derivative.

    Unfortunately, I need to develop a MFC SDI application, which needs to function as a active document server (full server). I have created a project, in which the SDI view is based upon a CFormView class (so that I get a resource for my a placeholder). But when I make the CreateManagedControl() call, which you place in OnInitDialog(), I get

    an MFC winform related error 🙁 – There is no OnInitDialog method for a CFormView, but I tried putting the call various other places. Each time I get the runtime error.

    Do you have any idea what could be the problem?

    I’m not that into MFC, so it might not be a winform related problem.

    I thank you for the guide, and hope the above problem was as least partly understandable.

  2. yvesdolc says:

    Thomas found the solution before I could look at his issue: "I have made a active document server based on a CView, and the winform control is just given a rect instead of a placeholder control."

  3. George says:

    I am trying to host a .Net control in an ActiveX control window. So I tried similar steps mentioned in the article, but i get an error message ‘Failed to create control:unspecified error’ when I simply build theinstrument with /clr switch and trying to create the ActiveX control in test container. Any idea?

  4. Natasa says:

    Has anyone managed to wrap a Windows Forms control as an ActiveX control in MFC 8?