如何创建移动适配器

上次修改时间: 2011年3月17日

适用范围: SharePoint Foundation 2010

本主题说明如何创建移动适配器类,此类使移动设备能够访问 Microsoft SharePoint Foundation 页上的 Web 部件。

有关适配 Web 部件的具体示例,请参阅演练:创建移动适配器

设置您的开发环境

必要的开发任务

  1. 如果希望移动设备能够访问的 Web 部件页不存在,则必须创建它们。有关详细信息,请参阅 SharePoint Foundation 中的 Web 部件基础结构WebPartPage

    备注

    不要创建 WebPartMobilePage 类的页。这些页是在移动设备请求 Web 部件页 (WebPartPage) 时由运行时创建的。

  2. 如果要针对移动访问适配的 Web 部件不存在,则必须创建它们。有关详细信息,请参阅 SharePoint Foundation 中的 Web 部件基础结构Web Parts Overview

创建和部署移动适配器类

  1. 在 Visual Studio 类库项目中,添加对 System.Web 和 Microsoft.SharePoint.dll 的引用,然后为命名空间 Microsoft.SharePoint.WebPartPages 添加 using(在 Visual Basic 中为 Imports)语句。您可能需要为其他命名空间添加 using 语句,具体取决于适配器实现的详细信息。通常,移动适配器将调用 System.Web.UI.MobileControlsMicrosoft.SharePointMicrosoft.SharePoint.MobileControls 中的类型。

  2. 添加一个名为 WebPartClassMobileAdapter 的类,其中 WebPartClass 为要适配的 Web 部件的名称。例如,如果 Web 部件为 StockListWebPart,则将适配器类命名为 StockListWebPartMobileAdapter。将其设置为从 WebPartMobileAdapter 继承。

  3. 设置命名空间,使其符合命名空间命名指南(该链接可能指向英文页面)中的准则。对于移动适配器,请使用与 MyCompany.SharePoint.WebPartPages.MobileAdapters 类似的内容。

  4. 虽然 WebPartMobileAdapter.Control 属性未标记为 virtual 或 override(在 Visual Basic 中为 Overridable 和 Overrides),但您可能需要通过隐藏和替换此属性来有效重写它。您可以通过使用 new 关键字(在 Visual Basic 中为 Shadows)在派生类中声明新的 Control 属性来做到这一点。有关可能需要执行此操作的原因以及执行此操作的方法的详细信息,请参阅 WebPartMobileAdapter.Control 的参考主题。

  5. 如果默认实现不适合对 Web 部件的移动访问,则重写 CreateControlsForSummaryView() 方法。总的说来,重写将创建所需的任何子控件,并按照这些子控件在移动设备上的显示顺序将它们添加到 Controls 集合中。通常,您至少需要一个小图标和一个标题以便在移动设备上的摘要视图中显示 Web 部件。(如果这就是您希望在摘要视图中显示的所有内容,则您无需重写 CreateControlsForSummaryView()。)为了使您能够更轻松地执行此操作,提供了下面两种帮助程序方法:CreateWebPartIcon(WebPartMobileAdapter.WebPartIconLink)CreateWebPartLabel()

    但有时需要获得更多信息,即使是在摘要视图中也是如此。例如,假定要适配的 Web 部件具有多个类型相同的子项目。您可以利用图标和标题的后面的 Label 控件将子项目的总数添加到摘要视图中。下面的代码演示如何执行此操作。

    重要注释重要信息

    此示例做出两种假设:第一种假设是,要适配的 Web 部件具有 Count 属性(类型为 String),它返回子项目的总数;第二种假设是,此属性是可访问的,因为前面的步骤中提到已将 Control 属性隐藏和替换。

    protected override void CreateControlsForSummaryView()
    {
        Image iconImage = this.CreateWebPartIcon(WebPartIconLink.LinkToDetailView);
        iconImage.BreakAfter = false;
        this.Controls.Add(iconImage);
    
        Label titleLabel = this.CreateWebPartLabel();
        titleLabel.BreakAfter = false;
        this.Controls.Add(titleLabel);
    
        Label count = new Label() { Text=this.Control.Count.ToString() }
        this.Controls.Add(count);
    }
    
    Protected Overrides Sub CreateControlsForSummaryView()
            Dim iconImage As Image = Me.CreateWebPartIcon(WebPartIconLink.LinkToDetailView)
            iconImage.BreakAfter = False
            Me.Controls.Add(iconImage)
    
            Dim titleLabel As Label = Me.CreateWebPartLabel()
            titleLabel.BreakAfter = False
            Me.Controls.Add(titleLabel)
    
            Dim count As New Label() With {.Text=Me.Control.Count.ToString()} 
            Me.Controls.Add(count)
    End Sub
    

    请注意,在向 CreateWebPartIcon(WebPartMobileAdapter.WebPartIconLink) 方法传递 LinkToDetailView 时(如本示例所示),如果设备上的浏览器支持 CSS 和 ECMAScript 1.0 或更高版本,则将呈现一个箭头图标,此图标用作执行 SharePoint Foundation 移动适配器框架的展开脚本的可单击控件。当用户单击该控件时,Web 部件将展开为详细视图中,并且此图标将变成一个向下的箭头(其本身是一个执行折叠脚本的控件)。如果浏览器不支持 CSS 和 ECMAScript 1.0 或更高版本,则将呈现一个不同的图标,单击此图标可将用户导航到包含 Web 部件详细视图的页面 (mblwpdetail.aspx)。如果不希望 Web 部件在移动页面上具有详细视图,请改为将 NoLink 传递给 CreateWebPartIcon(WebPartMobileAdapter.WebPartIconLink)

    在重写 CreateControlsForSummaryView() 时可能需要执行的其他操作:

    • 如果您的呈现逻辑假设某些实体不为 null 或假设已满足其他条件,请考虑将重写设计为对这些假设进行测试;如果不满足这些假设条件,则不执行任何操作或提供交替呈现。例如,如果要适配的 Web 部件呈现一个列表视图,您可以通过测试 this.Control.View.MobileView 来进行检查,以确定该视图是否指定为移动视图。有关详细信息,请参阅 MobileView

    • 如果要适配的 Web 部件的可视方面不是仅由图标和标题来传达的,请考虑为摘要视图构造这些方面的小型版本。例如,如果饼图是 Web 部件的一部分,则对 CreateControlsForSummaryView() 的重写可以包括饼图的小型常用图像;或者,如果 Web 部件包含一张照片,则您的重写可以包含该图像的非常小的缩放版本。

  6. 如果默认实现不适合对 Web 部件的移动访问,则重写 CreateControlsForDetailView() 方法。默认实现将为 Web 部件呈现一个图标和标题,其后跟一条消息,指示不存在 Web 部件的详细视图。如果您已重写 CreateControlsForSummaryView() 且不希望提供详细视图,请重写 CreateControlsForDetailView() 并使其不执行任何操作,如下面的示例所示。

    protected override void CreateControlsForDetailView(){}
    
    Protected Overrides Sub CreateControlsForDetailView()
    End Sub
    

    如果您需要详细视图,则重写 CreateControlsForDetailView() 的过程与重写 CreateControlsForSummaryView() 的过程相同,只不过将显示 Web 部件的更多详细信息。例如,如果 Web 部件具有多个相同类型的子项目,请考虑在详细视图中显示其中的前几个项目。在下面的代码示例中,重写 CreateControlsForDetailView() 方法以将当前列表中最多三个项目显示为 Web 部件图标和标题下方的子项目。演练:创建移动适配器中对此代码进行了更详细地讨论。

    protected override void CreateControlsForDetailView()
    {
        Image iconImage = this.CreateWebPartIcon(WebPartIconLink.LinkToSummaryView);
        iconImage.BreakAfter = false;
        this.Controls.Add(iconImage);
    
        Label titleLabel = this.CreateWebPartLabel();
        this.Controls.Add(titleLabel);
    
        SPSite siteCollection = SPContext.Current.Site;
        SPUser currentUser = SPContext.Current.Web.CurrentUser;
        SPList taskList = siteCollection.AllWebs["MyGPSite"].Lists["Tasks"];
        SPListItemCollection allTasks = taskList.GetItems(taskList.DefaultView);
    
        // Use LINQ to filter out other users ... 
        var lightweightTasksOfUser = from SPListItem task in allTasks
                                     where task["AssignedTo"].ToString().EndsWith(currentUser.Name)
                                     select new {task.Title, Priority=task["Priority"]}; // ... and unneeded columns.
    
        Int16 itemCount = 1;
        foreach (var lightweightTask in lightweightTasksOfUser)
        {
            Image taskIcon = new Image() { ImageUrl = this.ItemBulletIconUrl,
                                           BreakAfter = false};
            this.Controls.Add(taskIcon);
    
            Label taskTitle = new Label { Text = lightweightTask.Title,
                                          BreakAfter = false};
            taskTitle.Font.Bold = BooleanOption.True;
            this.Controls.Add(taskTitle);
    
            Label priority = new Label() { Text = " " + lightweightTask.Priority };
            priority.Font.Size = FontSize.Small; 
            this.Controls.Add(priority);
    
            this.Controls.Add(new LiteralText());
    
            // Render no more than 3 tasks, but provide link to others.
            if (itemCount++ >= 3)
            {
                Link moreItemLink = new Link
                {
                    Text = "All my tasks",
                    href = SPMobileUtility.GetViewUrl(taskList, taskList.Views["My Tasks"])
                };
                this.Controls.Add(moreItemLink);
                break;
            } // end "if limit has been reached"
    
        } // end "for each lightweight task of the current user"
    } // end CreateControlsForDetailView
    
    Protected Overrides Sub CreateControlsForDetailView()
        Dim iconImage As Image = Me.CreateWebPartIcon(WebPartIconLink.LinkToSummaryView)
        iconImage.BreakAfter = False
        Me.Controls.Add(iconImage)
    
        Dim titleLabel As Label = Me.CreateWebPartLabel()
        Me.Controls.Add(titleLabel)
    
        Dim siteCollection As SPSite = SPContext.Current.Site
        Dim currentUser As SPUser = SPContext.Current.Web.CurrentUser
        Dim taskList As SPList = siteCollection.AllWebs("MyGPSite").Lists("Tasks")
        Dim allTasks As SPListItemCollection = taskList.GetItems(taskList.DefaultView)
    
        ' Use LINQ to filter out other users ... 
        Dim lightweightTasksOfUser = From task As SPListItem In allTasks
                                     Where task("AssignedTo").ToString().EndsWith(currentUser.Name)
                                     Select New With {Key task.Title, Key .Priority = task("Priority")} '... and unneeded columns.
    
        Dim itemCount As Int16 = 1
        For Each lightweightTask In lightweightTasksOfUser
            Dim taskIcon As New Image() With {.ImageUrl = Me.ItemBulletIconUrl, .BreakAfter = False}
            Me.Controls.Add(taskIcon)
    
            Dim taskTitle As Label = New Label With {.Text = lightweightTask.Title, .BreakAfter = False}
            taskTitle.Font.Bold = BooleanOption.True
            Me.Controls.Add(taskTitle)
    
            Dim priority As New Label() With {.Text = " " & lightweightTask.Priority}
            priority.Font.Size = FontSize.Small
            Me.Controls.Add(priority)
    
            Me.Controls.Add(New LiteralText())
    
            ' Render no more than 3 tasks, but provide link to others.
    
            If itemCount >= 3 Then
                itemCount += 1
                Dim moreItemLink As Link = New Link With {.Text = "All my tasks", .href = SPMobileUtility.GetViewUrl(taskList, taskList.Views("My Tasks"))}
                Me.Controls.Add(moreItemLink)
                Exit For
            End If ' end "if limit has been reached"
            itemCount += 1
        Next  ' end "for each lightweight task of the current user"
    End Sub ' end CreateControlsForDetailView
    
  7. 如果您需要在 InitLoadPreRenderUnload 事件中使用自定义逻辑,请分别重写 OnLoadForMobile(EventArgs)OnInitForMobile(EventArgs)OnPreRenderForMobile(EventArgs)OnUnloadForMobile(EventArgs) 方法。

  8. 如果您希望将移动用户重定向到自定义摘要视图页或详细视图页(而不是由内置默认页提供的页面),请重写 SummaryViewPageUrlDetailViewPageUrl 属性。

  9. 若要更改 Web 部件标题旁边显示的图标,请重写下列一个或多个属性:

    下面的代码演示如何重写上述某个属性的示例。在此对 TitleIconUrl 的重写中,如果 Web 部件显示一个列表,并且该列表在 ImageUrl 属性中有自己的图标,则将显示此图标。

    protected override string TitleIconUrl
    {
        get
        { 
            SPContext context = SPContext.GetContext(HttpContext.Current);
    
            if (String.IsNullOrEmpty(context.List.ImageUrl))
            {
                return base.TitleIconUrl;
            }
            return context.List.ImageUrl;
        }
    }
    
    Protected Overrides ReadOnly Property TitleIconUrl() As String
        Get
            Dim context As SPContext = SPContext.GetContext(HttpContext.Current)
    
            If String.IsNullOrEmpty(context.List.ImageUrl) Then
                Return MyBase.TitleIconUrl
            End If
            Return context.List.ImageUrl
        End Get
    End Property
    
  10. 编译程序集,并为它指定一个强名称,然后将它部署到全局程序集缓存 (GAC) 或服务器场中每台前端 Web 服务器上的 Web 应用程序的 \BIN 文件夹中。建议您使用 SharePoint Foundation 解决方案部署适配器来完成此操作。为简便起见,本主题假定您将程序集部署到 GAC。有关此选择的详细信息,请参阅将您的程序集放置在 Bin 或全局程序集缓存中。若只需将程序集复制到开发计算机的 GAC 中,请使用 gacutil.exe 实用工具。确保将适配器的每个新版本安装在 GAC 中的最简单方法是,从随 Visual Studio 中的后期生成事件一起启动的批处理文件运行该实用工具。此批处理文件应具有以下代码行,其中 AssemblyName 将替换为您的程序集的名称。

    备注

    此代码假定您遵循了如何:向 PATH 环境变量中添加工具位置中的建议。

    gacutil –if bin\debug\AssemblyName.dll
    

