1

余分なスレッドでresultを実行した後に (重い処理の結果を返す) にアクセスできるようにしたい. 主に予想されるように, 処理中に UI が有効になったのは望ましくない. 処理が完了した後は、Heavy Processresult

いくつかの検索中に、これを実現するためのいくつかのアプローチがあることがわかった私の記事を見て、あなたが知っている、または同様の状況で使用する最良のアプローチを提供してください

これは、可能な限り最善の方法で対処したいサンプルです。

        public ACollection DoProcess(Document docProcess) 
        {
            ACollection result = new ACollection ();

            ThreadStart threadStart = delegate
            {
                result = MyProcess(docProcess);
            };
            var threadProcess = new Thread(threadStart);
            threadProcess.Start();    

            return result ;
}

他の可能なアプローチは、IAsyncResult、BackgroundWorker、タイマーを使用して状態をチェックすることです。結果をメソッドに返してそれを処理し、それを UI コントロールにスレッドセーフな方法で直接送信する代わりに ...

同様のケースであなた自身の意見とサンプルを教えてください、事前に感謝します

編集 3: アプローチ - ブライアンの回答に基づく

        LenzCollection myResultCollection = new LenzCollection();       

        TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

        Task.Factory.StartNew(() =>
          {
              myResultCollection = DoCollect(docProcess);
              //Task.WaitAll();

              return myResultCollection;
          }).ContinueWith((task =>
          {
              myResultCollection = task.Result;
          }), ui);

        return myResultCollection;  

それはまだ待っていなかったので、望ましい結果が得られません

4

4 に答える 4

2

メソッドを実行する前に登録するイベントを実装するだけです。終了したら、メソッドでイベントを発生させます。

例えば:

public delegate void MyEventHandler(string result);
public class MyClass
{
  public event MyEventHandler MyEvent;
  private void Event(string result)
  {
    MyEventHandler handler = MyEvent;
    if(handler != null)
      handler(result);
  }

  public void DoSomethingLong()
  {
    //Do something
    Event("Finish");
  }
}

これで、次のように実行できます

MyClass.Event += MyEventHandler(On_Event);
Thread t = new Thread(MyClass.DoSomethingLong);
t.Start();    

void On_Event(string result)
{
  //Get executed when finished;
}

UI スレッドを呼び出す例

void On_Event(string result)
{
  if(this.InvokeRequired)
  {
    MyEventHandler handler = new MyEventHandler(On_Event);
    Invoke(handler, new object[] { result });
    return;
  }
  // At this point you can access your UI without having Cross-Threaded operation!
}
于 2012-04-13T10:18:51.157 に答える
2

デスクトップ (WinForms/WPF) アプリでは、BackgroundWorker が最適かつ最も簡単な方法です。これを処理するために設計されました。

于 2012-04-13T10:21:12.140 に答える
1

を使用している場合は.NET Framework 4.0 or +、別のスレッドからプロセスを実行し、Task.ContinueWithでプロセスを実行できます。たとえば、

Process pro = null; 
 Task.Factory.StartNew(() => {
   pro =new Process(..);
   pro.Start(); 
   pro.WaitForExit(); 
}).ContinueWith(..process data recieved from the pro)

編集

使わないwhile(...)で使うpro.WaitForExit()

お役に立てれば。

于 2012-04-13T10:20:11.400 に答える
1

オプション1:

TaskクラスとContinueWithメソッドを使用します。

TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(() =>
  {
    var result = MyProcess(docProcess);
    return result.ToString();
  }).ContinueWith((task =>
  {
    textBox1.Text = task.Result;
  }, ui);

ContinueWith正しい同期コンテキストをメソッドに渡すことを忘れないでください。変数を使用してどのようにそれを行ったかを見ることができuiます。

オプション #2:

newasyncおよびawaitキーワードを使用します。1

private async void SomeButton_Click(object sender, EventArgs args)
{
  textBox1.Text = await Task.Run(() =>
    {
      var result = MyProcess(docProcess);
      return result.ToString();
    });
}

明らかに、これは目にははるかに簡単で、マーシャリングと同期コンテキストのすべてを実行します。


1新しいキーワードは C# 5.0 で使用できるようになりますが、現在はAsync CTPを介して使用できます。CTP はTaskExの代わりに使用しTaskます。

于 2012-04-13T13:31:21.190 に答える