2016-05-07 18 views
0

私はC#WPFプロジェクトが比較的新しく、タスクを実行している間にユーザーインターフェイスが「ロックアップ」するというコードに問題があります。ここに関連するコードです:ここではManagedDLA2DContainerWPFでGUIがハングするのを防ぐ

public partial class MainWindow : Window { 

    // handles to ManagedDLAContainer objects 
    private ManagedDLA2DContainer dla_2d; 

    public MainWindow() { 
     InitializeComponent(); 

     // initalise aggregate containers 
     dla_2d = new ManagedDLA2DContainer(); 
    } 

    private void GenerateAggregate() { 
     // generate the 2D aggregate of size given by particles_slider value 
     Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); })); 

     // TODO: add particles to "canvas" on GUI as they are generated 
    } 

    private void GenerateButtonClick(object sender, RoutedEventArgs e) { 
     // set the coefficient of stickiness of aggregate 
     // to current value of stickiness_slider 
     dla_2d.SetCoeffStick(stickiness_slider.Value); 

     // start asynchronous task calling GenerateAggregate method 
     Task.Factory.StartNew(() => GenerateAggregate()); 
    } 

} 

は、いくつかのネイティブ、アンマネージドコードC++stickiness_sliderのマネージC++/CLIラッパーが単にWPFインターフェイスのSlider要素です。同様に、particles_sliderはインタフェースの別のSlider要素です。

public partial class MainWindow : Window { 

    // lock object for multi-threading tasks 
    private static readonly object locker = new object(); 

    // handles to ManagedDLAContainer objects 
    private ManagedDLA2DContainer dla_2d; 

    public MainWindow() { 
     InitializeComponent(); 

     // initalise aggregate containers 
     dla_2d = new ManagedDLA2DContainer(); 
    } 

    private void GenerateAggregate() { 
     // lock around aggregate generation 
     lock (locker) { 
      // generate the 2D aggregate of size given by particles_slider value 
      Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); })); 

      // TODO: add particles to "canvas" on GUI as they are generated 
     } 
    } 

    private void GenerateButtonClick(object sender, RoutedEventArgs e) { 
     // set the coefficient of stickiness of aggregate 
     // to current value of stickiness_slider 
     dla_2d.SetCoeffStick(stickiness_slider.Value); 

     Thread agg_gen_thread = new Thread(GenerateAggregate); 
     agg_gen_thread.Start(); 
     agg_gen_thread.Join(); 
    } 

} 

私はここで間違っているかもしれないもの理解するのに役立つ可能性のある情報が高く評価されています。私は、次のコードはまた、GUIがハングにつながることに注意してください。あなたが興味がある場合

はまた、このプロジェクトのすべてのコードはここにあります:https://github.com/SJR276/DLAProject

答えて

1

あなたはGenerateAggregateを実行する新しいスレッドを起動します。その後すぐにすべての作業をDispatcher.Invoke経由でユーザーインターフェイススレッドに送信します。だから基本的には、UIスレッドで長時間実行されているタスクを実行しているとブロックします。

代わりに、UIスレッドにディスパッチする必要があります(UIコントロールを更新するなど)。操作全体ではありません。

あなたの生成機能を仮定は次のようになります。

void Generate() { 
    MakeCpuIntensiveWork(); 
    UpdateUIWithResults(); 
} 

あなたが唯一のUIスレッドへの第二部を派遣する必要があります。あなたの場合、コメントで分かったように、唯一のUI部分はスライダの価値を得ています。このように分割することができます:

private void GenerateAggregate() 
{ 
    uint sliderValue = 0; 
    // generate the 2D aggregate of size given by particles_slider value 
    Dispatcher.Invoke(() => { sliderValue = (uint)particles_slider.Value; }); 
    dla_2d.Generate(sliderValue); 
    // TODO: add particles to "canvas" on GUI as they are generated 
} 
+0

'Dispatcher.Invoke'を指定しないと、別のスレッドがそのオブジェクトを所有しているため、呼び出し側スレッドがこのオブジェクトにアクセスできないという実行時例外が発生します。また、 'GenerateAggregate'はGUIにアイテムを追加するので(最終的に)、' Dispatch.Invoke'を使う必要があると私は理解しています。 – ArchbishopOfBanterbury

+0

メソッド全体ではなく、UIコントロールを更新する_only_パーツをディスパッチする必要があります。 – Evk

+0

ああ、わかりました。私は注意すべきです - 'Generate'はC++/CLIコードである' ManagedDLA2DContainer'クラスのメソッドです。実際にC++/CLIラッパーからUIを更新することは可能ですか? – ArchbishopOfBanterbury

関連する問題