使用 WPF 向控件和三维表面添加视频
|
本文使用了以下技术:
.NET Framework 3.0 |
![]() |
在 Karsten Januszewski 的演示过程中,他向我们展示了时下著名的 North Face 演示 (channel9.msdn.com/Showpost.aspx?postid=116327),它的特色之处在于将高质量的 Windows Media® Video (WMV) 剪辑映射在一个三维旋转式场景中的弯曲三维网格对象上。该演示是由 Fluid(另一个位于旧金山的互动工作室)和 Microsoft Windows Presentation Foundation 团队成员联合制作的。眼前发生的事实驱走了我的偏见。这种形式的演示是很难借助或根本无法借助 Flash 或任何其他相关平台完成的。
演示会后不久,我放弃了自己的成见,并下载了 Microsoft® .NET Framework 3.0 运行时,由此开始了我作为 Windows Presentation Foundation 互动设计师的职业生涯。 从那时起,Flash 与 Windows Presentation Foundation 孰是孰非的争论就几乎烟消云散了,原因是这两项技术真正竞争的领域并不多。而这种争论可能会在 Microsoft 用于传送跨平台网页(包括图形、视频、动画和音频)的最新解决方案发布之际再度成为众人讨论的焦点。这一即将发布的版本代号为“WPF/E”,您可以从“WPF/E”开发人员中心获得该版本的预览,网址为 msdn2.microsoft.com/bb187358.aspx。
能够将视频映射到三维表面的功能的确足以引起互动设计师的注意。但是在将音频和视频集成到 Windows Presentation Foundation 时,我们能够实现的功能远不止此,这一功能只能算是皮毛而已。本文将帮助您熟悉和了解 Windows Presentation Foundation 媒体集成的最新发展,并为您将媒体文件和感兴趣的可选图像添加到自己的应用程序提供必需的知识。
技术概览
目前有两种最常用的方法可以将数字媒体文件添加到 Win32® 应用程序中:使用 DirectShow® API 或嵌入 Windows Media Player ActiveX® 控件。借助 DirectShow,开发人员可以最大限度地控制媒体的集成,但这种做法与仅嵌入 Windows Media Player ActiveX 控件相比要复杂得多。
对于需要对媒体显示和管理进行细致控制的 Windows Presentation Foundation 应用程序来说,使用 DirectShow 仍然是一个可行的选择。您也可以将现有的 Win32 应用程序移植到 Windows Presentation Foundation 和 .NET Framework 3.0,这时就可以在 Windows Presentation Foundation 应用程序中实现 DirectShow 了。
虽然在 Windows Presentation Foundation 中您依然可以使用 Windows Media Player ActiveX 控件播放媒体,但新的 MediaElement 控件却是更加明智的选择。使用该控件您可以完成基本相同的操作,稍后您将对此有所了解;但不同之处在于它能够与 Windows Presentation Foundation 更好地集成。特别地是,它允许您使用阿尔法混合 (alpha-blending) 技术合成媒体,并呈现在三维表面上。
音频和视频都能与 Windows Presentation Foundation 集成,这为开发人员提供了多种可选方案,这些方案的复杂程度及其对媒体文件的控制方式都是各不相同的。但无论采用哪种控件或类,后台发生的操作都是大致相同的。大致的思路是这样的,当应用程序被要求在 Windows Presentation Foundation 中播放媒体文件时,会在后台启动 Windows Media Player 运行时播放该文件。Windows Presentation Foundation 实际上使用的是 Windows Media Player,而并不带有自己的媒体呈现引擎,这一点可以说是瑕瑜互见,长短并存的。Windows Media Player 的 Piggybacking 与使用 ActiveX 控件有些类似。
由于 Windows Media Player 负责 Windows Presentation Foundation 媒体播放,因此可以很容易判断哪些媒体格式能够与 Windows Presentation Foundation 兼容。基本上来说,最终用户使用现有 Windows Media Player 安装程序可以播放的任何一种格式都可以用 Windows Presentation Foundation 应用程序播放。要添加对其他媒体类型的支持,用户需要安装新的视频编解码器。
注意,由于必须运行 Windows Media Player 运行时才能播放媒体文件,因此当运行时在后台加载时,初次播放媒体会出现延迟。这使得精确控制媒体变得很困难,尤其是在 Windows Presentation Foundation 中尝试同步音频或视频与动画或其他事件,以及执行其他类似操作时。解决该问题的一种方法是,预加载媒体文件并保持其暂停状态,直到您准备就绪可以播放这些文件为止。另一种方法是使用动画引擎中的滑移,您可以借此创造其他依赖 MediaElement 的动画,这样一来,至少所有的延迟都是相同的。这虽然不是最佳的工作流程,但 Windows Presentation Foundation 媒体团队正在为下一版本的解决方案忙碌着。幸运的是,对于音频播放,我们还可以选择 System.Media.SoundPlayer 类,它允许对 WAV 文件进行简单的播放,而无需 Windows Media Player。本文稍后将介绍如何使用上述 System.Media.SoundPlayer 类。
使用 MediaElement 控件
到目前为止,将媒体添加到 Windows Presentation Foundation 应用程序最简便的方法就是使用新提供的 MediaElement 控件。与 Windows Presentation Foundation 中其他所有控件一样,该控件可以使用 XAML 进行添加或使用 C#/Visual Basic®在代码隐藏文件中添加。MediaElement 使您可以对媒体文件执行基本的播放和控制操作,并能够运行于以下两种模式之一:独立模式或时钟模式。
独立模式是默认模式,其工作方式与传统媒体播放器非常相似:
<MediaElement Source="myMedia.wmv" Width="320" Height="240" LoadedBehavior="Manual" />
您要设置好 Source 属性(为指向某一媒体文件的 URI)。媒体文件加载时执行何种操作取决于 LoadedBehavior 属性。该属性必须设置为 MediaState 枚举中的某个值:Close、Manual、Pause、Play 或 Stop。为了使用 MediaElement 控件的 Play、Pause 或 Stop 方法控制媒体的播放,LoadedBehavior 属性必须设置为 Manual。
图 1 显示了一个简易媒体播放器的示例,该播放器使用运行于独立模式的 MediaElement 控件。图 2 显示了用于实现该控件的 XAML 和 C# 代码。
![图 1 简易 MediaElement 控件](http://msdn.microsoft.com/msdnmag/issues/07/03/digitalmedia/zh/fig01.gif)
图 1 简易 MediaElement 控件
以时钟模式运行 MediaElement 控件,就可以使用功能强大的 Windows Presentation Foundation 动画引擎来控制媒体的播放。要启用时钟模式,可以选择将 MediaElement 定为 MediaTimeline 的一部分,也可以选择从某一 MediaTimeline 显式创建一个 MediaClock,并将其分配给 MediaElement(尽管不建议使用该方法)。这种方法听起来可能难以理解,但实际上是说您可以将 MediaElement 附加到某个 Storyboard 并使用 Windows Presentation Foundation 动画引擎动态显示其位置。这样就可以实现媒体播放与您应用程序中其他动画之间的同步。
下面给出一个 XAML 代码的示例,在时钟模式下使用 Storyboard 播放媒体时需要该代码:
<MediaElement Name="myMedia" Width="320" Height="240" /> <Grid.Triggers> <EventTrigger RoutedEvent="Grid.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard Storyboard.TargetName="myMedia"> <MediaTimeline Source="myMedia.wmv" BeginTime="00:00:00" Duration="00:05:00" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Grid.Triggers>
注意,媒体文件的源要在 MediaTimeline 设置,而并非在 MediaElement 中。MediaTimeline 通过 Storyboard.TargetName 附加属性来确定目标 MediaElement 控件。如果您不熟悉 Windows Presentation Foundation 动画引擎,可能不太好理解时钟模式。因此您需要在勇于尝试这一功能前先习惯 Windows Presentation Foundation 动画的基本功能。
设置好 MediaElement 并配置其模式后,就可以对许多属性进行读写操作,以进一步增强媒体播放的体验。您只需使用某个有效的 TimeSpan 对象来设置 Position 属性,即可获取或设置媒体文件的位置。通过读取 BufferingProgress 和 DownloadProgress 属性可以向用户显示缓冲和播放进度。对于音频控件,可以设置 Balance 和 Volume 属性,以自定义或动态模拟媒体的音轨。现在考虑一下,如果这些值被数据绑定到几个滑块,会发生什么事情?您可以让用户完全控制媒体的听觉体验!
MediaElement 还可以触发许多非常实用的事件。使用 MediaOpened 和 MediaEnded,您可以根据媒体是已经开始还是结束来很方便地触发应用程序的其他部分。缓冲操作期间,当视频出现静止时,BufferingStarted 和 BufferingEnded 事件让您能够将反馈显示给用户。如果与 BufferingProgress 属性联合使用,就可以将缓冲百分比显示给用户,这与使用 Windows Media Player 查看流视频时的情景十分相似。
根据自身的经验,以及 Windows Presentation Foundation 媒体团队的交谈对此的肯定,我建议您,除非时钟模式是绝对必要的,否则通常应在独立模式下使用 MediaElement 控件。标准的媒体播放和控制不需要涉及 Storyboard 或 MediaTimeline。MediaElement 应该是媒体集成的默认选择,因为它可以通过 XAML 进行添加,这样媒体就可以交给设计师来实现,开发人员则可以获得解放并投入到其他工作中。
使用 MediaPlayer 类
如果 MediaElement 控件无法为您的应用程序提供足够的播放功能和控制,您可以考虑下一个选择,使用位于 System.Windows.Media 命名空间的 MediaPlayer 类。由于该类并不是 Windows Presentation Foundation 控件元素,因此要实现 MediaPlayer,唯一的方法就是使用 C# 或 Visual Basic 在代码隐藏文件中创建它。下面这个简单的示例说明了如何使用 C# 来实现一个 MediaPlayer:
MediaPlayer mp = new MediaPlayer(); Try { mp.Open(new Uri("myMedia.wmv")); } catch(Exception ex) { MessageBox.Show(ex.Message); }
MediaPlayer 类的可用属性和方法与 MediaElement 控件有着惊人的类似。这不仅仅是一种巧合。从本质上看,MediaElement 是对 MediaPlayer 类的高级封装。使用 MediaPlayer 时有一点需要特别注意,即它不提供任何直观的视觉化呈现,也无法直接添加到视觉树。要播放视频,您需要将 MediaPlayer 绘制在可视表面之上,然后再将该表面添加到视觉树。这使得 MediaPlayer 成为播放音频的较佳选择,因为很显然这样做不需要视觉化的呈现。对于标准的视频播放,MediaElement 控件则是一个更好的选择,因为它继承自 UIElement 类,所以可以被直接添加到应用程序中的视觉树。
和 MediaElement 控件一样,MediaPlayer 实例既可以运行于独立模式,也可以运行于时钟模式。作为播放控件来说,MediaPlayer 本质上也与 MediaElement 控件极其相似。那么 MediaPlayer 到底有何不同之处呢?嗯,其中一点不同就是 MediaPlayer 并不涉及 LoadedBehavior 或 UnloadedBehavior 属性,因为这些属性是 MediaElement 控件独有的。如果您计划使用 VideoDrawing 类将媒体绘制到三维表面上,就必须使用 MediaPlayer,因为 VideoDrawing 的 Player 属性并不接受 MediaElement 控件作为其值。(别着急,稍后我会为您讲解如何将视频绘制到三维表面和其他表面。)
另一个优点(也可能成为缺点,这取决于您的具体情况)是,由于 MediaPlayer 并不是通过 XAML 来实现的,因此未加入到视觉树中。如果您的媒体文件不需要视觉化呈现,那么不属于视觉树也是有一定好处的。另外二者在加载媒体文件到应用程序的方式上也存在一些区别。在 MediaElement 控件中,您要设置其 Source 属性,但在使用 MediaPlayer 类时,您调用的是 Open 方法并传入一个有效的 Uri 对象。
因此,如果应用程序不要求使用 XAML 实现媒体文件,或媒体文件具有自动的视觉化呈现,那么 Media Player 可能是您的最佳选项,因为它可以提供 MediaElement 控件的所有功能,同时没有令人头疼的额外开销。
在 WPF 控件内部嵌入视频
由于 MediaElement 控件继承自 System.Windows.UIElement 类,因此可以被放置在任何其他 UIElement 能够放置的位置。这种示例很多,例如在一个 Button 控件内部嵌入一个 MediaElement 控件,就创建了一个视频按钮。您可以使用以下 XAML 代码来实现此目的:
<Button Name="myVideoButton" Click="playVideo" Width="320" Height="240"> <MediaElement Name="myVid" Source="myMedia.wmv" LoadedBehavior="Manual" Width="320" Height="240" /> </Button>
在这段代码中,一个 Button 控件内部嵌入了 MediaElement,并将其 LoadedBehavior 属性设置为 Manual。Button 控件的 click 事件调用一个方法(未显示),通知 MediaElement 开始播放文件。通过寥寥几行代码,您已经创建了一个互动视频缩略图。各种各样富于创造性的可能都向您敞开,这是因为 Windows Presentation Foundation 实际上将 MediaElement 控件看作是与视觉树中其他任何 UI 元素一样的元素。下一节中您将发现甚至可以将 MediaElement 中的视频播放绘制到其他 Windows Presentation Foundation 对象之上,从而创造出意想不到地丰富的用户体验。
“湿地板”技巧
最近,“玻璃”效果和“倒影”效果在所有可视界面上大行其道。毫无疑问,总有一天您会被要求在 Windows Presentation Foundation 中提供这类方法,而幸运的是,这一点很容易做到。凭借 Windows Presentation Foundation 提供的功能全面的画笔系统,您可以轻松地将一个控件绘制到另外一个控件上。在该示例中,我将使用 VisualBrush 将 MediaElement 控件中的视频播放绘制到一个矩形上,创建该视频的完美反射效果。在设计界,这种效果被称为“湿地板”。
创建“湿地板”效果最简单方法是将 MediaElement 控件放置在 StackPanel 控件的第一个插槽中。然后在下面创建一个尺寸与视频相同的矩形。接下来,将 VisualBrush 作为矩形的填充,并将其 Visual 属性数据绑定到 MediaElement 控件。最后翻转倒影创建一个镜像图像,并应用 OpacityMask 将倒影淡化。
图 3 显示操作完成后的效果,而图 4 则显示了 XAML 代码。在传统的 Win32 编程中,要进行这类可视化操作,其复杂程度往往是让人难以置信。而且,由于 Windows Presentation Foundation 提供了强大的数据绑定功能,因此这种倒影是一种实时的效果,能够随着您视频的更新而自动更新。
![图 3 已完成的“湿地板”效果](http://msdn.microsoft.com/msdnmag/issues/07/03/digitalmedia/zh/fig03.gif)
图 3 已完成的“湿地板”效果
将视频映射到三维表面之上
如果必须从 Windows Presentation Foundation 中选出一个最受人欢迎的常用功能,我认为应该是将视频文件映射到三维网格对象之上这一功能。North Face 演示向我们展示了这一功能对于创造极具视觉冲击的用户界面的帮助是多么强大。尽管许多人将这一效果描绘成唬人的噱头或“吃资源”的猛兽,但我认为,只要应用适度,这一技术可以使普通应用程序摇身一变,转而能够向用户提供震撼的体验。
就性能而言,显示三维网格并使其实现动画效果无疑会造成相当大的系统开销。如果还要显示映射在三维网格之上的全动态视频,那么所需的开销将是巨大的。就像喝摩卡星冰乐 (mocha frappucino) 一样,关键还是要适度。大致说来,我发现只要将三维网格的复杂性(多边形计数)维持在必要的最低水平,Windows Presentation Foundation 就可以表现出很优秀的三维性能。Windows Presentation Foundation 媒体团队承诺会在将来的版本中减少三维媒体需要的开销,尽管其开销会始终大于二维媒体。
在介绍如何将视频映射到三维对象之前,我们先看一下在 Windows Presentation Foundation 中设置一个三维场景都需要哪些元素。首先,也是最重要的,需要在场景中放置一个三维对象。.NET Framework 3.0 中不包含任何三维基元类。但 Microsoft 的某位员工创建了一个名为 Mesh3DObjects 的类,使用它可以创建各种基元对象。(有关该类的详细信息,请参阅 Karsten Januszewski 编写的教程,网址为 msdn.microsoft.com/library/en-us/dnlong/html/avalon2d-3d.asp。)
要在 Windows Presentation Foundation 中创建一个三维场景,需要使用特定的元素组。首先,需要三维对象,而且该对象需要具备某种材料才能在场景中可见。这些材料要通过画笔(如 SolidColorBrush、LinearGradientBrush、ImageBrush 或 VisualBrush)来创建。稍后您将知道如何使用 VisualBrush 将视频或任何其他可视元素映射到一个三维表面之上。这种技巧从本质上讲与之前讨论的“湿地板”技巧是相同的。
三维网格和这些材料需要分组放入一个 GeometryModel3D 元素内部,这样做可以创建一个有效的 Windows Presentation Foundation 三维对象。为了使三维场景可见,我们需要向场景内添加一个或多个光源。然后,正如没有照相机就无法拍照片一样,Windows Presentation Foundation 中也不能缺少三维场景。最后,要完成场景,还需要将所有这些项包装在 Viewport3D 控件中以便进行封装处理。
功能正常的三维场景准备就绪后,您就可以开始享受将视频和其他媒体映射到三维网格之上的乐趣了。使用 VisualBrush 将视频绘制到三维表面上,整个过程即可完成。以下的代码段中,一个 VisualBrush 被应用于一个三维对象的 DiffuseMaterial:
<GeometryModel3D.Material> <DiffuseMaterial> <DiffuseMaterial.Brush> <VisualBrush> <VisualBrush.Visual> <MediaElement Source="myMedia.wmv" /> </VisualBrush.Visual> </VisualBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </GeometryModel3D.Material>
图 5 显示的是映射到 Windows Presentation Foundation 三维表面之上的视频的某一帧。
![图 5 映射到一个 WPF 三维表面](http://msdn.microsoft.com/msdnmag/issues/07/03/digitalmedia/zh/fig05.gif)
图 5 映射到一个 WPF 三维表面
在 Windows Presentation Foundation 中,您可以使用另外一种方法将视频映射到三维表面。VideoDrawing 类属于 System.Windows.Media 命名空间,它的作用是名副其实的,就是绘制视频。该类可以通过 DrawingBrush 将来自 MediaPlayer 实例的视频绘制到任何与画笔兼容的表面之上。为了实现这一目的,您需要将 DrawingBrush 的 Drawing 属性设置为 VideoDrawing 类的一个实例。该 VideoDrawing 实例可以通过将自己的 Player 属性设置为一个包含视频文件的 MediaPlayer 实例来呈现视频。最后,可以将 DrawingBrush 应用于一个三维对象的 DiffuseMaterial 的 Brush 属性。以下代码段显示了一个使用 C# 来实现的示例:
MediaPlayer mp = new MediaPlayer(); mp.Open(myValidMediaUri); VideoDrawing vd = new VideoDrawing(); vd.Player = mp; DrawingBrush db = new DrawingBrush(); db.Drawing = vd; diffuseMat.Brush = db; vd.Player.Play();
使用 VisualBrush 或 VisualDrawing 类的主要差异之一在于,VisualDrawing 类必须在代码隐藏文件中才能得以创建和实现(使用 C# 或 Visual Basic)。此外,VideoDrawing 类仅对 MediaPlayer 实例起作用,对于 MediaElement 控件则不起作用。从性能方面考虑,两种方法之间的差异不大,因为二者都需要 Windows Presentation Foundation 为其创建一个呈现视频的表面,以起到桥梁作用,以便将视频正确映射到三维物体。
呈现来自视频帧的视图
视频应用程序可能有必要捕捉视频流的屏幕快照并将其显示为位图。在某些商业 DVD 播放软件中您可以看到这类示例,在播放视频的过程中用户只需随时单击一个照相机图标,就可以从视频中捕捉一张屏幕快照。如果您不希望将一组视频文件全部实际地连接到 MediaElement 控件,可以为这组视频文件创建缩略图。而且有时还可能借此创建一些运行时视频效果,尽管对于此类操作您最好还是先深入研究 DirectShow API 才能取得满意的效果。
与 Windows Presentation Foundation 中的大多数情况一样,完成一项任务可以有多种方法,显示视频帧的位图也是如此。不管使用哪种方法,要在 Windows Presentation Foundation 中呈现可视元素的位图,核心的功能都是通过 RenderTargetBitmap 类来实现,该类属于 Windows.Media.Imaging 命名空间。该类的功能之强大令人惊异,它可以从 Windows Presentation Foundation 应用程序视觉树中的任何一个项创建位图。
要使用该类呈现一个位图,首先需要新建一个 DrawingVisual 对象,该对象将传递给 RenderTargetBitmap.Render 方法。接下来,新建一个 DrawingContext 对象,稍后将传递给 DrawingVisual.Render 方法。借助该 DrawingContext 实例,您可以将各种图形绘制到 DrawingVisual 对象中。要绘制一个视频帧,可以调用 DrawingContext.DrawVideo 方法,并传入一个当前正在播放视频文件的 MediaPlayer 实例。另外还需要传入一个 Rect 值,该值确定了要捕捉的视频文件区域。
现在,您可以真正地从包含已捕捉视频帧的 DrawingVisual 实例呈现位图了。要实现这一点,您只需将其传递给 RenderTargetBitmap.Render 方法即可。现在您的 RenderTargetBitmap 实例中已包含了该视频帧,但只有将其传递给 BitmapFrame.Create 方法后,它才能够成为位图。要查看该位图帧,只需将此方法调用设为一个 Image 控件的 Source 属性的值即可。以下代码段显示了如何使用 C# 来实现这一帧捕捉技巧:
RenderTargetBitmap rtb = new RenderTargetBitmap(320, 240, 1 / 200, 1 / 200, PixelFormats.Pbgra32); DrawingVisual dv = new DrawingVisual(); DrawingContext dc = dv.RenderOpen(); dc.DrawVideo(myMediaPlayer, new Rect(0, 0, 320, 240)); dc.Close(); rtb.Render(dv); Image im = new Image(); im.Source = BitmapFrame.Create(rtb);
目标位图的格式是通过将一个有效的 PixelFormats 枚举值传递给 RenderTargetBitmap 构造函数来设置的。将视频帧呈现为位图的功能乍一看似乎毫不起眼,但实际上除了应用于简单的视频屏幕捕获工具外,这种功能还有很多其他的用途。
WPF 中的其他音频功能
到目前为止,我所讨论的有关 Windows Presentation Foundation 媒体集成的大部分内容都是适用于视频和音频的。但另外还有几个类可用于处理 Windows Presentation Foundation 中的音频播放。如前所述,Windows Presentation Foundation 中播放的媒体实际上是由一组 Windows Media Player 运行时来驱动的,要播放文件必须先加载这些运行时。而当您尝试同步媒体文件和用户事件或动画时,就会导致一个严重的问题(尽管可以通过时间线中的滑移行为来缓解)。而就音频而言,我们可以通过某些替代方法绕过这一问题。
SoundPlayer 类属于 System.Media 命名空间,它能提供一个简单的接口来加载和播放 WAV 音频文件。这些 WAV 文件可以是外部资源、流式资源或嵌入式资源。与借助 MediaElement 控件播放音频文件相比,这种音频播放方法的开销要低得多,因为它根本不依赖 Windows Media Player 来播放文件。
要将一个 WAV 文件加载到 SoundPlayer 实例中,首先要将 SoundLocation 属性设置为该 WAV 文件的位置,然后再调用 Load 方法来启动加载过程。文件完全加载后,就可以使用 SoundPlayer.Play 方法来播放文件了。文件在完全加载到内存之前是不会开始播放的。
在 XAML 中,您可以使用 SoundPlayerAction 控件来播放轻型音频,该控件使您能够在 EventTrigger 内部播放 WAV 文件。对于实现诸如按钮翻转的界面声音来说,这一功能是非常实用的。将该控件置入 EventTrigger 的 EventTrigger.Actions 块中即可使用。以下代码段显示的是响应一个按钮的 MouseEnter 事件对 SoundPlayerAction 进行调用的操作:
<EventTrigger RoutedEvent="Button.MouseEnter" SourceName="myButton"> <EventTrigger.Actions> <SoundPlayerAction Source="media/overSound.wav"/> </EventTrigger.Actions> </EventTrigger>
总结
在本文中,我为大家介绍了将音频和视频集成到 Windows Presentation Foundation 应用程序的方法。如果 Windows Presentation Foundation 为您的项目提供的控制无法满足您的需要,您总是可以恢复为使用 DirectShow API 进行媒体集成。但是能够借助 XAML 添加音频和视频这一点使得简单的媒体集成可以交给设计师来做,从而解放了开发人员,使其能够集中精力进行更复杂的代码编写工作。到此,我已经将以前的怀疑态度抛到九霄云外。Windows Presentation Foundation 提供了令人惊奇又极其丰富的视觉体验,这使得媒体集成不仅是可能的,更是令人极度兴奋的!
Lee Brimelow 是 Frog Design 的一名高级设计技术专家,他专攻 Flash 和 WPF,是一名屡获殊荣的互动设计师。他开设的 WPE 技术博客 www.thewpfblog.com 受到了大家的广泛欢迎。
![Subscribe](http://msdn.microsoft.com/msdnmag/images/promo/subbutton.gif)