WPF/E解读系列(一)

    作为系列的开篇,写的也许简单了些,笼统了些,如果大家有意见或者建议,请通过kennethbyron@gmail.com与我联系.另外考虑到更多人阅读方便,所以这次直接写中文版的,英文版的等系列全部出完,打包提供下载.下面”眼”归正传.

    正如WPF/E项目经理Joe Stegman说的那样,WPF/E是WPF Everywhere.那么究竟WPF/E是什么呢?它又是如何工作的呢?让我们现在就看看它.
    这有几个WPF/E的页面效果演示,如果无法正常显示,请下载并安装WPF/E客户端运行库(1.1M)

  演示地址:
Page Turner
Sprawl Game
Film Strip Slide-Show
Media Library
Simple Video Playback

概要:

  1. WPF/E开发背景及开发目标
  2. WPF/E的实质和前景
  3. WPF/E的实现原理及工作机制基础
  4. WPF/E参考资源

1.WPF/E开发背景及开发目标

    随着.NET框架3.0的正式发布,Windows Presentation Foundation(WPF)即Windows表现层基础,Windows Communication Foundation(WCF)即Windows通信层基础和Windows Workflow Foundation(WWF)即Windows工作流基础,三大基础成为开发组织方式新的实现,为开发分工协作提供了更好的模型和支持,并大幅度的完善了微软.NET类库.WPF作为表现层基础开发库,提供了对DirectX更好的支持,优化了2D和3D表现层引擎,与WinForm开发紧密结合,实现了传统的Win32和WinForm对XAML(拓展应用程序标记语言)程序的支持和装载功能.然而WPF却未能实现ASP.NET WebForm装载XAML程序,而且在非3.0运行库支持平台上WPF无法正常工作.
    出于WPF的局限性,WPF/E应需而生,WPF/E对Web应用开发ASP.NET 2.0作出拓展,实现
  • 更轻松,更自由的网络应用程序开发
  • 提高网络应用程序对媒体文件的表现效果和支持性
  • 应用最新的标准
  • 采用友好的AJAX和XAML表现
    当然.WPF/E并非仅仅定义在网络应用上,它的跨平台性,可拓展性及优越的兼容性势必使WPF/E在实际应用上得到更多层面的拓展.

2.WPF/E的前景和实质

    WPF/E是对图形界面,动画效果,媒体文件及XAML程序支持性的拓展,相信大家对WPF的展示效果也有所了解,在VISTA下,WPF将界面效果展示得淋漓尽致,玻璃,半透明,圆角,多边不规则图形,倒影等等.当然WPF的展示效果还不仅于此,WPF的动画效果也令人叹为观止,倒映,水波纹,滚动,浮动等等.试想下,如果我们将这些效果应用在网页上,那么动画页面便不再仅仅是FLASH的天地了.
    说了这么多.WPF/E到底是什么呢?
    WPF/E实际是通过JavaScript在普通的HTML页面上,将一个XAML程序以对象的方式呈现.
    而仅仅是呈现么?
    当然不是,在呈现之后.NET Framework会讲传统的HTML DOM树与XAML程序生成的XAML DOM树结合.这样我们可通过JavaScript同时将两个DOM树联系起来,形成HTML,ASP.NET和XAML的交互.这样整个Web应用程序形成了一个可以相互通信的有机体系.
    同时,WPF/E仅仅是小型的客户端运行库,所以它可以轻松实现跨平台安装,并且对媒体文件的支持非常好,其内建的WMV,WMA,MP3解码器摆脱了以往需要安装Windows Media Player才可以播放Windows媒体文件的烦恼.
    WPF/E将于明年被集成到ASP.NET,.NET FxCL及CLR Managed Code中.

3.WPF/E的实现原理及工作机制基础

    首先来看一下下面这幅简单的WPF/E页面结构图

Simple WPF/E Structure


    如上图,在一个普通的HTML文档中,WPF/E通过object或embed对象元素,以ActiveX控件的形式,将XAML程序的一个实例插入页面中,参数以object或embed的param属性传入XAML程序.然后WPF/E建立XAML DOM树,通过HTML DOM树和XAML DOM树,我们可以轻松的取得页面中任何对象的ID属性,并可以随意在JavaScript中引用其对象.
    现在我们来模拟一下上面的过程.

    1.建立XAML元素并指定ID

