作为系列的开篇,写的也许简单了些,笼统了些,如果大家有意见或者建议,请通过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
概要:
- WPF/E开发背景及开发目标
- WPF/E的实质和前景
- WPF/E的实现原理及工作机制基础
- 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](https://i-blog.csdnimg.cn/blog_migrate/e4870363fff6659b28025debf6dee97a.gif)
如上图,在一个普通的HTML文档中,WPF/E通过object或embed对象元素,以ActiveX控件的形式,将XAML程序的一个实例插入页面中,参数以object或embed的param属性传入XAML程序.然后WPF/E建立XAML DOM树,通过HTML DOM树和XAML DOM树,我们可以轻松的取得页面中任何对象的ID属性,并可以随意在JavaScript中引用其对象.
现在我们来模拟一下上面的过程.
1.建立XAML元素并指定ID
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
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
<
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
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
<
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
>
效果:
![FF Sample](https://i-blog.csdnimg.cn/blog_migrate/88e3695a449ca55e1edfdd7790db9f30.jpeg)
随着CTP的发布,通常该加载过程会被封装在一个JavaScript方法中, 当页面被加载时,浏览器通过object的classid属性或embed的pluginspage来找到特定类型的ActiveX控件,创建控件实例,并指定该ActiveX控件的ID,由该ActiveX控件寻找param中name为SourceElement的script XAML元素,或param中name为Source的XAML程序地址参数,ActiveX控件在容器元素中创建XAML程序的一个实例.
具体如下:
调用方法:
1
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
new agHost("wpfeControl1Host",// 容器元素ID
2
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
//(用来放置WPF/E ActiveX控件的HTML元素常用<div>)
3
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"wpfobj", // 我们创建的WPF/E ActiveX控件的ID
4
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"900", // 宽度
5
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"710", // 高度
6
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"#ffB42600",
// 背景色
7 null, // SourceElement (Scrpt标记名,包含XAML)
8
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"mainPage.xaml", // Source XAML源文件地址
9
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"false", // 是否无窗口
10
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
"24", // 最大祯率
11
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
null); // OnError事件 (方法名--无括号)
封装的源代码(aghost.js):
1
var
hosts
=
new
Object();
2
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
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![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if(errorhandler == null)
{
7
errorhandler = "aghost_errorhandler";
8
}
9
10
//IE detection
11![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if((navigator.appVersion.indexOf('MSIE') != -1))
{
12![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
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![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if (sourceelement != null)
{
16
innerHTML += ' <param name="SourceElement" value="'+sourceelement+'" />';
17
}
18![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if (source != null)
{
19
innerHTML += ' <param name="Source" value="'+source+'" />';
20
}
21![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if (framerate != null)
{
22
innerHTML += ' <param name="MaxFrameRate" value="'+framerate+'" />';
23
}
24![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if (errorhandler != null)
{
25
innerHTML += ' <param name="OnError" value="'+errorhandler+'" />';
26
}
27![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if (backgroundcolor != null)
{
28
innerHTML += ' <param name="BackgroundColor" value="'+backgroundcolor+'" />';
29
}
30![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
if (windowlessmode != null)
{
31
innerHTML += ' <param name="WindowlessMode" value="'+windowlessmode+'" />';
32
}
33
innerHTML += '<//object>';
34
}
35![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
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![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
43
//FF/Windows detection
44![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
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![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
67
//MAC detection
68![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
else if(navigator.userAgent.indexOf("Macintosh") != -1)
{
69![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
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![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
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![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
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
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
function
aghost_errorhandler(line, col, hr, string)
{
105
if(line !=0 && col !=0)
106![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
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
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
<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
// 设置文本内容为当前日期
3
sender.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
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
function
e1Enter(sender, args)
{
3
sender.stroke = "red";
4
}
5
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
6
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
function
e1Leave(sender, args)
{
7
sender.stroke = "black";
8
}
9
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
10
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
function
e1Down(sender, args)
{
11
sender.fill = "Green";
12
}
13
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
14
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
function
e1Up(sender, args)
{
15
sender.fill = "LightBlue";
16
}
17
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
18
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
function
e1Move(sender, args)
{
19
sender.fill = "yellow";
20
}
从程序员的角度来说,如何取得HTML及XAML文件中的对象是很关键的.HTML DOM树和XAML DOM树可以使我们方便的取得页面中的任何一个对象.
![](https://i-blog.csdnimg.cn/blog_migrate/d711290ff56de49a58b161b9bd1c07aa.png)
上图显示了一个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内的子对象
![](https://i-blog.csdnimg.cn/blog_migrate/4d2c830a0b8d1326b83b379127fdd1df.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a0df3a7e9c3435903ecf7eb2f7fc7dad.png)
想取得XAML内的子对象需要用到XAML元素的FindName(“strName”)方法,如:
1
function
onLoaded(sender)
{
2
// 取得XAML根元素
3
var control = document.getElementById("WpfeControl1");
4
// 获得特定子对象的引用
5
var object = control.findName("myTextBlock");
6![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
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
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
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