Silverlight魔幻银灯
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2 Silverlight最佳实践

2.1 第一个SiIverIight

2.1.1 创建第一个Silverlight应用程序

在当前的情况下,我们可以使用很多工具创建一个Silverlight应用,这里我分别介绍使用VS 2005、VS 2008和Expression Blend创建Silverlight应用的过程,并针对不同工具创建的应用所具有的特性进行介绍。

下面首先介绍使用VS 2005进行Silverlight的开发。

当你安装好Silverlight 1.0的SDK之后,它会自动附加一个Silverlight 1.0用于VS 2005开发的模板,这个模板目前只有在C#工程中才有体现。所以要创建Silverlight 1.0的应用,首先要从“文件”菜单中选择新建项目命令,出现如图2-1所示的“新建项目”对话框。

选择Silverlight之后就可以创建一个Silverlight 1.0的应用了。不过,这里要提醒大家注意几个问题,第一,这里创建的Silverlight 1.0应用是一个单纯的XAML应用,而且这个应用基于VS 2005的内嵌浏览器和内嵌的轻量级Web应用服务器(官方名称叫做Cassini),所以如果要把这个项目发布到一个Web应用当中,则最好在解决方案中建立一个新的ASP.NET项目,并为ASP.NET项目添加Silverlight项目的引用(此过程使用VS 2008更方便,在下面我们还会详细介绍)。第二,由于是轻量级应用,这个应用不能进行跨域访问,或者说对跨域的http访问有安全警告,在访问本地资源的时候也有若干安全限制。(在第5章介绍Downloader对象的时候还会做详细介绍。)

图2-1 “新建项目”对话框

成功建立项目之后,可以通过解决方案资源管理器看到如图2-2所示的若干文件

图2-2 建立工程之后的文件

2.1.2 Silverlight 1.0版本项目文件介绍

项目中共包含5个文件,我们下面来一一介绍它们。

这几个工程文件的关系如图2-3所示。

图2-3 项目文件的关系

1.Default.html

Default.html文件是Silverlight应用的宿主文件,文件的内容如下所示:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.
w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>SilverlightJSApplicationDemo</title>
        <script type="text/javascript" src="Silverlight.js"></script>
        <script type="text/javascript" src="Default.html.js"></script>
        <script type="text/javascript" src="Scene.xaml.js"></script>
    </head>
    <body>
        <div id="SilverlightPlugInHost">
            <script type="text/javascript">
                createSilverlight();
            </script>
        </div>
    </body>
    </html>

这里需要注意以下几点。

首先文件中包含了3个JS文件,其中Silverlight.js是Silverlight赖以运行的基础,没有这个文件Silverlight应用将无法启动。鉴于这个文件的重要性,我们会在下面详细介绍。Default.html.js文件是用于创建Silverlight应用的文件,也是把记录Silverlight显示内容的XAML文件引入到项目中的实体文件。同时,如果我们在页面中还有自己的业务逻辑,一般也写在这个Default.html.js中,在VS 2005中IDE贴心地把这个文件和Default.html合并成一个显示位置,让我们可以一眼看出它是针对Default.html的业务逻辑载体,这种合并显示的方式酷似ASP.NET中的后置cs或者vb后缀的业务逻辑代码。而Scene.xaml.js则是Scene.xaml的逻辑文件,在Silverlight 1.0的项目中我们使用JS文件来记录业务逻辑,所以记录Scene.xaml业务逻辑的后缀文件就是Scene.xaml.js。不要小看这个文件,这个文件是整个Silverlight引用的灵魂所在,没有这个文件Silverlight只是一个普通的页面呈现效果;而有了这个文件,Silverlight就可以焕发出动态的魅力。不过按照一般的设计思路,业务逻辑文件的引用应该写在页面呈现文件当中,也就是应该写在Scene.xaml中。确实如此,让宿主文件引用包含文件的业务逻辑确实有点不合逻辑,所以在Silverlight 1.1中,对XAML文件的后置逻辑代码引用被写到了Silverlight文件当中。这一变更使Silverlight看起来更像是一个完全独立的应用结构,而不再是一个寄托于ASP.NET的附加的小附件。

