65.9K
CodeProject 正在变化。 阅读更多。
Home

SharePoint 2010 站点操作菜单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (7投票s)

2010年11月14日

CPOL

8分钟阅读

viewsIcon

103766

downloadIcon

957

为 SharePoint 2010 站点操作菜单创建包含子菜单的菜单项

Image1.PNG

引言

SharePoint 已经存在很多年并且越来越受欢迎,尤其是 SharePoint 2010 发布之后。自定义 SharePoint 应用程序时,一项常见的任务是向“站点操作”菜单添加菜单项,以便授权用户可以轻松访问功能。在本文中,我将介绍三种方法,可以将您自己的菜单项、子菜单或弹出菜单添加到“站点操作”菜单。

站点操作菜单

几乎所有处理过 SharePoint 的人都熟悉“站点操作”菜单。它提供了对诸如启用页面编辑之类的功能的访问,或者在 SharePoint 2010 中,可以显示新的 RibbonBar。SharePoint 2010 还让开发人员对该菜单及其项目有了更多的控制权。default.master v4.master 母版页包含以下标记,用于在适当的每个页面上渲染基本的“站点操作”菜单。

<sharepoint:siteactions id="SiteActions1" runat="server" 
    accesskey="<%$Resources:wss,tb_SiteActions_AK%>" 
    menunotvisiblehtml=" " prefixhtml="" suffixhtml="">
    <customtemplate>
      <SharePoint:FeatureMenuTemplate runat="server" featurescope="Site" 
      groupid="SiteActions" location="Microsoft.SharePoint.StandardMenu" 
      useshortid="true">
	<SharePoint:MenuItemTemplate id="MenuItem_EditPage" runat="server" 
    clientonclicknavigateurl="javascript:ChangeLayoutMode(false);" 
    description="<%$Resources:wss,siteactions_editpagedescriptionv4%>" 
    imageurl="/_layouts/images/ActionsEditPage.png" menugroupid="100" 
    sequence="110" text="<%$Resources:wss,siteactions_editpage%>" />

    ... more items ... 
    </SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</Sharepoint:iteactions>    

向“站点操作”菜单添加附加项的一种方法是,当然,修改母版页并包含另一个 MenutItemTemplate 元素。

MenuItemTemplate 的所有属性都可以在 http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.menuitemtemplate_properties.aspx [^] 中找到,大多数属性都是不言自明的,并且对于任何 WebControl 都是通用的。但是,有几个属性需要解释。

PermissionString:此属性提供了一个逗号分隔的列表,其中包含来自 SPBasePermission 枚举的项目,用于指定访问菜单项所需的用户权限级别。

PermissionMode:此属性决定如何应用 PermissionString 中指定的权限,可以是“Any”(任意)或“All”(全部)。

ClientOnClickScript:此属性控制用户单击菜单项时执行的客户端操作。如代码设置所示,此属性将删除 ClientOnClickNavigateUrlClientOnClickScriptContainingPrefixedUrl 属性的任何设置。

[DefaultValue(""), Category("Behavior")]
public string ClientOnClickScript
{
    get
    {
        return this.m_clientOnClickScript;
    }
    set
    {
        if (value == null)
        {
            value = string.Empty;
        }
        this.m_clientOnClickScript = value;
        this.ViewState["ClientOnClickScript"] = value;
        this.m_clientOnClickNavigateUrl = null;
        this.ViewState["ClientOnClickNavigateUrl"] = null;
        this.m_clientOnClickScriptContainingPrefixedUrl = null;
        this.ViewState["ClientOnClickScriptContainingPrefixedUrl"] = null;
        this.clientOnClickUsingPostBackEvent = null;
    }
}

ClientOnClickNavigateUrl:使用此属性,您可以设置一个 URL 来导航,或者一个 JavaScript 函数来执行,当单击菜单项时。如您所见,它设置了 ClientOnClickScript 属性,因此它将覆盖该属性中的任何设置,所以属性应用于元素的顺序将影响用户单击菜单项时发生的情况。

[Category("Behavior"), DefaultValue("")]
public string ClientOnClickNavigateUrl
{
    get
    {
        return this.m_clientOnClickNavigateUrl;
    }
    set
    {
        if (value == null)
        {
            value = string.Empty;
        }
        value = SPUtility.GetServerRelativeUrlFromPrefixedUrl(value);
        value = value.Replace("'", @"\'");
        if ((value.StartsWith("javascript:") || value.StartsWith("%")) 
		|| value.StartsWith("?"))
        {
            this.ClientOnClickScript = "window.location = '" + value + "';";
        }
        else
        {
            this.ClientOnClickScript = "STSNavigate2(event,'" + value + "');";
        }
        this.m_clientOnClickNavigateUrl = value;
        this.ViewState["ClientOnClickNavigateUrl"] = value;
    }
}

