数据绑定设计

创建用于 SharePoint 2010 的 Silverlight 4 Web 部件

Paul Stubbs

下载示例代码

Microsoft SharePoint 2010 提供了一个易于在其中自定义工具的业务协作平台,组织可以依托这个平台并实现成长。并且,在构建自定义 SharePoint 解决方案时,最好在前端使用 Silverlight。

Web 部件是大部分 SharePoint 解决方案的核心部分。目前,大部分开发人员都考虑在其 SharePoint 应用程序中使用 Silverlight,在 Web 部件中使用它似乎是一个确凿无疑的方向,而且 Web 部件是在 SharePoint 中创建 Silverlight 应用程序的最常见方式。但是 Web 部件并非唯一选择。

您也可以在菜单、导航、对话框、页面布局和母版页等可在其中放置对象标记的任何位置使用 Silverlight。这赋予了设计人员极大的灵活性,可以创造出如同集成到 SharePoint 中的绝佳体验。使用此方法,Silverlight 就好像是对 SharePoint 的自然扩展。

不论是 SharePoint 平台还是 Silverlight,其涉及的广度和深度都会令开发人员望而生畏。事实上,开发人员通常会将注意力完全放在 SharePoint 上,而设计人员则更熟悉 Silverlight。要构建有用的 SharePoint 应用程序,您必须对这两种技术都有所了解。在本文中,我将向您简要介绍 Silverlight 与 SharePoint 2010 的集成,并介绍在 SharePoint 解决方案的前端使用 Silverlight 的基础知识。

Silverlight 和 SharePoint 工作流

配合使用 Silverlight 和 SharePoint 的第一步是使用正确的工具。Visual Studio 和 Expression Blend 被设计为协同工作,通过使用二者,Silverlight 开发人员可以在不打开或安装 SharePoint 的情况下,使用 SharePoint 中提供的示例数据来创建功能强大的应用程序。同样,SharePoint 开发人员可以将 Silverlight 应用程序集成到 SharePoint 中,而无需了解或深入研究 XAML 代码。

在本文中,我将介绍如何创建简单的 Silverlight Web 部件,该部件使用 Silverlight 的 SharePoint 客户端对象模型来呈现 SharePoint 列表。该应用程序也是 SharePoint 沙盒应用程序,网站集管理员可以安装和管理该应用程序。该应用程序还可通过 SharePoint Online 标准帐户运行。

图 1 显示出最终应用程序在 SharePoint 上运行时的外观。

图 1 已完成的 Silverlight/SharePoint 应用程序

SharePoint 示例数据

为了使 Silverlight 和 SharePoint 开发人员独立工作,Silverlight 开发人员将需要基于 SharePoint 数据的示例数据。这样,Silverlight 开发人员可以完全自由地创建插入 SharePoint 中后仍可正确工作的应用程序。

Expression Blend 具有多种功能,可支持设计时数据和示例数据。在本示例中,我将使用 XML 格式的示例数据。这意味着 SharePoint 开发人员必须创建表示应用程序将使用的 SharePoint 列表的 XML 文件。您可以按照自己需要的任意形状建立此示例数据文件,但是,如果采用与从 SharePoint 返回的形状相同的形状建立该文件,则会事半功倍。例如,使用 WCF 数据服务实体和 SharePoint 的 RESTful ListData 服务返回的形状,与使用 Silverlight 客户端对象模型返回的数据形状不同。

在本应用程序中,我将使用 Silverlight 4 中提供的一些新数据绑定功能以及 Silverlight 的 SharePoint 客户端对象模型。没有内置的方法可用于生成此示例数据,因此您需要创建一个简单的控制台应用程序以生成 SharePoint 示例数据。在本例中,我创建了一个使用 Microsoft .NET Framework 客户端对象模型的 Visual Basic 控制台应用程序,以根据前五个列表项生成 XML 文档(请参见图 2)。

