2012-03-14 23 views
3

私は少し重労働を起こす小さなプロジェクトを終了しました。私はこの短い計算時間で、私のGUIがフリーズすることに気づいた。だから私はいくつかの研究を行いましたが、私はこれを発見しました=>http://www.codeproject.com/Articles/4381/Threading-out-tasks-in-a-C-NET-GUIコンストラクタで新しいスレッドを開始する

私はこのプロジェクトを実装し始めましたが、この特定の実装が私のプロジェクトでは機能しないことに気付きました。

私のプロジェクトには、他のすべてのクラスを管理するクラスと1つの「マネージャ」があります。このManagerクラスを初期化すると、すでにコンストラクタで重い作業が行われています。私の質問に

がどのように私はコンストラクタを持つ新しいスレッドを開始していますか?

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) 
     { 


      if (System.IO.File.Exists(e.FullPath) == true) 
      { 

       Manager mgr = new Manager(e, handreader); // here starts the heavy lifting 
       Thread mgrThread = new Thread(new ThreadStart(mgr)); // what to do ? 
       sl.Text = mgr.test(); 
       txtLog.Text = mgr.output(); 


      } 
     } 

編集:私は私のプログラムを修正することを決め 大丈夫。重い持ち上げは1つの機能にありますが、私は間違いを犯したと思います。

全体のプログラムは次のようになります。

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) 
     { 


      if (System.IO.File.Exists(e.FullPath) == true) 
      { 
       Manager mgr = new Manager(e, handreader, txtLog, sl); 
       //sl.Invoke(new MethodInvoker(mgr.test)); 
       sl.Invoke(new MethodInvoker(mgr.test)); // first try 
       Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try 

      } 
     } 

sl.Invoke(new MethodInvoker(mgr.test)); // first try作品が、それはまだ私のGUIをフリーズします。

Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try 

この行は何もしません。

私のテスト機能:

public void test() 
    { 
     StringBuilder builder = new StringBuilder(); 
     foreach (PlayerController pc in fm.lPc) 
     { 
      Range range = new Range(handReader.hand, handReader.handversus, pc); 
      builder.Append(pc.getHeroCardsSimple()+" vs 100% range = "+range.vsRange()+"\r\n"); 
     } 
     sl.Text = builder.ToString(); 
    } 

答えて

3

これには別の方法を使用する必要があります。あなたのコンストラクタはまだGUIスレッド上で呼び出されています。

Func<Manager> asyncConstructor; 
    private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e) 
    { 
     asyncConstructor = new Func<Manager>(() => new Manager()); 

     asyncConstructor.BeginInvoke(ManagerConstructed, null); 
    } 

    private void ManagerConstructed(IAsyncResult result) 
    { 
     Manager mgr = asyncConstructor.EndInvoke(result); 
     //we can only access form controls from the GUI thread, 
     //if we are not on the gui thread then 
     //do the changes on the gui thread. 
     if (this.InvokeRequired) 
     { 
      this.Invoke(new Action(() => 
      { 
       sl.Text = mgr.test(); 
       txtLog.Text = mgr.output(); 
      })); 
     } 
    } 
+1

メインの質問に答えても、私はJonに同意します:コンストラクタで重い物をしないでください! – ChrFin

+0

はい、もちろんですが、それは別の質問です – Bas

2
は「労働者」のいくつかの種類にコンストラクタのうち、「力仕事」を移動したスレッドでその方法を実行します

変更からマネージャー:

public Manager(/*params*/) 
{ 
    //params 
} 

public void DoWork() 
{ 
    //heavy lifting 
} 

Manager mgr = new Manager(e, handreader); 
Thread mgrThread = new Thread(new ThreadStart(mgr.DoWork)); 
mgrThread.Start(); 

ATTENTIONへの呼び出しに

public Manager(/*params*/) 
{ 
    //params 
    //heavy lifting 
} 

:あなたは/にアクセスした場合、スレッドのUI要素を変更し、ドン」その呼び出しを呼び出すことを忘れないでください!

+0

はあなたの推薦を実装しようとしましたが、成功せず –

+0

はちょうどあなたの編集を確認:あなたはスレッドを開始するのを忘れました!私の編集を参照してください... – ChrFin

1

さて、あなた使用することができます

Thread mgrThread = new Thread(() => new Manager(e, handreader)); 

は...しかし、あなたはあなたのコードの残りのマネージャーへの参照を持っていません。

コンストラクタでの重い作業は、いろいろな理由で、一般的には悪い考えです。他の場所に移動する方が良いでしょう。

// Constructor just sets things up 
Manager mgr = new Manager(e, handreader); 
// DoWork method does the real work 
Thread mgrThread = new Thread(mgr.DoWork); 
関連する問題