ClientOnClickScriptContainingPrefixedUrl:与 ClientOnClickNavigateUrl 类似,此属性允许您设置一个 URL 或一个 JavaScript 函数来执行。属性设置器调用 SPUtility.ReplaceEmbeddedPrefixedUrlsWithServerRelativeUrls 来替换 string 中找到的任何内置前缀,例如 ~site~sitecollection,以及服务器相对 URL。再次,设置了 ClientOnClickScript,并且属性在元素中应用的顺序很重要。

[DefaultValue(""), Category("Behavior")]
public string ClientOnClickScriptContainingPrefixedUrl
{
    get
    {
        return this.m_clientOnClickScriptContainingPrefixedUrl;
    }
    set
    {
        if (value == null)
        {
            value = string.Empty;
        }
        value = SPUtility.ReplaceEmbeddedPrefixedUrlsWithServerRelativeUrls(value, true);
        this.ClientOnClickScript = value;
        this.m_clientOnClickScriptContainingPrefixedUrl = value;
        this.ViewState["ClientOnClickScriptContainingPrefixedUrl"] = value;
    }
}

VisibilityFeatureId:使用此属性指定菜单项所依赖的功能 ID(guid)。如果该功能尚未为该网站激活,则菜单项将不会被渲染。

添加子菜单

要添加子菜单,您必须使用 SubMenuTemplate 控件而不是 MenuItemTemplate。这里应该注意的是,SubMenuTemplate 不能用于提供任何操作,MenuItemTemplateClientOnClickXXX 属性不可用,它仅仅是其他菜单项的容器。

<submenutemplate 
id="MenuItem_Custom" 
description="Custom menu with submenu" 
runat="server" 
text="Custom Menu" 
sequence="100" 
menugroupid="90" 
imageurl="/_layouts/images/settingsIcon.png" />
  <menuitemtemplate 
     id="MenuItem_CustomSub" 
     description="A submenu item" 
     runat="server" 
     text="SubMenu" 
     sequence="110" 
     menugroupid="100" 
     imageurl="/_layouts/images/settingsIcon.png" 
     clientonclickscript="alert('Submenu item clicked')" />
</submenutemplate />

SubMenuTemplate 当然可以包含其他 SubMenuTemplates 来生成多级菜单结构。

Image2.PNG

虽然此方法可能适用于一次性情况,但它不是可重现的或推荐的做法。对于可重用解决方案,您应该创建并部署 SharePoint 功能。

通过代码创建菜单

通过 Visual Studio 2010 和 SharePoint 2010 的集成,创建功能现在比以前的版本更容易。要开始创建修改“站点操作”菜单的功能,请在 Visual Studio 2010 中创建一个 SharePoint 2010 模块项目,确保选择的是场解决方案而不是沙盒解决方案。项目创建后,您将看到以下结构。可以删除 Sample.txt 文件,因为它未使用。

Image3.PNG

Elements.xml 文件现在应该如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Module1">
  </Module>
</Elements>

删除 Module 元素,并根据下图替换为 CustomAction 元素:

<elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <customaction 
   id="MANSoftDev_SiteAction" 
   sequence="1" 
   controlclass="MANSoftDev.SiteAction.SiteActionCode" 
   controlassembly="MANSoftDev.SiteAction, Version=1.0.0.0, 
	Culture=neutral, PublicKeyToken=2e15c7b1150d656d" 
   rights="ManageWeb" 
   location="Microsoft.SharePoint.StandardMenu" 
   groupid="SiteActions">
  </customaction>
</elements>

GroupIdLocation 属性告诉 SharePoint CustomAction 将放置在哪里。在这种情况下,位置是 StandardMenu,组是 SiteActions,将其放置在“站点操作”菜单中。LocationsGroups 的完整列表可以在 http://msdn.microsoft.com/en-us/library/bb802730.aspx[^] 中找到。Rights 属性是 SPBasePermissions 枚举值的逗号分隔列表。但是,与前面的示例不同,用户必须拥有所有指定的权限,而不是任意权限。ControlAssemblyControlClass 属性是 SharePoint 2010 新增的,允许您指定将控制此 CustomAction 的类。这对于实现至关重要。ControlAssembly 是实现该类的程序集的四部分名称。ControlClass 是类的完全限定名。请注意,它必须包含完整的命名空间,仅仅提供类名是不够的。要生成此类,请向解决方案添加类库项目,并对程序集进行签名,因为它将部署到 GAC。创建项目后,添加对 System.Web Microsoft.SharePoint 的引用,然后,重命名现有的 Class1 文件,或删除它并添加另一个派生自 WebControl 的类,最终得到这个。