图 2 返回数据 XML 的控制台应用程序

Imports Microsoft.SharePoint.Client
Imports System.Text

Module Module1
  Sub Main()
    Dim context As New _
      ClientContext("http://intranet.contoso.com")
    Dim sampleListItems As ListItemCollection
    Dim sampleList As List = _
      context.Web.Lists.GetByTitle("Contacts")

    Dim qry As New Microsoft.SharePoint.Client.CamlQuery
    qry.ViewXml = "<View><RowLimit>5</RowLimit></View>"
    sampleListItems = sampleList.GetItems(qry)

    context.Load(sampleListItems)

    context.ExecuteQuery()

    'Build the Sample XML Data
    Dim SampleData = _
      <SharePointListItems></SharePointListItems>
    'Iterate through each row using Linq 
    'and XML Literals
    For Each item In sampleListItems
      Dim sampleItem = <ListItem>
        <%= From fieldValue In item.FieldValues _
        Select <<%= fieldValue.Key %>>
        <%= fieldValue.Value %></> %>
        </ListItem>
      SampleData.Add(sampleItem)
    Next
    'Write the file to disk
    System.IO.File.AppendAllText( _
      "C:\SharePointSampleData.xml", _
      SampleData.ToString())
  End Sub
End Module

得到 SharePointSampleData.xml 文件之后,您便可以在 Expression Blend 中将其用作设计时数据源。

使用示例数据进行设计

得到示例数据 XML 文件后,您便可以打开 Expression Blend 并创建新的 Silverlight 4 应用程序。

在“Data(数据)”面板中,单击右上角的“Create Sample Data(创建示例数据)”图标,选择“Import Sample Data from XML(从 XML 导入示例数据)”,然后浏览到 SharePointSampleData.xml 文件。您还可以选中块,以在应用程序运行时查看示例数据。否则,您将只能在 Blend 或 Visual Studio 设计器中查看示例数据。

图 3 显示出 Contacts 列表。客户端对象模型实际返回的是包含 45 个字段的字典,因此,要查看完整内容,必须在图中向下滚动。

图 3 示例 Contacts 列表

下一步是创建数据绑定列表框。在“Data(数据)”面板中,确保设置了“List Mode(列表模式)”图标。该图标位于“Data(数据)”面板的左上方。现在,选择希望在列表框中显示的字段。在本例中,我选择了 Title(实际上是名字)和 LastName。将字段从列表中拖放到设计图面上。Expression Blend 将创建与字段进行数据绑定的列表框和数据模板。将列表框排列到设计图面的左侧,以便为详细信息腾出空间。

创建数据绑定详细信息同样非常简单。从“Data(数据)”面板窗口左上方的图标中选择“Details Mode(详细信息模式)”。选择要作为详细信息字段显示的字段。将这些字段拖动到设计图面上。Expression Blend 将创建绑定到列表框中选定项目的每个字段。如果按 F5 运行应用程序,则将看到用示例数据填充的列表框。在列表框中更改选定项目时,将会看到右侧详细信息随之更改(请参见图 4)。

图 4 在 Expression Blend 中处理应用程序

现在,您已经拥有了功能完备的应用程序,并且该应用程序与 SharePoint 示例数据进行了数据绑定。作为 Silverlight 设计人员,您可以继续测试和优化应用程序,而无需了解有关 SharePoint 的任何信息。在本示例中,我进行了一些设计工作,排列了所有字段并从 Silverlight 工具包添加了“Sketch(素描)”主题。

Silverlight Web 部件

此时,Silverlight 开发人员可以将项目文件移交给 SharePoint 开发人员。这样做的原因是 Expression Blend 和 Visual Studio 共享相同的项目文件。SharePoint 开发人员在 Visual Studio 2010 中打开项目并能够查看应用程序的所有部分,因此可以在 Visual Studio 设计器中处理该应用程序(请参见图 5)。

图 5 在 Visual Studio 中处理应用程序

