C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: Excelに二次元配列のデータを設定する方法


(過去ログ 121 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■72708 / inTopicNo.1)  Excelに二次元配列のデータを設定する方法
  
□投稿者/ さとすけ (1回)-(2014/07/08(Tue) 10:09:41)

分類:[C#] 

2014/07/08(Tue) 12:09:27 編集(投稿者)
Excelに二次元配列を設定する処理を作ろうとしています。

sheet.get_Range("A2", "EG8707").Value2 = rng;

の設定では実行できたのですが

sheet.get_Range(sheet.Cells[1, 1], sheet.Cells[1, 2]).Value2 = rng;

の設定ではコンパイルエラーとなってしまいました。

Excelの範囲指定は、数値で指定したいので出来れば後者の方法が望ましいのですが
どのようにすればそれが可能になるか、ご存知の方がいらっしゃいましたらご教授下さい。

---- ソース ----
// Excelにセットする二次元配列を生成
object[,] rng = new object[rows.Count, columnNames.Count];
for (int i = 0; i < rows.Count; i++)
{
	for (int j = 0; j < columnNames.Count; j++)
	{
		rng[i, j] = "aaa";
	}
}

// ↓コンパイルOK -> 動作も問題なし
sheet.get_Range("A2", "EG8707").Value2 = rng;

// ↓コンパイルエラー
sheet.get_Range(sheet.Cells[1, 1], sheet.Cells[1, 2]).Value2 = rng;
----------------

---- コンパイルエラーメッセージ ----
動的な式のコンパイルに必要な1以上の方が見つかりません。参照を指定されていることを確認してください
------------------------------------

---- VisualStudio ----
Professional 2012
.Net Framework 4.5.50709
----------------------

---- 参照設定内容 ----
Microsoft.Office.Core (ver.2.5.0.0)
Microsoft.Office.Interop.Excel (ver.1.7.0.0)
----------------------

引用返信 編集キー/
■72714 / inTopicNo.2)  Re[1]: Excelに二次元配列のデータを設定する方法
□投稿者/ 魔界の仮面弁士 (42回)-(2014/07/08(Tue) 13:38:13)
2014/07/08(Tue) 13:59:52 編集(投稿者)

No72708 (さとすけ さん) に返信
> Excelの範囲指定は、数値で指定したいので
たとえば、"EG8707" 範囲の Range オブジェクトに対し、
Column プロパティを呼び出せば、列番号 137 という値を得られます。


あるいは、Address メソッドの 第3引数 に xlR1C1 を指定するという
方法もあります。自前で算出しても良いけれど…。
http://www.happy2-island.com/excelsmile/smile03/capter00718.shtml


> rng[i, j] = "aaa";
全部同じ値の場合は、配列ではなく、単一値を代入しても OK です。


> sheet.get_Range("A2", "EG8707").Value2 = rng;
> の設定では実行できたのですが
> sheet.get_Range(sheet.Cells[1, 1], sheet.Cells[1, 2]).Value2 = rng;

A2 → [1,1] / "EG8707" → [1,2] だと、設定範囲が全然違うような気が。


なお Cells プロパティは、「引数を持たないプロパティ」であるため、
相互運用機能アセンブリによっては、
 range0 = sheet.Cells; // Sheet's property `Cells`
 range1 = range0[1, 1]; // Range's indexer (default property `Item`)
 range2 = range0[1, 2]; // Range's indexer (default property `Item`)
 // range3 = sheet.get_Range(range1, range2);
 range3 = sheet.Range[range1, range2]; // Sheet's property `Range`
 range3.Value = rng;
のように、逐次変数に受けておいた方が安全かも。(後の解放処理のためにも)

# とはいえ、Microsoft.Office.Interop.Excel (ver.1.7.0.0) がそれに該当するのかどうかは未調査です。


> コンパイルに必要な1以上の方が
「1 以上の型」かも。


> 出来れば後者の方法が望ましいのですが
こんな感じで如何でしょう。

//
// using Excel= Microsoft.Office.Interop.Excel;
//
Excel.Application xlApp = new Excel.Application();
xlApp.Visible = true;
Excel.Workbooks books = xlApp.Workbooks;
Excel.Workbook book = books.Add();
Excel.Sheets sheets = book.Worksheets;
Excel.Worksheet sheet = sheets[1] as Excel.Worksheet;


Excel.Range range0 = sheet.Cells;
Excel.Range range1 = range0.Item[2, 1];
Excel.Range range2 = range0.Item[8707, 137];
Excel.Range range3 = sheet.Range[range1, range2];
range3.Value = rng;

// 以下、解放処理は省略
引用返信 編集キー/
■72721 / inTopicNo.3)  Re[2]: Excelに二次元配列のデータを設定する方法
□投稿者/ さとすけ (2回)-(2014/07/08(Tue) 18:55:04)
ご返信ありがとうございます。

ご提示頂きましたソースをこちらでコンパイルしようとしたところ
次の2行でエラーが発生してしまいました。
エラーメッセージも先のものと同じで起因も同じではないかと予想しています。
(おそらく当方の環境の問題)

---
Excel.Range range1 = range0.Item[2, 1];
Excel.Range range2 = range0.Item[8707, 137];
---
# エラーメッセージ「動的な式のコンパイルに必要な・・・」

