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

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

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

エクセルファイルを作成して表示する方法について

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

■92205 / inTopicNo.1)  エクセルファイルを作成して表示する方法について
  
□投稿者/ 河童 (67回)-(2019/09/01(Sun) 09:38:12)

分類:[C#] 

エクセルファイルを作成して表示する方法について

フォームにあるボタンのクリック時イベントでエクセルファイルを作成して、
それを開いて表示したいと思っています。

エクセルファイルの作成はできたのですが、
1.Interop.Excelで作成
2.ClosedXMLで作成
それぞれわからないことがあります。

1.Interop.Excelで作成
インストールされているエクセルのバージョンがExcel2007、2010、2019とばらばらなことと、
プロセスが残りやすいのであまり使用しない方がいいとネット情報にありました。
確かにタスクマネージャーのプロセスに「EXCEL」が残っていたことがありました。
今のコード上で解放の処理はしているのですが、どこか修正すべき点はありまか?

2.ClosedXMLで作成
ClosedXMLでエクセルを作成して保存はできるのですが、今回は保存までは必要なく
エクセルにデータを入力して、エクセルを開いた状態のままにしておきたいです。
ClosedXMLで作成したエクセルを開いたままにする方法はありますか?

	using ClosedXML.Excel;
	using Excel = Microsoft.Office.Interop.Excel;
	using System.Runtime.InteropServices;

        private Microsoft.Office.Interop.Excel.Application xls = null;     // Excel自体 
        private Microsoft.Office.Interop.Excel.Workbook book = null;       // ブック 
        private Microsoft.Office.Interop.Excel.Worksheet sheet = null;     // シート

        public void ExcelVisibleToggle(Microsoft.Office.Interop.Excel.Application xls, bool setting)
        {
            if (xls.Visible == !setting)
            {
                xls.Visible = setting;
            }
        }

        // エクセル使用
        private void btnExcel_Click(object sender, EventArgs e)
        {

            this.xls = new Microsoft.Office.Interop.Excel.Application();
            // Excelを非表示:レスポンス向上
            ExcelVisibleToggle(xls, false);

            this.book = xls.Workbooks.Add();

            this.sheet = (Microsoft.Office.Interop.Excel.Worksheet)this.book.Sheets["sheet1"];

            // エクセルファイルに項目名を表示
            Excel.Range w_rgn = this.sheet.Cells;
            try
            {
                w_rgn[1, 1].value = "項目名1";
                w_rgn[1, 2].value = "項目名2";
                w_rgn[1, 3].value = "項目名3";
                w_rgn[1, 4].value = "項目名4";
                w_rgn[1, 5].value = "項目名5";

                int cell_row = 2;
                // DataGridViewのソースリストをループ
                foreach (dgvKoumokuLst d in DgvKoumokuLst)
                {
                    w_rgn[cell_row, 1].value = d.koumoku1;
                    w_rgn[cell_row, 1].EntireColumn.AutoFit();
                    w_rgn[cell_row, 2].value = d.koumoku2;
                    w_rgn[cell_row, 2].EntireColumn.AutoFit();
                    w_rgn[cell_row, 3].value = d.koumoku3;
                    w_rgn[cell_row, 3].EntireColumn.AutoFit();
                    w_rgn[cell_row, 4].value = d.koumoku4;
                    w_rgn[cell_row, 4].EntireColumn.AutoFit();
                    w_rgn[cell_row, 5].value = d.koumoku5;
                    w_rgn[cell_row, 5].EntireColumn.AutoFit();
                    cell_row++;

                }
            }
            finally
            {
                // Excelのオブジェクト開放する
                Marshal.ReleaseComObject(w_rgn);
                w_rgn = null;
            }

            // シートを選択
            ExcelVisibleToggle(xls, true);      // Excel表示

            // Sheet解放
            Marshal.ReleaseComObject(sheet);
            // Book解放
            //xlBook.Close();
            Marshal.ReleaseComObject(book);

            // Excelアプリケーションを解放
            //xlApp.Quit();
            Marshal.ReleaseComObject(xls);

        }


        // ClosedXML使用
        private void btnClosedXML_Click(object sender, EventArgs e)
        {

            // エクセルオープン
            var workbook = new XLWorkbook();
            var worksheet = workbook.Worksheets.Add("CSV一覧");
            worksheet.Cell(1,1).Value = "Hello world";

            // 項目名を表示
            worksheet.Cell(1, 1).Value = "項目1";
            worksheet.Cell(1, 2).Value = "項目2";
            worksheet.Cell(1, 3).Value = "項目3";
            worksheet.Cell(1, 4).Value = "項目4";
            worksheet.Cell(1, 5).Value = "項目5";

            int cell_row = 2;
            // DataGridViewのソースリストをループ
            foreach (dgvKoumokuLst d in DgvKoumokuLst)
            {
                worksheet.Cell(cell_row, 1).Value = d.koumoku1;
                worksheet.Column("A").AdjustToContents();
                worksheet.Cell(cell_row, 2).Value = d.koumoku2;
                worksheet.Column("B").AdjustToContents();
                worksheet.Cell(cell_row, 3).Value = d.koumoku3;
                worksheet.Column("C").AdjustToContents();
                worksheet.Cell(cell_row, 4).Value = d.koumoku4;
                worksheet.Column("D").AdjustToContents();
                worksheet.Cell(cell_row, 5).Value = d.koumoku5;
                worksheet.Column("E").AdjustToContents();

                cell_row++;

            }
            
            // workbook.SaveAs(@"C:\Temp\test1.xlsx");

            // CmnMsgBox.Show("出力完了", 2);

            // 作成したエクセルファイルを開いて表示したい

        }

引用返信 編集キー/
■92206 / inTopicNo.2)  Re[1]: エクセルファイルを作成して表示する方法について
□投稿者/ 魔界の仮面弁士 (2345回)-(2019/09/01(Sun) 17:44:36)
No92205 (河童 さん) に返信
> 2.ClosedXMLで作成
> ClosedXMLでエクセルを作成して保存はできるのですが、今回は保存までは必要なく
> エクセルにデータを入力して、エクセルを開いた状態のままにしておきたいです。
> ClosedXMLで作成したエクセルを開いたままにする方法はありますか?

