博客地址 http://blog.csdn.net/foxdave
本篇描述自定义sharepoint菜单的一种方式,自定义菜单适用于一些门户等需求的网站
自定义的菜单有自己的数据源,可以是数据表,可以是XML,本篇叙述的是采用XML数据源作为菜单的声明定义部分,将XML以文件的格式保存到网站中自己创建的配置文档库中
XML菜单的格式形如下面的格式,其中有菜单标题title属性,有菜单所属的权限用户组SPGroups属性,有菜单的链接url属性,实际应用中可以添加更多的字段。
<SiteMap>
<SiteMapNode title="我的项目" SPGroups="质量技术中心;造价中心;分公司;第3分公司;工程部;资金中心;核算中心;运营中心;内审中心;财务中心;核算中心;测试组;资金组" >
<SiteMapNode title="项目管理" url="/_layouts/SP_MIP/PI/PI_BasicInfoSearchInfo.aspx" SPGroups="质量技术中心;资金中心;核算中心;造价中心;财务中心;分公司;第3分公司;工程部;运营中心;内审中心;核算中心;测试组;资金组"/>
</SiteMapNode>
</SiteMap>
我们要给网站管理员提供一个接口来定义导航菜单,比如放到网站设置里,如图所示
新建一个SharePoint解决方案,添加一个元素Element用来定义这个网站设置菜单(CustomActionGroup和CustomAction节点)。代码如下(这里包含我后期添加的一个用户修改密码的功能,这里不做说明)
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomActionGroup
Id="SPMIPNavigation"
Title="SPMIP导航"
Description = "SPMIP导航"
Location = "Microsoft.SharePoint.SiteSettings"
Sequence = "1999"
ImageUrl="/_layouts/Images/SiteSettings_SPMIPNavigation_48x48.png">
</CustomActionGroup>
<CustomAction
Id="SPMIPTopNav"
GroupId="SPMIPNavigation"
Location="Microsoft.SharePoint.SiteSettings"
Rights="ManageWeb"
Sequence="2000"
Title="顶部导航"
Description="顶部导航">
<UrlAction Url="{SiteUrl}/_layouts/SP_MIP/TopNav.aspx" />
</CustomAction>
<CustomAction
Id="SPMIPLeftNav"
GroupId="SPMIPNavigation"
Location="Microsoft.SharePoint.SiteSettings"
Rights="ManageWeb"
Sequence="2010"
Title="左侧导航"
Description="左侧导航">
<UrlAction Url="{SiteUrl}/_layouts/SP_MIP/LeftNav.aspx" />
</CustomAction>
<CustomAction
Id="SPMIPChangePassword"
GroupId="PersonalActions"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="修改密码"
Description="修改密码"
ImageUrl="{SiteUrl}/_layouts/images/Welcome_SPMIPChangePwd_32x32.png">
<UrlAction Url="javascript:Show();"/>
</CustomAction>
</Elements>
添加相应的网站资产,如设置图片。添加两个页面TopNav.aspx和LeftNav.aspx。两个页面其实没什么区别,以TopNav为例,添加一个多行文本框,一个保存按钮就可以了。
核心页面代码
<table border="0" width="100%" cellspacing="0" cellpadding="0">
<wssuc:InputFormSection ID="InputFormSection" Title="顶部导航" runat="server" Description="顶部导航">
<Template_InputFormControls>
<wssuc:InputFormControl ID="InputFormControl" runat="server">
<Template_Control>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="right" style="padding-bottom: 5px">
<a href="javascript:topnav_showFullScreen('<%= txtNavXml.ClientID %>', '<%= txtNavXmlPop.ClientID %>');"
style="color: #0072bc;">
<asp:Literal ID="ltl" runat="server" Text="全屏编辑" />
</a>
</td>
</tr>
<tr>
<td>
<asp:TextBox ID="txtNavXml" runat="server" Wrap="false" TextMode="MultiLine" Rows="22"
Width="600px" />
</td>
</tr>
</table>
</Template_Control>
</wssuc:InputFormControl>
</Template_InputFormControls>
</wssuc:InputFormSection>
<wssuc:ButtonSection ID="bts" runat="server" ShowStandardCancelButton="false">
<Template_Buttons>
<asp:Button runat="server" class="ms-ButtonHeightWidth" Text="保存" ID="btnSave" OnClick="btnSave_OnClick" />
<asp:Button runat="server" class="ms-ButtonHeightWidth" Text="取消" ID="btnClose" OnClientClick="TopNav_Close_Click(); return false;" />
</Template_Buttons>
</wssuc:ButtonSection>
</table>
<table id="tblFullScreen" border="0" cellpadding="0" cellspacing="0" class="tblPop">
<tr>
<td align="center" valign="top">
<table border="0" cellpadding="5" cellspacing="0" width="100%">
<tr>
<td>
<asp:TextBox ID="txtNavXmlPop" runat="server" Wrap="false" TextMode="MultiLine" Rows="28"
Width="99%" />
</td>
</tr>
<tr>
<td align="center">
<a href="javascript:topnav_hideFullScreen('<%= txtNavXml.ClientID %>', '<%= txtNavXmlPop.ClientID %>');"
style="color: #0072bc;">
<asp:Literal ID="ltlClose" runat="server" Text="关闭" />
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
按钮后台的处理事件要做的事情就是把XML配置文件的内容读取出来,并把用户更改的XML定义保存回文档库的XML文件中。
protected void btnSave_OnClick(object sender, EventArgs e)
{
try
{
Config.Save(base.Web, this.txtNavXml.Text, Config.NavType.Top);
SPUtility.Redirect("settings.aspx", SPRedirectFlags.RelativeToLayoutsPage, HttpContext.Current);
}
catch (Exception exception)
{
SPMIPTrace.WriteError("SPMIPNavigation", exception);
}
} protected void Page_Load(object sender, EventArgs e)
{
if (!base.IsPostBack)
{
this.txtNavXml.Text = Config.Load(base.Web, Config.NavType.Top);
}
}
class Config
{
public static string Load(SPWeb web, NavType navType)
{
string str = null;
try
{
StreamReader reader;
SPList settingList = SPMIPUtility.CheckSettingList("SPMIPSetting");
switch (navType)
{
case NavType.Top:
{
SPFile topNavSettingFile = settingList.RootFolder.Files["TopNav.xml"];
if (topNavSettingFile.Exists)
{
using (reader = new StreamReader(topNavSettingFile.OpenBinaryStream()))
{
str = reader.ReadToEnd();
}
}
break;
}
case NavType.Left:
{
SPFile leftNavSettingFile = settingList.RootFolder.Files["LeftNav.xml"];
if (leftNavSettingFile.Exists)
{
using (reader = new StreamReader(leftNavSettingFile.OpenBinaryStream()))
{
str = reader.ReadToEnd();
}
}
break;
}
}
return str;
}
catch (Exception exception)
{
SPMIPTrace.WriteError("SPMIPNavigation", exception);
return str;
}
} public static bool Save(SPWeb web, string fileContent, NavType navType)
{
bool flag = false;
try
{
SPList settingList = SPMIPUtility.CheckSettingList("SPMIPSetting");
byte[] bytes = Encoding.UTF8.GetBytes(fileContent);
web.AllowUnsafeUpdates = true;
switch (navType)
{
case NavType.Top:
settingList.RootFolder.Files.Add("TopNav.xml", bytes, true);
break;
case NavType.Left:
settingList.RootFolder.Files.Add("LeftNav.xml", bytes, true);
break;
}
flag = true;
}
catch (Exception exception)
{
SPMIPTrace.WriteError("SPMIPNavigation", exception);
}
return flag;
} public enum NavType
{
Top,
Left
}
}
大致的功能就完成了,下一讲叙述如何在母版页应用这个菜单声明。