namespace MANSoftDev.SiteAction
{
    public class SiteActionCode : WebControl
    {
    }
}

在继续之前,最好将类库程序集添加到部署包中,并将其部署到 GAC,并在 web.config 文件中的 SafeControls 部分添加适当的设置。为此,您需要修改 Visual Studio 2010 项目中的包。打开包设计器,然后单击底部的“高级”选项卡。

Image4.PNG

在这里,单击“添加”按钮,然后选择“从项目输出添加程序集…”以显示对话框。从下拉列表中选择类库项目,注意 Location 文本框已填充了程序集名称。接下来,单击“安全控件”网格中的“单击此处添加新项”按钮,然后填写适当的设置。单击“确定”按钮返回到上一个屏幕,您会注意到信息已添加到“其他程序集”网格中。再次,确保 SharePoint 项目不是沙盒解决方案,否则无论这些设置如何,程序集都不会部署到 GAC。

Image5.PNG

现在已将程序集添加到部署包中,我们可以继续进行编码。要添加必要的 MenuItemTemplate SubMenuTemplates 来重新创建前面的示例,您需要重写 CreateChildControls 方法并添加如下所示的代码:

protected override void CreateChildControls()
{
    SubMenuTemplate sub = new SubMenuTemplate();
    sub.Text = "Custom Menu";
    sub.Description = "Custom menu with submenu";
    sub.ImageUrl = "/_layouts/images/settingsIcon.png";
    sub.MenuGroupId = 90;
    sub.Sequence = 100;

    Controls.Add(sub);

    MenuItemTemplate item = new MenuItemTemplate("SubMenu");
    item.Description = "A submenu item";
    item.ImageUrl = "/_layouts/images/settingsIcon.png";
            
    sub.Controls.Add(item);

    SubMenuTemplate sub2 = new SubMenuTemplate();
    sub2.Text = "Custom Menu";
    sub2.Description = "Custom menu with submenu";
    sub2.ImageUrl = "/_layouts/images/settingsIcon.png";

    sub.Controls.Add(sub2);

    item = new MenuItemTemplate("SubMenu");
    item.Description = "A submenu item";
    item.ImageUrl = "/_layouts/images/settingsIcon.png";

    sub2.Controls.Add(item);
}

这里没有什么令人惊讶或困难的,这只是创建控件并按正确的顺序将它们添加到正确的 Controls 集合的问题。第一部分提到的属性仍然可以应用于此处,为简单起见,没有设置任何 OnClientClickXXX 属性。

从 Elements.xml 创建菜单

尽管从代码创建菜单相对简单易懂,但有些人可能更喜欢使用更声明式的方法,并在 Elements.xml 文件中定义菜单结构。但是,这仍然需要代码来将菜单项添加到“站点操作”菜单。首先,向类库项目添加另一个类,该类再次派生自 WebControl 并实现 CreateChildControls 方法。然后,向 SharePoint 项目添加另一个模块。像以前一样删除 Sample.txt 文件,并将上一个 Elements.xml 文件的内容复制到刚刚创建的文件中,并将 ControlClass 属性更改为匹配新创建的类。

<elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <customaction 
   id="MANSoftDev_SiteAction" 
   sequence="1" 
   controlclass="MANSoftDev.SiteAction.SiteActionDeclarative" 
   controlassembly="MANSoftDev.SiteAction, Version=1.0.0.0, 
	Culture=neutral, PublicKeyToken=2e15c7b1150d656d" 
   location="Microsoft.SharePoint.StandardMenu" 
   groupid="SiteActions">
  </customaction>
</elements>

现在您有了一个起点,您可以开始在 Elements.xml 文件中将菜单项添加为 CustomAction 元素。重要的属性是 Location GroupId。这些将在代码中使用来创建与菜单组对应的 FeatureMenuTemplate

<elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <customaction 
   id="MANSoftDev_SiteAction" 
   sequence="1" 
   controlclass="MANSoftDev.SiteAction.SiteActionDeclarative" 
   controlassembly="MANSoftDev.SiteAction, Version=1.0.0.0, 
	Culture=neutral, PublicKeyToken=2e15c7b1150d656d" 
   location="Microsoft.SharePoint.StandardMenu" 
   groupid="SiteActions">
  </customaction>

  <customaction 
   id="subMenu" 
   title="SubMenu" 
   description="A submenu item" sequence="100" 
   imageurl="/_layouts/images/settingsIcon.png" 
   location="MANSoftDev.CustomMenu" 
   groupid="MANSoftDev_Sub1">
  </customaction>

  <customaction 
   id="subMenu" 
   title="SubMenu" 
   description="A submenu item" 
   sequence="100" 
   imageurl="/_layouts/images/settingsIcon.png"
   location="MANSoftDev.CustomMenu" 
   groupid="MANSoftDev_Sub2">
  </customaction>
  
