2009-05-28 10 views
1

なぜこのようなことが起こっているのかわかりませんが、EventHandler内に新しいフォームを作成すると、メソッドが終了するとすぐに消えます。C#EventHandlerで作成されたWindowsフォームがすぐに消えます

ここに私のコードです。わかりやすく編集しましたが、論理的にはまったく同じです。

static void Main() 
{ 
    myEventHandler = new EventHandler(launchForm); 
    // Code that creates a thread which calls 
    // someThreadedFunction() when finished. 
} 

private void someThreadedFunction() 
{ 
    //Do stuff 

    //Launch eventhandler 
    EventHandler handler = myEventHandler; 
    if (handler != null) 
    { 
     handler(null, null); 
     myEventHandler = null; 
    } 
} 

private void launchForm(object sender, EventArgs e) 
{ 
    mf = new myForm(); 
    mf.Show(); 
    MessageBox.Show("Do you see the form?"); 
} 

private myForm mf; 
private EventHandler myEventHandler; 

メッセージボックスが表示される限り、新しいフォームが表示されますか?ある。 OKをクリックすると、フォームが消えます。

私には何が欠けていますか?私は、クラス変数に新しいフォームを割り当てることによって、メソッドが終了した後も生き続けると思っていました。どうやら、これは当てはまりません。

+0

説明:someThreadedFuncは、メインUIスレッド以外のスレッドで呼び出されます(launchFormも同様です)。 –

+0

正しい。ごめんなさい。私は3ページのコードを貼り付けることなく明確になるように最善を尽くしました。 –

答えて

5

この問題は、カスタムスレッドからハンドラ内のコードを実行していて、ではなく、Windowsメッセージポンプを操作するために必要なUIスレッドがであると考えられます。ここでInvokeメソッドを使用して、フォームがUIスレッドに確実に表示されるようにします。

private void launchForm(object sender, EventArgs e) 
{ 
    formThatAlreadyExists.Invoke(new MethodInvoker(() => 
    { 
     mf = new myForm(); 
     mf.Show(); 
     MessageBox.Show("Do you see the form?"); 
    })); 
} 

これは、あなたがすでにApplication.Runを使用して実行した(formThatAlreadyExistsと呼ばれる)のWinFormsオブジェクトを持っていると想定しています。また、あなたのコードにInvoke呼び出しを置くためのより良い場所があるかもしれませんが、これは少なくともそれの例を使用することができます。

+0

私はあなたが提案したものを試しました。コンパイラエラーが発生する: ラムダ式がデリゲート型ではないため 'System.Delegate'と入力できない。また、Invokeの後に2番目のカッコをハイライト表示します。 –

+0

@Andrew:申し訳ありませんが、テストする必要があります。引数型がSystem.Delegateなので、ラムダ式をMethodInvoker型でラップする必要があります。今はうまくいくはずです。 – Noldorin

+0

さて、コンパイルされましたが、今これを取得します。System.InvalidOperationException:InvokeまたはBeginInvokeは、ウィンドウハンドルが作成されるまでコントロールで呼び出すことができません。 at System.Windows.Forms.Control.MarshaledInvoke(コントロール呼び出し元、デリゲートメソッド、オブジェクト[] args、ブール型同期) at System.Windows.Forms.Control.Invoke(Delegateメソッド、Object [] args) at launchFormオブジェクト送信者、EventArgs e) –

0

dbf.Show(); 

タイプミスですか?それは代わりにこれになっていますか?

mf.Show(); 

あなたが表示する予定のもの以外の他のフォームが表示されている可能性はありますか?

+0

ええ、それはタイプミスでした。ごめんなさい。 –

1

私はあなたがスレッドでフォームを作成すると、そのスレッドがフォームを所有していると思います。 UI要素を作成するときは、常にメイン(UI)スレッドで行う必要があります。

1

これはフォームstaスレッドではないように見えるので、フォームを表示すると、スレッドは終了し、スレッドはジョブを終了します。スレッドを参照するものはないので、自己終了します。そのための最良の解決策ではありませんが、コード例が必要な場合はshowdialog()を使用して状態を維持してください。私はこの同じプロセスを「読み込み....」フォームに使用します

public class Loading 
{ 
    public delegate void EmptyDelegate(); 
    private frmLoadingForm _frmLoadingForm; 
    private readonly Thread _newthread; 
    public Loading() 
    { 
     Console.WriteLine("enteredFrmLoading on thread: " + Thread.CurrentThread.ManagedThreadId); 
     _newthread = new Thread(new ThreadStart(Load)); 
     _newthread.SetApartmentState(ApartmentState.STA); 
     _newthread.Start(); 
    } 

    public void Load() 
    { 
     Console.WriteLine("enteredFrmLoading.Load on thread: " + Thread.CurrentThread.ManagedThreadId); 
     _frmLoadingForm = new frmLoadingForm(); 
     if(_frmLoadingForm.ShowDialog()==DialogResult.OK) 
     { 

     } 
    } 


    /// <summary> 
    /// Closes this instance. 
    /// </summary> 
    public void Close() 
    { 
     Console.WriteLine("enteredFrmLoading.Close on thread: " + Thread.CurrentThread.ManagedThreadId); 
     if (_frmLoadingForm != null) 
     { 
      if (_frmLoadingForm.InvokeRequired) 
      { 
       _frmLoadingForm.Invoke(new EmptyDelegate(_frmLoadingForm.Close)); 
      } 
      else 
      { 
       _frmLoadingForm.Close(); 
      } 
     } 
     _newthread.Abort(); 
    } 
} 
public partial class frmLoadingForm : Form 
{ 

    public frmLoadingForm() 
    { 
     InitializeComponent(); 
    } 
} 
+0

私は言ったように私は言ったように私は言ったように私はあなたが何をしているのか理解できないが、私は言ったように、このコードを便利に持っていないだろう、これはあなたが望むものを達成するだろう frmLoadingFormはあなたのケースmyForm私はこの他のクラスを試してみて、これをもっときれいなコードにしようとしました:) –

+0

コンソールでは、呼び出しがどのようにうまく動作するのかを知っています。あなたの現在のコードでなぜ失敗したのかを見てください –

0

非UIスレッドでウィンドウを作成しました。スレッドが異常終了すると、それに合わせてウィンドウが表示されます。物語の終わり。 UIスレッドでmessageboxを作成するメソッドを実行するデリゲートを渡して、メインフォームでinvokeを実行します。 MessageBoxはモーダルウィンドウなので、launchFormメソッドでバックグラウンドスレッドをブロックしたくない場合は、必要なUIでカスタムフォームを作成し、ShowDialog()ではなくshow()を呼び出します。

関連する問題