SharePoint 开发人员首先要做的是将一个空 SharePoint 项目添加到包含 Silverlight 项目的现有解决方案中。他将使用此 SharePoint 项目部署 Silverlight 应用程序文件 (.xap) 并创建一个 Silverlight Web 部件,该部件用于承载 Silverlight 应用程序。

与以前构建 SharePoint 解决方案相比,使用 Visual Studio 2010 可以更轻松地完成这些任务。右键单击解决方案,然后选择“Add New Project(添加新项目)”。浏览到 SharePoint 2010 模板并选择“Empty SharePoint Project(空白 SharePoint 项目)”。在“New Project(新建项目)”向导中,请务必保留默认选择,以便创建作为沙盒解决方案的项目。这是最佳实践,可为您提供最灵活和安全的部署选项。Silverlight 还可与沙盒解决方案很好地协作,因为 Silverlight 在客户端上运行,不受在沙盒中运行的服务器端代码的许多限制。

虽然创建顺序无关紧要,但最好先创建 Web 部件。这样,您便可以嵌套将在 Web 部件下部署 Silverlight .xap 文件的模块。这可以保持项目的组织结构良好,并且随着解决方案的不断增大易于进行跟踪。

右键单击项目并选择“Add New Item(添加新项)”,以将 Web 部件添加到 SharePoint 项目。从 SharePoint 2010 模板文件夹中选择 Web 部件。这将在项目中创建新的空 Web 部件。

Web 部件仅由三项组成。第一项是 Elements.xml 文件。这是 SharePoint 解决方案文件,用于说明某个功能中的项。

第二项是 Web 部件定义文件,其扩展名为 .webpart。此文件部署到 SharePoint Web 部件库中,并定义 Web 部件代码和 Web 部件的所有属性。

第三个文件是代码文件。所有这三个文件均放在项目结构中的文件夹下。

这便是有趣的地方。如果您是从头开始创建 Web 部件,则在创建新 Web 部件时,添加到项目中的所有文件都是必需的。在本例中,由于 SharePoint 已经附带 Silverlight Web 部件,因此您无需使用所有自动生成的文件。您要做的就是在此现有 Web 部件上进行构建。为此,您只需将 .webpart 文件指向 Silverlight Web 部件的代码并包括所有属性。

创建内置 Silverlight Web 部件 .webpart 文件的副本。实际上可以自动创建。在 SharePoint 中,将 Silverlight Web 部件添加到任意页面。在设计模式中,单击 Web 部件的下拉菜单并选择“Export(导出)”。这样,您便可以创建可添加到项目中的 .webpart 文件副本。现在,只需要更改几个属性,例如 Silverlight 应用程序的路径、标题、说明等。此外,由于您现在使用的是来自内置 Microsoft.SharePoint.dll 的 Web 部件代码,因此不再需要 Web 部件的 .cs 文件。可以直接删除此文件。图 6 显示出 .webpart 文件在被添加到项目后的外观的一个示例。

图 6 默认 .webpart 文件摘录

<webParts>
  <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
    <metaData>
      <type name="Microsoft.SharePoint.WebPartPages.SilverlightWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <importErrorMessage>$Resources:core,ImportErrorMessage;
      </importErrorMessage>
    </metaData>
    <data>
      <properties>
        <property name="HelpUrl" 
                  type="string" />
        <property name="AllowClose" 
                  type="bool">True</property>
        <property name="ExportMode" 
                  type="exportmode">All</property>
        <property name="Hidden" 
                  type="bool">False</property>
        <property name="AllowEdit" 
                  type="bool">True</property>
        <property name="Description" 
                  type="string">Contacts Web Part</property>
        ...