</elements>

ControlClass 中,您将再次重写 CreateChildControls 方法来创建与上面所示的 CustomAction 元素对应的 SubMenuTemplatesFeatureMenuTemplates

protected override void CreateChildControls()
{
    // Initialize collections
    SubMenus = new List();
    FeatureMenus = new Dictionary();

    // Create the SUbMenuTemplates
    SubMenuTemplate submenu = CreateSubMenu();
    Controls.Add(submenu);

    submenu = CreateSubMenu();
    Controls.Add(submenu);

    // Create the FeatureMenuTemplates
    FeatureMenuTemplate featureMenu = CreateFeatureMenu("MANSoftDev_Sub1");
    Controls.Add(featureMenu);

    featureMenu = featureMenu = CreateFeatureMenu("MANSoftDev_Sub2");
    Controls.Add(featureMenu);            
}

private FeatureMenuTemplate CreateFeatureMenu(string groupId)
{
    FeatureMenuTemplate featureMenu = new FeatureMenuTemplate();
    featureMenu.Location = "MANSoftDev.CustomMenu";
    featureMenu.GroupId = groupId;

    FeatureMenus.Add(groupId, featureMenu);

    return featureMenu;
}

CreateSubMenu 方法很简单,并且与前面使用的基于代码的方法类似。但是,CreateFeatureMenu 方法是通过 GroupId 属性将 CustomAction 元素链接到 FeatureMenuTemplate 的地方。如果此时调试代码,您会发现 FeatureMenuTemplates 中没有子项;但是,在 OnPreRender 方法中,它们有。魔力发生在 FeatureMenuTemplate 控件的 CreateChildControls 方法中。在这里,SharePoint 将使用 internal SPElementProvider 来提取 CustomAction 元素,并根据 GroupId 进行匹配,然后创建添加到 Controls 集合的 MenuItemTemplates

...
SPElementProvider availableProvider = SPElementProvider.GetAvailableProvider();
...

if (element2.Location != "CommandUI.Ribbon.Custom")
{
    MenuItemTemplate menuItem = new MenuItemTemplate();
    menuItem.Description = element2.Description;
    menuItem.ClientOnClickNavigateUrl = 
SPCustomActionElement.ServerRelativeUrlFromTokenizedUrl
			(element2.UrlAction, web, list, null);
    menuItem.Text = element2.Title;
    menuItem.Sequence = element2.Sequence;
    menuItem.MenuGroupId = element2.MenuGroupId;
    menuItem.ImageUrl = element2.ServerRelativeImageUrl;
    this.OnAddMenuItem(new AddMenuItemEventArgs(menuItem));
    if (menuItem.Visible)
    {
        this.Controls.Add(menuItem);
    }

    ...

OnPreRender 事件期间,您将遍历 FeatureMenuTemplates 并将 MenuItemTemplates 移动到适当的 SubMenuTemplate ,并将第二个级别的 SubMenuTemplate 添加到父级别。

protected override void OnPreRender(EventArgs e)
{
    // Add the first level menu items
    while(FeatureMenus["MANSoftDev_Sub1"].Controls.Count != 0)
    {
        MenuItemTemplate menu = FeatureMenus
	["MANSoftDev_Sub1"].Controls[0] as MenuItemTemplate;
        SubMenus[0].Controls.Add(menu); 
    }

    // Add the second level menu items
    while(FeatureMenus["MANSoftDev_Sub2"].Controls.Count != 0)
    {
        MenuItemTemplate menu = FeatureMenus
	["MANSoftDev_Sub2"].Controls[0] as MenuItemTemplate;
        SubMenus[1].Controls.Add(menu);
    }

    // Add the second level submenu to the top
    SubMenus[0].Controls.Add(SubMenus[1]);

    base.OnPreRender(e);
}

如您所见,此方法比前几种方法稍复杂,并且需要 Elements.xml 和代码之间的协调。但是,它可以让一个团队成员定义菜单,而另一个团队成员编写行为,或者创建一个可以在多个项目中重用的方法。

结论

我介绍了三种用于 SharePoint 2010 构建和部署带有子菜单的 SiteAction 菜单项的方法。不能说哪种方法“更好”,选择哪种方法将取决于您的需求。本文旨在介绍不同的技术,并为您提供选择最适合您项目的知识。

历史

  • 首次发布:2010 年 11 月 14 日
© . All rights reserved.