---
sheet.get_Range(sheet.Cells[1, 1], sheet.Cells[1, 2]).Value2 = rng;
---
# エラーメッセージ「動的な式のコンパイルに必要な・・・」

ただ、"A2"などの指定では動くので

> 方法もあります。自前で算出しても良いけれど…。
> http://www.happy2-island.com/excelsmile/smile03/capter00718.shtml

こちらの方法での実装で乗り切ろうと思います。
とても貴重な情報をありがとうございました。

また、解放についてのアドバイスもありがとうございました。

---- 修正済みソースその1 ----
// データをExcelへセット
String start = "A2";
String end = MakeExcelPosition(columnNames.Count, rows.Count + 1);
Excel.Range dataRange = null;
try
{
	dataRange = sheet.get_Range(start, end);
	dataRange.Value2 = data;
}
finally
{
	System.Runtime.InteropServices.Marshal.ReleaseComObject(dataRange);
}
------------------------------

---- 修正済みソースその2 ----
private String MakeExcelPosition(int x, int y)
{
	// 文字コードのリストを生成
	List<int> ret = new List<int>();
	while (x > 26)
	{
		ret.Add(x % 26);
		x = x / 26;
	}
	if (x == 26)
	{
		ret.Add(x % 26);
	}
	else
	{
		ret.Add(x);
	}

	// x軸のExcel表記を生成
	StringBuilder excelX = new StringBuilder();
	for (int i = ret.Count - 1; i >= 0; i--)
	{
		int asciiCode = ret[i] + 65 - 1;
		if (asciiCode == 64)
		{
			asciiCode = 90;
		}
		excelX.Append((char)asciiCode);
	}

	// 最後にyをそのまま足す
	excelX.Append(y);

	return excelX.ToString();
}
------------------------------

>>rng[i, j] = "aaa";
> 全部同じ値の場合は、配列ではなく、単一値を代入しても OK です。

> A2 → [1,1] / "EG8707" → [1,2] だと、設定範囲が全然違うような気が。

すいません、ご指摘の通りです。
サンプルがあまりよくありませんでした。


解決済み
引用返信 編集キー/
■72723 / inTopicNo.4)  Re[3]: Excelに二次元配列のデータを設定する方法
□投稿者/ 魔界の仮面弁士 (45回)-(2014/07/08(Tue) 20:09:53)
No72721 (さとすけ さん) に返信
> エラーメッセージも先のものと同じで起因も同じではないかと予想しています。
> (おそらく当方の環境の問題)

もしかして、参照設定に「Microsoft.CSharp.dll」が漏れていたりはしませんか?

これが抜けていると、Microsoft.CSharp.RuntimeBinder.Binder クラスを
利用できないため、【dynamic 型】の利用時に、
 CS1969『動的な式のコンパイルに必要な 1 つ以上の型が見つかりません。参照が指定されていることを確認してください。』
というエラーが発生することになります。


>>方法もあります。自前で算出しても良いけれど…。
>>http://www.happy2-island.com/excelsmile/smile03/capter00718.shtml
> こちらの方法での実装で乗り切ろうと思います。

失礼、うっかり VBA コードを紹介してしまいました。

C# なので、こちらを紹介した方が良かったかな…今更ですが。
http://zecl.hatenablog.com/entry/20090206/p1
引用返信 編集キー/
■72729 / inTopicNo.5)  Re[4]: Excelに二次元配列のデータを設定する方法
□投稿者/ さとすけ (3回)-(2014/07/09(Wed) 10:14:18)
> もしかして、参照設定に「Microsoft.CSharp.dll」が漏れていたりはしませんか?

まさにその通りでした。。
参照設定を追加したところ、ご提示頂きましたソースをコンパイル出来るようになりました。
ご指摘本当にありがとうございます。

以下のように修正しました。

---- 修正済みソースその1 ----
SetExcelData(sheet, 1, 2, columnNames.Count, rows.Count + 1, data);
------------------------------

---- 修正済みソースその2 ----
#region GetExcelRange (private : Excel範囲を取得)
private Excel.Range GetExcelRange(Excel.Worksheet sheet, int startX, int startY, int endX, int endY)
{
	Excel.Range range0 = null;
	Excel.Range range1 = null;
	Excel.Range range2 = null;
	Excel.Range range3 = null;
	try
	{
		range0 = sheet.Cells;
		range1 = range0.Item[startY, startX];
		range2 = range0.Item[endY, endX];
		range3 = sheet.Range[range1, range2];
	}
	finally
	{
		if (range0 != null)
		{
			System.Runtime.InteropServices.Marshal.ReleaseComObject(range0);
		}
		if (range1 != null)
		{
			System.Runtime.InteropServices.Marshal.ReleaseComObject(range1);
		}
		if (range2 != null)
		{
			System.Runtime.InteropServices.Marshal.ReleaseComObject(range2);
		}
	}
	return range3;
}
#endregion

#region SetExcelData (private : Excelへデータを設定)
private void SetExcelData(Excel.Worksheet sheet, int startX, int startY, int endX, int endY, object[,] data)
{
	Excel.Range range = null;
	try
	{
		range = GetExcelRange(sheet, startX, startY, endX, endY);
		range.Value2 = data;
	}
	finally
	{
		if (range != null)
		{
			System.Runtime.InteropServices.Marshal.ReleaseComObject(range);
		}
	}
}
#endregion
------------------------------

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -