SharePoint向けExcelエクスポートの改善

SharePointのExcelへの標準エクスポートオプションは、かなり珍しい方法で機能します。 エクスポートボタンをクリックすると、SharePointはExcelが開く特別な形式の要求ファイルを提供し、Excel自体がデータをドラッグします。



このアプローチの利点は、接続があるためExcelのデータを更新できることです。 しかし、さらに不利な点があります:





少量のコードで、ユーザーが何にも気付かないように、標準のエクスポート機能を独自のものに置き換えることができます。





エクスポートボタンの置換



リボンの既存の要素を置き換えるには、既存の要素のIDと等しいLocation



パラメーターを使用して、新しいCommandUIDefinition



を追加する必要があります。 すべての標準要素は、ファイルC:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ 14 \TEMPLATE\GLOBAL\XML\CMDUI.XML



にありますC:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\ 14 \TEMPLATE\GLOBAL\XML\CMDUI.XML



for SharePoint 2010(または15 for SharePoint 2013)。



Excelのエクスポートボタンを置き換えるには、IdがRibbon.List.Actions.ExportToSpreadsheet



およびRibbon.Library.Actions.ExportToSpreadsheet



と等しいボタンを見つけて、プロジェクトに完全にコピーする必要があります。 新しい要素のLocation



として、これらのIDを指定する必要があります。



コピーペーストがたくさん
 <CommandUIDefinitions> <CommandUIDefinition Location="Ribbon.Library.Actions.ExportToSpreadsheet"> <Button Id="Ribbon.Library.Actions.ExportToSpreadsheet-Replacement" Sequence="40" Command="ExportToSpreadsheet-Replacement" Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-152" Image16by16Left="-32" Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="-352" Image32by32Left="0" LabelText="$Resources:core,cui_ButExportToSpreadsheet;" ToolTipTitle="$Resources:core,cui_ButExportToSpreadsheet;" ToolTipDescription="$Resources:core,cui_STT_ButExportListToSpreadsheet;" TemplateAlias="o2" /> </CommandUIDefinition> <CommandUIDefinition Location="Ribbon.List.Actions.ExportToSpreadsheet"> <Button Id="Ribbon.List.Actions.ExportToSpreadsheet-Replacement" Sequence="40" Command="ExportToSpreadsheet-Replacement" Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-152" Image16by16Left="-32" Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="-352" Image32by32Left="0" LabelText="$Resources:core,cui_ButExportToSpreadsheet;" ToolTipTitle="$Resources:core,cui_ButExportToSpreadsheet;" ToolTipDescription="$Resources:core,cui_STT_ButExportListToSpreadsheet;" TemplateAlias="o1" /> </CommandUIDefinition> </CommandUIDefinitions>
      
      







Id="Ribbon.Calendar.Calendar.Actions.ExportToSpreadsheet"



カレンダー用の別のボタンもあり、同じことを行うことができます。



コントロールを作成する



ボタンはサーバーコードを呼び出す必要があります。 動作を標準ボタンに似せるには 、各ページに配置されるDelegateControlを作成するのが最善です。 Id="AdditionalPageHead"



コンテナがあります:

 <Control Id="AdditionalPageHead" Sequence="1000" ControlAssembly="$SharePoint.Project.AssemblyFullName$" ControlClass="$SharePoint.Type.7fd7c6f0-4eda-48ce-ac8f-aa9f9d2666ac.FullName$"/>
      
      





カスタムボタンは、コントロールによって処理されるPostBackを呼び出します。 リストビューページでボタンをクリックすると、追加のパラメータを渡す必要はありません。 また、リストビューをWebパーツとして通常のページに追加した後、リストIDとビューをサーバーに転送する必要があります。



残念ながら、ボタンがクリックされたビューのIDを取得するのは簡単なことではありません。 したがって、リストIDを渡すことのみに制限します。



 <CommandUIHandlers> <CommandUIHandler Command="ExportToSpreadsheet-Replacement" CommandAction="javascript:(function(){var x=SP.ListOperation.Selection.getSelectedList(); if (x) {__doPostBack('ExportToSpreadsheet-Replacement', x);}})();" /> </CommandUIHandlers>
      
      







