環境 :
Microsoft Office SharePoint Server 2007
Visual Studio 2008 (Professional Edition 以上)
こんにちは。
SharePoint WCM (セミナー補足) :
セミナーのフォローアップ記事 Part 2 です。
メニュー / ツリー / ナビゲーションも、デフォルトのものではなく、細かなカスタマイズを必要とするケースが多くなります。ご紹介したように、これを解決する基本は、やはり ASP.NET です。
例えば、発行機能が有効になっているサイトでは、下記のようにページが発行されるたびにタブが増えていきます。

SharePoint では、あちこちに垂直、水平などでさまざまな動的メニュー / 動的ツリーを表示することができますが、今回は、ここ(上図)をカスタマイズしてみましょう。
予備知識
まず、この仕組みですが、ASP.NET のサイトマップの仕組みを使用しているだけです。(よって ASP.NET を知っている方なら、むずかしくありません。)
まず、上図の箇所のマークアップソース (default.master) をみてみましょう。(注意 : 編集に際しては default.master を直接編集せず、コピーなどをして、そのコピーしたマスターページを編集してください。)
<asp:ContentPlaceHolder id="PlaceHolderHorizontalNav" runat="server">
<SharePoint:AspMenu
ID="TopNavigationMenu"
Runat="server"
DataSourceID="topSiteMap"
EnableViewState="false"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
Orientation="Horizontal"
StaticDisplayLevels="2"
MaximumDynamicDisplayLevels="1"
DynamicHorizontalOffset="0"
StaticPopoutImageUrl="/_layouts/images/menudark.gif"
StaticPopoutImageTextFormatString=""
DynamicHoverStyle-BackColor="#CBE3F0"
SkipLinkText=""
StaticSubMenuIndent="0"
CssClass="ms-topNavContainer">
<StaticMenuStyle/>
<StaticMenuItemStyle CssClass="ms-topnav" ItemSpacing="0px"/>
<StaticSelectedStyle CssClass="ms-topnavselected" />
<StaticHoverStyle CssClass="ms-topNavHover" />
<DynamicMenuStyle BackColor="#F2F3F4" BorderColor="#A7B4CE" BorderWidth="1px"/>
<DynamicMenuItemStyle CssClass="ms-topNavFlyOuts"/>
<DynamicHoverStyle CssClass="ms-topNavFlyOutsHover"/>
<DynamicSelectedStyle CssClass="ms-topNavFlyOutsSelected"/>
</SharePoint:AspMenu>
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource">
<Template_Controls>
<asp:SiteMapDataSource
ShowStartingNode="False"
SiteMapProvider="SPNavigationProvider"
id="topSiteMap"
runat="server"
StartingNodeUrl="sid:1002"/>
</Template_Controls>
</SharePoint:DelegateControl>
</asp:ContentPlaceHolder>
セミナーでご説明した「SharePoint 用に継承されたクラス」が使われていますが、基本はASP.NETと同じ???です。が、しかし、う~ん、ASP.NET を知っている人でもちょっと面くらってしまうかもしれませんね。実は、おぼえてしまえば難しいものではありません。
まず、<SharePoint:AspMenu /> は、SharePoint 独自のメニューを使用しているだけで、基本的には <asp:Menu /> の SharePoint 版だと思ってもらえれば充分です。
そして、<SharePoint:DelegateControl /> のタグですが、これは ASP.NET を知っている人でも初めて見るタグかもしれませんが、「委任コントロール」と言う SharePoint の機能で、上記の ControlId 値の「TopNavigationDataSource」に一致する複数のコントロールのフィーチャー (機能) の中で Sequnce 番号の優先順位がもっとも高いフィーチャー (コントロールのフィーチャー) がここに設定されるというものです。つまり、このようにすることで、サイトごとに表示を切り替えることができるようになっています。(どのフィーチャーが有効であるかはサイトごとに異なるため、このように記述することで、同じマスターページを使ってサイトごとに異なったコントロールが挿入できます。)
セミナーでは別の方法でデモをしましたが、例えば、発行機能が有効になっているサイトでは、以下の通り書き換えても同じ意味になります。(SharePoint ハイブの FUTURES\Navigation フォルダのフィーチャーが使用されています。) このように記述すると、ASP.NET な方でも意味を理解していただけるでしょう。。。
<%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
. . . . .
<asp:ContentPlaceHolder id="PlaceHolderHorizontalNav" runat="server">
<SharePoint:AspMenu . . .>
. . . . .
</SharePoint:AspMenu>
<PublishingNavigation:PortalSiteMapDataSource
ShowStartingNode="True"
SiteMapProvider="CombinedNavSiteMapProvider"
id="topSiteMap"
StartFromCurrentNode="true"
StartingNodeOffset="0"
EnableViewState="false"
TreatStartingNodeAsCurrent="true"
TrimNonCurrentTypes="Heading"
runat="server"/>
</asp:ContentPlaceHolder>
ということで、普通の ASP.NET 同様、ただ単に、Menu とサイトマップを使っているだけなのです。
カスタムのサイトマッププロバイダーを使ったカスタムな表示項目
ここまで仕組みがわかったら、あとは普通の ASP.NET のようにカスタマイズすれば終わりです。ここに独自のリンクを表示する独自なサイトマッププロバイダーを作成してみましょう。ここで紹介するコードはあまり意味がありませんが、このコードが理解できれば、あとはコードを自由に変更して、例えば、「特定の列 (フィールド) に値が設定されているページだけをメニューに表示する」など、自由にメニューの表示項目を設定できます。
まず、カスタムのプロバイダーを実装します。Visual Studio でクラスライブラリのプロジェクトを新規作成して、以下を参照追加します。
System.Web.dll
System.Configuration.dll
Microsoft.SharePoint.dll
下記のコードを実装します。
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;
namespace CustomSamples
{
public class MyTestSiteMapProvider : StaticSiteMapProvider
{
private SiteMapNode rootNode = null;
private DateTime lastModified;
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes)
{
base.Initialize(name, attributes);
// (初期化なし)
}
public override SiteMapNode BuildSiteMap()
{
// 5 分に 1 回更新 (それ以外はキャッシュを使用)
if ((rootNode != null) && ((DateTime.Now - lastModified).Minutes < 5))
return rootNode;
// 状態を更新するため排他ロック !
lock (this)
{
Clear();
rootNode = new SiteMapNode(this, "Home", "/Default.aspx", "ホーム", "これはホームです");
SPWeb web = SPControl.GetContextWeb(HttpContext.Current);
foreach (SPList list in web.Lists)
{
// [ページ] ライブラリを取得 !
if (list.BaseTemplate == (SPListTemplateType)850)
{
foreach (SPListItem item in list.Items)
{
if(item.Level == SPFileLevel.Published)
{
SiteMapNode node = new SiteMapNode(this,
"Site" + item.ID.ToString(),
SPUrlUtility.CombineUrl(web.ServerRelativeUrl, item.Url),
item.Title);
AddNode(node, rootNode);
}
}
}
}
lastModified = DateTime.Now;
}
return rootNode;
}
protected override SiteMapNode GetRootNodeCore()
{
if (rootNode == null)
BuildSiteMap();
return rootNode;
}
}
}
上記のように、ここでは、[ページ] ライブラリの公開ページを検索して設定しているだけなのであまり意味がありませんが、このようにして、いかようにでもメニューに提供する項目をコードで記述することができます。 (上記の通り、ASP.NET における普通のサイトマッププロバイダーです。)
署名を添付してビルドし、dll を GAC に登録します。
つぎに、SharePoint の web.config を開き、以下 (太字) を追加します。(下記は、作成したクラスライブラリにあわせてアセンブリ名など変更してください。)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration>
. . . . .
<siteMap defaultProvider= . . . >
<providers>
. . . . .
<add name="MyCustomProvider" description="Provider for custom navigation" type="CustomSamples.MyTestSiteMapProvider, CustomSamples, Version=1.0.0.0, Culture=neutral, PublicKeyToken=133b75b7653d82a9" />
</providers>
</siteMap>
. . . . .
iisreset をおこないます。
さいごに、前述のマークアップコードで示したマスターページ (.master) のサイトマップデータソース / プロバイダーの設定箇所を下記 (太字) の通り変更して、このカスタムのサイトマッププロバイダーを使用するようにします。
<asp:ContentPlaceHolder id="PlaceHolderHorizontalNav" runat="server">
<SharePoint:AspMenu . . .>
. . . . .
</SharePoint:AspMenu>
<asp:SiteMapDataSource
ShowStartingNode="false"
SiteMapProvider="MyCustomProvider"
id="topSiteMap"
runat="server"/>
</asp:ContentPlaceHolder>
以上で完了です。
ここでは、サイトマッププロバイダーのカスタマイズ (つまり、表示されるアイテムのカスタマイズ) しか説明していませんが、メニューなどのスタイルも当然フルカスタマイズできます。ちょうど 1 週間ほど前に、SharePoint Team Blog でも以下のような投稿がありましたので、実際のインターネットサイトでどのようなスタイル設定をおこなったか、など、是非参考にしてみてください。(xslt の編集など、昨日のセミナーを思い出していただくと、カスタマイズ方法がいろいろ連想していただけると思います。)
How We Did It: SharePoint.Microsoft.com :
http://blogs.msdn.com/sharepoint/archive/2009/06/18/how-we-did-it-sharepoint-microsoft-com.aspx