2.Silverlight.js

这个文件是整个Silverlight文件的重要组成部分,它会判断用户所使用的操作系统以及浏览器版本,并根据用户的系统配置建议用户下载适当的Silverlight版本。不过由于系统自带的文件对内容进行了混淆处理,十分不便于阅读,笔者在这里专门整理了一套重新排版的内容,并对关键字进行了解说。(重新排版的文件内容放在附录A当中)

作为整个Silverlight启动项目的第一步,Silverlight.js需要获取的是用户计算机所安装的一切配置包及响应的操作系统,以及系统已经具有的.NET运行时环境内容,根据这些条件,Silverlight的运行时环境可以判断自己需要下载和安装哪个版本的安装包以便保证Silverlight系统能正常运行。用户可以使用如下代码来获取内容(实际上Silverlight.js使用的也是类似代码):

    <script language="javascript">
        alert(window.navigator.userAgent);
    </script>

在笔者的操作系统中,使用Internet Explorer 7时获取的内容如下:

    Mozilla/4.0(compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322;.NET CLR 3.0.04506.30;.NET CLR 3.0.04506.648;.NET CLR 3.5.21022;MS-RTC LM 8; InfoPath.2)

而使用FireFox 2.0打开以后看到的内容就是:

    Mozilla/5.0(Windows;U;Windows NT 5.1;zh-CN;rv:1.8.1.11)Gecko/20071127 Firefox/2.0.0.11

在这里可以使用indexOf(关键字)的方法判断返回结果是否包含指定字符串,从而得知系统中包含哪些配置。

接下来系统开始判断用户是否已经安装了Silverlight的运行时环境。

    if(Silverlight.ua.Browser == 'MSIE')
            {
                control = new ActiveXObject('AgControl.AgControl');
            }
            else
            {
                if(navigator.plugins["Silverlight Plug-In"])
                {
                    container = document.createElement('div');
                    document.body.appendChild(container);
                    container.innerHTML= '<embed type=
                        "application/x-Silverlight" />';
                    control = container.childNodes[0];
                }
            }

这段代码首先判断浏览器是否是IE,如果不是,就尝试判断是否是支持Silverlight插件的其他浏览器(FireFox、Safari都是这种浏览器),尝试建立一个新的插件对象实例。下面的代码就是创建Silverlight实例所需要的一些代码。值得一提的是,如果判断用户没有安装Silverlight运行时环境,系统会分别指向不同的网站提供Silverlight运行时环境下载,以便用户找到这个应用。

3.Default.html.js

这个文件是创建Silverlight实例的应用文件,内容如下:

    function createSilverlight()
    {
        var scene = new SilverlightJSApplicationDemo.Scene();
        Silverlight.createObjectEx({
            source: 'Scene.xaml',
            parentElement: document.getElementById('SilverlightPlugInHost'),
            id: 'SilverlightPlugIn',
            properties: {
                width: '400',
                height: '400',
                background:'#ffffffff',
                isWindowless: 'false',
                version: '0.8'
            },
            events: {
    onError: null,
                onLoad: Silverlight.createDelegate(scene,scene.handleLoad)
            },
            context: null
        });
    }
    if(!window.Silverlight)
        window.Silverlight = {};
    Silverlight.createDelegate = function(instance,method){
        return function(){
            return method.apply(instance,arguments);
        }
    }

下面的参数传递给Silverlight.createObject和Silverlight.createObjectEx方法,其中一些参数对应OBJECT或EMBED标签的输出结果,一些参数对应Silverlight对象模型的属性,所以,可以在运行时代码中得到这些初始化参数的值。

(1)source——对XAML内容的文件的引用,对应Silverlight插件的Source属性。