次に、サーバーで、リストビューページまたは通常のページでボタンが押されているかどうかを確認する必要があります。



 protected override void OnLoad(EventArgs e) { if (this.Page.Request["__EVENTTARGET"] == "ExportToSpreadsheet-Replacement") { var spContext = SPContext.Current; SPList list; SPView view; if (spContext.ViewContext.View != null) { list = spContext.List; view = spContext.ViewContext.View; } else { var listId = new Guid(this.Page.Request["__EVENTARGUMENT"]); var web = spContext.Web; list = web.Lists[listId]; view = list.DefaultView; } ExportData(list.Title + " - " + view.Title, GetDataTable(list, view)); } }
      
      







ビューデータテーブルの取得は非常に簡単です。



 private static System.Data.DataTable GetDataTable(SPList list, SPView view) { var query = new SPQuery(view); SPListItemCollectionPosition position; var flags = SPListGetDataTableOptions.UseBooleanDataType | SPListGetDataTableOptions.UseCalculatedDataType; var result = list.GetDataTable(query, flags, out position); while (position != null) { list.AppendDataTable(query, flags, result, out position); } return result; }
      
      







Excelファイルの生成





最後の手順は、Excelファイルを作成してクライアントに提供することです。 Excelを生成する最も簡単な方法の1つは、ClosedXmlライブラリ( http://closedxml.codeplex.com/ )を使用することです。



 private void ExportData(string title, System.Data.DataTable table) { var wb = new XLWorkbook(); var ws = wb.Worksheets.Add(title); ws.Cell(1, 1).InsertTable(table); var response = this.Page.Response; response.Clear(); response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; var filename = title+".xlsx"; response.AddHeader("content-disposition", GetContentDisposition(filename)); // Flush the workbook to the Response.OutputStream using (var memoryStream = new MemoryStream()) { wb.SaveAs(memoryStream); memoryStream.WriteTo(response.OutputStream); } response.End(); }
      
      







メソッドの最初の3行は実際にExcelドキュメントを形成し(ClosedXmlのおかげです)、他のすべてはクライアントにファイルを送信するためのコードです。



content-disposition



応答ヘッダーは、ブラウザごとに非常に異なって認識されるため、正しいロシア名のファイルを指定するには、タンバリンで踊る必要があります。



StackOverflowで正しいcontent-disposition



ヘッダーを生成するコードを見つけましたstackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http



 private string GetContentDisposition(string filename) { var request = this.Page.Request; string contentDisposition; if (request.Browser.Browser == "IE" && (request.Browser.Version == "7.0" || request.Browser.Version == "8.0")) contentDisposition = "attachment; filename=" + Uri.EscapeDataString(filename); else if (request.UserAgent != null && request.UserAgent.ToLowerInvariant().Contains("android")) // android built-in download manager (all browsers on android) contentDisposition = "attachment; filename=\"" + MakeAndroidSafeFileName(filename) + "\""; else contentDisposition = "attachment; filename=\"" + filename + "\"; filename*=UTF-8''" + Uri.EscapeDataString(filename); return contentDisposition; } private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c); private string MakeAndroidSafeFileName(string fileName) { char[] newFileName = fileName.ToCharArray(); for (int i = 0; i < newFileName.Length; i++) { if (!AndroidAllowedChars.ContainsKey(newFileName[i])) newFileName[i] = '_'; } return new string(newFileName); }
      
      







おわりに



すべてが実稼働環境で機能するには、ClosedXml.dllファイルとDocumentFormat.OpenXml.dllファイルをパッケージに追加する必要があります。 リボンとコントロールボタンは、サイトレベルまたはWebレベルの1つの機能に配置する必要があります。



プロジェクト全体はリンクで見ることができます-spsamples.codeplex.com/SourceControl/latest#ExportToExcel



準備ができたWSPファイルはこちら-spsamples.codeplex.com/releases/view/117220



ほとんどのコードはユニバーサルであり、SharePointに依存しません。 ASP.NETプロジェクトでも同様のアプローチを使用できます。



All Articles