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?