2017-07-15 16 views
0

ディスパッチャーを追加しましたが、ボタンを押したときにコマンドが実行された後でもUIがフリーズしました。WPFのディスパッチャーでもボタンのフリーズUIが発生する

私の現在の未遂修正

 new Thread(() => 
     { 
      Parallel.ForEach(BootstrapNodes, 
      new ParallelOptions { MaxDegreeOfParallelism = 2 }, 
      (node) => 
       { 
        Console.WriteLine(String.Format("Currently bootstrapping {0} on {1}", 
        node.NodeName, 
        node.IPAddress)); 
        ChefServer.BootstrapNode(node); 
       }); 
     }).Start(); 

UI

 Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => { 
      Parallel.ForEach(BootstrapNodes, 
      new ParallelOptions { MaxDegreeOfParallelism = 2 }, 
      (node) => 
       { 
        Console.WriteLine(String.Format("Currently bootstrapping {0} on {1}", 
        node.NodeName, 
        node.IPAddress)); 
        ChefServer.BootstrapNode(node); 
       }); 
      })); 

をフリーズバージョンは、私は私の機能に深く潜るする必要がありますかUIがフリーズを避けるために呼び出しますか?私はどこにでもスレッドを産み出さないようにしようとしています。

編集: 私のバックグラウンドタスクは非常に高価です。

+0

バックグラウンドスレッドからUIスレッドのUIコントロールへのスレッドセーフ書き込みを「起動」していないのですか? –

+0

この例をご覧ください:https://stackoverflow.com/a/1644254 –

+0

@RobertHarveyありがとうございました。だから、私の場合、私の操作は非常にコストがかかり、私が思ったようにディスパッチャスレッドに属さない。並行foreachがUIのフリーズを避けないでしょうか?なぜ私がまだUI上でブロックされているのかわかりません –

答えて

2

ラムダ全体をUIスレッドに移動しています。そこで、UIに非同期(パラレル)になります。バックグラウンドで計算した情報を使用して実際にUIを更新するコードだけをUIスレッドに配置してください。

// runs in a background thread 
public void backgroundFoo() 
{ 
    // do heavy stuff here 
    var result = Work(); 

    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => 
    { 
     // update UI here after the work as been done ... 
     Console.WriteLine(... result.Anything ...); 
    })); 
} 
+0

事は、私はデータをUIに深く結び付けているので、UIの更新は非同期で行われるということです。 UIをフリーズすることなく、ボタンのクリックでバックグラウンド計算を実行したいだけです。 –

+0

あなたはその 'Invoke()'(あなたの質問にあるもの)を削除して、あなたが言ったようにUIが "way down"に更新された場所に置くことができると思います。 'Invoke()'を使わずにすべてを動かし、UI /メインスレッドに手を差し伸べるたびに 'Invokes()'を実行してください。 – Waescher

+0

興味深いですが、なぜINotifyPropChangeに接続され、フォーム上のUI要素にバインドされたものを呼び出す必要がありますか?これらのUIの変更はすべて、実装の性質によって非同期に発生します。 –

0

私はこれに対してMicrosoftのReactive Framework(Rx)を使用します。

このコードは、あなたのために働く必要があります:あなたは計算が終了したい場合は

IDisposable subscription = 
    BootstrapNodes 
     .ToObservable() 
     .Select(node => 
      Observable 
       .Start(() => 
       { 
        Console.WriteLine(String.Format("Currently bootstrapping {0} on {1}", 
        node.NodeName, 
        node.IPAddress)); 
        ChefServer.BootstrapNode(node); 
       })) 
     .Merge(maxConcurrent : 2) 
     .ObserveOnDispatcher() 
     .Subscribe(u => { },() => 
     { 
      // Back on UI thread - Code completed 
     }); 

は早いだけsubscription.Dispose()を呼び出します。

WPFのビットを取得するには、NuGet "System.Reactive.Windows.Threading"を使用します。

0

WPFのディスパッチャは、のスレッド安全性を確保するために使用されており、UIはフリーズ解除されていません。 BackgroundWorkerを使用すると、重い作業を行うことができます。

using System; 
using System.ComponentModel; 
using System.Threading.Tasks; 
using System.Windows; 

namespace ThreadingSample.WPF 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private BackgroundWorker _worker; 
     public MainWindow() 
     { 
      InitializeComponent(); 
      _worker = new BackgroundWorker(); 
      _worker.DoWork += WorkHeavy; 
      _worker.ProgressChanged += ReportWork; 
      _worker.RunWorkerCompleted += UpdateUI; 
      _worker.WorkerReportsProgress = true; 
     } 

     private void ReportWork(object sender, ProgressChangedEventArgs e) 
     { 
      //get node object from e.UserState 
      //update ui... 
      //Console.WriteLine(String.Format("Currently bootstrapping {0} on {1}", 
      //node.NodeName, 
      //node.IPAddress)); 
     } 

     private void UpdateUI(object sender, RunWorkerCompletedEventArgs e) 
     { 
      //update ui... 
     } 

     private void WorkHeavy(object sender, DoWorkEventArgs e) 
     { 
      //heavy work.... 
      Parallel.ForEach(BootstrapNodes, 
      new ParallelOptions { MaxDegreeOfParallelism = 2 }, 
      (node) => 
      { 
       _worker.ReportProgress(node); 
       ChefServer.BootstrapNode(node); 
      }); 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      if (_worker.IsBusy == false) 
      { 
       _worker.RunWorkerAsync(); 
      } 
     } 
    } 
} 
関連する問題