三、在MFC应用程序中加入和WPF相关的代码
先提一下,gcnew关键字被用于建立一个管制类型的实例,在本例中将建立一个垃圾回收集合栈的实例。所有被gcnew分配的内存空间将被垃圾回收器自动管理,而开发人员并不需要为什么时间释放它们而操心。
为了使用WPF程序,关键是System::Windows::Interop::HwndSource类。这个类将在Win32窗口中使用WPF程序,因此,WPF程序可以作为MFC窗口的子窗口放到UI上。而在WPF对象和Win32窗口之间的通讯要通过引用C++程序中被存储的静态字段。这些静态字段的代码如下:
ref class Globals
{
public:
static System::Windows::Interop::HwndSource^ gHwndSource;
static WPFControls::AnimClock^ gwcClock;
};
HWND hwndWPF; // 和WPF相关的hwnd
为了建立一个HwndSource,首先需要建立一个HwndSourceParameters结构,这个结构需要如下的参数:
1. 类、窗口、窗口类型
2. 窗口的初始位置
3. 窗口的初始尺寸
4. 父窗口
一但我们将HwndSourceParameters结构编写完,就可以将这个结构到HwndSource的构造方法HwndSource(HwndSourceParameters)中。
最后,我们将WPF时钟的引用赋值给HwndSource对象的RootVisual属性,并通过调用Handle.ToPointer()返回HwndSource的HWND。代码如下:
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();
}
因此,无论用户如何变化时钟,我们的MFC代码都会调用RefereshWPFControl()来刷新WPF时钟。
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;
}
现在我们已经有了大部分我们需要的功能了,而最后的任务是在MFC对话框代码中找个地方调用HwndSource实现创建函数。当然,有很多地方可以做这个工作,但是OnCreate也许是最好的位置。在OnCreate事件句柄中调用GetHwnd()函数的代码如下:
int CMFCHostWPFDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
hwndWPF = GetHwnd(this->GetSafeHwnd(), 20, 28, 205, 130);
return 0;
}
四、结论 我们现在可以看到,通过集成WPF和Win32/MFC应用程序可以为我们增添很多非常酷的特性来加强用户体验。本文所提供的实例只是抛砖引玉,读者可以使用这项技术做出更复杂的应用程序来。