- PR -

TreeViewのDragDropでの例外について

投稿者投稿内容
ぶち
常連さん
会議室デビュー日: 2006/02/15
投稿数: 29
投稿日時: 2006-10-30 15:03
こんにちは。

TreeViewのDragDropについての質問です。

DragDrop内で発生した例外は
MyApplication_UnhandledExceptionでひろうことはできないのでしょうか?

DragDrop内で意図的に0割を行ってもDragDrop内のエラー発生箇所以降の
処理は行われませんが、次のイベントの処理に移ってしまいます。

環境は
VB.NET 2005
Windowsアプリケーション

わかりにくい説明で申し訳ありませんがよろしくお願いします。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-10-30 16:40
引用:

ぶちさんの書き込み (2006-10-30 15:03) より:

DragDrop内で発生した例外は
MyApplication_UnhandledExceptionでひろうことはできないのでしょうか?


無理だと思います。

引用:

DragDrop内で意図的に0割を行ってもDragDrop内のエラー発生箇所以降の
処理は行われませんが、次のイベントの処理に移ってしまいます。


Try ~ Catch であれば、例外を補足することはできます。

ところで、なぜ UnhandledException として例外をキャッチしたいのでしょうか?

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
ぶち
常連さん
会議室デビュー日: 2006/02/15
投稿数: 29
投稿日時: 2006-10-30 17:06
じゃんぬねっとさん、返信ありがとうございます。

try〜catchで確かに例外は補足できるのですが、
理想的な処理としては、catchした箇所ではロールバックのみを行い
その後、例外をthrowしたいと思っています。

例外をthrowする理由は、ここで発生する例外の原因は
バグやDBアクセス時に何か致命的なエラーが発生した場合と
考えられるのでアプリを終了させたいと思っています。

DragDrop以外の箇所はこの方法でうまくいっているので
統一したいということで質問しました。

ただ、無理ということだと別の方法を考えないといけませんね。。。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2006-10-30 17:40
ドラッグ&ドロップはスレッドを跨ぎますからね。
別スレッドで発生した例外はメインスレッドには通知されません。

そこでキャッチした例外を変数に格納しておいて、
終了後にその変数が null かどうかで判断する方法がとられることが多いです。
別スレッド、非同期デリゲート、例外あたりで検索してみると結構ヒットします。

というか、例外は発生させてはいけないのが前提で、
DragEffect を使ってドロップさせないように制御するのが王道です。
ぶち
常連さん
会議室デビュー日: 2006/02/15
投稿数: 29
投稿日時: 2006-10-30 19:16
masaさん、返信ありがとうございます。

ドラッグ&ドロップはスレッドが違うということですね。。。
たしかにそれでは、例外は通知されませんね。

非同期デリゲートで調べてみたのですが、
いまいちよくわかりません。

メインスレッドからスレッドを作成してという基本的な動きは
わかるのですが、TreeViewのDragDropでどう応用させればいいか
わかりません。

もう少しヒントをいただけないでしょうか?

例外を発生させないのが前提というのはよくわかりますが
先ほども記述したようにバグ等で例外が発生した場合のことを
考えてこのような処理方法を考えています。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2006-10-31 09:11
ドラッグ&トドロップ処理の内部で別スレッドが作成されていますから、
あえてプログラムコードでスレッドを沸けたりする必要はないと思います。

DragDrop とか DragOver などのイベントの処理の中で
例外が発生しそうな部分をTry Catch で囲みます。
そしてキャッチした例外を変数にセットしておけば発生したかどうかわかります。
下の例のようにすれば発生した時点で何かをさせることも可能です。

どんな処理なのかがわかりませんから目的に沿っているかどうかはわかりませんが、
参考にしてみてください。

private void textBox1_DragDrop(
 object sender,
 System.Windows.Forms.DragEventArgs e) {

 try {
  // 例外を発生させてみる
  int i = 0;
  i = 1 / i;
 } catch ( Exception ex ) {
  // 発生した例外を退避
  this.ExceptionInDragDrop = ex;
 }
}

// ドラッグ&ドロップ中に発生した例外
private Exception ExceptionInDragDrop {
 get { return m_ExceptionInDragDrop; }
 set {
  if ( m_ExceptionInDragDrop == value ) { return; }
  m_ExceptionInDragDrop = value;
  OnExceptionInDragDropChanged();
 }
}
private Exception m_ExceptionInDragDrop;

// ExceptionInDragDrop が変更されたときの処理(少し手抜き)
private void OnExceptionInDragDropChanged() {
 System.Diagnostics.Debug.WriteLine(
  "例外発生:" + this.ExceptionInDragDrop.ToString()
 );
}

※ VB.NET って書いてあるのに後で気づきました。
少し書式は違いますが伝わりますよね?
ぶち
常連さん
会議室デビュー日: 2006/02/15
投稿数: 29
投稿日時: 2006-10-31 09:55
masaさん、丁寧な解説ありがとうございます。

ですが、申し訳ないのですがもう一点質問です。

別スレッド内で発生した例外を別スレッドで処理をしている間は
メインスレッドでは感知できませんよね?

できれば、コーティング例でいうとm_ExceptionInDragDropに
例外が設定されていたらメインスレッドで例外をthrowすると
いうような処理にしたいのですが。。。

ここでよくわからないのがメインスレッドで例外をthrowする
という処理をどこのメソッドで記述すればいいかということです。

何度も何度も申し訳ありませんがよろしくお願いします。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2006-10-31 10:21
残念ながらドラッグドロップ中にスローさせても握りつぶされます。
例外が発生したときには呼び出し元へ通知されますが、
ドラッグドロップに呼び出し元はありませんよね?

private void OnExceptionInDragDropChanged() {
 // 例外をスローしても通知はされない
 throw this.ExceptionInDragDrop;
}

ロールバックなどは例外をキャッチしたときに処理をするしかないでしょうね。

スローした例外をどこかでキャッチしたとしてそこにロールバック処理を記述するのと、
この例でいう OnExceptionInDragDropChanged にロールバック処理を記述するのとで違いはないように思います。
あえてスローさせる意味はないように思いますが、どのような理由でしょう。


<追記>

「コントロール・フォームが存在しているスレッド」をメインスレッドとするなら、
コントロール・フォームの InvokeRequired プロパティを調べることによって
現在のコードがメイン・サブスレッドのどちらで実行されているかがわかります。

ドラッグドロップの場合は内部でスレッド切り替えが行われていますので、
DragDrop イベントに記述した処理自体はメインスレッドで行われています。
しかし、呼び出し元が別スレッドにあるため、発生した例外は握りつぶされます。

握りつぶされる前に自分でキャッチして変数に格納しておくなり、
キャッチと同時に必要な処理を行ったりする必要があります。



[ メッセージ編集済み 編集者: masa 編集日時 2006-10-31 10:26 ]

スキルアップ/キャリアアップ(JOB@IT)