<property name="Height" 
                  type="unit">480px</property>
        <property name="ChromeType" 
                  type="chrometype">None</property>
        <property name="Width" 
                  type="unit">640px</property>
        <property name="Title" 
                  type="string">Contacts Demo</property>
        <property name="ChromeState" 
                  type="chromestate">Normal</property>
        <property name="TitleUrl" 
                  type="string" />
        <property name="Url" 
                  type="string">
        ~site/_catalogs/masterpage/SilverlightApplication1.xap
        </property>
        <property name="WindowlessMode" 
                  type="bool">True</property>
      </properties>
    </data>
  </webPart>
</webParts>

将 Silverlight 部署到 SharePoint

此时,您已拥有了功能完备的 Silverlight 应用程序和承载该 Silverlight 应用程序的 Web 部件。 现在,需要创建 SharePoint 模块以将实际 Silverlight .xap 文件部署到 SharePoint。

Visual Studio 2010 具有内置功能可实现此操作,因此挂接所有内容都相当简单。 右键单击 Web 部件文件夹并选择“Add New Item(添加新项)”。 从 SharePoint 2010 模板中选择“Module(模块)”模板。

默认情况下将生成一个包含 elements.xml 文件的新模块,与您添加到 Web 部件功能的模块一样。 该模块中也包含 sample.txt 文件。 请删除 sample.txt 文件,因为您不需要该文件。

可以通过一种特殊的方法添加对项目中 Silverlight 应用程序的引用。 在解决方案资源管理器中选择 Module 文件夹并查看属性。 单击“Project Output References(项目输出引用)”属性以打开“Project Output References(项目输出引用)”对话框。 在该对话框中,单击“Add(添加)”按钮以添加新引用。 在“Project Name(项目名称)”下拉菜单中,选择 Silverlight 应用程序项目。 将“Deployment Type(部署类型)”设置为“Element File(元素文件)”,然后关闭对话框。

现在已添加了对 Silverlight 应用程序的引用。 这与添加标准项目引用的方法相同,Silverlight 项目在 SharePoint 项目之前构建,并且 Silverlight 项目的输出(.xap 文件)将被复制到 SharePoint 项目并被内置到 SharePoint 解决方案文件(.wsp 文件)中。

最后一步是设置 Silverlight 应用程序的部署路径。 这是 .xap 文件将被复制到的位置以及 Web 部件将从中加载应用程序的位置。

打开 Module 文件夹下的 elements.xml 文件。 将文件元素的 URL 属性设置为与 .webpart 文件中的 URL 属性相同。 在本例中,您要将解决方案部署到母版页库,因此,请将该值设置为:

~site/_catalogs/masterpage/
  SilverlightApplication1.xap

请注意,路径开头的波形符是一个特殊的 SharePoint 通配符,用于指示站点的根。

现在,将解决方案部署到 SharePoint 以验证所有内容是否设置正确。 将 SharePoint 项目设置为默认启动项目,然后按 F5。 Visual Studio 将构建和打包解决方案。 虽然 Visual Studio 将打开 SharePoint 网站并附加调试器,但您仍需要将 Web 部件添加到页面。 我发现,开发解决方案时执行此操作的最简单方法是将 Web 部件添加到新网站页面。

客户端对象模型

当所有内容就绪之后,您便可以将 Silverlight 应用程序绑定到实际 SharePoint 数据。 SharePoint 2010 包括 CLR、Silverlight 和 ECMAScript 的客户端对象模型。 这样,您就可以使用熟悉的对象模型方便地访问 SharePoint 数据,如列表和库。

在此特定示例中,您构建了一个 Silverlight 应用程序,因此需要添加对 Silverlight 客户端对象模型的引用。 Silverlight 客户端对象模型由以下两个文件组成:Microsoft.SharePoint.Client.Silverlight.dll 和 Microsoft.SharePoint.Client.Silverlight.Runtime.dll。 这两个文件位于 C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin\ 中。

在添加引用之后,您便可以编写代码以从 Contacts 列表中检索联系人。 首先,在 MainPage.xaml.cs 的顶部为 Microsoft.SharePoint.Client 添加 using 语句。 然后,需要定义一对类级别的字段用于保存返回的结果。 还需要处理页面加载的事件,用于加载列表数据:

