【原文地址】Silverlight Tutorial Part 1: Creating "Hello World" with Silverlight 2 and VS 2008
【原文发表日期】 Friday, February 22, 2008 5:57 AM
这是8个系列教程的第一部分,这系列示范如何使用Silverlight 2的Beta1版本建造一个简单的Digg客户端应用。这些教程旨在按顺序阅读,帮着解释Silverlight的一些核心编程概念。
使用 VS 2008 创建一个新的Silverlight 应用
我们来开始我们的Digg应用的开发,先选择Visual Studio 2008 中的文件->新项目菜单项,使用新项目对话框创建一个“Silverlight Application” (注:你需要在Beta1发布后,下载和安装 VS 2008的Silverlight工具才能得到这个支持):
我们将该项目命名为“DiggSample”。在点击OK按钮后, Visual Studio 会显示另外一个对话框,允许我们选择我们是否只要创建一个Silverlight应用项目,或者还要加一个服务器端的ASP.NET Web项目到包含Silverlight应用的解决方案里去:
在这个例程里,我们将选择还要添加一个ASP.NET Web Application 项目到解决方案里去,并将它命名为“DiggSample_WebServer”。在点击OK之后,Visual Studio 会为我们创建一个解决方案,里面包含一个Silverlight 客户端应用和一个ASP.NET web 服务器端应用:
如果我们做一次编译的话, Visual Studio 会自动把编译好的 Silverlight 应用拷贝到我们的web服务器项目中去,不需要手工的步骤或配置。VS为我们创建的默认的web服务器项目包含一个ASP.NET网页和一个静态的 HTML网页,我们可以用来运行和测试其中的Silverlight应用。
注: Silverlight应用可用于任何web服务器(包括Linux上的Apache),宿主于静态HTML文件或者任何服务器端生成的网页(包括PHP, Java, Python, Ruby等等)中。在这个Digg样例中,我们不会写任何服务器端的代码,而是将使用Silverlight的跨域networking功能,来直接访问Digg服务的API。我选择创建一个ASP.NET web服务器项目,主要是想获得自动的部署,并且使用它内置的web服务器来做测试。
理解Silverlight应用里都有些什么
在默认情形下,一个新建的Silverlight应用项目包含一个Page.xaml和一个 App.xaml文件,以及与它们相关的后台(code behind )类文件(可以用VB, C#, Ruby 或Python来编写):
XAML文件是XML文本文件,可以用来用声明的方式指定 Silverlight 或 WPF应用的用户界面。XAML还可更广泛地用来用声明的方式代表.NET对象。
App.xaml 文件一般用来声明譬如象画刷和样式对象这样可在整个应用中共享的资源。App.xaml的后台Application类可用来处理应用级的事件,象Application_Startup, Application_Exit 和Application_UnhandledException。
Page.xaml 文件,在默认情形下,是在应用激活时装载的起始的UI控件。在其中,我们可以使用UI控件来定义我们的用户界面,然后在Page的后台代码类里处理它们的事件(详见后文)。
在我们编译DiggSample项目时,在默认情形下,Visual Studio 会把代码和XAML标识编译进一个标准的 .NET 程序集文件中,然后把它和任何静态的资源(象图片或我们想要包含的静态文件)包装进硬盘上一个叫做“DiggSample.xap”的文件中去:
“.xap”文件(其音发作“zap”)使用标准的 .zip压缩算法来减小客户端下载的大小。一个“hello world”.NET Silverlight 应用(用VB或C#编写的)其大小大概为4KB。
注: Beta1版本中的一些控件是在程序集中实现的,如果使用这些控件的话,这些程序集会重新发布于应用的 .xap 文件中(会增加应用的大小,超出4KB的基底大小)。在Digg应用中使用的所有控件将会在Beta2版和最终版的核心Silverlight下载包中,这意味着完成的应用的总下载大小大概只在6-8KB范围内(所以是非常小,下载起来非常快)。
要宿主和运行一个Silverlight 2 应用,你可以把标签加到任何标准的HTML页面中(不需要 JavaScript )并将其指向 .xap 文件。Silverlight然后就会自动下载这个.xap 文件,生成实例,将其宿主于浏览器中的HTML网页中。这是跨浏览器(Safari, FireFox, IE等),跨平台(Windows, Mac, and Linux)工作的。
HTML和ASP.NET测试网页(内含标签,其引用指向我们的Silverlight 应用)是在我们创建项目时为我们自动添加的,这意味着我们只要点击F5编译,运行和测试就可以了。
学习如何添加控件和处理事件
现在我们的Digg应用什么都不做,在运行它时,只会调出一个空白的网页。
我们可以打开项目中的Page.xaml文件来改变它,往里面加些内容:
我们将开始改变网格的背景颜色,在其中声明一个Button控件。我们将给按钮一个"x:Name"属性,设置其值为“MyButton“,这会允许我们在后台代码类中用编程的方法引用它。我们还将设置它的Content, Width 和 Height 属性:
当我们运行应用时,我们的按钮将会在网页的中间出现,内含”Push Me“内容文字,象下面这样:
要给我们的按钮加行为的话,我们可以给它加一个"Click"事件处理函数。我们可以在源码视图中通过输入事件的名称来做:
然后就会提示我们在我们的后台代码类中该使用的事件处理函数:
然后我们可以输入一个要用的新事件处理方法的名称,或者只要点击回车键,使用默认的命名约定来命名事件处理方法:
然后VS就会自动地在我们的后台代码类文件中创建一个占位的事件处理函数实现。我们可以使用这个事件处理函数在按钮被点击时,用新的消息更新它的内容:
在做完上面的改动后,我们可以重新运行应用,再次点击按钮,现在它的内容就会被更新为“Pushed!”的消息:
【原文地址】Silverlight Tutorial Part 2: Using Layout Management
【原文发表日期】 Friday, February 22, 2008 5:55 AM
这是8个系列教程的第2部分,这个系列示范如何使用 Silverlight 2 的 Beta1 版本来创建一个简单的 Digg 客户端应用。这些教程请依次阅读,将有助于您理解 Silverlight 的一些核心编程概念。
理解布局管理
Silverlight 和 WPF 都支持一种灵活的布局管理系统,能让开发者和设计师轻松的定位 UI 上的控件。该布局系统对显式指定坐标的控件支持固定的定位模型;除此之外,还支持一种更为动态的定位模型,控件和布局能随着浏览器的大小改变而自动改变其大小和方位。
在 Silverlight 和 WPF 中,开发者可以用布局面板来协调包含在其中的控件的位置和大小。Silverlight Beta1 中内建的布局面板包括在 WPF 中最常用的3种:
- Canvas
- StackPanel
- Grid
Canvas面板
Canvas 面板是一种很基础的布局面板,它支持对其中的控件采用绝对坐标定位。
你可以通过一种 XAML 特性--- "附加属性” 对 Canvas 中的元素进行定位。用附加属性,你可以指定控件相对于其直接父 Canvas 控件的上、下、左、右坐标的位置。附加属性很有用,因为它让父面板可以扩展其中包含的控件的属性集。Canvas 通过定义扩展属性 Top 和 Left, 就能定义其中 Button (或其他任何 UI 元素)的 Left, Top,而不需要真正向 Button 类中添加这个属性,或 修改 Button 类。
我们可以向 Canvas 容器中添加两个按钮,指定其距离 Canvas 左侧的距离为 50 像素,离上边的距离则分别为 50 像素和 150 像素。使用如下 XAML 语法即可完成(其中 Canvas.Top 和 Canvas.Left 都是附加属性的例子):
这些代码绘制的界面效果如下:
Canvas 适用于其中包含的 UI 元素比较固定的情形,但是如果你想向其中添加更多的控件,或者 UI 需要改变大小或能够移动,Canvas 显得不太灵活。这时,你不得不忙于手写代码来移动 Canvas 中的东西(这很痛苦)。应付这种动态的场景,更好的办法通常是使用其它带有相关功能的内建语义的布局面板,如 StackPanel 和 Grid。
StackPanel
StackPanel 是一种简单的布局面板,它支持用行或列的方式来定位其中包含的控件。StackPanel 常用于安排页面上的一个很小的 UI 部分。
例如,我们可以用下面的 XAML 标签在页面上垂直的排布3个按钮:
在运行时刻,StackPanel 会自动在一个垂直地堆叠(stack)中排列我们的按钮(【译注:这也是为什么叫 StackPanel 的原因】),如下所示:
同样,我们还可以把 Orientation 属性设置为 Horizontal 而不是 Vertical (默认值):
这会让 StackPanel 水平地排布3个按钮,如下图所示:
Grid面板
Grid 控件是最灵活的布局面板,它支持用多行和多列的方式排布控件。在概念上,它和 HTML 里的 Table (表格)类似。
不同于 Table 的是,你不需要将控件内嵌到行/列元素中,而是通过定义 和 属性来定义 Grid 的行和列。这两个属性需要定义在 标签内。这样之后,你就可以在其中的控件上,用 XAML 的“附加属性”语法指定它属于哪一行、哪一列。
比如,我们可以用如下语法定义3行3列的 Grid 布局,然后在其中放置4个按钮:
以上代码会按下图方式排布按钮:
除了支持绝对尺寸定义(如:Height="60"),Grid 的 RowDefinition 和 ColumnDefinition 控件还支持自动改变大小的模式(Height="Auto"),这样会根据其中内容的尺寸自动改变 Grid 或 Row 的尺寸(你也可以指定最大或最小尺寸限制)。
Grid 的 Row 和 ColumnDefinitions 还支持叫做 "Proportional Sizing" (按比例缩放)的特性。用这个特性,可以让 Grid 的行列按相对比例的方式排放(如:你可以指定第二行的尺寸为第一行的2倍)。
你会发现 Grid 提供了非常多的功能和灵活性 - 而它也许会成为你最终最常用的布局面板控件。
用布局面板排布我们的 Digg 页面
我们创建 Digg 例子的目标,是得到最终看起来像下图的页面:
要创建这种布局,我们首先添加一个其中包含两个 RowDefinition 的根级 Grid 面板。第一行的高度是 40 像素,而第二行则占据所有剩下的空间(Height="*"):
小技巧:注意上面我将 Grid 的 ShowGridLines 属性设置为 True. 这样我们在运行时就能轻易的看到其行列的分界线:
接下来,我们在刚才的根级 Grid 面板里,添加第二个 Grid 面板到第一行的位置,用它来排布页面顶部的行(页面头部)。我们在其中创建3列:分别容纳标题,搜索文本框,和搜索按钮:
完成了这些后,我们就得到了 Digg 搜索页面的基本布局,如下所示:
注:如果不用嵌套的 Grid,我们还可以用一个 2行3列的 Grid 来完成这个布局,配合使用 Grid 的 ColSpan/RowSpan 特性来合并多个列中的内容(和你在 HTML table 中的做法类似)。我不这么做,而是选择使用嵌套 Grid 的原因,是因为这样更便于学习和理解。
现在我们已经完成了布局,接下来要做的是向其中添加控件。
对头部的行,我们用内建的 控件(设置其 CornerRadius 为 10,以得到圆角效果)并在其中添加一些文本来创建标题。我们用内建的 控件来创建第二列的搜索文本框。并在第3列放置一个搜索 . 然后我们在第二行放一些占位文字,稍后我们会在这里显示搜索结果。
注:下面我会直接在控件中内嵌样式信息(FontSize, Colors, Margins 等)。在这个系列教程中,晚一点我会演示如何用 Styles 来提取、封装这些设定到一个独立的文件中(类似 CSS),以便于在整个应用程序中重用。
现在,让我们运行一下应用程序,就会显示出如下的界面:
动态改变应用程序的尺寸
你也许注意到了,在上面的 XAML 中我们的顶层控件设置成了固定的高度和宽度:
这样设置,我们的 Silverlight 应用程序会一直保持这个固定的尺寸。放大浏览器的尺寸会更明显:
虽然在某些场合下,将内嵌的应用程序固定在 HTML 页面的一个固定尺寸的区域内会很有用,但我们的 Digg 搜索程序不一样,我们宁愿它能自动随着浏览器而缩放,就像一个普通的 HTML 页面那样。
好消息是,这很容易实现。只要去除根控件上的 Width 和 Height 属性就行了:
这样,我们的 Silverlight 应用程序就会自动扩展(或收缩),以填满其嵌入的 HTML 容器。因为我们用来测试的 SilverlightTestPage.html 文件将 Silverlight 控件放置在一个 HTML
注意页面头部中的文字内容的尺寸是如何随着浏览器宽度而自动改变的:
当我们缩小浏览器尺寸时,带水印的文本框和搜索按钮会保持同样的尺寸,因为其 Grid 容器列的宽度是固定的。包含 "Digg Search" 标题的 控件却会自动调整尺寸,因为其 Grid 列的宽度设置成了 Width="*".
我们不需要编写一行代码就可以启用这个布局行为,Grid容器和布局系统会为我们自动调整大小或流动其中的任何东西。
【原文地址】Silverlight Tutorial Part 3: Using Networking to Retrieve Data and Populate a DataGrid
【原文发表日期】 Friday, February 22, 2008 5:54 AM
这是8个系列教程的第三部分,这系列示范如何使用Silverlight 2的Beta1版本建造一个简单的Digg客户端应用。这些教程旨在按顺序阅读,帮着解释Silverlight的一些核心编程概念。
使用Networking取回Digg故事
Silverlight 2 有内置的networking API,允许Silverlight客户端调用远程的REST, SOAP/WS*, RSS, JSON和XML HTTP服务。Silverlight 2还包含了内置的socket API (System.Net.Sockets),允许Silverlight客户端通过非HTTP协议来通信(对聊天服务等这样的场景非常理想)。
跨域网络访问
Silverlight 2应用在做网络调用时,始终可以回调到它们的“原始(origin)”服务器(意味着它们可以调用下载的应用来自的同域的URL)。Silverlight 2应用还可以做跨域网络调用(意味着它们可以调用与下载的应用来自的不同的域上的URL),只要远程的web服务器拥有一个XML策略文件,表明客户端是允许做这些跨域调用的。
Silverlight 2 定义了一个XML策略文件格式,允许服务器管理员精确地控制一个客户端应该有些什么访问权。Silverlight 2 也遵守默认的Flash跨域策略文件格式-这意味着你可以使用Silverlight 2 来调用web上已经允许Flash客户端跨域访问的任何现有的远程REST, SOAP/WS*, RSS, JSON 或 XML 端点(end-point )。
Digg.com有一套非常酷的通过HTTP通信的Digg APIs。因为他们有一个Flash跨域策略文件在他们的服务器上,我们可以直接从我们的Silverlight Digg 客户端应用中调用它们(而不要求我们通过我们的web服务器去访问他们的API)。
Digg.com 主题 Feed API
我们要允许终端用户使用我们的应用输入一个搜索主题(譬如,“Programming”),然后点击“搜索”按钮,从Digg.com取回符合条件的前N条故事:
我们可以使用Digg.com List Stories REST API feed API 来实现。它在URL中接受一个主题参数(譬如,GET /stories/topic/programming),然后返回一个匹配那个主题的XML格式的Digg故事集。点击这里看一下这个XML格式的例子。
使用 System.Net.WebClient 来异步调用Digg REST Feed
在上面的搜索按钮被点击之后,我们将处理它的Click事件,从WaterMarkTextBox控件中取回要搜索的主题字符串,然后启动一个发向Digg的网络调用,为那个主题取回相应的XML列表。
Silverlight 在 System.Net 命名空间下包含了WebClient辅助类(该类也在完整的.NET 框架下)。我们可以使用这个类从URL异步下载内容。异步下载Digg故事的好处是,在等待远程服务器的回复时,我们的UI不用阻塞或变得没有反应(允许我们拥有一个非常流畅的用户体验)。
通过WebClient类执行异步下载,我们要做的是注册一个DownloadStringCompleted事件处理方法(它将在请求的内容被下载之后被调用),然后调用WebClient.DownloadStringAsync(url) 辅助方法来开始下载:
使用上面的代码,我们现在就可以异步取回一个XML数据的字符串,内含有关用户想要的任何主题的Digg故事。
使用LINQ to XML把XML格式的Digg故事分析成Story类对象
至此,我们可以取回Digg故事数据的XML片段了,下一步将是对其进行分析(parse),并将它转换成我们可以操作和绑定到控件上的DiggStory对象。
我们将首先定义一个DiggStory类,该类拥有可以映射到来自Digg的XML内容上的属性(我们将利用C#新的 "自动属性"的特性来实现):
然后我们就可以使用LINQ (是内置于 Silverlight 2中的)和 LINQ to XML (是包含在我们的Silverlight 应用中的一个额外的库 )来轻松地分析和过滤从Digg返回的XML文档,使用下面的代码把它翻译成一个DiggStory对象序列:
注意上面,我们现在有了来自XML的我们可以操作的强类型的DiggStory对象。
在DataGrid控件中显示Digg故事
我们将使用新的 Silverlight DataGrid 控件来在我们的应用中显示Digg故事。要使用它,我们要引用Silverlight Data 控件程序集,然后把前面网页上的“Todo”文字替换成一个DataGrid控件声明:
DataGrid允许你明确地配置列的声明和显示类型(为取得最大的控制),或者,你也可以设置它的AutoGenerateColumns属性成true,让DataGrid对数据源使用反射,基于你的对象的定义,为你创建默认的列。
然后我们就可以更新我们的后台代码类,用编程的方法将DataGrid的ItemSource属性绑定到在点击搜寻按钮时从Digg取回的故事序列:
现在,运行我们的Silverlight应用,做一个搜索的话,我们将看到从Digg取回的实时主题故事数据的列表:
Silverlight的Datagrid支持你预期客户端网格控件应该拥有的所有的标准功能:双向原地编辑,选择,卷动,改变表列大小等等。它还支持自动流动的布局,意味着它可以动态地扩展或收缩来充满包含它的内容容器。DataGrid还拥有一个丰富的模板模型,允许你对显示和表列数据的编辑进行定制。我在将来会撰写更多的贴子,讨论如何使用DataGrid。
【原文地址】Silverlight Tutorial Part 4: Using Style Elements to Better Encapsulate Look and Feel
【原文发表日期】 Friday, February 22, 2008 5:53 AM
这是8个系列教程的第4部分,这个系列示范如何使用 Silverlight 2 的 Beta1 版本来创建一个简单的 Digg 客户端应用。这些教程请依次阅读,将有助于您理解 Silverlight 的一些核心编程概念。
使用 Style 元素更好地封装观感(Look and Feel)
WPF 和 Silverlight 支持一种 Style 机制,它允许我们把控件的属性值封装成可重用的资源。我们可以把这些样式声明保存在独立于页面的其他文件中,然后就可以在一个应用程序中跨控件和页面重用(甚至跨多个应用程序重用)。在做一些基本定制的场景下,概念上类似于在 HTML 中重用 CSS.
注:除了定义基本属性设置(Color, Font, Size, Margins 等),WPF 和 Silverlight 里的样式还可以被用来定义和重用控件模板(Control Templates) - 控件模板可以带来超级丰富的皮肤功能,以及改变控件结构的功能(并支持目前 HTML 中的 CSS 做不到的定制场景)。我会在这个系列的第7部分讨论控件模板。
对我们的 Digg 例程而言,我们会在项目的 App.xaml 文件中定义样式。这使得该样式可以在整个应用程序中,被跨页面、跨控件地重用:
首先让我们来为 Digg 页面的 控件(以及其中的 标题)封装样式:
我们可以在 App.xaml 文件中,用下列标签来创建两个 Style 元素,分别封装 和 的设置信息,这些设置在前面是内联定义的:
注意上述代码中,我们是如何为每个 Style 元素赋予一个唯一的 "Key" 值的。接下来我们就可以更新我们的 > 和 控件,让它们用这些 keys 来引用对应的样式定义。我们会使用一种叫做“标签扩展”(markup extensions) 的 XAML 特性来完成它。标签扩展用于非字面量的值需要被设置时(另一个适用场景是绑定表达式)。
我们还可以对 Page.xaml 文件中的其它控件也做类似的分离样式的处理,这样做之后,文件内容会变成类似这样:
用这种方式封装样式设定,可以让开发者更好的关注应用程序的行为语义,并且还可以让我们跨控件/页面的重用样式。
注:Beta1 中需要注意的一个问题是,当你输错样式名称和属性定义时,其错误信息不是很清楚(它会引发异常,但不告诉哪里设置不对)。这会在 Beta2 中得到改进。同时,如果你在加载样式时看到错误消息,请一定仔细查看拼写错误。
【原文地址】Silverlight Tutorial Part 5: Using the ListBox and DataBinding to Display List Data
【原文发表日期】 Friday, February 22, 2008 5:51 AM
这是8个系列教程的第5部分,这个系列示范如何使用 Silverlight 2 的 Beta1 版本来创建一个简单的 Digg 客户端应用。这些教程请依次阅读,将有助于您理解 Silverlight 的一些核心编程概念。
用 ListBox 和 DataBinding 显示我们的 Digg 故事
前面我们使用了 DataGrid 控件来显示我们的 Digg 故事。当我们想用多列的格式来显示内容时,它很适合。然而对我们的 Digg 应用程序而言,也许我们想稍微改变一下页面的显示方式,让它看起来不太像网格,而更像一个列表。好消息是,这很容易实现 - 并且我们不需要改变任何程序代码。
首先我们将 DataGrid 控件替换为 控件。我们保持原有的控件名称 ("StoriesList"):
重新运行一下程序,搜索故事,ListBox 会显示搜索结果如下:
你可能觉得奇怪 - 为什么每个条目都变成了 "DiggSample.DiggStory"? 这是因为我们把 DiggStory 对象绑定给了 ListBox(而绑定的默认行为会调用这些对象的 ToString() 方法)。如果我们想改用每个 DiggStory 对象的 Title 属性来显示条目,可以设置 ListBox 的 DisplayMemberPath 属性:
这样做之后的效果如下:
如果要每次显示不止一个值,或者定制每个条目的布局,我们可以覆盖 ListBox 控件的 ItemTemplate,并提供一个自定义的 DataTemplate. 然后在这个 DataTemplate 内,定制每个 DiggStory 对象如何显示。
例如,我们可以用 DataTemplate 同时显示 DiggStory 的 Title 和 NumDiggs 值,如下所示:
在 DataTemplate 中,我们可以绑定 DiggStory 对象中我们所需的任何公共属性。注意上面我们是如何用 {Binding 属性名} 语法,配合两个 TextBlock 控件来完成这一点的。
设置了上述 DataTemplate 后,我们的 ListBox 会显示如下:
让我们再进一步,修改 DataTemplate 的定义如下。其中使用了两个 StackPanel - 一个用于水平地堆叠行,另一个用来垂直地堆叠文本块(TextBlock)。
上述 DataTemplate 会使我们的 ListBox 用如下方式显示条目:
我们在 App.xaml 文件中定义如下的 Style 规则(注意如何使用 LinearGradientBrush 来获得 DiggPanel 上的好看的渐变背景效果):
关于 ListBox 有一点值得注意 - 即使我们定制了其条目的显示方式,它仍然会提供悬浮以及选中状态的语义,不管你使用的是鼠标还是键盘(上/下方向键,Home/End,等):
ListBox 还支持完整的流式改变大小的功能 - 并在需要的时候提供内容的自动卷动功能(注意当窗口变小时,水平滚动条是如何出现的):
【原文地址】Silverlight Tutorial Part 6: Using User Controls to Implement Master/Detail Scenarios
【原文发表日期】 Friday, February 22, 2008 5:50 AM
这是8个系列教程的第六部分,这系列示范如何使用Silverlight 2的Beta1版本建造一个简单的Digg客户端应用。这些教程旨在按顺序阅读,帮着解释Silverlight的一些核心编程概念。
理解用户控件
Silverlight和WPF的一个根本性的设计目标是允许开发人员能够轻松地把UI功能封装成可重用的控件。开发人员可以通过从一个现有的Control类(或Control基类或象TextBox, Button等这样的控件)继承而来实现新的自定义控件。或者,他们也可以创建可重用的用户控件,这既方便使用XAML标识文件来组成一个控件的UI,而且实现起来也容易。
对我们的Digg应用,我们想要实现一个主从表场景,在其中,应用允许终端用户搜索一个主题,填充一个跟该主题相关的故事的列表,然后允许他们从中选择一个故事来调出细节。例如,从列表中选择一个下述故事:
会调出这个故事的细节视图:
我们将建造一个StoryDetailsView用户控件来实现这个细节视图,在从ListBox中选出一个故事时,我们将显示这个视图。
创建StoryDetailsView 用户控件
我们开始在Visual Studio中的DiggSample项目上右击,选择“添加新项”,这会调出一个新项的对话框,我们将选择UserControl模板,将我们要建的新控件命名为“StoryDetailsView”:
这会往我们的DiggSample项目中添加一个以此为名的新UserControl:
使用用户控件建造一个基本模式对话框
我们将使用我们的StoryDetailsView控件有效地显示一个包含故事细节的对话框。当我们的故事细节用户控件显示时,我们将要它出现在网页的其他内容的上方,确保终端用户在关闭细节视图之前无法操作页面上的其他东西。
有几种不同的方式我们可以实现这个模式对话框似的行为。对这个特定的场景,我们将先从打开StoryDetailsView.xaml用户控件着手,往其中加入如下XAML内容:
上面第一个控件是配置成Stretch以占据屏幕上剩下的空间,它的背景填充颜色是有点透明的灰色(因为它的Opactity 是 .765,你还可以看到一点它后面的东西 )。第二个控件然后将重叠在这个Rectangle控件之上,在屏幕上占据一个固定的宽度。它具有一个蓝色的背景色,内含一个Close(关闭)按钮。
在显示时,我们的StoryDetailsView用户控件目前将显示象下面这样的UI:
我们可以在该用户控件的后台代码文件中实现“CloseBtn_Click”事件处理方法,在按下按钮时,关闭按钮的事件处理函数将把用户控件的Visibility属性设成为“Collapsed”,这会导致它从屏幕上消失,用户将返回到下面的内容:
显示我们的StoryDetailsView控件
让我们的StoryDetailsView用户控件出现在屏幕上的一个简单的方式是把它加在Page.xaml文件的底部,然后将其默认的Visibility属性设成Collapsed(意味着在应用装载时是不可见的):
然后我们在Page.xaml的后台代码类中处理ListBox 控件的SelectionChanged事件:
当用户选择列表中的一个特定故事时,我们可以使用ListBox 的 SelectionChanged事件将 ShowDetailsView 用户控件的Visibility属性设成“Visible”:
这会导致我们的模式用户控件对话框出现,在用户点击它的“Close(关闭)”按钮时,它就会消失,用户就可以随意选择另一个故事,重复这个过程。
把故事数据传入我们的StoryDetailsView用户控件
最终我们想要我们的StoryDetailsView用户控件显示跟终端用户在故事ListBox中选择的故事有关的详细信息。
在我们的ListBox的SelectionChanged事件处理函数中(在我们的page的后台代码类中),我们可以通过ListBox的SelectedItem属性获取对应于用户所选择的ListBox中的条目行的那个DiggStory数据对象。
我们可以用来把这个 DiggStory 对象传入我们的StoryDetailsView用户控件的一个做法是,就在显示用户控件之前,把用户控件上的DataContext属性设置成所选择的DiggStory故事对象:
然后我们在我们的用户控件内编写代码,使用DataContext来显示结果,或者我们也可以使用数据绑定表达式绑定其值。
例如,我们可以象下面这样更新StoryDetailsView的XAML,使用数据绑定表达式来来显示所选故事的标题:
现在,当用户点击列表中的一个故事时:
我们ListBox的事件处理函数就会处理其选择,将用户控件的DataContext设成所选择的DiggStory对象,然后显示用户控件:
注意上面因为我们添加的数据绑定表达式的缘故,DiggStory的标题是如何出现在用户控件之中的。
完成我们的用户控件的布局
我们上面的例子演示了如何编写一个简单的主从表对话框工作流程的基本知识。我们可以往用户控件中加更多的控件,和数据绑定表达式来完成StoryDetailsView的显示:
我们可以通过更新StoryDetailsView的 控件,使之拥有下列内容,来如上图般显示:
之后,不需要任何代码改动。因为我们使用了数据绑定来从DataContext中取得数值,我们不需要编写任何额外的代码。
【原文地址】Silverlight Tutorial Part 7: Using Control Templates to Customize a Control's Look and Feel
【原文发表日期】 Friday, February 22, 2008 5:48 AM
这是8个系列教程的第七部分,这系列示范如何使用Silverlight 2的Beta1版本建造一个简单的Digg客户端应用。这些教程旨在按顺序阅读,帮着解释Silverlight的一些核心编程概念。
如何定制控件的观感(Look and Feel)
WPF和Silverlight编程模型中一个强大无比的功能,就是能够完全定制所使用的控件的观感(Look and Feel )。这允许开发人员和设计师对控件的界面以微妙和戏剧性的方式进行精雕细琢,促成无比的灵活性以创建出恰如所愿的用户体验。
在这篇教程里,我们将看一下你可以定制控件的几种方式,然后在结尾使用这些技术对我们的Digg应用的用户界面润色一下。
定制控件的内容
在这个系列的第一部分里,我们在页面上加了一个简单的按钮控件,示范了如何把它的内容设成一个自定义的“Push Me!”文字字符串。然后我们连接了一个Click事件处理函数,在它被点击时执行一些代码:
这导致按钮在浏览器里象下面这么显示:
关于按钮控件,也许会让你感到惊奇的一件事情是,它的Content属性,不必是象“Push Me!”这样简单的字符串。实际上,我们可以把Content属性设成我们想要的任何形状或控件序列:
譬如,我们可以嵌入一个StackPanel,内含 和 控件:
这会导致我们的按钮在运行时看上去会象下面这样。注意,它依然保留同样的功能行为(按它的话,按钮会陷下去,点击事件处理函数也会象以前一样触发):
我们也可以使用形状控件(象下面这样的Ellipse控件)来在按钮里面创建自定义的矢量图像:
注意上面我是怎么使用一个偏移RadialGradientBrush来加一个非常好看的反射式光泽来填充Ellipse控件的:
我们甚至可以搞些古怪,在按钮内嵌入可交互的象日历这样的控件:
在上面的例子中,日历控件是完全可以交互的,意味着终端用户可以前后翻月历,在日历里选择一个日期,然后按其中的按钮,触发Click事件处理函数:(注:我不清楚这是否会是一个好的用户体验,但它确实展示了你所能做之灵活性!)
我上面概述的这些类型的内容定制场景不仅对按钮控件有效,同样地对其他继承自ContentControl基类的其他控件也工作。
使用控件模板定制控件
为Silverlight 和 WPF所用的控件模型,所允许之定制,远远超出控件内部的内容。它还允许你用你想要的任何东西完全替换控件的视觉树(visual tree),同时还保持控件的同样行为。
例如,我们不想要我们的按钮拥有一个默认的长方形的按钮的外观,而是要它们有一个象下面这样的自定义的圆形按钮外观:
我们可以这么做,在App.xaml文件中创建一个“RoundButton”样式,在其中,我们将改写按钮的Template属性,提供一个内含一个Ellipse控件和一个TextBlock的ControlTemplate来替换按钮的默认长方形外观:
然后我们可以让引用这个Style资源来使用这个“RoundButton”的观感:
在控件模板中融入内容
你也许会注意到一件事情,在上面的“RoundButton”控件模板中,按钮的大小,以及显示在其中的内容,都是写死的(总是“Push Me!”)。
好消息是,WPF 和 Silverlight也能让我们对这些设置进行定制。我们可以在控件模板中通过使用 {TemplateBinding ControlProperty} 的标识扩展句法 (markup extension syntax) 来绑定到控件的属性来实现。这允许我们的控件模板随着外部开发人员设置在控件的属性而改变:
注意上面,不是加 控件来显示内容,而是使用控件。那会允许我们不光让按钮显示文字字符串,而且可以显示任何自定义的内容(就象我们在本教程早先时候做的那样)。
然后,我们可以在下面的三个按钮上使用上面的Style(每个按钮都有不同的内容和属性设置):
上面的按钮然后就会象下面这样显示(对了,缩小的日历控件还支持翻页和日期选择!):
如果我们想进一步,我们还可以往ControlTemplate中加故事板动画(来处理象“hover(悬浮)”,"focus(得到焦点)","pushed(按下)"这样的按钮状态)。这个能力允许我们创建非常优美的用户交互场景,同时还能促成HTML中不能实现的场景。
在应用中操作控件的开发人员可以对所有这些样式和控件交互定制保持一无所知,他们还可以依然如故地处理控件的事件和操作控件的对象模型,而让设计师另外使用样式和模板对控件的观感进行精雕细琢和定制。
对我们的Digg应用进行润色(Polishing up)
至此,我们讨论了控件模板工作原理的一些基础知识,让我们来在几个地方用它们来给我们的Digg应用的UI加些点缀。
目前,应用中一个明显需要一些加工的地方是我们用户控件的“Close”(关闭)按钮:
好消息是,这对我们(或者跟我们协作的设计师)来说很容易修正。我们可以在App.xaml文件中的 "CloseButton" 样式中加一个ControlTemplate,加一些自定义的矢量形状来提供一个比较好看的关闭按钮(注:比我更称职的设计师大概还会加悬浮和动画行为到矢量图像形状上去,让它更好看些):
重新运行我们的应用的话,按钮看上去象下图:
我们应用中我认为应该润色的第二个地方是ListBox的外圈界面。如果你仔细看的话,你可以看到Beta1版本中的ListBox有一个嵌套的边框,作为它的默认外观(注:我们还没最后决定要发布的默认皮肤,所以在最终版之前,这非常有可能会改变):
我们可以除去这个,通过定制它的控件模板来给与ListBox一个平的边框(flat border)。下面是一个以自定义模板样式化了的,有平的边框的ListBox :
注意我们是如何除去ListBox的边框控件的,我们只用了Silverlight中的控件(该控件允许其中任何内容做卷动),将一个控件嵌入其中,该控件负责ListBox中实际条目的显示(它使用了我们在第四部分中创建的 来显示这些条目)。
下面是它现在给与我们的List更为平直的外观:
比较酷的是,为了做这些观感的改动,我们不用更改应用中的任何代码,或者修改实际的控件的XAML标识。这种代码、设计的分离能在Silverlight和WPF应用中促进开发人员和设计师之间的流畅的工作流程。Expression Blend 和所有的 Expression Studio产品把这些控件设计功能提到了又一个高度,将提供方便这种定制的丰富的设计师工具集。
【原文地址】Silverlight Tutorial Part 8: Creating a Digg Desktop Application using WPF
【原文发表日期】 Friday, February 22, 2008 5:46 AM
这是8个系列教程的第八部分,这系列示范如何使用Silverlight 2的Beta1版本建造一个简单的Digg客户端应用。这些教程旨在按顺序阅读,帮着解释Silverlight的一些核心编程概念。
使用WPF创建一个Digg桌面应用
这最后一个教程的目的与前面7个有点不同。我们实际上不将在本教程里在Silverlight中运行代码,而是将使用WPF和.NET 3.5。我们将拿我们编写的,在浏览器中运行于Silverlight中的现有的Digg应用代码,重用它来以Windows桌面应用的方式运行。
随Silverlight发布的是一套与.NET 框架完整版本相兼容的API子集。这么做的目的就是允许开发人员学习一个共同的编程模型和工具集,能够在RIA web应用,丰富的Windows桌面应用和Office解决方案之间重用学到的技能,代码和内容。
下面是我采取的步骤,来重用我们现有的Digg Silverlight应用代码(运行于浏览器中),来建造一个Windows桌面应用的版本(运行于浏览器外)。
第一步:创建一个新的WPF桌面应用
我们先开始使用VS 2008创建一个新的WPF桌面应用。我们将之命名为“DiggDesktopSample”:
这会在VS中创建一个项目,内含2个文件,一个App.xaml,一个 Window.xaml:
注意,这个项目的结构与我们在本系列教程的第一篇里创建的Silverlight应用的结构非常类似(拥有一个App.xaml 文件,一个 Page.xaml 文件)。
第二步:把现有的Digg应用的代码拷贝进WPF应用中
我们将把现有的DiggApplication Silverlight代码拷贝/粘贴进我们的新DiggDesktopSample Windows项目中:
目前在Beta1版本中,这个拷贝/粘贴是个手工步骤,我们最终将有一个自动化的方式来在不同项目类型间移动代码。
第三步:修正几个问题
我需要做2个改动,才能使我们现有的Digg例程代码被成功编译:
1) Silverlight Beta1 XAML定义的命名空间 xmlns:URL与完整的WPF桌面版本不同。我需要改动我拷贝进新项目的XAML文件指向完整WPF的定义。这是在发布前我们还正在研究的东西。
2) 我需要把控件改成,把 控件改成。这2个控件是Silverlight Beta1 版本中新有的,不存在于完整的WPF版本中(但我们会在将来添加它们)。但我不用改动跟这些控件相关的任何代码,也不用改动网络调用,LINQ to XML, 或数据绑定代码。
做完这些小改动后,项目就可以干净地编译了。
第四步:把Digg应用宿主与桌面窗口中
然后我打开桌面项目中的Windows1.xaml 文件(它是在应用启动时装载的默认窗口)。
我把窗体的标题改成“Digg Desktop Version”,扩大了窗口默认的宽度和高度。
然后我把来自前面的Digg Silverlight 项目中的Page.xaml 用户控件加到窗口中作为根控件。这在窗口装载时,会载入该控件并使之可见。我不用改动Page类的代码,或者对其中的东西改名。因为是从UserControl继承而来,它是完全可以宿主于任何WPF窗口或控件中的。
我改动的最后一样东西是因为Digg REST API 服务器会试着检测是否是非浏览器/服务器在访问它,有时会在这些情形下给予一个拒绝访问的回复(大概是防止自动脚本访问他们的服务)而导致的一个问题。我通过让网络访问经过一个代理URL解决了这个问题(没有代码变动,只是URL改动)。
第五步: 运行应用
然后,我能够运行我们新的DIgg桌面应用。所有的功能都跟Silverlight的版本一样工作,应用的行为也完全一样:
在从列表中选择一个故事后,细节用户控件显示为:
浏览器版本和桌面版本间有几个细微的样式区别。这主要是因为WPF在默认情形下继承了基于当前用户选择的操作系统主题的默认样式(字体,颜色,卷动条等等),而Silverlight 则有一个我们在所有操作系统上都使用的默认主题。如果我们要使得桌面版本和浏览器版本绝对一致,我们可以在我们的样式和控件模板中更明确地指定,否则的话,桌面版本会基于用户的OS主题做稍微的变动。
结语
我们会在将来推出在Silverlight和WPF项目之间共享代码的更详细的注意事项和推荐的最佳实践指南。我认为你会发现你在建造Silverlight应用时学到的技能和知识可以很好地转移到完整的WPF的项目中去。我们也致力于一个非常高的兼容水平,能在解决方案间促进好的代码重用,促进控件,内容和代码的轻松共享和利用。
希望本文对你有所帮助,