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

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

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

Re[6]: C#でExcelシート上のチェックボックスの変更


(過去ログ 112 を表示中)

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

■66599 / inTopicNo.1)  C#でExcelシート上のチェックボックスの変更
  
□投稿者/ のぶ (19回)-(2013/05/10(Fri) 14:44:41)

分類:[C#] 

Excelのシート上にグループ化されたチェックボックスがあり
その中のチェックボックスに対してチェックの状態を変更したく以下のようにしてみました。

    public void CheckedInGroupCheckBox(string sheetName, string groupName, string checkboxName)
    {
      Excel.Worksheet sheet = sheets[sheetName];
      Excel.Shapes shapes = sheet.Shapes;
      Excel.Shape group = null;
      Excel.Shape chk = null;
      
      Excel.GroupShapes g = null;
      for (int i = 1; i < shapes.Count; i++)
      {
        group = shapes.Item(i);
        if (group.Name == groupName)
          break;
      }
      g = group.GroupItems;
      
      chk = g.Item(checkboxName); // ★

      ReleaseObj(ref sheet);
      ReleaseObj(ref shapes);
      ReleaseObj(ref group);
      ReleaseObj(ref chk);
    }

★の位置で目的のチェックボックスは取得できますが、
それに対してどの様にチェックを付ければいいのかが分かりません。

検索してみると、(VBAだと?)Valueに対してtrue/falseを設定すれば出来そうですが、
コンパイルエラーになってしまいます。
また、Worksheet.CheckBoxesメソッドではグループ化されたものは取得できませんでした。

※まだ貼り付けたメソッド自体試行錯誤中なので「そもそもどうやってtrue/false設定すんだよ!」という部分はスルーしてください。

引用返信 編集キー/
■66602 / inTopicNo.2)  Re[1]: C#でExcelシート上のチェックボックスの変更
□投稿者/ ラリホー (1回)-(2013/05/10(Fri) 16:38:41)
コンパイルエラーになる、とありますが、どんなコードを書いて、どんなエラーになったのでしょうか。
もしかしたら単純なミスなのかも知れませんので、ご提示ください。
引用返信 編集キー/
■66604 / inTopicNo.3)  Re[2]: C#でExcelシート上のチェックボックスの変更
□投稿者/ のぶ (20回)-(2013/05/10(Fri) 17:15:14)
No66602 (ラリホー さん) に返信
ご回答ありがとうございます。

> もしかしたら単純なミスなのかも知れませんので、ご提示ください。
失礼いたしました。補足致します。

★の次の行に
chk.Value = true;
と書きました。
そして、出てくるエラー内容は以下になります。
=== エラー内容 ===
'Microsoft.Office.Interop.Excel.Shape' に 'Value' の定義が含まれておらず、
型 'Microsoft.Office.Interop.Excel.Shape' の最初の引数を受け付ける拡張メソッドが見つかりませんでした。
using ディレクティブまたはアセンブリ参照が不足しています。
==================

このような状態になります。
chk自体Shapeとして取得しているので、CheckBoxとして認識できていないせいだろう・・・
とは思っていますが、何をどうしたらいいのかさっぱりです。

あと、何気なくExcel.○○と書いてしまってありますが
using Excel = Microsoft.Office.Interop.Excel;
としてあります。


引用返信 編集キー/
■66624 / inTopicNo.4)  Re[1]: C#でExcelシート上のチェックボックスの変更
□投稿者/ 魔界の仮面弁士 (212回)-(2013/05/12(Sun) 12:58:14)
No66599 (のぶ さん) に返信
> Excelのシート上にグループ化されたチェックボックスがあり
フォームコントロールのチェックボックスでしょうか。
それともActiveXのチェックボックスでしょうか。

前者であれば、Shape の DrawingObject プロパティから、Excel.CheckBox 型のオブジェクトを得られます。
あるいは、ワークシートの CheckBoxes メソッド経由で得ることもできます。

後者の場合は、DrawingObject から得たオブジェクトに対し、さらにその object プロパティを呼ぶことで、
MSForms.CheckBox 型を得ることができるでしょう。


> また、Worksheet.CheckBoxesメソッドではグループ化されたものは取得できませんでした。
CheckBoxes メソッドという事は、フォームコントロール版(Excel.CheckBox) の方ですね。

グループ化されている場合(Shape の Type プロパティが msoGroup の場合)は、
御存じのように GroupItems 経由で、個々の Shape 要素にアクセスできます。
それを、Type が msoFormControl になるまで再帰的に繰り返してみてください。