public partial class MainPage : UserControl {
  ClientContext ctx;
  ListItemCollection contactsListItems;

  public MainPage() {
    InitializeComponent();
    this.Loaded += MainPage_Loaded;
  }

  void MainPage_Loaded(
    object sender, RoutedEventArgs e) {
    LoadList();
  }
}

接下来,实现 LoadList 方法以从 SharePoint 检索数据。 首先,获取对当前客户端上下文的引用。 静态方法 ClientContext.Current 将上下文返回到加载 Web 部件的站点。 然后,您可以调用 GetByTitle 以获取对 Contacts 列表的引用。 Load 方法会将请求添加到查询。 然后调用 ExecuteQueryAnsc 进而调用 SharePoint Server:

void LoadList(){
  ctx = ClientContext.Current;

  if (ctx != null) { //null if not in SharePoint
    List contactsList = 
      ctx.Web.Lists.GetByTitle("Contacts");
    contactsListItems =
      contactsList.GetItems(
      CamlQuery.CreateAllItemsQuery());

    ctx.Load(contactsListItems);
    ctx.ExecuteQueryAsync(
      ContactsLoaded, ContactsLoadedFail);
  }
}

对 Silverlight 中服务器的调用是异步的。 ExecuteQueryAsync 方法使用两个回调委托,一个用于成功结果,一个用于失败结果。 在 ContactsLoaded 回调方法中,通过数据绑定将结果绑定到 Silverlight 设计人员在本文开头部分创建的 XAML。 在成功的回调中,您需要做的就是将列表框的 ItemsSource 属性设置为由客户端对象模型返回的联系人集合。 后台线程上也会发生回调,因此您将需要更新 Dispatcher 的 BeginInvoke 方法内部的属性:

// ContactsLoaded
void ContactsLoaded(object sender, 
  ClientRequestSucceededEventArgs args) {
  //call back on the UI thread
  this.Dispatcher.BeginInvoke(() => {
    ContactsListBox.ItemsSource = contactsListItems;
  });
}

失败的回调留待读者实现。

在运行应用程序之前还需要做一件事情:需要更改 Silverlight 绑定到数据源的方式。 请记住,我在本文开头创建了表示来自 SharePoint 的数据的 XML 文件,但此数据并非完全相同,因为 SharePoint 客户端对象模型实际返回的是字典字段值的集合。

Silverlight 4 中的一个新功能是能够绑定到索引器。 这意味着您可以使用键值名称作为绑定命令的字符串,对客户端对象模型返回的字典值进行数据绑定。 遗憾的是,没有一种很好的方法可用来处理这种复杂的基于字典的示例数据,但使用 Visual Studio 查找和替换工具来回更改绑定也足够简单。 例如,您需要将 Text="{Binding Title}" 更改为 Text="{Binding Path=FieldValues[Title]}"。 对所有字段执行此操作。 我已包含正则表达式代码以在本文的示例代码中来回切换。

将所有绑定更改为使用 Silverlight 4 索引器绑定后,您便可以运行应用程序。 浏览到您创建的用于承载 Silverlight 应用程序的网站页面。 其外观应类似于文章开头所示的图 1

动态加载的客户端对象模型

此时,应用程序已完成,不过我还想演示一点其他内容。 在测试版之后,SharePoint 已发生了一点改动。 使用 Visual Studio 的“Add References(添加引用)”对话框浏览文件以创建对 Silverlight 客户端对象模型的引用时,默认情况下,Visual Studio 将这两个文件包括在所构建的 .xap 程序包中。 这会使 Silverlight 程序包额外增加 407KB。

更好的选择是在运行时动态加载这些程序集。 这样,浏览器可以缓存这些常用文件,从而减少应用程序的大小和加载时间,同时提高应用程序的性能。

