まだ破棄されていない FormObjectDisposedException
の呼び出しからを取得します。Invoke
問題を示すサンプル コードを次に示します。
public partial class Form2 : Form
{
void Form2_Load(object sender, EventArgs e)
{
// Start a task that does an Invoke on this control
Task.Factory.StartNew(TaskWork);
// Sleep here long enough to allow the task that does the Invoke
// to execute to the point where it has:
// a. Posted the message and
// b. is waiting
Thread.Sleep(500);
// Cause ShowDialog to return by setting the DialogResult
DialogResult = DialogResult.OK;
}
void TaskWork()
{
// This call doesn't return, but instead throws an ObjectDisposedException
this.Invoke((MethodInvoker)(() => MessageBox.Show("Invoke succeeded")));
}
}
Form1 (メイン フォーム) からの呼び出しコードは次のとおりです。
public partial class Form1 : Form
{
Form2 m_form2 = new Form2();
void Form1_Load(object sender, EventArgs e)
{
// Call ShowDialog, but don't dispose it.
m_form2.ShowDialog();
// Cause the finalizers to run. This causes an AggregateException to be thrown
// due to the unhandled ObjectDisposedException from the Task.
GC.Collect();
}
}
Microsoft のソースを調べたところ、DestroyHandle の呼び出し中に例外が作成されることがわかりました (下記)。DestroyHandle は、終了時に ShowDialog によって呼び出されています。
source.NET\4\DEVDIV_TFS\Dev10\Releases\RTMRel\ndp\fx\src\WinForms\Managed\System\WinForms\Control.cs\1305376\Control.cs から:
protected virtual void DestroyHandle() {
// ...
// If we're not recreating the handle, then any items in the thread callback list will
// be orphaned. An orphaned item is bad, because it will cause the thread to never
// wake up. So, we put exceptions into all these items and wake up all threads.
// If we are recreating the handle, then we're fine because recreation will re-post
// the thread callback message to the new handle for us.
//
if (!RecreatingHandle) {
if (threadCallbackList != null) {
lock (threadCallbackList) {
Exception ex = new System.ObjectDisposedException(GetType().Name);
while (threadCallbackList.Count > 0) {
ThreadMethodEntry entry = (ThreadMethodEntry)threadCallbackList.Dequeue();
entry.exception = ex;
entry.Complete();
}
}
}
}
// ...
}
質問:
ShowDialog がハンドルを破棄するのはなぜですか (このフォームを再利用する可能性がある場合)。
ObjectDisposedException が発生するのはなぜですか。これは非常に誤解を招くものです (破棄されていないため)。オブジェクトが破棄されたときにのみハンドルが破棄されることをコードが期待しているかのようです(これは私が期待していたものです)。
これは有効であるべきですか?つまり、ShowDialog の後にコントロールを呼び出すことを許可する必要がありますか?
ノート:
もう一度実行する
.ShowDialog()
と、新しいハンドルが作成されます。実行後に を実行
.ShowDialog()
しようとするInvoke
と、「ウィンドウ ハンドルが作成されるまで、Invoke または BeginInvoke をコントロールで呼び出すことはできません」という InvalidOperationException が発生します。実行後、プロパティ
.ShowDialog()
にアクセスして を実行すると、成功します。Handle
Invoke