编辑 compat.browser 文件

  1. 在文本编辑器中打开文件 \\Inetpub\wwwroot\wss\VirtualDirectories\port_number\App_Browsers\compat.browser,其中 port_number 是 Web 应用程序的端口。然后滚动到 refID 属性值为"default"的 <browser> 元素。该元素具有一个类似于以下示例的子 <controlAdapters> 元素:

    <controlAdapters>
      <adapter controlType="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
        adapterType="Microsoft.SharePoint.WebPartPages.XsltListViewWebPartMobileAdapter, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <adapter controlType="Microsoft.SharePoint.WebPartPages.ListViewWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
        adapterType="Microsoft.SharePoint.WebPartPages.ListViewWebPartMobileAdapter, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <adapter controlType="Microsoft.SharePoint.Applications.GroupBoard.WebPartPages.WhereaboutsWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
        adapterType="Microsoft.SharePoint.WebPartPages.WhereaboutsWebPartMobileAdapter, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <adapter controlType="Microsoft.SharePoint.WebPartPages.ImageWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
        adapterType="Microsoft.SharePoint.WebPartPages.ImageWebPartMobileAdapter, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
    </controlAdapters>
    
  2. 将 <adapter> 元素添加为 <controlAdapters> 元素的子级,以将适配器类映射到该类依照上述示例中的模式适配的 Web 部件。请注意,controlType 属性和 adapterType 属性都是必需。二者是类的完全限定名和程序集的名称(由四个部分组成)。若要获取适配器程序集的公钥标记,请使用 Visual Studio 的"工具"菜单上的"获取程序集公钥"项。(如果此项未位于该位置,请参阅如何:创建用于获取程序集公钥的工具。)有关此 XML 标记的详细信息,请参阅浏览器定义文件架构(browsers 元素)

    以下是新 <adapter> 元素的示例。第一个示例针对的是用于适配随 SharePoint Foundation 附带的 UserTasksWebPart 的 Contoso 控件。第二个示例针对的是用于适配同一个 Northwinds 解决方案中的 Northwinds Web 部件的 Northwinds 控件。

      <adapter controlType="Microsoft.SharePoint.WebPartPages.UserTasksWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c "
        adapterType="Contoso.SharePoint.WebPartPages.UserTasksWebPartMobileAdapter, Contoso, Version=1.0.0.0, Culture=neutral, PublicKeyToken=eedb3d3ba3b4c675" />
    
      <adapter controlType="NorthWinds.SharePoint.WebPartPages.VotingWebPart, Northwinds, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ffec2e2af2b4c675"
        adapterType="NorthWinds.SharePoint.WebPartPages.VotingWebPartMobileAdapter, NorthWinds, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ffec2e2af2b4c675" />
    

    备注

    若要将适配器类部署到服务器场,必须更改每台前端 Web 服务器上的 compat.browser 文件,如上所述。不应使用自己的 compat.browser 文件覆盖现有 compat.browser 文件,或者您可以取消由其他 SharePoint Foundation 解决方案提供程序生成的适配器映射。请考虑将适配器作为 SharePoint Foundation 功能的一部分进行部署。在 FeatureActivated(SPFeatureReceiverProperties) 事件处理程序中,添加代码以创建计时器作业 SPJobDefinition,此作业将所需的 <adapter> 元素添加到每台前端 Web 服务器上的 compat.browser 文件中。有关使用计时器作业以编程方式编辑所有服务器上的 compat.brower 文件的详细信息,请参阅如何:在所有 Web 服务器上运行代码