ClosedXML の場合、SaveAs メソッドが Stream への保存をサポートしているので、この辺と組み合わせてみるとか。
http://atata.sakura.ne.jp/net/chap29.html

あるいは、シート内容を表示することだけが目的なら、ReoGrid を使うという手もあります。
オンメモリでのワークブック生成が可能ですし、それを表示するためのコントロールも用意されています。
https://reogrid.net/jp/document/


> 1.Interop.Excelで作成
個人的には積極的にお奨めはしていませんが、Excel の機能を十分に呼び出せる
強力な方法ではありますので、用途に応じて使い分けるものかなと思います。


> インストールされているエクセルのバージョンがExcel2007、2010、2019とばらばらなことと、
バージョンによって、void 戻り値なメソッドが object 戻り値なメソッドに変化したり、
省略可能な引数が追加されたりといった拡張が行われることがあります。

新しく追加した機能を使わないようにすれば、VBA においては大きな差にはなりませんし、
COM レベルにおいても、ディスパッチ ID と不可視属性の組み合わせが使われることで
ある程度の互換性が保たれてはいるのですが、それでも、上位バージョンのライブラリを使って
開発したアプリケーションを下位バージョン環境で動作させようとした場合には、
問題が生じる可能性があります。

また、ストアアプリ版と Windows Installer 版とでの動作の違いや、Office 365 での
更新サイクルの短期化などがあるため、バージョン違いを正確に考慮して
コーディングするのは、ますます難しくなってきています。


> プロセスが残りやすいのであまり使用しない方がいいとネット情報にありました。
解放手続きの話という事で、このあたりも。
https://social.msdn.microsoft.com/Forums/ja-JP/0d9c6273-bade-4f6a-a0de-5adb748d15eb/office?forum=officesupportteamja


たとえば、COM オブジェクトを引数に渡すタイプのメソッドを呼び出す場合、
参照設定なしで dynamic や object を渡した場合と、
PIA を経由で明示的な Excel の型として渡した場合と、
動的生成された IA の型を通じて渡した場合とで、参照カウントの増数が異なるらしく、
ReleaseComObject 時の戻り値の値が変化したこともあります。


> // Excelを非表示:レスポンス向上
アプリケーションを非表示にすることがレスポンス向上に繋がるかは、実はケースバイケースです。
シートを非表示にしたり、描画抑制するなどして操作する方法であれば、レスポンス向上になることが多いのですが、
Application.Visible = false; については、向上する場合もあれば、むしろ低下することもあるのでご注意ください。

本体が非表示となった場合、Excel.exe がバックグラウンド処理に回されることから、実行環境によっては、
処理速度が半分未満に低速化することがあります。OS 設定や プロセッサ構成などの要因によって、
謙虚に反映されてしまう場合もあれば、問題無い場合もありますので、実際の環境で試した上で判断が必要です。


> this.book = xls.Workbooks.Add();
books = xls.Workbooks;
book = books.Add();
とします。Marshal.IsComObject(books) が true である場合、
book のみならず books も解放対象となります。


> this.sheet = (Microsoft.Office.Interop.Excel.Worksheet)this.book.Sheets["sheet1"];
こちらも同様で、
// sheets = book.Worksheets;
sheets = book.Sheets;
sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets["sheet1"];
としたうえで、Marshal.IsComObject(sheets) が true なら、sheets も解放対象です。


> w_rgn[1, 1].value = "項目名1";
Excel.Range w_rgn11 = w_rgn[1, 1];
w_rgn11.Value = "項目名1";
if (Marshal.IsComObject(w_rgn11)) {
 Marshal.ReleaseComObject(w_rgn11);
}

なお、C# のバージョンが古い場合には、
 w_rgn11.set_Value(Type.Missing, "項目名1");
の形式が求められることがあります。今回は当てはまりませんけれども。


> w_rgn[cell_row, 1].EntireColumn.AutoFit();
これも、EntireColumn が返すオブジェクトを変数に受けておくべきです。

rngEntireColumn.AutoFit();
if (Marshal.IsComObject(rngEntireColumn)) {
 Marshal.ReleaseComObject(rngEntireColumn);
}


個別の解放手続き面倒であれば、アプケーションドメインを別途立てて実行し、
作業した AppDomain ごと Unload するという手もありますが、それはそれで面倒かも。
引用返信 編集キー/
■92207 / inTopicNo.3)  Re[2]: エクセルファイルを作成して表示する方法について
□投稿者/ 河童 (68回)-(2019/09/01(Sun) 22:09:00)
No92206 (魔界の仮面弁士 さん) に返信

アドバイス、ありがとうございました。

質問でエクセルの保存は必要ないと言いましたが、保存することにしました。
保存するならば、ClosedXMLで処理できます。

エクセルのバージョンがOffice 365 ProPlus に順次導入することになりました。
xlsx形式で保存して、各自必要なときにファイルを開いてもらうようにしました。

印刷処理をExcelから実行しようと思いましたが、
このためだけにExcelを起動する必要もないのかなと感じだしました。
C#で印刷処理は作成したことがないので勉強する必要があります。

本当にいろいろ教えてくださり、ありがとうございました。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


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

このトピックに書きこむ