(2)parentElement——对包含createSilverlight方法调用的HTML文件中块级元素的引用,在实例化后成为Silverlight插件的宿主元素。

(3)id——HTML DOM中对实例化的Silverlight插件的唯一标识。

(4)properties——Silverlight插件实例化属性的集合,参见表2-1。

(5)events——能够在初始化时设置的Silverlight插件的事件集合,参见表2-2。

(6)initParams——用户定义的初始化参数集合。

(7)context——作为参数传给OnLoad事件处理器的唯一标识,可以被同一页面中的多个Silverlight插件共享。这个值唯一地标识了哪个插件被加载,表2-2列出了能够作为Silverlight插件初始化参数(在properties参数内)定义的参数。

表2-1对基本属性做了更加详细的说明。

表2-1 Silverlight初始化基本参数

表2-2列出了能够作为Silverlight插件初始化事件定义的参数。

表2-2 Silverlight初始化参数

Silverlight.js文件中含有Silverlight运行时版本检测的IsInstalled方法,在调用CreateObject或CreateObjectEx方法进行初始化Silverlight控件之前,它可以用来验证特定版本的Silverlight运行时的时候已经安装。如果指定的版本或者与当前Silverlight运行时兼容的版本已经安装,IsInstalled方法则返回true,否则返回false。下面的HTML代码显示了如何调用IsInstalled方法。

    <div id="pluginHost" >
      <script type="text/javascript">
        // Determine whether the specified Silverlight runtime version is
        // installed
        var version = "3.0"; //这一版本并不存在
        var isInstalled = Silverlight.isInstalled(version);
        // Create the plug-in if the specified Silverlight runtime version is
        // installed
        if(isInstalled)
        {
            var parentElement = document.getElementById("pluginHost");
            createSilverlight();
        }
        else
        {
            alert("Silverlight runtime version"+version+"not installed.");
        }
      </script>
    </div>

Silverlight插件的版本号用下面格式的字符串表示:

    versionMajor.versionMinor.buildNumber.revisionNumber

一般来说,你只需要给CreateObject或者IsInstalled函数传递versionMajor. versionMinor即可。所安装的Silverlight完整的build+revision版本号可能等于或者也可能不等于函数参数指定的版本。如果更复杂的检测成功了,那么,更简单的检测也必须是成功的。例如,如果IsVersionSupported("1.0.01820.55")返回的是true,那么,IsVersionSupported("1.0.01820")和IsVersionSupported("1.0")也一定是返回true。相反,如果更简单的检查失败了,那么,更复杂的检查也必然失败。例如,IsVersionSupported("1.0")返回false,那么IsVersionSupported("1.0.01820")和IsVersion Supported("1.0.01820.55")也一定返回false。

initParams初始化参数允许你指定用户定义的参数值,这些参数值可以在运行时通过访问插件的InitParams属性得到。下面JavaScript例子显示了如何在CreateSilverlight.js中的用户定义的CreateSilverlight方法中指定initParams参数值。

    function createSilverlight()
    {
        Silverlight.createObject(
            "plugin.xaml",            // 源代码名称
            parentElement,            // DOM对象所引用的DIV层的名称
            "myPlugin",               // 全局唯一的plug-in id
            {                          // Plug-in属性
                width:'600',          // 以像素方式显示plug-in的宽度
                height:'200',         // 以像素方式显示plug-in的高度
                version:'1.0'          // Plug-in版本
            },
            { },                      // No events defined-use empty list
            "param1,param2");        // 内建参数值
    }

要在运行时得到initParams初始化参数值,需要使用插件的InitParams属性。下面的JavaScript例子显示了如何使用InitParams属性得到参数值。

    function onLoaded(sender,eventArgs)
    {
        // 获取一个plug-in的引用对象.
        var plugin = sender.getHost();
        // 从初始化参数中获取参数值.
        var params = plugin.initParams.split(",");
        // 显示参数值.
        var msg = "Params: ";
        for(var i = 0; i < params.length; i++)
        {
            msg += params[i] + " ";
        }
        alert(msg);
    }