該当する Shape にまで行き当たったら、あとは上記のように、Shape の DrawingObject プロパティから
操作対象のチェックボックス型を得ることができるはずです。


> 検索してみると、(VBAだと?)Valueに対してtrue/falseを設定すれば出来そうですが、
> コンパイルエラーになってしまいます。
Excel.CheckBox の場合も MSForms.CheckBox の場合も、Value プロパティでチェック状態が変わります。
引用返信 編集キー/
■66638 / inTopicNo.5)  Re[2]: C#でExcelシート上のチェックボックスの変更
□投稿者/ のぶ (21回)-(2013/05/13(Mon) 09:42:34)
No66624 (魔界の仮面弁士 さん) に返信
ご回答ありがとうございます。
また、お返事遅くなり申し訳ありません。

>>Excelのシート上にグループ化されたチェックボックスがあり
> フォームコントロールのチェックボックスでしょうか。
> それともActiveXのチェックボックスでしょうか。
お察し頂けた様にフォームコントロールのものを使用しています。


> 該当する Shape にまで行き当たったら、あとは上記のように、Shape の DrawingObject プロパティから
> 操作対象のチェックボックス型を得ることができるはずです。
chkを取得後、chkからDrawingObjectプロパティからさらにオブジェクトを取得することによって
チェック状態の変更に成功いたしました。

書き換えたコードも掲載させていただきます。
一応目的は果たせたので解決済みとしますが、何か突っ込みどころがあるようでしたらお願いいたします。

public void CheckedInGroupCheckBox(string sheetName, string groupName, string checkboxName)
{
Excel.Worksheet sheet = sheets[sheetName];
Excel.Shapes shapes = sheet.Shapes;
Excel.Shape group = null;
Excel.Shape chk = null;

Excel.GroupShapes g = null;
for (int i = 1; i <= shapes.Count; i++) //Count未満でなぜ取得できていたのか・・・
{
group = shapes.Item(i);
if (group.Name == groupName)
break;
}

g = group.GroupItems;

chk = g.Item(checkboxName);
var ch = chk.DrawingObject; //DrawingObjectから取得
ch.Value = true; //取得したオブジェクトに対してValueプロパティでチェック状態を変更する

ReleaseObj(ref sheet);
ReleaseObj(ref shapes);
ReleaseObj(ref group);
ReleaseObj(ref g);
ReleaseObj(ref chk);
}

解決済み
引用返信 編集キー/
■66639 / inTopicNo.6)  Re[3]: C#でExcelシート上のチェックボックスの変更
□投稿者/ 魔界の仮面弁士 (213回)-(2013/05/13(Mon) 11:18:45)
No66638 (のぶ さん) に返信
> ReleaseObj(ref sheet);
これって、おそらくは COM 解放の Marshal.ReleaseComObject ですよね。
宣言は void ReleaseObj<T>(ref T) でしょうか。

たとえば Shape は、Parent プロパティで Worksheet を返してきます。
今の解放順を逆にして、子階層から処分した方が良いと思ます;念のため。

> 何か突っ込みどころがあるようでしたらお願いいたします。
ループ中のそれぞれの Shape/GroupShapes や
DrawingObject も、 COM オブジェクトじゃないですかね。
引用返信 編集キー/
■66643 / inTopicNo.7)  Re[4]: C#でExcelシート上のチェックボックスの変更
□投稿者/ のぶ (22回)-(2013/05/13(Mon) 13:10:37)
No66639 (魔界の仮面弁士 さん) に返信
> ■No66638 (のぶ さん) に返信
>>ReleaseObj(ref sheet);
> これって、おそらくは COM 解放の Marshal.ReleaseComObject ですよね。
> 宣言は void ReleaseObj<T>(ref T) でしょうか。
お察しの通りCOM解放用のメソッドです。
ただ、ジェネリックスは使用せずオーバーロードで・・・という恥ずかしい書き方をしていました。。。
ジェネリックスについて完全に忘れていたので、以下の様に書き換えました。

private void ReleaseObj<T>(ref T shape)
{
if (shape == null) return;
while (Marshal.ReleaseComObject(shape) != 0) ;
shape = default(T);
}

> たとえば Shape は、Parent プロパティで Worksheet を返してきます。
> 今の解放順を逆にして、子階層から処分した方が良いと思ます;念のため。
そうですね。他の時でしたら「使った逆順で解放する」と心がけていましたが、
Excelの操作で頭がいっぱいでそこまで気が回っていませんでした。
ご指摘ありがとうございます。


> ループ中のそれぞれの Shape/GroupShapes や
> DrawingObject も、 COM オブジェクトじゃないですかね。
ループ中の場合も解放した方がいいのでしょうか?
一応一番最後に
ReleaseObj(ref g);
という形でGroupShapesに関しては開放しています。

