webmaster 2008-7-2 16:16
mfc wpf怎么结合使用?在MFC中使用WPF技术
WPF是Windows Presentation Foundation的缩写。它是微软.NET Framework3.0的一个子系统。这种技术允许开发人员高效地创建可视化的应用程序,并改善用户体验。由于WPF的发布,使用Windows程序在富控件的设计、开发上更如虎添翼。WPF主要关注一套应用程序服务:用户接口、2D和3D、矢量图、动画、数据绑字、音频,并提供一个在UI和商业逻辑之间的非常清晰的界限。
WPF API是被管制的代码,但是大多数Win32/MFC程序是非管制的C++代码。按着惯例,WPF API不能通过非常制程序调用。然后,通过使用VC编译器的/clr选项,我们可以建立一个由管制和非管制混合而面的系统。在这个系统中,我们可以使管制和非管制代码无缝地混合在一起。
有一个要注意的是在C++工程中不允许编译XAML文件。因此,我们必须建立一个包含在本例中所需要的所有XAML而的C# DLL,然后在C++工程中包含这个Dll引用。
有两种基本的技术可以融合WPF和Win32/MFC代码:
1. 将WPF放到Win32/MFC程序中:使用这种技术,开发人员可以使用WPF的高级图形能力来渲染Win32/MFC应用程序。
2. 将Win32/MFC放到WPF中:使用这种技术,开发人员可以在WPF中使用已经存在的
Win32/MFC控件,并通过一定的机制来传递数据。
在本文中将采用第一种方法。
1
[size=2][b]三、
[/b][b]融合Win32/MFC[/b][b]和WPF[/b][b]程序[/b][/size]
[size=2]
上面部分所说的是本例的基本规则,下面在本节中将介绍如何编写具体的实现代码。在本例中,我首先会演示使用XAML和C#建立WPF内容,并在VC++中引用这个DLL。[/size]
[size=2]
本例的目的是建立一个用于设置日期和时间的设置工具,其中动画部分使用WPF实现。程序的其他部分仍然使用MFC实现。[/size]
[size=2]
[size=10.5pt]这个演示程序由两部分组成:一个是[/size][size=10.5pt]MFCHostMPF[/size][size=10.5pt](由[/size][size=10.5pt]VC++/MFC[/size][size=10.5pt]代码组成),另一个是[/size][size=10.5pt]WPFControls[/size][size=10.5pt](由[/size][size=10.5pt]XAML[/size][size=10.5pt]和[/size][size=10.5pt]C#[/size][size=10.5pt]代码组成)。这个[/size][size=10.5pt]MFCHostWPF[/size][size=10.5pt]工程将由[/size][size=10.5pt]WPFControls[/size][size=10.5pt]工程所产生的[/size][size=10.5pt]DLL[/size][size=10.5pt]作为一个外部的引用。如图[/size][size=10.5pt]2[/size][size=10.5pt]所示:
[img]http://image.it168.com/cms/2008-1-28/Image/200812812547.jpg[/img]
[size=10.5pt]向[/size][size=10.5pt]MFC[/size][size=10.5pt]工程中加入一个[/size][size=10.5pt]WPF[/size][size=10.5pt]引用。如图[/size][size=10.5pt]3[/size][size=10.5pt]和图[/size][size=10.5pt]4[/size][size=10.5pt]所示:
[img]http://image.it168.com/cms/2008-1-28/Image/200812812114.jpg[/img][/size][/size][/size]
[size=2][size=10.5pt][size=10.5pt][size=10.5pt]
[/size][font=宋体][size=10.5pt]图[/size][/font][size=10.5pt]3
[img=384,307]http://image.it168.com/cms/2008-1-28/Image/200812812129.jpg[/img]
[/size][/size][/size][/size]
webmaster 2008-7-2 16:16
[size=2][b]三、在MFC[/b][b]应用程序中加入和WPF[/b][b]相关的代码[/b][/size]
[size=2]
先提一下,gcnew关键字被用于建立一个管制类型的实例,在本例中将建立一个垃圾回收集合栈的实例。所有被gcnew分配的内存空间将被垃圾回收器自动管理,而开发人员并不需要为什么时间释放它们而操心。[/size]
[size=2][/size]
[size=2]
为了使用WPF程序,关键是System::Windows::Interop::HwndSource类。这个类将在Win32窗口中使用WPF程序,因此,WPF程序可以作为MFC窗口的子窗口放到UI上。而在WPF对象和Win32窗口之间的通讯要通过引用C++程序中被存储的静态字段。这些静态字段的代码如下:
[/size]
[size=2][/size]
[size=2][color=#0000ff]ref[/color]
[color=#0000ff]class[/color][/size][size=2][color=#000000] Globals{[/color][color=#0000ff]public[/color][/size][size=2][color=#000000]:[/color][color=#0000ff]static[/color][color=#000000] System::Windows::Interop::HwndSource[/color][color=#000000]^[/color][/size][size=2][color=#000000] gHwndSource;[/color][color=#0000ff]static[/color][color=#000000] WPFControls::AnimClock[/color][color=#000000]^[/color][/size][color=#000000][size=2] gwcClock;};[/size][/color]
[size=2] [/size]
[size=2]HWND hwndWPF; // 和WPF相关的hwnd[/size]
[size=2]
为了建立一个HwndSource,首先需要建立一个HwndSourceParameters结构,这个结构需要如下的参数:[/size]
[size=2]1. 类、窗口、窗口类型 [/size]
[size=2]2. 窗口的初始位置[/size]
[size=2]3. 窗口的初始尺寸 [/size]
[size=2]4. 父窗口 [/size]
[size=2]
一但我们将HwndSourceParameters结构编写完,就可以将这个结构到HwndSource的构造方法HwndSource(HwndSourceParameters)中。[/size]
[size=2]
[size=10.5pt]最后,我们将[/size][size=10.5pt]WPF[/size][size=10.5pt]时钟的引用赋值给[/size][size=10.5pt]HwndSource[/size][size=10.5pt]对象的[/size][size=10.5pt]RootVisual[/size][size=10.5pt]属性,并通过调用[/size][size=10.5pt]Handle.ToPointer()[/size][size=10.5pt]返回[/size][size=10.5pt]HwndSource[/size][size=10.5pt]的[/size][size=10.5pt]HWND[/size][size=10.5pt]。代码如下:[/size][/size][size=10.5pt]
[size=2][color=#000000]HWND GetHwnd(HWND parent, [/color][color=#0000ff]int[/color][color=#000000] x, [/color][color=#0000ff]int[/color][color=#000000] y, [/color][color=#0000ff]int[/color][color=#000000] width, [/color][color=#0000ff]int[/color][/size][size=2][color=#000000] height){System::Windows::Interop::HwndSourceParameters[/color][color=#000000]^[/color][color=#000000] sourceParams [/color][color=#000000]=[/color][/size][color=#000000][size=2] gcnew System::Windows::Interop::HwndSourceParameters([/size][/color][size=2][color=#000000]"[/color][color=#000000]MFCWPFApp[/color][color=#000000]"[/color][/size][size=2][color=#000000]);sourceParams[/color][color=#000000]->[/color][color=#000000]PositionX [/color][color=#000000]=[/color][/size][size=2][color=#000000] x;sourceParams[/color][color=#000000]->[/color][color=#000000]PositionY [/color][color=#000000]=[/color][/size][size=2][color=#000000] y;sourceParams[/color][color=#000000]->[/color][color=#000000]Height [/color][color=#000000]=[/color][/size][size=2][color=#000000] height;sourceParams[/color][color=#000000]->[/color][color=#000000]Width [/color][color=#000000]=[/color][/size][size=2][color=#000000] width;sourceParams[/color][color=#000000]->[/color][color=#000000]ParentWindow [/color][color=#000000]=[/color][/size][size=2][color=#000000] IntPtr(parent);sourceParams[/color][color=#000000]->[/color][color=#000000]WindowStyle [/color][color=#000000]=[/color][color=#000000] WS_VISIBLE [/color][color=#000000]|[/color][/size][size=2][color=#000000] WS_CHILD;Globals::gHwndSource [/color][color=#000000]=[/color][/size][color=#000000][size=2] gcnew System::Windows::Interop::HwndSource([/size][/color][color=#000000][size=2]*[/size][/color][size=2][color=#000000]sourceParams);DateTime tm [/color][color=#000000]=[/color][/size][size=2][color=#000000] DateTime::Now;Globals::gwcClock [/color][color=#000000]=[/color][/size][size=2][color=#000000] gcnew WPFControls::AnimClock();Globals::gwcClock[/color][color=#000000]->[/color][/size][size=2][color=#000000]ChangeDateTime(tm.Year,tm.Month,tm.Day,tm.Hour,tm.Minute,tm.Second);FrameworkElement[/color][color=#000000]^[/color][color=#000000] myPage [/color][color=#000000]=[/color][/size][size=2][color=#000000] Globals::gwcClock;Globals::gHwndSource[/color][color=#000000]->[/color][color=#000000]RootVisual [/color][color=#000000]=[/color][/size][size=2][color=#000000] myPage;[/color][color=#0000ff]return[/color][color=#000000] (HWND) Globals::gHwndSource[/color][color=#000000]->[/color][/size][color=#000000][size=2]Handle.ToPointer();}[/size][/color]
[size=2] 因此,无论用户如何变化时钟,我们的MFC代码都会调用RefereshWPFControl()来刷新WPF时钟。[/size]
[color=#0000ff][size=2]void[/size][/color][size=2][color=#000000] RefreshWPFControl(){FrameworkElement[/color][color=#000000]^[/color][/size][size=2][color=#000000] page;DateTime tm [/color][color=#000000]=[/color][/size][size=2][color=#000000] DateTime::Now;Globals::gwcClock[/color][color=#000000]->[/color][/size][size=2][color=#000000]ChangeDateTime(tm.Year,tm.Month,tm.Day,tm.Hour,tm.Minute,tm.Second);page [/color][color=#000000]=[/color][/size][size=2][color=#000000] Globals::gwcClock;Globals::gHwndSource[/color][color=#000000]->[/color][color=#000000]RootVisual [/color][color=#000000]=[/color][/size][size=2][color=#000000] page;[/color][color=#0000ff]return[/color][/size][color=#000000][size=2];}[/size][/color]
[size=2]现在我们已经有了大部分我们需要的功能了,而最后的任务是在MFC对话框代码中找个地方调用HwndSource实现创建函数。当然,有很多地方可以做这个工作,但是OnCreate也许是最好的位置。在OnCreate事件句柄中调用GetHwnd()函数的代码如下:
[/size][color=#0000ff][size=2]int[/size][/color][size=2][color=#000000] CMFCHostWPFDlg::OnCreate(LPCREATESTRUCT lpCreateStruct){[/color][color=#0000ff]if[/color][color=#000000] (CDialog::OnCreate(lpCreateStruct) [/color][color=#000000]==[/color]
[color=#000000]-[/color][color=#000000]1[/color][/size][size=2][color=#000000])[/color][color=#0000ff]return[/color]
[color=#000000]-[/color][color=#000000]1[/color][/size][size=2][color=#000000];hwndWPF [/color][color=#000000]=[/color][color=#000000] GetHwnd([/color][color=#0000ff]this[/color][color=#000000]->[/color][color=#000000]GetSafeHwnd(), [/color][color=#000000]20[/color][color=#000000], [/color][color=#000000]28[/color][color=#000000], [/color][color=#000000]205[/color][color=#000000], [/color][color=#000000]130[/color][/size][size=2][color=#000000]);[/color][color=#0000ff]return[/color]
[color=#000000]0[/color][/size][color=#000000][size=2];}[/size][/color]
[b][size=2]四、结论[/size][/b]
[size=2]
我们现在可以看到,通过集成WPF和Win32/MFC应用程序可以为我们增添很多非常酷的特性来加强用户体验。本文所提供的实例只是抛砖引玉,读者可以使用这项技术做出更复杂的应用程序来。[/size]
[/size]1