2017-10-16 11 views
0

このトピックを読んでいただきありがとうございます。C#(WPF)非同期スレッド、GUIへのインターフェイス

新しいWPFアプリケーション(C#でビルド)については、デザインに関する質問があります。 ここ数日、私はC#(.NET 4.5ベース)で非同期プログラミングについて多くのことを読んできました。

私たちがしたいことは:独立したバックグラウンドタスクを実行する新しい非同期スレッドを作成することです。このスレッドに利用可能なデータがある場合は、このデータを(パブリックインターフェイスによって)メインプログラムに送信します。したがって、スレッドはメインプログラムのデータを設定し、すぐに再びスレッドに戻ります。メインプログラムは、データが変更されたときにイベント(INotifyPropertyChanged)を発生させます。

この非同期スレッドを作成するにはどうすればよいでしょうか?または、少なくとも、この機能を設計するにはどうすればよいでしょうか?

現時点では、スレッドを作成するアプリケーションをビルドしました。 これは、現時点では非同期に動作しません。

public MainWindow() 
    { 
     InitializeComponent(); 

     InitGuiInterface(this); 

     //Create thread 
     new OuterLabel_Thread(this); 
    } 

そしてここで、以下のクラス "OuterLabel_Thread.cs":事前に

public class OuterLabel_Thread 
{ 
    private MainWindow context = null; 
    private bool exit = false; 
    private int count = 0; 

    public OuterLabel_Thread(MainWindow context) 
    { 
     this.context = context; 

     Console.WriteLine("Running sample thread"); 
     Thread thread = new Thread(delegate() 
     { 
      Console.WriteLine("Sample thread started"); 

      //start new task 
      //run(); 
      Task.Factory.StartNew(run); 
     }); 
     thread.Start(); 
    } 

    public void Exit() 
    { 
     exit = true; 
    } 

    private void run() 
    { 
     while (!exit) 
     { 
      DateTime Time1 = DateTime.Now; 

      if (context != null && context.GuiInterface != null) 
      { 
       //context.GuiInterface.UpdateThreadCount(count, "label_code_content"); 
      } 
      Console.WriteLine("Background thread count = " + count); 

      count++; 
      if (count > 1000) 
      { 
       exit = true; 
      } 
      //Console.WriteLine((DateTime.Now - Time1).TotalMilliseconds.ToString()); 
      Thread.Sleep(10); 
     } 
    } 
} 

感謝を! 種類:

Rein。

+0

なぜ非同期待ち時間を使用しないのですか? UIスレッドの管理とスレッド間エラーの回避が容易になります。そして、自分のスレッドを管理するのではなく、会話の問題を避けることができます。 – CodeMonkey

+0

私はAsyncとawaitの使用経験はあまりありません。私はこれらの指示が何をするか知っています。 あなたの提案は依然としてスレッドの使い方に基づいていますか?その場合スレッドをどのように呼び出す必要がありますか? – Rein92

+0

データを継続的に提供するサービスを作ることを望んでいるのですか、ボタンをクリックするだけで長時間実行するタスクですか? – CodeMonkey

答えて

1

最良の方法は、非同期を使用しても+待つとタスクです。

private async void LaunchButton_OnClick(object sender, RoutedEventArgs e) 
    { 
     resultLabel.Content = "Task running"; 
     resultLabel.Content = await SomeLongRunningTaskAsync(); 
    } 

    private Task<string> SomeLongRunningTaskAsync() 
    { 
     return Task.Run(
      () => 
      { 
       // Put your background work in here. with Task.Run it's not going to run on UI 
       int count = 0; 
       while (count < 1000) 
       { 
        count++; 
        Thread.Sleep(10); 
       } 

       return "Task done"; 
      }); 
    } 
+0

コメントありがとうございます。このコードをアプリケーションにコピーしました。 タスクの行の1つにブレークポイントを設定しているとき(例: "Thread.Sleep(10);" 私のメインプログラムもフリーズします。もう一方の方法も同様です。それは正しい? – Rein92

+0

デバッガブレークポイントがヒットすると、アプリケーションは常にフリーズします。 UIスレッドがブロックされていないかどうかを検出する簡単な方法は、ウィンドウのサイズを変更して移動させることです。別の方法は、クリックすることができるボタンを有することである。 UIがブロックされていると、正しくクリックできなくなります – Dbl

+0

Ahaa。もちろん。私はそれについて考えなかった。 – Rein92

1

あなたはスレッドを生かしておきたいと思っていますが、わかっている限り、あなたは1000マークに到達するタイミングを正確にはわからないので、asyncが間違った選択になることがあります。私が間違っているなら私を訂正してください。あなたのケースでは

私は、BackgroundWorkerのを使用することをお勧めします:

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int count = 0; 
    BackgroundWorker worker = sender as BackgroundWorker; 
     while (!exit) 
     { 
      DateTime Time1 = DateTime.Now; 
      worker.ReportProgress(count); 
      count++; 
      if (count > 1000) 
      { 
       exit = true; 
      } 
      Thread.Sleep(10); 
     } 
} 

// This event handler updates the progress. 
     private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      resultLabel.Text = ("Background thread count = " + e.ProgressPercentage.ToString()); 
     } 

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Cancelled == true) 
     { 
      resultLabel.Text = "Canceled!"; 
     } 
     else if (e.Error != null) 
     { 
      resultLabel.Text = "Error: " + e.Error.Message; 
     } 
     else 
     { 
      resultLabel.Text = "Done!"; 
     } 
    } 
+0

合意。 BackgroundWorkerはかなり強力ですが、過小評価されたクラスです。また、多くのBackgroundWorkerインスタンスで実行されている操作は、別々のスレッドで実行されている場合と同じです。 –

+0

ご意見ありがとうございます。この場合、スレッドを作成する必要はありませんが、これは正しいのでしょうか? – Rein92

+0

BGWはスレッド自体を作成します。ここにいくつかの情報があります。https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx –

0

サービスや長期実行タスクを探しているかどうかわかりません。

他の人が、私はそれはあなたが生産コードでこれを使用する前に、最大読みくださいSynchronizationContextのようないくつかの先進的なconcpetsを使用してサービス

を作った長時間実行されるタスクの良い例を持っているので。 Google asyncとStephen Clearyが待っています。

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     var foo = new FooService(); 
     foo.StartService(); // UI thrad calling 
    } 
} 

public class FooService 
{ 
    private SynchronizationContext _context; 
    private CancellationTokenSource _cts; 
    private CancellationToken _token; 
    private Task _task; 

    public void StartService() 
    { 
     _context = SynchronizationContext.Current; // Depends on the UI thread being the one to start the service or this will fail 
     _cts = new CancellationTokenSource(10000); // Run for 10 seconds 
     _token = _cts.Token; 
     _task = Task.Run(() => Run(), _token); 
    } 

    public async Task Stop() 
    { 
     _cts.Cancel(); 
     await _task; // wait for task to finish 
    } 

    private void Run() 
    { 
     while (!_token.IsCancellationRequested) 
     { 
      // Do work     
      Thread.Sleep(1000); 
      // Alternative use Control.Invoke() if you have access to a UI element, to delegate to the UI thread 
      _context.Send((id) => Console.WriteLine($"Delegate from thread {id} to thread {Thread.CurrentThread.ManagedThreadId}"), Thread.CurrentThread.ManagedThreadId); 
     } 
    } 
} 
関連する問題