(1)使用InplaceInstallPrompt参数

如果指定版本的Silverlight插件没有安装,inplaceInstallPrompt初始化参数决定是否出现安装对话框。它的默认值是false。也就是说,如果Silverlight.js文件中版本检查返回false,那么将会出现如图2-4所示的Silverlight标准安装对话框。

图2-4 Silverlight标准安装对话框

当单击Silverlight标准安装对话框时,就会出现Silverlight下载页面。

(2)设置InplaceInstallPrompt参数为true

当inplaceInstallPrompt参数设置为true时,如果指定版本的Silverlight插件没有安装,那么将会出现如图2-5所示的Silverlight本地安装对话框。

当在Silverlight本地安装对话框的上半部分单击时,Silverlight就开始下载。Silverlight本地安装对话框的下半部分提供指向Silverlight许可条款和Silverlight隐私信息的链接。你不用修改Silverlight.js来改变提示文字、颜色和链接的位置,或者去除这些链接。

图2-5 Silverlight本地安装对话框

注意 Silverlight支持的所有浏览器,除了Internet Explorer外,都需要重启浏览器才能使Silverlight正常工作。你应当在你的网站中(而不是在安装对话框上)提醒用户需要重启浏览器。

(3)使用OnLoad事件

OnLoad初始化参数指定OnLoad事件调用的事件处理器函数。OnLoad事件发生在Silverlight插件中的XAML内容完全加载完毕之后。

任何UIElement派生的类,如Canvas、TextBlock或Rectangle,加载后也会触发OnLoad事件。只读属性ISilverlightoaded是在Onload事件之前设置的,标识Silverlight插件是否已经加载。

注意 JavaScript提供了一套允许你在页面中响应页面改变的事件,其中包括页面的OnLoad事件。你可以在同一页面中同时使用Silverlight插件的OnLoad事件和页面的OnLoad事件,在这种情况下,OnLoad事件发生在页面的OnLoad事件之前。

(4)使用OnLoad事件的context参数

context参数表示用户定义的唯一标识,可以作为参数传递给OnLoad事件处理器,也可以由同一页面上的多个Silverlight插件共用。OnLoad context参数与context初始化参数的值一致。

下面的HTML例子说明了如何在同一页面中定义两个Silverlight插件宿主元素。

    <div id="pluginHost" >
      <script type="text/javascript">
        // Create a variable that references the HTML element that hosts the
        // plug-in
        var parentElement = document.getElementById("pluginHost");
        // Create variables that contain unique identifiers for the plug-in
        var name = "mySilverlightPlugin_1";
        var context = "context_1";
        // Initialize and create the plug-in
        createSilverlight();
      </script>
    </div>
    <div id="pluginHost2" >
      <script type="text/javascript">
        // Create a variable that references the HTML element that hosts the
        // plug-in
        var parentElement = document.getElementById("pluginHost2");
        // Create variables that contain unique identifiers for the instance
        var name = "mySilverlightPlugin_2";
        var context = "context_2";
        // Initialize and create the plug-in
        createSilverlight();
      </script>
    </div>

下面的JavaScript例子说明了用户定义的CreateSilverlight.js文件中相应的CreateSilverlight方法。请注意这个方法使用同一变量parentElement、name、context的不同值,使用变量的新值替换掉旧值来重新定义现有的JavaScript。

    <div id="pluginHost" >
      <script type="text/javascript">
        // Create a variable that references the HTML element that hosts the
        // plug-in
        var parentElement = document.getElementById("pluginHost");
        // Create variables that contain unique identifiers for the plug-in.
        var name = "mySilverlightPlugin_1";
        var context = "context_1";
        // Initialize and create the plug-in
        createSilverlight();
      </script>
    </div>
    <div id="pluginHost2" >
      <script type="text/javascript">
        // Create a variable that references the HTML element that hosts the
        // plug-in
        var parentElement = document.getElementById("pluginHost2");
        // Create variables that contain unique identifiers for the instance.
        var name = "mySilverlightPlugin_2";
        var context = "context_2";
        // Initialize and create the plug-in
        createSilverlight();
      </script>
    </div>

