2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

長野高専Advent Calendar 2024

Day 14

SpreadsheetGearにおける結合セルの取り扱い

Last updated at Posted at 2024-12-13

はじめに

この記事は長野高専 Advent Calendar 2024の14日目の記事です。
OBですが参加しております。主催ありがとうございます!

本記事では、C#のスプレッドシートライブラリであるSpreadsheetGearで、結合セルがどのように扱われるか簡単に説明します。
業務で扱っていて少しややこしかった(当社比)ので、備忘録的記事となります。
正直なところこのライブラリを使っている人は本当に少ない(エンタープライズ向けなところはある)ので、需要が無さすぎる記事かと思いますが、自分のために書き残させてください。

わざわざ記事を書いていますが、大体のことは公式ドキュメントに書いてあります。

前提

今回使用しているライブラリは以下の通りです。

  • SpreadsheetGear2023 Ver9.2.44.102

説明に使用するworkbook, worksheetは以下のように定義しているものとします。

SpreadsheetGear.IWorkbook workbook = SpreadsheetGear.Factory.GetWorkbook();
SpreadsheetGear.IWorksheet worksheet = workbook.ActiveWorksheet;

結合セルのあれこれ

主に行う操作として以下の内容を説明します。

  • 結合、解除
  • 結合セルか、そうでないかのチェック
  • アドレス取得
  • 値セット、取得

結合、解除

結合したい範囲のIRangeを定義して、IRange.Merge()メソッドを実行することでセル範囲が結合されます。

// B2からE5を結合する
SpreadsheetGear.IRange range = worksheet.Cells["B2:E5"];
range.Merge();

merge.png

結合解除したい範囲のIRangeを定義して、IRange.UnMerge()メソッドを実行することでセル結合が解除されます。UnMerge()を使用するとIRangeに含まれるすべてのセル結合が解除されます。

注意点として、IRangeがセル結合を含んでおり、その範囲がセル結合を完全に内包していない場合はSystem.InvalidOperationExceptionがスローされます。
IRangeがセル結合を含まない場合は、UnMerge()を実行しても何も起きません。

// セル結合を解除する
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.Merge();
range1.UnMerge();
// A1からF6はセル結合を完全に内包しているのでOK
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.Merge();
SpreadsheetGear.IRange range2 = worksheet.Cells["A1:F6"];
range2.UnMerge();
// A1からB2はセル結合を一部しか含まないためNG
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.Merge();
var range2 = worksheet.Cells["A1:B2"];
range2.UnMerge();     // InvalidOperationException
// 結合セルが含まれない場合は何も起きない
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.UnMerge();    // 何も起きない

unMerge.png

結合セルか、そうでないかのチェック

チェックしたい範囲のIRangeIRange.MergeCellsプロパティを参照することで、セル範囲が結合セルであるかどうかをチェックできます。
MergeCellsプロパティは、厳密には

  • MergeCells = trueIRange.Merge()と同じ操作
  • MergeCells = falseIRange.UnMerge()と同じ操作

という挙動をするプロパティですが、プロパティの操作で結合の状態が変化するのは不自然だと思う(個人の感想)ので、結合・解除はメソッドを使用して、MergeCellは参照するだけに留める使い方をしています。

MergeCellsは、IRangeの含むセルすべてが結合セルに属する場合true、一つでも結合セルではないセルを含む場合はfalseとなります。

// range1に含まれるセルは全て結合セルのためtrue
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.Merge();
Console.WriteLine(range1.MergeCells);    // true
// IRangeの含むセルすべてが結合セルの場合trueとなるので
// 2個以上結合セルがあってもtrueになる場合がある
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.Merge();
SpreadsheetGear.IRange range2 = worksheet.Cells["F2:G5"];
range2.Merge();
// 2個以上の結合セルを含むセル範囲
SpreadsheetGear.IRange range3 = worksheet.Cells["B2:G5"];
Console.WriteLine(range3.MergeCells);    // true
// 1つでも結合セルでないセルを含む場合はfalse
SpreadsheetGear.IRange range1 = worksheet.Cells["B2:E5"];
range1.Merge();
SpreadsheetGear.IRange range2 = worksheet.Cells["B2:G5"];
Console.WriteLine(range2.MergeCells);    // false

