概要
・Visual Stadio 2019 Blazor Server で DioDocs for Excel を使用してみたが
DioDocsのテンプレート機能が少し使いにくかったので、オリジナルで作成してみた。
※明細の表が複数でも出力可能になる。
手順
1.Visual Stadio 2019 で新しいプロジェクトで Blazor Server を選択し
「DioDocs2」と言う名称でプロジェクトを作成する。
2.プロジェクトの追加で、コンソールアプリケーションを選択し、「Reports」という名称
で追加する。
3.プロジェクトのプロパティ設定で、出力の種類を「クラスライブラリ」に変更する。
4.以下のファイルを追加
DioDocsReports.cs
using System.Collections.Generic;
using GrapeCity.Documents.Excel;
using Reports.Model;
namespace Reports
{
/// <summary>
/// DioDocs帳票作成クラス
/// </summary>
public static class DioDocsReports
{
/// <summary>ワークブック</summary>
private static Workbook _Workbook;
/// <summary>ヘッダー定義記号(左)長さ</summary>
private static int _HederKigoLeftLen = 4;
/// <summary>明細定義記号(左)長さ</summary>
private static int _DetailKigoLeftLen = 3;
/// <summary>
/// テンプレートOPEN
/// </summary>
/// <param name="fileName">ファイル名</param>
/// <returns>ワークブック</returns>
public static Workbook OpenTemplate(string fileName)
{
_Workbook = new Workbook();
_Workbook.Open(fileName, OpenFileFormat.Xlsx);
return _Workbook;
}
/// <summary>
/// シート削除
/// </summary>
/// <param name="fileName">ファイル名</param>
public static void DeleteSheet(string sheetName)
{
_Workbook.Worksheets[sheetName].Delete();
}
/// <summary>
/// PDF出力(シート)
/// </summary>
/// <param name="fileName">ファイル名</param>
public static void OutputPdfSheet(string fileName)
{
_Workbook.ActiveSheet.Save(fileName);
}
/// <summary>
/// PDF出力(ブック)
/// </summary>
/// <param name="fileName">ファイル名</param>
/// <returns>ステータス</returns>
public static void OutputPdf(string fileName)
{
_Workbook.ActiveSheet.Save(fileName);
}
/// <summary>
/// Excel Save
/// </summary>
/// <param name="fileName">ファイル名</param>
public static void Save(string fileName)
{
_Workbook.Save(fileName);
}
/// <summary>
/// マージン設定
/// </summary>
/// <param name="top">上</param>
/// <param name="bottom">下</param>
/// <param name="left">左</param>
/// <param name="right">右</param>
public static void SetMargin(double top, double bottom, double left, double right)
{
var sheet = _Workbook.ActiveSheet;
sheet.PageSetup.TopMargin = top;
sheet.PageSetup.BottomMargin = bottom;
sheet.PageSetup.LeftMargin = left;
sheet.PageSetup.RightMargin = right;
}
/// <summary>
/// ヘッダーエリア設定
/// </summary>
/// <param name="row1">行1</param>
/// <param name="col1">列1</param>
/// <param name="rowcnt">行数</param>
/// <param name="colcnt">列数</param>
public static List<AreaModel> SetHeaderArea(int row1, int col1, int rowcnt, int colcnt)
{
List<AreaModel> areaList = new List<AreaModel>();
var range = _Workbook.ActiveSheet.Range[row1, col1, rowcnt, colcnt];
for (int r = 0; r < range.RowCount; r++)
{
for (int c = 0; c < range.ColumnCount; c++)
{
var tmp = range[0 + r, c].Value == null ? null : range[0 + r, c].Value.ToString();
if (!string.IsNullOrEmpty(tmp))
{
if ((tmp.Length > 5) && (tmp.Substring(0, _HederKigoLeftLen) == "{***") && tmp.Substring(tmp.Length - 1, 1) == "}")
{
var addData = new AreaModel()
{
AreaName = tmp.Substring(_HederKigoLeftLen, tmp.Length - _HederKigoLeftLen).Replace("}", ""),
Row = row1 + r,
Col = col1 + c
};
areaList.Add(addData);
range[0 + r, c].Value = "";
}
}
}
}
return areaList;
}
/// <summary>
/// 明細エリア設定
/// </summary>
/// <param name="row1">行1</param>
/// <param name="col1">列1</param>
/// <param name="rowcnt">行数</param>
/// <param name="colcnt">列数</param>
public static List<AreaModel> SetDetailArea(int row1, int col1, int rowcnt, int colcnt)
{
List<AreaModel> areaList = new List<AreaModel>();
var range = _Workbook.ActiveSheet.Range[row1, col1, rowcnt, colcnt];
for (int r = 0; r < range.RowCount; r++)
{
for (int c = 0; c < range.ColumnCount; c++)
{
var tmp = range[r, c].Value == null ? null : range[r, c].Value.ToString();
if (!string.IsNullOrEmpty(tmp))
{
if ((tmp.Length > (_DetailKigoLeftLen + 1)) && (tmp.Substring(0, _DetailKigoLeftLen) == "{**") && (tmp.Substring(tmp.Length - 1, 1) == "}"))
{
if ((tmp.Substring((_DetailKigoLeftLen + 1), 1) != "*"))
{
var addData = new AreaModel()
{
AreaName = tmp.Substring(_DetailKigoLeftLen, tmp.Length - _DetailKigoLeftLen).Replace("}", ""),
Row = row1 + r,
Col = col1 + c
};
areaList.Add(addData);
range[0 + r, c].Value = "";
}
}
}
}
}
return areaList;
}
/// <summary>
/// ヘッダーデータ設定
/// </summary>
/// <typeparam name="T">テーブル</typeparam>
/// <param name="list">データリスト</param>
/// <param name="areaList">エリアリスト</param>
public static void SetHedar<T>(List<T> list, List<AreaModel> areaList)
{
foreach (var a in list)
{
foreach (var property in a.GetType().GetProperties())
{
foreach (var dat in areaList)
{
if (dat.AreaName == property.Name)
{
_Workbook.ActiveSheet.Cells[dat.Row, dat.Col].Value = a.GetType().GetProperty(property.Name).GetValue(a);
}
}
}
break;
}
}
/// <summary>
/// 明細データ設定
/// </summary>
/// <typeparam name="T">テーブル</typeparam>
/// <param name="list">データリスト</param>
/// <param name="areaList">エリアリスト</param>
public static void SetDetail<T>(IEnumerable<T> list, List<AreaModel> areaList)
{
foreach (var a in list)
{
foreach (var property in a.GetType().GetProperties())
{
foreach (var dat in areaList)
{
if (dat.AreaName == property.Name)
{
_Workbook.ActiveSheet.Cells[dat.Row++, dat.Col].Value = a.GetType().GetProperty(property.Name).GetValue(a);
}
}
}
}
}
/// <summary>
/// Cellデータ設定
/// </summary>
/// <typeparam name="data">値</typeparam>
/// <param name="list">データリスト</param>
/// <param name="areaList">エリアリスト</param>
public static void SetCell(object obj, int row, int col)
{
_Workbook.ActiveSheet.Cells[row, col].Value = obj;
}
/// <summary>
/// コピーテンプレート(シート)
/// </summary>
public static void CopyTemplete()
{
// テンプレートのシートをアクティブ
_Workbook.Worksheets["temp"].Activate();
// テンプレートのシートをコピー
var copy_worksheet = _Workbook.ActiveSheet.Copy();
// コピーしたシートに名前を設定
copy_worksheet.Name = _Workbook.Worksheets.Count.ToString();
// コピーしたシートをアクティブ
copy_worksheet.Activate();
}
/// <summary>
/// ページコピー
/// </summary>
/// <param name="row"></param>
/// <param name="col"></param>
/// <param name="page"></param>
public static void PageCopy(int row, int col, int page)
{
for (int c = 1; c < page; c++)
{
_Workbook.ActiveSheet.Range[0, 0, row - 1, col - 1].Copy(_Workbook.ActiveSheet.Range[c * row, 0, row - 1, col - 1]);
_Workbook.ActiveSheet.HPageBreaks.Add(_Workbook.ActiveSheet.Range[c * row, 0]);
}
}
/// <summary>
/// 明細行コピー
/// </summary>
/// <param name="list"></param>
/// <param name="areaList"></param>
public static void SetDetailCopy(int lineNo, int gyoCnt)
{
for (int c = 1; c < gyoCnt; c++)
{
_Workbook.ActiveSheet.Range[lineNo, 0, 1, 999].Insert(InsertShiftDirection.Down);
_Workbook.ActiveSheet.Range[lineNo, 0, 1, 999].Copy(_Workbook.ActiveSheet.Range[lineNo + 1, 0, 1, 999]);
}
}
}
}
CreateReports.cs
using System.Collections.Generic;
using GrapeCity.Documents.Excel;
namespace Reports
{
public class CreateReports
{
private Workbook _Workbook;
public void PdfOutput()
{
List<HeaderModel> hederList = new List<HeaderModel>();
List<UserModel> DataList = new List<UserModel>();
var dat0 = new HeaderModel()
{
Shozoku = "0001:大阪府"
};
hederList.Add(dat0);
var dat1 = new UserModel()
{
Id = "0001",
Name = "テスト01",
Gender = "M",
Age = 20,
};
DataList.Add(dat1);
var dat2 = new UserModel()
{
Id = "0002",
Name = "テスト02",
Gender = "F",
Age = 21,
};
DataList.Add(dat2);
for(var c = 3; c < 60; c++)
{
var dat3 = new UserModel()
{
Id = c.ToString("0000"),
Name = "テスト" + c.ToString(),
Gender = "M",
Age = c + 21,
};
DataList.Add(dat3);
}
// テンプレートOPEN
var _Workbook = DioDocsReports.OpenTemplate(@"C:\Test\DioDocs2\DioDocs2\Template\ユーザー一覧表.xlsx");
// テンプレートシートをコピー
DioDocsReports.CopyTemplete();
// ヘッダー領域を設定
var listHeader = DioDocsReports.SetHeaderArea(0, 0, 5, 8);
// 明細領域を設定
var listDetail = DioDocsReports.SetDetailArea(6, 0, 1, 8);
// データ件数に合わせて明細行をコピー
DioDocsReports.SetDetailCopy(6, DataList.Count);
// ヘッダー領域にデータを設定
DioDocsReports.SetHedar<HeaderModel>(hederList, listHeader);
// 明細領域にデータを設定
DioDocsReports.SetDetail<UserModel>(DataList, listDetail);
// テンプレートのシートを削除
DioDocsReports.DeleteSheet("temp");
// PDF出力
DioDocsReports.OutputPdf(@"C:\Test\DioDocs2\DioDocs2\wwwroot\DownLoad\ユーザー一覧表.pdf");
DioDocsReports.Save(@"C:\Output\ユーザー一覧表.xlsx");
}
}
/// <summary>
/// 詳細モデル
/// </summary>
public class UserModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int Age { get; set; }
}
/// <summary>
/// ヘッダーモデル
/// </summary>
public class HeaderModel
{
public string Shozoku { get; set; }
}
}
5.NavMenu.razor を以下のように修正
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
/// -->追加
<li class="nav-item px-3">
<NavLink class="nav-link" href="PdfOutput">
<span class="oi oi-print" aria-hidden="true"></span>PdfOutput
</NavLink>
</li>
/// <--追加
</ul>
</div>
6.Page フォルダに以下のファイルを追加
PdfOutput.razor
@page "/PdfOutput"
@using Reports
@inject IJSRuntime jsRuntime
<h3>PdfOutput</h3>
<button class="btn btn-primary" @onclick="CreatePdf">Pdf</button>
PdfOutput.razor.cs
using System;
using System.Threading.Tasks;
using System.Text.Json;
using System.Security.Cryptography;
using Microsoft.JSInterop;
using Microsoft.AspNetCore.Components;
using Reports;
namespace DioDocs2.Pages
{
public partial class PdfOutput
{
public async Task CreatePdf()
{
try
{
var rep = new CreateReports();
rep.PdfOutput();
rep = null;
await Task.Delay(10);
await jsRuntime.InvokeVoidAsync("DownLoad", @"ユーザー一覧表.pdf");
}
catch (Exception ex){
var a = ex.Message;
}
}
}
}
7.テンプレートファイル用のフォルダを追加 ...DioDocs2\Template
8.PDF出力用のフォルダを追加 ...DioDocs2\DioDocs2\wwwroot\DownLoad\
10._Host.cshtml を以下のように修正
@page "/"
@namespace DioDocs2.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DioDocs2</title>
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="DioDocs2.styles.css" rel="stylesheet" />
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
<script>
// ファイルダウンロード
function DownLoad(fileName) {
const link = document.createElement('a');
link.setAttribute("type", "hidden");
link.href = './DownLoad/' + fileName;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
link.remove();
}
</script>