最新の SharePoint 開発については SharePoint Framework を参照してください。(この開発手法は、古い情報です。)
SharePoint Add-ins 開発
- 概要
- .NET CSOM を使ったプログラミングと認証
- Cross-domain library を使ったプログラミング
- App Part の開発
- List Definition の開発と Client Side Rendering (CSR)
- Remote Event Receiver の開発と Debug
- UI Custom Action の開発 (Ribbon のカスタマイズ)
- Workflow の開発
- On-Premises (SharePoint Server) で動く SharePoint Add-ins の作成 (Authentication)
- クラウド ビジネス アプリ (Cloud Business App)
- Patterns and Practices (PnP) による CSOM 拡張ライブラリー
こんにちは。
今回は、SharePoint Add-ins (SharePoint アドイン, 旧 App for SharePoint) のカスタム リスト定義 (List Definition) とリスト インスタンス (List Instance) の開発 (プログラミング) を解説します。
まず、ご存じない方のために、基本事項を補足します。
リスト定義とは、例えば、SharePoint に既に含まれている「タスク」、「お知らせ」、「ディスカッション掲示板」などのリスト (ドキュメント ライブラリーを含む) のひな形 (テンプレート) であり、リスト インスタンスは、このリスト定義から実際に作成された「リスト」 (または、「ドキュメント ライブラリー」) です。(厳密には、リスト定義とは別に「リスト テンプレート」があり、SharePoint ではこれらもテンプレートとして表示されますが、ここでは細かな説明は省略します。)
SharePoint Add-ins でも、従来の SharePoint 開発同様、リスト定義とリスト インスタンスを開発 (プログラミング) でき、考え方のベースは同じですが、いくつか SharePoint 2013 独自の注意点や新機能もあるので以下に補足しながら解説します。
なお、今回から、ちゃんと日本語版を使用します !
基本は従来と同じ、しかし … (App Event Receiver の活用)
では、さっそくリスト定義とリスト インスタンスを構築してみましょう。
Visual Studio 2012 を起動し、[Apps for SharePoint 2013] (SharePoint Add-ins) のプロジェクトを新規作成します。
リスト定義 (List Definition) のような SharePoint の artifacts の場合には、SharePoint-hosted (SharePoint ホスト型) でホストされます。(SharePoint-hosted については、「SharePoint Add-ins の動作と概要」参照。) このため、今回は、ウィザードで、[SharePoint ホスト型] (SharePoint-hosted) を選択してプロジェクトを作成してください。
作成されたプロジェクトをマウスで右クリックして、[追加] – [新しい項目] を選択すると、下記の通り、SharePoint の artifacts を追加する画面が表示されます。ここで、「List1」という名前のリストを追加します。
リストを追加すると、リスト定義と、そのリスト定義から派生したリスト インスタンスが自動作成されます。
以降の開発 (プログラミング) の基本は、SharePoint 2010 の頃と同様です。ですので、事前に、「SharePoint のリスト定義の作成」を読んで理解しておいてください。
例えば、作成された「List1」をダブルクリックして表示される下図で、[列] タブを選択して列の追加や変更が可能です。(下図では、「Address」という名前の列を追加しています。)
この編集内容は、下図の通り、schema.xml に反映されます。(リスト定義の schema.xml については、「SharePoint のリスト定義の作成」を参照してください。)
<?xml version="1.0" encoding="utf-8"?><List xmlns:ows="Microsoft SharePoint" title='' ...> <MetaData>. . .<Fields> <Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}"Type="Text"Name="Title"DisplayName="$Resources:core,Title;"Required="TRUE" ... /> <Field ID="{56ec54d2-3c20-4284-9d74-564ceced0e82}"Type="Text"Name="Address"DisplayName="Address" /></Fields>. . .
また、上図で [リスト] タブを選択して、表示される画面で [リストをサイド リンク バーに表示する] (Display list at Quick Launch) のチェックを選択すると、リスト インスタンスは SharePoint サイトの左のバー (Quick Launch) に表示されます。
この内容は、これまで (SharePoint 2010 まで) と同様、リスト インスタンスのフィーチャーの Elements.xml に下記の通り反映されます。(Elements.xml についても、「SharePoint のリスト定義の作成」を参照してください。)
<?xml version="1.0" encoding="utf-8"?><Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <ListInstancetitle=''OnQuickLaunch="TRUE"TemplateType="10000"Url="Lists/List1"Description="マイ リスト インスタンス"> </ListInstance></Elements>
ただ、この設定をおこなっても、そもそもリスト定義やリスト インスタンスが別サイト (サブ サイト) に反映されるという点に注意してください。例えば、ユーザーが SharePoint Online (Office 365) を使っていて、https://contoso.sharepoint.com/sites/test1 のサイトで SharePointApp1 の Add-ins を追加した場合、以下のサブ サイトが作成され、ここにリスト定義やリスト インスタンスが追加されます。(「SharePoint Add-ins の動作と概要」の解説を参照。)
https://contoso-<atbitary identity>.sharepoint.com/sites/test1/<sub site with project name>
(例えば、https://contoso-3202b4c1a25bf7.sharepoint.com/sites/test1/SharePointApp1)
つまり、リスト インスタンスをサイド リンク バー (Quick Launch) に表示しても、ユーザーが使っている https://contoso.sharepoint.com/sites/test1 のサイド リンク バー (Quick Launch) ではなく、https://contoso-<atbitary identity>.sharepoint.com/sites/test1/<sub site with project name> のサイド リンク バー (Quick Launch) に設定されるので、意味がありません。
このような場合、従来の SharePoint 開発同様、カスタム コードを使って設定をおこなうことができます。SharePoint Add-ins では、従来使用していた Feature Receiver は使用できず、App Event Receiver を使用します。
例えば、Host Web (ユーザーが使用しているサイト) に Quick Launch を追加するには、(Visual Studio の) ソリューション エクスプローラーで Add-ins のプロジェクトをクリックし、下図の通り [アプリのハンドルがインストールされました] (Handle App Installed) を「True」に設定します。
アプリがインストールされた際のハンドラーが、Remote App (マニフェストの入っている Add-ins とは別プロジェクト) として作成されます。(Provider-hosted で作成されます。) この作成された Web アプリケーションの AppEventReceiver.svc.cs に、下記の通りコードを記述します。ここではインストール時の処理のみ作成していますが、同様に、アンインストール時の処理も記述しておきましょう。
. . .using System.ServiceModel;using System.ServiceModel.Channels;using System.Net;. . .public class AppEventReceiver : IRemoteEventService{ public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) {SPRemoteEventResult result = new SPRemoteEventResult();if (properties.EventType != SPRemoteEventType.AppInstalled) return result;HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpRequestMessageProperty.Name];SharePointContextToken contextToken = TokenHelper.ReadAndValidateContextToken(properties.ContextToken,requestProperty.Headers[HttpRequestHeader.Host]);string accessToken = TokenHelper.GetAccessToken( contextToken, properties.AppEventProperties.HostWebFullUrl.Authority).AccessToken;using (ClientContext clientContext = TokenHelper.GetClientContextWithAccessToken(properties.AppEventProperties.HostWebFullUrl.ToString(),accessToken)){ Web site = clientContext.Web; NavigationNodeCollection collQuickLaunchNode =site.Navigation.QuickLaunch; NavigationNodeCreationInformation ciNavicationNode =new NavigationNodeCreationInformation(); ciNavicationNode.Title = "List1"; Uri navUri = new Uri(properties.AppEventProperties.AppWebFullUrl,"SharePointApp1" + "/" + "Lists/List1"); ciNavicationNode.Url = navUri.ToString(); ciNavicationNode.AsLastNode = true; collQuickLaunchNode.Add(ciNavicationNode); clientContext.Load(collQuickLaunchNode); clientContext.ExecuteQuery();}return result; } . . .
なお、この場合、Add-ins に「サイト コレクション」への Manage のアクセス許可 (Permission) を設定してください。(アクセス許可の考え方については、「SharePoint Add-ins の動作と概要」を参照してください。)
補足 : Remote Event Receiver のデバッグ実行をおこなう際は注意してください。普通にデバッグ実行すると、Office 365 のサーバーから localhost のサービスへの接続に失敗します。
Remote App を Azure にホストするなどして動作させます。
この Remote Event Receiver の動作とプログラミングについては、次回、解説します。
また、[サイト コンテンツ] から、この Add-ins をクリックした場合に、リスト (上記の List1) が表示されるように、AppManifest.xml を下記の通り編集しておくと良いでしょう。
<?xml version="1.0" encoding="utf-8" ?><App . . .> <Properties><Title>SharePointApp1_Remote</Title><StartPage>~appWebUrl/Lists/List1</StartPage> </Properties> . . .</App>
Client Side Rendering (CSR) と List View、List Form のカスタマイズ
カスタム リストを使った現実のアプリケーションでは、リスト ビューやリスト フォーム (DisplayForm, EditForm, NewForm) のカスタマイズが頻繁に必要となります。しかし、これまでは、「SharePoint 2010 : リスト定義における XSL を使用したビューのカスタマイズ」を読んでいただくとおわかりの通り、SharePoint 独自の XML (CAML) や XSL を使用して編集をおこなう必要があり、結構面倒でした。(例えば、JavaScript を埋め込む場合には、XSLT の中に埋め込み、文字列をエスケープするなど煩雑なコードの記述が必要でした。)
SharePoint 2013 では、Client Side Rendering (CSR) と呼ばれる方式で、SharePoint が作成するリスト ビューやリスト フォームの UI を JavaScript を使用してカスタマイズ (クライアント側で Overrides) できるようになっており、こうした Pain が解消されています。
ここでは、この SharePoint 2013 からの Client Side Rendering (CSR) について補足しておきます。
まず、特定のビューに CSR を適用するには、schema.xml を開いて、下記の通り、使用する JavaScript ファイル (.js ファイル) を挿入します。(下記で、~site は、Add-ins のサイトを表すトークンです。List1Sample.js は、このあとで作成します。clienttemplates.js は CSR に必要なので、挿入しておいてください。)
. . .<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" . . ."> <Toolbar Type="Standard" /> <XslLink Default="TRUE">main.xsl</XslLink> <JSLink>clienttemplates.js|~site/Scripts/jquery-1.7.1.min.js|~site/Scripts/List1Sample.js</JSLink> <RowLimit Paged="TRUE">30</RowLimit> . . .
また、特定のフォーム (DisplayForm、EditForm、NewForm) に CSR を適用するには、schema.xml に下記の通り記述して .js ファイルを挿入します。(下記は、Display Form に適用した場合の例です。)
. . .<Forms> <Form Type="DisplayForm"Url="DispForm.aspx"SetupPath="pagesform.aspx"WebPartZoneID="Main"JSLink="~site/Scripts/jquery-1.7.1.min.js|~site/Scripts/List1Sample.js" /> <Form Type="EditForm"Url="EditForm.aspx"SetupPath="pagesform.aspx"WebPartZoneID="Main" /> <Form Type="NewForm"Url="NewForm.aspx"SetupPath="pagesform.aspx"WebPartZoneID="Main" /></Forms>. . .
つぎに、この List1Sample.js を作成します。SharePoint Add-ins の SharePoint-hosted (SharePoint ホスト型) のプロジェクトでは、下図の通り、既に、Scirpts フォルダーとその下の js ファイルがモジュールとして追加されています。(SharePoint のモジュールとは、SharePoint に配置されるイメージ ファイル、スタイル シートなどのファイルやフォルダーのことです。) 今回は、ここに、List1Sample.js を追加します。
これをおこなうには、下図の「Scripts」フォルダーを右クリックして、[追加] – [新しい項目] メニューを選択して、「List1Sample.js」という名前で [JavaScript ファイル] を追加します。(下図の Elements.xml には、この追加されたファイルの設定も自動的に記述されます。)
例えば、リスト ビューで、Address 列に、Bing Maps へのハイパーリンク (href) を設定するには、List1Sample.js を以下の通りプログラミングします。
function List1Overrides() { var overrideCtx = {}; overrideCtx.Templates = {}; overrideCtx.BaseViewID = '1'; overrideCtx.ListTemplateType = 10000; // Note1 : Override field rendering overrideCtx.Templates.Fields = {'Address': { 'View': FieldsOverrides_Address }, }; // Note2 : Register overrides SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);};function FieldsOverrides_Address( ctx, field, listItem, listSchema) { var value = listItem[field.Name]; return '<a name="www.bing.com/maps/?v=2&where1=' +encodeURI(value) +'">' +value +'</a>';}// Note3 : Execute override using CSRRegisterModuleInit("List1Sample.js", List1Overrides); // for MDSList1Overrides(); // for non-MDS// Note4 : Needed for ScriptOnDemandif (typeof (Sys) != "undefined" && Boolean(Sys) && Boolean(Sys.Application)) { Sys.Application.notifyScriptLoaded();}if (typeof (NotifyScriptLoadedAndExecuteWaitingJobs) == "function") { NotifyScriptLoadedAndExecuteWaitingJobs("List1Sample.js");}
上記の Note1 では、「Address」という Field のリスト ビューの表示 (View) の際の動作を FieldsOverrides_Address 関数で Override しています。
また、Note3、Note4 は、削除しないでください。MDS (Minimal Download Strategey) モードで表示している場合には Note3 の前者が、それ以外の場合には Note3 の後者が呼ばれます。(RegisterModuleInit は、/_layouts/15/init.js にあります。SharePoint 2013 では、通常、MDS モードが有効ですが、SPWeb の EnableMinimalDownload を設定することで Disable にできます。)
実行結果は、下図の通りになります。Address 列のリンクをクリックすると、Bing Maps に飛び、その住所が表示されます。
また、OnPreRender、OnPostRender によって、レンダリング (描画) の前後で呼ばれる処理を作成 (Override) できます。
例えば、下記は、リスト ビューで、偶数行のみ背景色を変更するサンプル コードです。レンダリング (描画) の後の処理として PostRender_RowColoring を登録していますが、function の配列を渡して複数の処理を登録することもできます。
また、GenerateIIDForListItem は、ListItem から IID を取得する関数で、前述の clienttemplates.js で定義されています。
function List1Overrides() { var overrideCtx = {}; overrideCtx.Templates = {}; overrideCtx.BaseViewID = '1'; overrideCtx.ListTemplateType = 10000; overrideCtx.Templates.Fields = {'Address': { 'View': FieldsOverrides_Address }, }; overrideCtx.OnPostRender = PostRender_RowColoring; SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);};. . .function PostRender_RowColoring(ctx) { //// without jquery ... //for (var i = 0; i < ctx.ListData.Row.length; ++i) { // if (i % 2) { //var iid = GenerateIIDForListItem(ctx, ctx.ListData.Row[i]); //var row = document.getElementById(iid); //row.style.backgroundColor = '#aaaaff;'; // } //} // with jquery ... $.each(ctx.ListData.Row, function (i, val) {if (i % 2) { var iid = GenerateIIDForListItem(ctx, val); $(selectorEscape(iid)).css('background-color', '#aaaaff');} });}// Escape jquery selector// (SharePoint uses comma and dollar mark for iid and id.)function selectorEscape(arg) { return arg.replace(new RegExp('(,|\.|'|\$|&|\/|\\|!|\||\+|\*|~|=|>|;|:|#|"|\^|\(|\)|\[|\])', 'g'),'\$1'); //var result = iid; //result = result.replace(/,/g, '\,'); //result = result.replace(/($)/g, '\$'); //return result;}. . .
実行結果は、下記の通りになります。
また、フォームカスタマイズをおこなうには、以下の通り記述します。
例えば、DisplayForm で、上記同様、Address の内容をハイパーリンクにして Bing Maps に飛ばすには、以下の通り記述します。
. . .function List1FormsOverrides() {var overrideCtx = {};overrideCtx.Templates = {};overrideCtx.ListTemplateType = 10000;overrideCtx.Templates.Fields = {'Address': {'DisplayForm': DisplayFormOverrides_Address},};SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);};function DisplayFormOverrides_Address(ctx) {var formCtx =SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);if (formCtx.controlMode != SPClientTemplates.ClientControlMode.DisplayForm)return '';elsereturn '<a name="www.bing.com/maps/?v=2&where1=' +encodeURI(formCtx.fieldValue) +'">' +formCtx.fieldValue +'</a>';}. . .RegisterModuleInit("List1Sample.js", List1FormsOverrides); // for MDSList1FormsOverrides(); // for non-MDS. . .
実行結果は、下記の通りになります。(リンクをクリックすると Bing Maps に飛び、住所が表示されます。)
なお、NewForm、EditForm を Override する場合は、下記の通り、必要な Callback を登録しておいてください。特に、GetValue Callback が登録されていない場合、リストに値が設定されないので注意してください。(2013/02/25 追記)
. . .function NewFormOverrides_Address(ctx) { var formCtx =SPClientTemplates.Utility.GetFormContextForCurrentField(ctx); var inputId = formCtx.fieldName + '_' + formCtx.fieldSchema.Id + '_$TextField'; var inputObj = null; if (formCtx.controlMode == SPClientTemplates.ClientControlMode.NewForm) {// ClientValidator Callbackvar validators = new SPClientForms.ClientValidation.ValidatorSet();formCtx.registerClientValidator(formCtx.fieldName, validators);// Init CallbackformCtx.registerInitCallback(formCtx.fieldName, function () { inputObj = $('#' + selectorEscape(inputId));});// Focus CallbackformCtx.registerFocusCallback(formCtx.fieldName, function () { if (inputObj != null)inputObj.focus();});// ValidationError CallbackformCtx.registerValidationErrorCallback(formCtx.fieldName, function (errorResult) {});// GetValue CallbackformCtx.registerGetValueCallback(formCtx.fieldName, function () { if (inputObj == null)return ''; elsereturn inputObj.val();});formCtx.updateControlValue(formCtx.fieldName, '');// original : <span dir="none"><input title='' class="ms-long ms-spellcheck-true" id="Address_afb7686f-7d8a-4f53-9643-ad4c6e40bc6f_$TextField" type="text" maxlength="255" value="" /><br/></span>return '<span dir="none"><input title="' + formCtx.fieldSchema.Address + '" ' + 'class="ms-long ms-spellcheck-true" ' + 'id=' + STSHtmlEncode(inputId) + ' ' + 'type="text" ' + 'maxlength="' + formCtx.fieldSchema.MaxLength + '" ' + 'value="" ' + '/><br/></span>'; } return '';}. . .
CSR は、 従来のリスト UI のカスタマイズの手法 (「SharePoint 2010 : リスト定義における XSL を使用したビューのカスタマイズ」を参照) と組み合わせても良いでしょう。実際、SharePoint が生成する HTML は膨大なため、よりシンプルな HTML (必要最小限の HTML) を生成し、さらに高度な (動的な) UI カスタマイズは CSR を使った JavaScript で実装する方法も考えられます。
補足 : 例えば、カスタム リスト ビュー (スタイル) と CSR を併用する場合、「SharePoint 2010 : リスト定義における XSL を使用したビューのカスタマイズ」で紹介している <Xsl> を使った手法を使用してください。(「SharePoint 2010 : リスト定義における XSL を使用したビューのカスタマイズ」の CAML を使った手法は、<JSLINK> とは併用できません。)
また、CSR を呼び出し元は、/_layouts/15/vwstyles.xsl の RenderListView です。Custom XSL を使用する場合は、vwstyles.xsl に記述されている CSR の処理 (RenderListView の前後) を XSL に含めてください。
補足 : schema.xml を変更する際には、こちら に記載した通り、キャッシュ (cache) されることがあるので注意してください。(schema.xml の変更が反映されないことがあります。)
※ 変更履歴 :
2015/05/05 App for SharePoint (SharePoint 用アプリ) を SharePoint Add-ins (SharePoint アドイン) に名称変更
Categories: Uncategorized
10 replies»