Hosting WPF Content in an MFC Application
Adding WPF-Related Code to an MFC Application
For your information, the gcnew keyword is used to create an instance of managed type; this will create the instance on the garbage collected heap. All memory allocated by gcnew will be managed automatically by the garbage collector and developers will not need to worry about freeing them up.
To host WPF content, the key is on the System::Windows::Interop::HwndSource class. This class will take care of wrapping the WPF content in a Win32 window, so that the WPF content can be incorporated into your user interface (UI) as a child window. Communication with the WPF content object is done by using the reference stored in the static fields. They're declared as static to prevent them from being inadvertently garbage collected.
ref class Globals
{
public:
static System::Windows::Interop::HwndSource^ gHwndSource;
static WPFControls::AnimClock^ gwcClock;
};
HWND hwndWPF; //The hwnd associated with the hosted WPF page
To create an HwndSource, first create an HwndSourceParameters structure and populate it with the following parameters:
- Class, window, and styles
- Initial position of the window
- Initial size of the window
- The parent window
Once you have populated the HwndSourceParameters structure, pass it to the HwndSource(HwndSourceParameters) constructor for the HwndSource.
Then, you create your WPF clock class by calling its constructor WPFControls::AnimClock(). You also initialize the date & time by calling its ChangeDateTime() method.
Finally, you assign the reference of the WPF clock object to the HwndSource object RootVisual property and return the HWND of the HwndSource by calling Handle.ToPointer().
HWND GetHwnd(HWND parent, int x, int y, int width, int height)
{
System::Windows::Interop::HwndSourceParameters^ sourceParams =
gcnew System::Windows::Interop::HwndSourceParameters
("MFCWPFApp");
sourceParams->PositionX = x;
sourceParams->PositionY = y;
sourceParams->Height = height;
sourceParams->Width = width;
sourceParams->ParentWindow = IntPtr(parent);
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;
Globals::gHwndSource =
gcnew System::Windows::Interop::HwndSource(*sourceParams);
DateTime tm = DateTime::Now;
Globals::gwcClock = gcnew WPFControls::AnimClock();
Globals::gwcClock->ChangeDateTime(tm.Year,tm.Month,tm.Day,
tm.Hour,tm.Minute,tm.Second);
FrameworkElement^ myPage = Globals::gwcClock;
Globals::gHwndSource->RootVisual = myPage;
return (HWND) Globals::gHwndSource->Handle.ToPointer();
}
So, whenver the user makes date or time changes, your MFC code will call RefereshWPFControl() to refresh the WPF clock.
void RefreshWPFControl()
{
FrameworkElement^ page;
DateTime tm = DateTime::Now;
Globals::gwcClock->ChangeDateTime(tm.Year,tm.Month,tm.Day,
tm.Hour,tm.Minute,tm.Second);
page = Globals::gwcClock;
Globals::gHwndSource->RootVisual = page;
return;
}
Now that you have all your needed functions set, the last task is to find a place in your MFC dialog code to call the HwndSource instance creation function. There are a few possible locations to call it; one good place is in the OnCreate event handler.
Handle the WM_CREATE notification
Call the GetHwnd() function in the OnCreate event handler when the application first starts.
int CMFCHostWPFDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
hwndWPF = GetHwnd(this->GetSafeHwnd(), 20, 28, 205, 130);
return 0;
}
Conclusion
As you can see now, by applying WPF in Win32/MFC applications you can add lots of "perks" to the overall user experience while the program logics remain coded in the Win32/MFC style.
Comments
All suggestions and corrections are welcome.
About the Author
Downloads
More for Developers
Top Authors
- Voted: 13 times.
- Voted: 11 times.
- Voted: 11 times.
- Voted: 8 times.
- Voted: 8 times.
- Paul Kimmel 214 articles
- Zafir Anjum 120 articles
- 15Seconds.com 99 articles
- Tom Archer - MSFT 83 articles
- Jeffrey Juday 82 articles


All