以前にもExcelの読み書きについて書きましたが、その後社内で開発中のツールなどで応用してきた内容を簡略化してここに記します。
上の画像のデータの流れのイメージは観客席設計で利用する段床断面の計算ツールで、パラメーター入力をExcelで行い、
ボタンを押せばGetコンポーネントがExcelから必要なパラメーターを吸い出して、1階席から4階席までのパラメーターをそれぞれ出力し、その後のSetコンポーネントにデータを渡します。
SetコンポーネントはExcelで入力したパラメーターを元に視線の解析と段床断面の計算を行い、計算結果をExcelの出力欄にフィードバックするものですが、今回は読み取ったパラメーターに-1を掛けて出力欄に返しているだけです。
Getコンポーネントにはもう一つの機能を持たせていて、コンポーネントの出力(TP1~TP4)にSetコンポーネントが繋がっていない時にはExcelの出力欄の値を消しておくというものです。
丁寧に書けばもっとスマートなコードになるとは思うのですが、ざっくりとした流れを追った簡易なものとして記しておきます。
Microsoft.Office.Interop.ExcelをC#コンポーネントで使うためにはどうするかは、前述の記事を確認下さい。2年前の記事ですが大して変わりないと思います。
以下のコードはRunScript以下のコードだけを書いていますが、usingにはMicrosoft.Office.Interop.Excelが必要です。
Getコンポーネント
private void RunScript(bool activate, bool update, string sheet, ref object TP1, ref object TP2, ref object TP3, ref object TP4)
{
if(activate || update)
{
Microsoft.Office.Interop.Excel.Application xlApp =
(Microsoft.Office.Interop.Excel.Application)
System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");Microsoft.Office.Interop.Excel.Workbook wBook = xlApp.ActiveWorkbook;
Microsoft.Office.Interop.Excel.Worksheet wSheet = (Worksheet) wBook.Sheets[sheet];Range cellRange = wSheet.get_Range("A1:L23");
Range range1st = cellRange.Range["B4:B23"];
Range range2nd = cellRange.Range["E4:E23"];
Range range3rd = cellRange.Range["H4:H23"];
Range range4th = cellRange.Range["K4:K23"];this.CheckOutputRecipients(range1st, 1);
this.CheckOutputRecipients(range2nd, 2);
this.CheckOutputRecipients(range3rd, 3);
this.CheckOutputRecipients(range4th, 4);TP1 = range1st;
TP2 = range2nd;
TP3 = range3rd;
TP4 = range4th;
}
}//
private void CheckOutputRecipients(Range rangeData, int index)
{
if(this.Component.Params.Output[index].Recipients.Count == 0)
{
rangeData.Offset[0, 1].ClearContents();
}
}
//
}
Setコンポーネント
private void RunScript(System.Object TP)
{
if(TP != null)
{
Range rangeData = (Range) TP;
object[,] valueArray = (object[,]) rangeData.get_Value();for(int i = 1; i <= valueArray.Length; i++)
{
valueArray[i, 1] = -(double) valueArray[i, 1];
}
rangeData.Offset[0, 1].Value2 = valueArray;
}
}
補足①
Excelの読み書きの際にその最中の画面の更新を一時的に止めるために使われるApplication.ScreenUpdatingプロパティは使っていません。
何万行も繰り返して更新する場合には一度止めた方が効果的なようですが、今回は範囲指定して一度に読み書きを行っているので、使っても計算時間に大きな差が出なかったためです。
補足②
Worksheet.SelectメソッドやWorksheet.Activateメソッドを必要なさそうなので使っていません。一つのコードの中で複数のシートにまたいでデータの読み書きをする場合にはシートを選択しながらコードを管理する必要があると思います。必要がない限りは書かない方が計算が速いです。
補足③
色々調べてみるとC#でExcelファイルの読み書きを行う際に、Microsoft.Office.Interop.Excelを使った方法は処理が遅いなどの理由から他のライブラリを使った方が良いという記事も目にしました。
自分の場合、何万ものデータの読み書きを行う訳でもなく、古くからある方法なのでリファレンスも多く、今回はMicrosoft.Office.Interop.Excelを使っています。
一つのパラメーターを受け渡すという内容でしたが、実際にはもっとたくさんの値を注意深く読み書きしています。
実際のフォーマットは以下のようなもので、ぼかした画像で恐縮ですがいつか改めてツールの紹介などもできればと思います。
コメントをするにはログインしてください。