下面的JavaScript例子显示了被两个插件实例使用的相应的OnLoad事件处理器函数,context参数对应于插件的context初始化参数的值。

    function onLoad(plugin,userContext,sender)
    {
        alert(plugin.id + " : " + userContext + " : " + sender.toString());
    }

Silverlight.js文件生成的OnLoad事件签名与为OnLoad记载的事件签名是不同的,OnLoad直接在插件级反应事件签名。Silverlight.js OnLoad包装了插件级的OnLoad,并添加了以下特性:

如果多个插件实例宿主在同一个HTML页面中,加载实例的事件处理器将会有潜在的冲突。Silverlight.js文件中的CreateObject和CreateObjectEx增加了一个可选的context初始化参数。通常,这个参数设定为一个单独的字符串,context值作为事件处理器参数被传回,这样,就能简化编写检测那个插件的OnLoad被处理的处理器逻辑。

不使用通用的sender对象,Silverlight.js里面的OnLoad作为事件处理器的第一个参数值传递实际的Silverlight插件实例。这可以省去对sender.GetHost()的调用,并且允许你为一个变量来保存返回值,很容易访问到Silverlight插件实例。

2.1.3 第一个Silverlight实例

我们还要稍稍提及一下XAML,虽然第一个Demo的XAML文件可能稍微有点复杂,但是它包含了所有的XMAL文件基本特征。

    <Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http:
//schemas.microsoft.com/winfx/2006/xaml">
      <Canvas.Resources>
        <Storyboard x:Name="mouseEnter">
          <ColorAnimation Duration="00:00:00.25" To="#3DFFFFFF" Storyboard.
TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(Solid ColorBrush.Color)" />
        </Storyboard>
        <Storyboard x:Name="mouseDown">
          <ColorAnimation Duration="00:00:00.2" To="#22000000" Storyboard.
TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(Solid ColorBrush.Color)" />
        </Storyboard>
        <Storyboard x:Name="mouseUp">
          <ColorAnimation Duration="00:00:00.2" To="#3DFFFFFF" Storyboard.
TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(Solid ColorBrush.Color)" />
        </Storyboard>
        <Storyboard x:Name="mouseLeave">
          <ColorAnimation Duration="00:00:00.25" To="#00FFFFFF" Storyboard.
TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(Solid ColorBrush.Color)" />
        </Storyboard>
      </Canvas.Resources>
      <Canvas Width="120" Height="44">
        <Rectangle StrokeThickness="4" RadiusX="17" RadiusY="36" Width="120"
Height="44" Stroke="#46000000">
          <Rectangle.Fill>
            <LinearGradientBrush EndPoint="0.5,-0.409"
StartPoint="0.5,1.409">
            <GradientStop Color="#FFD3BE46" Offset="0.242"/>
            <GradientStop Color="#FFD79B03" Offset="0.333"/>
            </LinearGradientBrush>
          </Rectangle.Fill>
        </Rectangle>
        <TextBlock Width="67" Height="23.2" Canvas.Left="29" Canvas.Top="10"
Foreground="#FFEFEFEF" Text="Click Me" />
        <Rectangle StrokeThickness="4" RadiusX="16" RadiusY="36" Width="104"
Height="32" Canvas.Left="8" Canvas.Top="1.3">
          <Rectangle.Fill>
            <LinearGradientBrush EndPoint="0.5,-0.409"
StartPoint="0.5,1.409">
            <GradientStop Color="#00FFFFFF" Offset="0.13"/>
            <GradientStop Color="#FFFFFFFF" Offset="1"/>
            </LinearGradientBrush>
          </Rectangle.Fill>
        </Rectangle>
        <Rectangle RadiusX="17" RadiusY="36" Width="114" Height="38"