在 SharePoint 测试版之后的版本中,SharePoint 将两个客户端对象模型文件打包到名为 Microsoft.SharePoint.Client.xap 的单个 .xap 文件中。 此文件与其他客户端对象模型文件位于相同的位置,即 C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin。 您仍需要添加对客户端对象模型文件的引用,因为这可以提供所需的 IntelliSense 和编译支持。 但您将需要在 Silverlight 应用程序的引用文件夹中选择各个文件,并将“复制本地”属性设置为 false。 将此属性设置为 false 可防止 Visual Studio 将这些文件添加到 .xap 程序包中。

接下来,您需要添加代码以动态加载客户端对象模型程序集。 这是非常通用的代码,略加修改即可在任何 .xap 程序包中的任何 Silverlight 应用程序中使用。 首先更改页面加载的事件以调用代码来下载和加载程序集。 在本示例中,将回调委托传递给 LoadList 方法。 这样,在加载程序集并做好使用准备后,您便可以从 SharePoint 加载列表数据,如下所示:

void MainPage_Loaded(
  object sender, RoutedEventArgs e) {
  LoadClientOM loadClientOM = 
    new LoadClientOM(delegate() { LoadList(); });
  loadClientOM.Run();
}

将新的类文件添加到名为 LoadClientOM.cs 的项目中,并添加图 7 中所示的代码。 此代码使用 WebClient 从 /_layouts/clientbin/Microsoft.SharePoint.Client.xap 下载 .xap 程序包。 程序包下载完毕后,您需要从程序包加载各个程序集。

图 7 加载 Microsoft.SharePoint.Client.xap

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Windows.Resources;
using System.Reflection;

namespace SilverlightApplication1 {
  public class LoadClientOM {
    private bool isDownloaded = false;
    private Action action;

    public LoadClientOM(Action action) {
      this.action = action;
    }

    public void Run() {
      WebClient client = new WebClient();
      client.OpenReadCompleted += 
        new OpenReadCompletedEventHandler(
        client_OpenReadCompleted);
      client.OpenReadAsync(new Uri(
        "/_layouts/clientbin/Microsoft.SharePoint.Client.xap", 
        UriKind.Relative));
    }

    void client_OpenReadCompleted(object sender, 
      OpenReadCompletedEventArgs e) {
      Stream assemblyStream;
      AssemblyPart assemblyPart;

      assemblyStream = Application.GetResourceStream(
        new StreamResourceInfo(e.Result, "application/binary"), 
        new Uri("Microsoft.SharePoint.Client.Silverlight.Runtime.dll", 
        UriKind.Relative)).Stream;
      assemblyPart = new AssemblyPart();
      Assembly b = assemblyPart.Load(assemblyStream);

      assemblyStream = Application.GetResourceStream(
        new StreamResourceInfo(e.Result, "application/binary"), 
        new Uri("Microsoft.SharePoint.Client.Silverlight.dll", 
        UriKind.Relative)).Stream;
      assemblyPart = new AssemblyPart();
      Assembly a = assemblyPart.Load(assemblyStream);

      this.isDownloaded = true;

      if (action != null) {
        action();
      }
    }
  }
}

现在可再次运行应用程序。 您可以看到应用程序外观完全相同,但现在是在运行时从服务器动态加载 Silverlight 客户端对象模型。 在这个简单的应用程序中难于发现性能上的不同,但在动态加载时应表现出较好的性能。

Paul Stubbs 也是一位 Microsoft 技术推广专家,主要从事 SharePoint 和 Office、Silverlight 和 Web 2.0 社交网络的信息工作者开发社区方面的工作。他编写过三本关于使用 Office、SharePoint 和 Silverlight 开发解决方案的图书。您可以通过以下网址阅读他的博客:blogs.msdn.com/b/pstubbs

衷心感谢以下技术专家对本文的审阅: Mike Morton , John Papa Unni Ravindranathan