1 < script type = " text/xaml "  id = " agControlXaml " >
2     < Canvas    xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation
4                        xmlns:x = http://schemas.microsoft.com/winfx/2006/xaml   >
5          < Rectangle x:Name = " myRect "  Fill = " Orange "  Width = " 100 "  Height = " 100 "  Canvas.Top = " 10 "  Canvas.Left = " 10 " />
6     </ Canvas >
7 </ script >
    
    2.在HTML页面中插入一个DIV做为XAML程序的容器

1 < div  class ="agHost"  id ="agControlHost" >
2 </ div >

    3.在页面中插入一个object/embed元素.用来承载ActiveX控件.并由该ActiveX控件负责调用XAML程序

1 < object  id ="AgCtrl1"  height ="312px"  width ="354px"  codebase ="xcpctrl.cab#version=0,0,3,0"
2               classid ="CLSID:32C73088-76AE-40F7-AC40-81F62CB2C1DA" >
3     < param  name ="SourceElement"  value ="agControlXaml"   />
4     < param  name ="BackgroundColor"  value ="White"   />
5 </ object >

    这样就可以生成一个简单的WPF/E页面了.完整代码如下: 

IE6+
 1 < html  xmlns ="http://www.w3.org/1999/xhtml" >
 2 < head >
 3 </ head >
 4 < body >
 5 < script  type ="text/xaml"  id ="agControlXaml" >
 6        <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 7                        xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml >
 8            <Rectangle x:Name="myRect" Fill="Orange" Width="100" Height="100" Canvas.Top="10" Canvas.Left="10"/>
 9        </Canvas>
10
</ script >
12 < div >
13     < object  id ="AgCtrl1"  height ="312px"  width ="354px"  
                          codebase
="xcpctrl.cab#version=0,0,3,0"  
                          classid
="CLSID:32C73088-76AE-40F7-AC40-81F62CB2C1DA" >
14         < param  name ="SourceElement"  value ="agControlXaml"   />
15         < param  name ="BackgroundColor"  value ="White"   />
16     </ object >
17 </ div >
18 </ body >
19 </ html >

FF

 1 < html  xmlns ="http://www.w3.org/1999/xhtml" >
 2 < head >
 3 </ head >
 4 < body >
 5      < script  type ="text/xaml"  id ="agControlXaml" >
 6        <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
 7            <Rectangle x:Name="myRect" Fill="Orange" Width="100" Height="100" Canvas.Top="10" Canvas.Left="10"/>
 8        </Canvas>
 9    