for (int i = 1; i <= shapes.Count; i++)
{
group = shapes.Item(i);
if (group.Name == groupName)
break;
ReleaseObj(ref group); // ←こうすべき??
}
引用返信 編集キー/
■66644 / inTopicNo.8)  Re[5]: C#でExcelシート上のチェックボックスの変更
□投稿者/ 魔界の仮面弁士 (214回)-(2013/05/13(Mon) 14:08:38)
No66643 (のぶ さん) に返信
> if (shape == null) return;
念のため、IsComObject も使った方が良いかも。

> while (Marshal.ReleaseComObject(shape) != 0) ;
FinalReleaseComObject というものもありますよ。

自分の場合は、常に 0 まで解放されると都合が悪い場合もあったので、
全解放/一回だけReleaseComObject の 2 パターンの実装を
用意するようにしています。参考までに。

> ループ中の場合も解放した方がいいのでしょうか?
逆に質問です。

たとえば i == 3 のときに groupName が見つかった場合、
1番目2番目のオブジェクトは、元のコードではどのタイミングで
解放されるでしょうか?

ちなみに、for ではなく foreach だと、解放はさらに面倒なことになります。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=54129&KLOG=91


AppDomain のアンロード時や、GC 回収以外のタイミングでの解放に任せるのであれば、
あえて ReleaseComObject しないという選択肢もあるのですけれどね。
http://social.msdn.microsoft.com/forums/ja-jp/csharpgeneralja/thread/0F210F52-3667-4E66-9DD6-4480EEDE48DE
引用返信 編集キー/
■66651 / inTopicNo.9)  Re[6]: C#でExcelシート上のチェックボックスの変更
□投稿者/ のぶ (23回)-(2013/05/13(Mon) 15:03:57)
2013/05/14(Tue) 09:29:26 編集(投稿者)
2013/05/13(Mon) 15:54:58 編集(投稿者)

本題とずれすぎてしまったので、こちは解決済みとして締めたいと思います。

No66644 (魔界の仮面弁士 さん) に返信
何度もお付き合い頂きありがとうございます。

>> if (shape == null) return;
> 念のため、IsComObject も使った方が良いかも。
>
>> while (Marshal.ReleaseComObject(shape) != 0) ;
> FinalReleaseComObject というものもありますよ。
>
> 自分の場合は、常に 0 まで解放されると都合が悪い場合もあったので、
> 全解放/一回だけReleaseComObject の 2 パターンの実装を
> 用意するようにしています。参考までに。
今回は0まで解放してしまって大丈夫なので、IsComObjectによる判定と
FinalReleaseComObjectによる全開放という形に変更しました。
ご指摘ありがとうございます。
private void ReleaseObj<T>(ref T shape)
{
//if (Marshal.IsComObject(shape) && shape == null) return;
if (shape == null || !Marshal.IsComObject(shape)) return; //条件がおかしかったので修正
//while (Marshal.ReleaseComObject(shape) != 0) ;
Marshal.FinalReleaseComObject(shape);
shape = default(T);
}


>>ループ中の場合も解放した方がいいのでしょうか?
> 逆に質問です。
>
> たとえば i == 3 のときに groupName が見つかった場合、
> 1番目2番目のオブジェクトは、元のコードではどのタイミングで
> 解放されるでしょうか?
確かにその通りですね。。
都度解放していかなければ残りますね。
#言われれば分かるけど、自分で思いつかない。。。んー・・・


> ちなみに、for ではなく foreach だと、解放はさらに面倒なことになります。
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=54129&KLOG=91
これは恐らく大変だろうなと感じて回避してました。
と言ってもfor内で解放していなかったので結果としては同じ事してましたが・・・

> AppDomain のアンロード時や、GC 回収以外のタイミングでの解放に任せるのであれば、
> あえて ReleaseComObject しないという選択肢もあるのですけれどね。
> http://social.msdn.microsoft.com/forums/ja-jp/csharpgeneralja/thread/0F210F52-3667-4E66-9DD6-4480EEDE48DE
現状としては、Excel操作用のラップクラスを作成し、その中で色々な操作を完結できるようにし、
Disposableパターンを適用してExcel.Applicationや、Excel.Workbooks等の解放をDisposeメソッド内で行っています。
URLを拝見すると、任意のタイミングでGC.Collect()を呼び出せばReleaseComObjectがなくても大丈夫というように読み取りましたが、
私の場合ですと、Disposeメソッド内で呼び出せば解放されるということでしょうか?
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -