SharePoint 页面导航 Web 部件






4.56/5 (4投票s)
一个 Web 部件,供用户放置在其页面上,用于跨网站集进行导航。

引言
我新工作的一个良好开端。我获得了很多新的机会来探索 SharePoint。在企业环境(与软件公司不同)中工作,让我直接接触到了用户的需求。我们有不少用户接受过 SharePoint 培训,知道如何创建和添加页面到他们的部门网站。SharePoint 缺少的一个 Web 部件是允许用户将导航部分放置在其每个页面上,以便他们可以从一个页面移到另一个页面的功能。我通过创建一个导航部分来解决这个问题,该导航部分可以查询网站集内的库,并使用 JavaScript 菜单栏向用户显示这些链接。
安装
希望大多数人都知道如何安装 Web 部件,但如果您需要帮助,请按照以下步骤操作
- 将 Mullivan.Shared.dll 和 Mullivan.SharePoint.WebParts.dll 加入 GAC。
- 在 SharePoint Web Config 中注册 Mullivan.SharePoint.WebParts.dll。
转到 C:\inetpub\wwwroot\wss\VirtualDirectories\<端口号>\web.config。在
SafeControls
节点之间添加以下内容<SafeControl Assembly="Mullivan.SharePoint.WebParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c37a514ec27d3057" Namespace="Mullivan.SharePoint.WebParts" TypeName="*" Safe="True" />
- 转到“站点设置” -> “Web 部件” -> 在菜单上单击“新建”。
滚动到底部,勾选 Mullivan.SharePoint.WebParts.LibraryNavigationWebPart,然后滚动回顶部,单击“填充库”。
完成!您应该会在“Web 部件”集合中看到它。
配置
将 Web 部件放置在页面上后,您将需要修改其设置。您会在属性窗格顶部的“导航”类别中看到。在这里,您将配置导航控件中的每个选项卡。单击加号添加,或双击任何现有项目进行编辑。
- 标题 - 您希望选项卡显示的文本。如果留空,则默认为列表标题。
- 列表 URL - 单击“浏览”以指向您要查询的列表。
- 显示字段 - 列表字段的内部 SharePoint 名称,当用户鼠标悬停在选项卡上时,将使用该字段作为显示文本。
- 查询 - 将针对该列表执行的 Camel 查询,用于过滤项目。在构建查询时,请务必使用列的内部名称。
示例

单击“确定”,您的第一个选项卡就创建好了。然后您可以移动它并按适当的顺序排列选项卡。
Using the Code
我们公司有三个不同的环境,能够轻松部署这些 Web 部件至关重要。这意味着 SharePoint 的布局目录中不能有任何必须手动放入的资源,例如图片、页面等。因此,在创建此 Web 部件时,我们要做的三件事是:嵌入我们的 JavaScript、CSS 和图片。
第一步是将所有 JavaScript 嵌入此 DLL 中,并使用 ScriptManager 进行提取。因此,选择您的 JS 项目(JS/LibraryNavigation.js),转到属性窗格,将“生成操作”设置为“嵌入的资源”。
现在,我们需要在 AssemblyInfo.cs 中添加对嵌入资源的引用。只需在文件底部追加该行即可。因此,我们需要为 WebResource 提供资源的路径及其 MIME 类型。路径的格式为“<默认命名空间>.<文件夹>.<文件名>”。如果您有多个文件夹,则格式为“<默认命名空间>.<文件夹1>.<文件夹2>.<文件名>”。
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c0e90cc1-f501-4b02-97aa-fffccacfa00f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: WebResource("Mullivan.SharePoint.WebParts.JS.Utility.js", "text/javascript")]
这样,我们就可以获取 JavaScript 资源的 URL 并将其注册到页面上了。
ClientScriptManager csm = this.Page.ClientScript;
Type lnType = this.GetType();
//Register our JavaScript file
if (!csm.IsClientScriptIncludeRegistered(
@"Mullivan.SharePoint.WebParts.JS.LibraryNavigation.js"))
{
string url = csm.GetWebResourceUrl(lnType,
@"Mullivan.SharePoint.WebParts.JS.LibraryNavigation.js");
csm.RegisterClientScriptInclude(lnType,
"Mullivan.SharePoint.WebParts.JS.LibraryNavigation.js",
ResolveClientUrl(url));
}
太棒了!现在我们已经连接了 JavaScript。让我们开始注册 CSS。我们通过与 JavaScript 文件相同的步骤来嵌入 CSS 文件。也就是说,将“生成操作”设置为“嵌入的资源”,并在 AssemblyInfo.cs 中添加 WebResource
对象。在 SharePoint 中注册 CSS 文件可能会很棘手。这是因为我们可以使用 CSSRegistration
类,但有一个问题。SharePoint 总是会在我们注册的 CSS 文件之后加载 Core.css。您可能会问这有什么关系?好吧,在 CSS 中,页面中最后加载的文件获胜。它的 CSS 样式将覆盖之前的任何样式。在我们的例子中,我们想更改 Web 部件中超链接的样式。如果我们不让我们的 CSS 最后加载,那么 Core.css 的超链接样式将覆盖我们的。所以,这里有一个让我们的 CSS 文件最后加载的技巧。
protected override void OnPreRender(EventArgs e)
{
ClientScriptManager csm = this.Page.ClientScript;
Type lnType = this.GetType();
RegisterStyleSheet(ResolveUrl(csm.GetWebResourceUrl(lnType,
@"Mullivan.SharePoint.WebParts.CSS.LibraryNavigation.css")));
base.OnPreRender(e);
}
private void RegisterStyleSheet(string cssUrl)
{
//Find the HtmlHead control in the masterpage file
HtmlHead header = FindControl<HtmlHead>(this.Page.Master.Controls);
if (header != null)
{
Literal literal = new Literal();
literal.Text = string.Format("<link href=\"{0}\" type" +
"=\"text/css\" rel=\"stylesheet\"/>", cssUrl);
//Add our link to our CSS file to the header
header.Controls.Add(literal);
}
}
private T FindControl<T>(ControlCollection controlCollection)
where T : Control
{
foreach (Control c in controlCollection)
{
if (c.GetType() == typeof(T))
return (T)c;
else
{
T child = FindControl<T>(c.Controls);
if (child != null)
return child;
}
}
return null;
}
现在,您需要转到设置图片和嵌入的资源,并在 AssemblyInfo.cs 中添加 WebResource
对象。现在,我们可以渲染我们的 HTML,并将我们的图像标签设置为指向我们的 web 资源 URL。
ClientScriptManager csm = this.Page.ClientScript;
Type lnType = this.GetType();
string libNavLeftUrl = ResolveUrl(csm.GetWebResourceUrl(lnType,
"Mullivan.SharePoint.WebParts.Images.LibNav_Left.jpg"));
string libNavMidUrl = ResolveUrl(csm.GetWebResourceUrl(lnType,
"Mullivan.SharePoint.WebParts.Images.LibNav_Mid.jpg"));
string libNavRightUrl = ResolveUrl(csm.GetWebResourceUrl(lnType,
"Mullivan.SharePoint.WebParts.Images.LibNav_Right.jpg"));
string libNavOverUrl = ResolveUrl(csm.GetWebResourceUrl(lnType,
"Mullivan.SharePoint.WebParts.Images.LibNav_Over.jpg"));
string libNavSubItemMidUrl = ResolveUrl(csm.GetWebResourceUrl(lnType,
"Mullivan.SharePoint.WebParts.Images.LibNav_SubItem_Mid.jpg"));
string libNavSubItemOverUrl = ResolveUrl(csm.GetWebResourceUrl(lnType,
"Mullivan.SharePoint.WebParts.Images.LibNav_SubItem_Over.jpg"));
writer.WriteLine("<div class=\"lnwp_Container\">");
writer.WriteLine("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
//create td with middle background image
writer.WriteLine(string.Format("<tr style=\"background" +
"-image:url('{0}')\">", libNavMidUrl));
writer.WriteLine("<td>");
writer.WriteLine(string.Format("<div class=\"lnwp_LeftImage\" style" +
"=\"background-image:url('{0}')\" />", libNavLeftUrl));
writer.WriteLine("</td>");
好的,现在我们已经嵌入了所有资源,我们可以考虑用户将如何配置此 Web 部件。在我们的 Web 部件配置中,只需放入两个文本框,让它们提供 SPWeb URL 和列表名称,这会非常简单。但是,我认为让它们使用内容查询 Web 部件使用的列表/Web 选择器会更酷!所以,我们来偷点 JavaScript!
这是我们 Web 部件配置面板中“浏览”按钮的 HTML。{n} 标签是我稍后执行的字符串替换。{0} 是我们 web 部件的 ClientID。{1} 是保存配置 XML 的视图状态文本框的 ClientID。最后,{7} 是 SPSite 的 RelativeServerUrl
。
<input type="button"
id="{0}_ListUrl_BUILDER"
value="Browse..."
title="Click to use list picker."
tabindex="0"
class="ms-PropGridBuilderButton"
style="display:inline;cursor:pointer;width:55px;text-align:center"
onclick="javascript:LPNW_LaunchListPicker('{1}','{0}', '{7}')" />
这是我们调用的 OnClick
方法
function LPNW_LaunchListPicker(viewStateId, clientId, serverUrl) {
var callback = function(results) {
LPNW_SetList(clientId, results);
};
LaunchPickerTreeDialog('CbqPickerSelectListTitle', 'CbqPickerSelectListText',
'listsOnly', '', serverUrl, lastSelectedListId, '',
'', '/_layouts/images/smt_icon.gif', '', callback);
}
function LPNW_SetList(clientId, results) {
var listTextBox = document.getElementById(clientId + "_ListUrl_EDITOR");
if (results == null
|| results[1] == null
|| results[2] == null) return;
if (results[2] == "") {
alert("You must select a list!.");
return;
}
lastSelectedListId = results[0];
var listUrl = '';
if (listUrl.substring(listUrl.length - 1) != '/')
listUrl = listUrl + '/';
if (results[1].charAt(0) == '/')
results[1] = results[1].substring(1);
listUrl = listUrl + results[1];
if (listUrl.substring(listUrl.length - 1) != '/')
listUrl = listUrl + '/';
if (results[2].charAt(0) == '/')
results[2] = results[2].substring(1);
listUrl = listUrl + results[2];
listTextBox.value = listUrl;
}
所以,我们将从中获得一个看起来像这样的字符串:<WebRelativeServerUrl>\<ListTitle>
。您可能会问 ListTitle!?!?如果管理员更改了列表的名称怎么办?列表的 URL 保持不变,但标题会改变!!好吧,我们需要在 C# 后台代码中进行一些解析,以便从 SharePoint 获取我们的 SPList
对象。我将演示一下。
private NavLink GetNavLink(LibNavLink link)
{
NavLink navLink = new NavLink();
SPSite site = SPContext.Current.Site;
using (SPWeb web = site.OpenWeb(GetWebUrl(link.ListUrl)))
{
string listName = GetListName(link.ListUrl);
SPList list = web.Lists[listName];
if (list == null)
throw new Exception(string.Format("List {0} could not be found.",
link.ListUrl));
//Set Defaults
if (string.IsNullOrEmpty(link.DisplayField))
{
if (list.BaseType == SPBaseType.DocumentLibrary)
link.DisplayField = "BaseName";
else
link.DisplayField = "Title";
}
navLink.Title = link.Title;
navLink.Url = MullivanUtility.GetServerUrl(this.Page.Request) +
list.DefaultViewUrl;
SPQuery query = new SPQuery();
if (!string.IsNullOrEmpty(link.Query))
query.Query = link.Query;
query.ViewAttributes = "Scope=\"Recursive\"";
query.ViewFields = string.Format("<FieldRef Name=\"EncodedAbsUrl\" />" +
"<FieldRef Name=\"{0}\" />", link.DisplayField);
SPListItemCollection items = list.GetItems(query);
foreach (SPItem item in items)
{
NavLink subLink = new NavLink();
subLink.Title = item[link.DisplayField].ToString();
subLink.Url = item["EncodedAbsUrl"].ToString();
navLink.SubLinks.Add(subLink);
}
}
return navLink;
}
private string GetWebUrl(string listUrl)
{
string webUrl = string.Empty;
listUrl = listUrl.TrimEnd('/');
int lastIndex = listUrl.LastIndexOf("/");
if (lastIndex > -1)
webUrl = listUrl.Substring(0, lastIndex);
return webUrl.TrimEnd('/');
}
private string GetListName(string listUrl)
{
string listName = string.Empty;
listUrl = listUrl.Trim('/');
int lastIndex = listUrl.LastIndexOf("/");
if (lastIndex > -1)
listName = listUrl.Substring(lastIndex + 1, listUrl.Length - lastIndex - 1);
return listName;
}
关注点
项目中还包含另外两个 Web 部件。天气 Web 部件是从 Mossman 的一个博客(这里)获取的。另一个是我刚刚写过的一个 Web 部件。它是一个非常棒的 Web 部件,它查询分析数据库,并按用户或匿名方式返回最常用的内容。我称之为“最受欢迎 Web 部件”。在这里查看。
结论
请告诉我您的想法。如果您有任何想法,我一定会看看是否能提供更新。希望您觉得这个 Web 部件很有用。
历史
- 2009 年 1 月 14 日:初始帖子
- 2009 年 3 月 19 日:更新源代码
- 2009 年 3 月 24 日:已更新源代码