</ script >
10      < div >
11          < embed  id ="AgCtrl1"  height ="312px"  width ="354px"  SourceElement ="agControlXaml"  BackgroundColor ="White"  type ="application/xcp-plugin" />
12      </ div >
13 </ body >
14 </ html >

    效果:
            IE Sample            FF Sample

    随着CTP的发布,通常该加载过程会被封装在一个JavaScript方法中, 当页面被加载时,浏览器通过object的classid属性或embed的pluginspage来找到特定类型的ActiveX控件,创建控件实例,并指定该ActiveX控件的ID,由该ActiveX控件寻找param中name为SourceElement的script XAML元素,或param中name为Source的XAML程序地址参数,ActiveX控件在容器元素中创建XAML程序的一个实例.

    具体如下:
    调用方法:

 1 new agHost("wpfeControl1Host",// 容器元素ID
 2                                                             //(用来放置WPF/E ActiveX控件的HTML元素常用<div>)
 3                       "wpfobj",                    // 我们创建的WPF/E ActiveX控件的ID
 4                       "900",                          // 宽度
 5                       "710",                          // 高度
 6                       "#ffB42600",               // 背景色
 7                          null,                             // SourceElement (Scrpt标记名,包含XAML)
 8                       "mainPage.xaml",      // Source XAML源文件地址
 9                       "false",                          // 是否无窗口
10                      "24",                              // 最大祯率
11                       null);                             // OnError事件 (方法名--无括号)

    封装的源代码(aghost.js):

  1    var  hosts   =   new  Object();
  2    function  agHost(hostElementID, id, width, height, backgroundcolor, sourceelement, source, windowlessmode, framerate, errorhandler)  {
  3    var hostElement = document.getElementById(hostElementID);
  4    var innerHTML;
  5//assign error handler
  6    if(errorhandler == null{
  7    errorhandler = "aghost_errorhandler";
  8    }

  9    
 10//IE detection
 11    if((navigator.appVersion.indexOf('MSIE') != -1)) {   
 12    try 
 13        var WPFE = new ActiveXObject("AgControl.AgControl.0.8");
 14        innerHTML = '<object id="'+id+'" width="'+width+'" height="'+height+'" classid="CLSID:32C73088-76AE-40F7-AC40-81F62CB2C1DA">';
 15      if (sourceelement != null{
 16          innerHTML += ' <param name="SourceElement" value="'+sourceelement+'" />';
 17      }

 18      if (source != null{
 19          innerHTML += ' <param name="Source" value="'+source+'" />';
 20      }

 21      if (framerate != null{
 22          innerHTML += ' <param name="MaxFrameRate" value="'+framerate+'" />';
 23      }

 24      if (errorhandler != null{
 25          innerHTML += ' <param name="OnError" value="'+errorhandler+'" />';
 26      }

 27      if (backgroundcolor != null{
 28          innerHTML += ' <param name="BackgroundColor" value="'+backgroundcolor+'" />';
 29      }

 30      if (windowlessmode != null{
 31          innerHTML += ' <param name="WindowlessMode" value="'+windowlessmode+'" />';
 32      }

 33      innerHTML += '<//object>';
 34      }

 35        catch(e) {   
 36        innerHTML =  '<div width="'+width+'" height="'+height+'" >'; 
 37        innerHTML += 'You must install "WPF/E" (codename) December 2006 CTP to view this page: ';
 38        innerHTML +=  '<A href="http://go.microsoft.com/fwlink/?LinkID=77792&clcid=0x409">Get "WPF/E!"</A>';
 39        innerHTML += '</div>'
 40        }
     
 41    }

 42
 43    //FF/Windows detection
 44    else if((window.GeckoActiveXObject && navigator.userAgent.indexOf('Windows') != -1)) {   
 45      innerHTML = '<embed id="'+id+'" width="'+width+'" height="'+height+'" pluginspage="http://go.microsoft.com/fwlink/?LinkID=77792&clcid=0x409';
 46         if (source != null) {
 47             innerHTML += '" Source="'+source;
 48         }
 49         if (sourceelement != null) {
 50          innerHTML += '" SourceElement="'+sourceelement;
 51         }
 52         if (framerate != null) {
 53             innerHTML += '" MaxFrameRate="'+framerate;
 54         }
 55         if (errorhandler != null) {
 56             innerHTML +='" OnError="'+errorhandler;
 57         }
 58         if (backgroundcolor != null) {
 59             innerHTML += '" BackgroundColor="'+backgroundcolor;
 60         }
 61         if (windowlessmode != null) {
 62             innerHTML += '" WindowlessMode="'+windowlessmode;
 63         }
 64      innerHTML += '" type="application/ag-plugin"/>';
 65      }

 66
 67    //MAC detection
 68      else if(navigator.userAgent.indexOf("Macintosh"!= -1){
 69        if(navigator.userAgent.indexOf("Firefox/1.5.0.8"!= -1 || navigator.userAgent.indexOf("Safari"!= -1){   
 70          innerHTML = '<embed id="'+id+'" width="'+width+'" height="'+height+'" pluginspage="http://go.microsoft.com/fwlink/?LinkID=77793&clcid=0x409';
 71         if (source != null) {
 72             innerHTML += '" Source="'+source;
 73         }
 74         if (sourceelement != null) {
 75          innerHTML += '" SourceElement="'+sourceelement;
 76         }
 77         if (framerate != null) {
 78             innerHTML += '" MaxFrameRate="'+framerate;
 79         }
 80         if (errorhandler != null) {
 81             innerHTML +='" OnError="'+errorhandler;
 82         }
 83         if (backgroundcolor != null) {
 84             innerHTML += '" BackgroundColor="'+backgroundcolor;
 85         }
 86         if (windowlessmode != null) {
 87             innerHTML += '" WindowlessMode="'+windowlessmode;
 88         }
 89      innerHTML += '" type="application/ag-plugin"/>';
 90
 91        //Disable Safari caching
 92          // For more information, see http://developer.apple.com/internet/safari/faq.html#anchor5 
 93      innerHTML += "<iframe style='visibility:hidden'/>";
 94      }

 95      else {     
 96        innerHTML =  '<div width="'+width+'" height="'+height+'" >'; 
 97        innerHTML += 'You must be running Firefox 1.5.0.8 to view "WPF/E" content on this page.  ';
 98        innerHTML +=  '<A href="http://go.microsoft.com/fwlink/?LinkID=78984&clcid=0x409">Visit the "WPF/E" product site for more details.</A>';
 99        innerHTML += '</div>'        
100        }
        
101  }
  
102    hostElement.innerHTML = innerHTML;
103  }

104    function  aghost_errorhandler(line, col, hr, string)  {
105    if(line !=0 && col !=0)
106    {
107      var str = "("+line+","+col+"): "+string+"/n";
108      str += "HRESULT: "+hr;
109      alert(str);
110    }

111  }
  

    通过封装,简化了页面调用XAML的过程,使得页面代码更加清晰,分离了设计和实现代码.所以,我们看到的WPF/E页面的源代码通常是下面这样的: 

 1 <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
 2 < HTML >< HEAD >< TITLE > "WPF/E" CTP(December 2006 < TITLE >
 3 < script  type ="text/javascript"  src ="js/aghost.js
 4 </HEAD>
 5 <BODY>
 6     <DIV id=" wpfeControl1Host" style ="width:900; height:710; background:White" >
 7        <SCRIPT type="text/javascript">
 8    new agHost("wpfeControl1Host",   // hostElementID (HTML element to put WPF/E 
 9                                     // ActiveX control inside of -- usually a <div>)
10                          "wpfobj",             // ID of the WPF/E ActiveX control we create
11                          "900",                // Width
12                          "710",                // Height
13                          "#ffB42600",          // Background color
14                          null,                 // SourceElement (name of script tag containing xaml)
15                          "mainPage.xaml"// Source file
16                          "false",              // IsWindowless
17                          "24",                 // MaxFrameRate
18                          null);                // OnError handler (method name -- no quotes)
19        
</ SCRIPT >
20      </ DIV >
21 </ BODY ></ HTML >

    同时WPF/E支持事件模型,该模型通过JavaScript实现.事件的声明在XAML元素中.当声明某事件时,预定义的事件以属性的方式写在XAML元素的属性集中,并将一个JavaScript函数作为事件处理方法赋值给事件.

1 < Canvas  xmlns ="http://schemas.microsoft.com/client/2007"
2                 xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
3                 Loaded ="javascript:onLoaded"   >
4      < TextBlock  x:Name ="myTextBlock"   />
5 </ Canvas >

    当事件被触发时,窗体会自动调用JavaScript函数

1 function  onLoaded(sender)  {
2// 设置文本内容为当前日期
3sender.FindName("myTextBlock").Text = Date();
4}

    CTP中的预定义时间包括如下几个:

    下面是几个简单的事件:

 1 /* XAML */
 2 < Canvas
 3                    xmlns ="http://schemas.microsoft.com/client/2007"
 4                    xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml" >
 5     < Ellipse  x:Name ="e1"  MouseMove ="javascript:e1Move"
 6                    MouseEnter ="javascript:e1Enter"  MouseLeave ="javascript:e1Leave"
 7                    MouseLeftButtonDown ="javascript:e1Down"  MouseLeftButtonUp ="javascript:e1Up"
 8                    Height ="100"  Width ="100"  Canvas.Left ="80"  Canvas.Top ="30"
 9                   Stroke ="Black"  StrokeThickness ="2"  Fill ="LightBlue" />
10   </ Canvas >
11

 1 /* JavaScript */
 2 function  e1Enter(sender, args)  {
 3sender.stroke = "red";
 4}

 5
 6 function  e1Leave(sender, args)  {
 7sender.stroke = "black";
 8}

 9
10 function  e1Down(sender, args)  {
11sender.fill = "Green";
12}

13
14 function  e1Up(sender, args)  {
15sender.fill = "LightBlue";
16}

17
18 function  e1Move(sender, args)  {
19sender.fill = "yellow";
20}

    从程序员的角度来说,如何取得HTML及XAML文件中的对象是很关键的.HTML DOM树和XAML DOM树可以使我们方便的取得页面中的任何一个对象.

    上图显示了一个WPF/E页面的DOM结构.当XAML文件被加载到页面时.我们可以获取标准的DOM树取得XAML对象的ID.
    通过JavaScript取得XAML中对象实例引用的具体实现方法如下:

 1 < script type = " text/javascript " >
 2      //  先创建一个WPF/E ActiveX控件.
 3      new  agHost( " agControl1Host " // HostElementID
 4                             " ag6 " ,                        //  WPF/E ActiveX control ID
 5                             " 300px " ,                    //  Width
 6                             " 300px " ,                    //  Height
 7                             " #D6D6D6 " ,            //  BackgroundColor
 8                             null ,                          //  SourceElementID
 9                             " myxaml.xaml " ,      // The XAML uri
10                             " false " ,                     //  IsWindowless
11                             " 30 " ,                         //  MaxFrameRate
12                             null                            //  OnError handler. 
13                            );
14 </ script >

    通过下面的JavaScript.我们可以取得XAML对象

1 var  ag6  =  document.getElementById( " ag6 " );

    接下来.试一下取得XAML内的子对象


    想取得XAML内的子对象需要用到XAML元素的FindName(“strName”)方法,如:

 1 function  onLoaded(sender)  {
 2    // 取得XAML根元素 
 3    var control = document.getElementById("WpfeControl1");
 4    // 获得特定子对象的引用 
 5    var object = control.findName("myTextBlock");
 6    if (object != null{
 7        alert(object.ToString() + " found");
 8    }

 9}

10

    同样,我们也可以动态的通过JavaScript在XAML中创建子对象,具体方法如下:

1 /* XAML */
2 < Canvas  Width ="300"  Height ="300"
3                  xmlns ="http://schemas.microsoft.com/client/2007"
4                  xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
5                  Background ="Transparent"
6                  MouseLeftButtonDown ="javascript:createEllipse" >
7      < TextBlock  Text ="click for circle" ? FontSize ="40" />
8 </ Canvas >
9

1 /* JavaScript */
2 function  createEllipse(sender, args)  {
3    var agControl = document.getElementById("ag7");
4    var e = agControl.createFromXaml('<Ellipse Height="200" Width="200" Fill="Blue"/>');
5    var canvas = sender;
6    canvas.children.Add(e);
7}

4.WPF/E参考资源

SDK文档
http://msdn2.microsoft.com/en-us/library/bb188266.aspx

Channel9对WPF/E项目经理的采访视频
http://channel9.msdn.com/showpost.aspx?postid=263358

WPF/E开发中心
http://msdn2.microsoft.com/en-us/asp.net/bb187358.aspx

开发工具

VS2005 Express
http://msdn.microsoft.com/vstudio/express/
Expression
http://www.microsoft.com/products/expression/en/default.mspx

PS:   系列内容简介 

  • Chapter I The history background, aim, nature and mechnism basic of WPF/E
  • Chapter II Focusd on XAML and animation presetation of WPF/E
  • Chapter III Hosting a XAML App in a HTML page
  • Chapter IV Encapsulated Java Script in WPF/E
  • Chapter V Understanding work behind pages
  • Chapter VI Develop and implemented WPF/E projects on VS2005
  • Chapter VII Demo projects and Questions review

      12.07.2006
    KennethByron

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值