UnMerge()で意図せずSystem.InvalidOperationExceptionが起きたら萎えるので、結構大事だったりします。

注意点として、IRangeが結合セルの一部であっても、セルすべてが何らかの結合セルに属する場合、MergeCellsはtrueになります。

// 1つでも結合セルでないセルを含む場合はfalse
SpreadsheetGear.IRange range1 = worksheet.Cells["B1:D5"];
range1.Merge();
Console.WriteLine(range1.MergeCells);    // true ← :)

SpreadsheetGear.IRange range2 = worksheet.Cells["B1:C5"];
Console.WriteLine(range2.MergeCells);    // true ← ?????????

B1-D3.png
じゃあ手元にあるセル範囲がビタビタに結合セルだと判別したい場合はどうするんだ!
B1:D3に対してMergeCellsを見ても、B1:C3に対してMergeCellsを見ても、どちらもtrueが返ってきます。
そうじゃなくて、「手元にあるB1:D3が結合セルそのものを表しているかどうか」をチェックしたい場合があります。

そんな場合は、次のプロパティを活用しましょう。

アドレス取得

定義されたIRangeIRange.Addressプロパティを参照することで、そのセル範囲のアドレスを取得できます。
しかし、IRange.Addressがそのまま結合セルのセルアドレスを示すとは限りません。
結合セルのセルアドレスは、IRange.MergeArea.Adderssプロパティを参照することで取得できます。

IRange.MergeAreaとは

IRange.MergeAreaプロパティは、IRangeが1セルを指す場合にのみ使用でき、そのセルが属する結合セルのIRangeを返します。

// セル結合
SpreadsheetGear.IRange range1 = worksheet.Cells["B1:D5"];
range1.Merge();
Console.WriteLine(range1.Address);       // $B$1:$D$5

// 1セルを指定
SpreadsheetGear.IRange range2 = worksheet.Cells["C2"];
Console.WriteLine(range2.Address);       // $C$2
Console.WriteLine(range2.MergeArea.Address);    // $B$1:$D$5

MergeArea.Addressを活用することで、以下のような判定が可能になります。

// チェックしたいアドレス
var address = "$B$1:$D$5";

SpreadsheetGear.IRange range1 = worksheet.Cells[address];
if (range1[0, 0].MergeArea.Address == address) {
    Console.WriteLine("結合セルそのもの");
} else {
    Console.WriteLine("ビタビタではない");
}

これで上で述べた要望が解決できそうです。

値セット、取得

結合セルに対しての値セットと取得は、通常のセルと同様IRange.Valueで行います。

SpreadsheetGear.IRange range1 = worksheet.Cells["B1:D5"];
range1.Merge();
// 値セット
range1.Value = "hoge";

// 値取得
var hoge = range1.Value;

この「値」の扱いに気を付ける必要があります。(Excelと挙動が若干異なります)

値セット

結合セルに対して値をセットした後、その結合を解除すると、それぞれのセルの値はどのようになっているでしょうか。マージ直後、解除直後でセルの状態を以下に示します。

SpreadsheetGear.IRange range1 = worksheet.Cells["B1:D5"];
range1.Merge();
range1.Value = "hoge";    // マージ直後
range1.UnMerge();         // 解除直後

マージ直後

sono1.png

解除直後

sono2.png

Excelとの相違点は、「セル結合解除時に元のセルに値が入るかどうか」です。
Excelでは解除時に左上セルのみに値が入りますが、SpreadsheetGearでは、結合解除時に元のすべてのセルに値が入ります。

値取得

B1からD5を結合して、C2から値を取得した場合の違いを見てみましょう。

SpreadsheetGear

SpreadsheetGear.IRange range1 = worksheet.Cells["B1:D5"];
range1.Merge();
range1.Value = "hoge";
Console.WriteLine(worksheet.Cells["C2"]);    // hoge

Excel

valGet.png

結合セルから値を取得するときも、値セットと同様に「すべてのセルに値が入っているかどうか」の違いが表れてきます。

おわりに

いかがだったでしょうか?
仕事を始めて2年が経とうとしています。少しずつではありますが、C#とライブラリについて理解できてきた気がします。

記事にするほどでもない備忘録でしたが、最後までお読みいただきありがとうございました。

付録

SpreadsheetGear2023 Reference

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?