Fill="#00FFFFFF" x:Name="highlightEllipse" Canvas.Left="3" Canvas.Top="3"/>
      </Canvas>
    </Canvas>

这个略微有一点复杂的XAML文件包含两个对象内容,一个用于显示动画效果的资源文件中的Storyboard;另一个用于绘制矩形、文本框等对象的Canvas。这两个部分的内容我们会在后面介绍动画和矩形绘制的章节进行更进一步的描述,所以这里只是走马观花地看一下整体结构。一个XAML文件首先由一对<Canvas></Canvas>进行封装,表示整个XAML文件只是一个大的Canvas对象,这一点在后面使用VS 2008建立Silverlight 1.1应用的时候会有更详细的说明,其中的对象事件处理模型会直接说明,这个XAML文件的一切内容都继承自Canvas这个基类。对于这个XAML文件的格式,我们在第1章XAML文件内容中已经进行了详细介绍,这里不再赘述。最后需要说明的一点是,通常出于设计的考虑,我们会在大的Canvas上封装若干小的Canvas,以便达到方便访问的效果。

对应的事件处理模型函数保存在Scene.xaml.js文件中,文件内容如下:

    if(!window.SilverlightJSApplicationDemo)
        window.SilverlightJSApplicationDemo = {};
    SilverlightJSApplicationDemo.Scene = function()
    {
    }
    SilverlightJSApplicationDemo.Scene.prototype =
    {
        handleLoad: function(plugIn,userContext,rootElement)
        {
            this.plugIn = plugIn;
            // Sample button event hookup: Find the button and then attach event
            // handlers
            this.button = rootElement.children.getItem(0);
            this.button.addEventListener("MouseEnter",Silverlight.
                  createDelegate(this,this.handleMouseEnter));
            this.button.addEventListener("MouseLeftButtonDown",Silverlight.
                  createDelegate(this,this.handleMouseDown));
            this.button.addEventListener("MouseLeftButtonUp",Silverlight.
                  createDelegate(this,this.handleMouseUp));
            this.button.addEventListener("MouseLeave",Silverlight.
                  createDelegate(this,this.handleMouseLeave));
        },
        // Sample event handlers
        handleMouseEnter: function(sender,eventArgs)
        {
            // The following code shows how to find an element by name and call
            // a method on it
            var mouseEnterAnimation = sender.findName("mouseEnter");
            mouseEnterAnimation.begin();
        },
        handleMouseDown: function(sender,eventArgs)
        {
            var mouseDownAnimation = sender.findName("mouseDown");
            mouseDownAnimation.begin();
        },
        handleMouseUp: function(sender,eventArgs)
        {
            var mouseUpAnimation = sender.findName("mouseUp");
            mouseUpAnimation.begin();
            // Put clicked logic here
            alert("clicked");
        },
        handleMouseLeave: function(sender,eventArgs)
        {
            var mouseLeaveAnimation = sender.findName("mouseLeave");
            mouseLeaveAnimation.begin();
        }
    }

这里的结构也比较简单,除了注册几个事件处理函数之外,并没有任何特别的内容。关于JS如何和XAML对象打交道的内容我们会在后面的章节进行更详细的介绍。

应用程序运行的时候我们会看到如图2-6所示的效果。

图2-6 第一个Silverlight的Demo

鼠标划过按钮时会看到按钮颜色变化的动画效果,单击按钮会得到一个弹出的Click警告对话框。关于这一运转的内在逻辑的介绍会成为后面章节的最重要内容。使用VS 2008创建Silverlight 2应用

VS 2008在安装了Silverlight 2插件之后同样可以创建Silverlight应用,创建过程基本和VS 2005下的操作相同,创建之后的项目文件如图2-7所示。

图2-7 Visual Studio 2008创建Silverlight 2应用