将您的适配器注册为安全控件

  1. 必须将您的适配器注册为安全控件。

    提示提示

    建议您通过使用 SharePoint Foundation 解决方案部署适配器来注册适配器。仅在您的开发计算机是单个前端 Web 服务器时需要执行本节中的步骤。使用 SharePoint Foundation 解决方案,可以在部署解决方案时自动在所有前端 Web 服务器上将控件注册为安全控件。有关使用解决方案部署将控件注册为安全控件的详细信息,请参阅解决方案概述手动创建解决方案Solution 架构

  2. 在 Visual Studio 项目中,添加名称为 webconfig.*.xml 格式的 XML 文件,将 * 替换为您公司的名称或任何其他 SharePoint Foundation 解决方案提供商可能不会使用的其他一些名称。

  3. 向该文件中添加 <action> 元素,如下面标记中所示。<SafeControl> 元素的 TypeName 属性可以是适配器类的名称(如 UserTasksWebPartMobileAdapter)。如果同一命名空间中有多个适配器类,则可以使用"*"作为 TypeName 的值。下面是一个示例。

    <action>
      <remove path="configuration/SharePoint/SafeControls/SafeControl[@Assembly=MyCompany.SharePoint.WebPartPages.MobileAdapters3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=yourAssemblyPublicKeyToken']" />
    
      <add path="configuration/SharePoint/SafeControls">
        <SafeControl
          Assembly="MyCompany.SharePoint.WebPartPages.MobileAdapters3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=yourAssemblyPublicKeyToken"
          Namespace="MyCompany.SharePoint.WebPartPages.MobileAdapters3"
          TypeName="*"
          Safe="True"
          AllowRemoteDesigner="True"
        />
      </add>
    </action>
    
    警告注释警告

    将"*"用作 TypeName 的值可使命名空间中的每个类都成为安全控件。如果程序集中的某些类不应被指定为安全控件,请将这些类移动到一个不同的程序集或避免使用"*"。

    有关 <SafeControl> 元素和 webconfig.*.xml 文件的详细信息,请参阅How to: Create a Supplemental .config File使用 Web.config 文件

  4. 保存该文件。此时必须将该文件复制到开发计算机上的文件夹 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\CONFIG 中。在开发计算机上执行此操作的最简单方式是,将以下代码行添加到后期生成事件命令行或在后期生成事件命令行中执行的批处理文件中。

    备注

    此代码假定您遵循了如何:向 PATH 环境变量中添加工具位置中的建议。

    xcopy /y webconfig.MyCompany.xml "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG"
    stsadm –o copyappbincontent
    
  5. stsadmn.exe 命令 copyappbincontent 执行在 webconfig.*.xml 中定义的"<action>"。在这种情况下,该命令将您的适配器的新 <SafeControl> 元素插入 Web 应用程序根目录中的 web.config 文件中。(它首先删除适配器的任何现有 <SafeControl> 元素。这使您能够对每个版本重新运行 stsadm 操作,而无需复制 <SafeControl> 元素。)有关 copyappbincontent 和 stsadm.exe 的详细信息,请参阅 Stsadm 命令行工具操作名称:Copyappbincontent(该链接可能指向英文页面)