在Silverlight 2中应用程序的结构发生了根本变化,程序结构向WPF应用程序结构靠拢,所以在创建工程的时候,有了一个新的选项,即是否创建一个ASP.NET应用网站作为Silverlight的宿主文件,如果选择创建,则在Silverlight工程当中包含两个项目:一个是Silverlight工程,而另一个是ASP.NET工程,其中ASP.NET工程包含对Silverlight工程的项目引用。如果选择不创建,也可以把Silverlight工程添加到一个现有的ASP.NET网站之中,或者在Silverlight编译的时候由系统自动生成一个HTML页面来作为宿主。在下面的例子中,我们选择随同Silverlight同时创建一个ASP.NET网站的方式来进行开发。

工程被创建之后的项目结构如图2-8所示。

可以看到图2-8中的工程包含两个项目文件,其中名为silverlight2web的项目文件中包含几个基本文件,如Default.aspx、silvergliht2TestPage.apsx和silverlight2 TestPage.html,这里的silverlight2TestPage.aspx文件就是运行时的Silverlight的宿主文件。需要额外注意的是两个文件夹Bin和ClientBin,根据以往的经验,Bin目录是ASP.NET运行时若干动态链式链接库文件目录,而ClientBin则是全新的目录,后者将是Silverlight被编译之后所生成的XAP文件的存放地点。关于这个使用zip压缩格式进行打包的文件,我们在下面的章节还会进行详细的剖析。

图2-8 Silverlight 2 VS 2008项目文件图

Silverlight工程的内容则和1.0有了明显的变化,项目文件包括两个XAML文件和两个CS文件。其中前置文件分别是App.xaml和Page.xaml,后置文件分别是App.xaml.cs和Page.xaml.cs。

App.xaml文件本身可以认为是整个Silverlight启动的主进程,如果你无法理解这个概念,则可以用Windows应用程序的概念理解,每个Windows应用程序都会有一个叫做main的函数,作为应用程序入口,里面会有一个Application.run()的方法调用,这样主进程启动之后,各个窗体窗口才会被实例化和绘制。用这种方法理解Silverlight会轻松很多,这个App.xaml文件和它的后置代码App.xaml.cs文件就是这个主进程文件,而Page.xaml文件及Page.xaml.cs文件则分别是窗体的样式文件和它的后置逻辑代码处理文件。

App.xaml文件的内容如下:

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/ xaml/
        presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="silverlight2.App"
        >
        <Application.Resources>
        </Application.Resources>
    </Application>

可以看出,这个使用Application标记记录的文件并没有对应用程序进行过多干预,而对Page的引用写在了后置页面App.xaml.cs文件中,其代码如下所示:

    private void Application_Startup(object sender,StartupEventArgs e)
        {
            this.RootVisual = new Page();
        }

这里创建了一个Page类的实例,并把它显示出来。对于Page页面的内容,我们可以看到如下所示的内容。

    <UserControl x:Class="silverlight2.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Grid x:Name="LayoutRoot" Background="White">
        </Grid>
    </UserControl>

应用程序的结构发生了很大变化,页面已经变成了一个使用UserControl标记记录的用户自定义控件,也就是说,一个应用中用户可以创建各种控件,并把这些控件加载到应用当中。

首先我们创建一个Silverlight 1.0的应用,Blend启动界面如图2-9所示,启动之后选择对应的Silverlight工程种类,如图2-10所示。然后进入程序设计界面,如图2-11所示。

图2-9 Expression Blend启动界面

图2-10 第一个Silverlight应用

图2-11 Expression Blend设计图示

项目结构和VS 2005创建的应用完全一致,所不同的是这里呈现了各种页面设计工具的元素,默认界面下没有我们熟悉的代码,所有XAML的内容都会被表示成一图形元素,这种所见即所得的方式非常适合美工开展工作。

Blend的功能十分丰富,下面我们分别介绍其中的几个重点功能。