2012-03-09 14 views
3

私は、ソケットインターフェイスを介してコマンドを受け取り、GUIでそれらを実行するアプリケーションを開発しています。このアプリケーションはC#.NET 4.0で開発されており、そのGUI用にWPFを使用しています。C#GUIスレッドエラー

ソケットインターフェイスには、ソケットをリッスンしてコマンドを処理し続けるワーカースレッドがあります。たとえば、Show Popupコマンドを受け取った場合、ワーカースレッドはポップアップを作成して表示するマネージャクラスを呼び出しますメイン画面に表示されます。

ポップアップを作成し、メイン画面を呼び出すマネージャ方法は以下の通りです:PopupType1がある

public void ProcessPopup(PopupModel model) 
{ 
    switch (model.ScreenType) 
    { 
     case Screens.Type1: 
      popup = new PopupType1(); 
      break; 
     case Screens.Type2: 
      popup = new PopupType2(); 
      break; 
     case Screens.Type3: 
      popup = new PopupType3(); 
      break; 
     case Screens.Type4: 
      popup = new PopupType4(); 
      break; 
    } 

    viewModel.SetModel(model); 

    if (!Dispatcher.CurrentDispatcher.Equals(App.Current.Dispatcher)) 
    { 
     App.Current.Dispatcher.Invoke((ThreadStart)delegate { mainScreen.ShowPopup(popup); }); 
    } 
    else 
    { 
     mainScreen.ShowPopup(popup); 
    } 
} 

クラス:

public partial class PopupType1 : UserControl 
{ 
    public PopupType1() 
    { 
     InitializeComponent(); 
    } 
} 

問題は、私は新しいPopupType1をcraeteときオブジェクト私は以下の例外を受け取ります:

System.InvalidOperationException: The calling thread must be STA, because many UI components require this. 
    at System.Windows.Input.InputManager..ctor() 
    at System.Windows.Input.InputManager.GetCurrentInputManagerImpl() 
    at System.Windows.Input.InputManager.get_Current() 
    at System.Windows.Input.KeyboardNavigation..ctor() 
    at System.Windows.FrameworkElement.FrameworkServices..ctor() 
    at System.Windows.FrameworkElement.EnsureFrameworkServices() 
    at System.Windows.FrameworkElement..ctor() 
    at System.Windows.Controls.Control..ctor() 
    at System.Windows.Controls.UserControl..ctor() 
    at MyApp.Views.PopupType1..ctor() 
    at MyApp.Manager.ProcessPopup(PopupModel model) 
    at MyApp.CommunicationController.ProcessAsync(XDocument messageXml) 

私はいくつかのことを試しました私のワーカースレッドをSTAスレッドに変換したり、ポップアップの作成を処理するために新しいSTAスレッドを作成するのが好きですが、解決されるよりも多くの問題が発生しました。

最後に、私のアプリケーションが動作中にいくつかの "フリーズ"を経験しているので、私はこれをやっていることを言及することが重要です。そして、WPF GUIスレッドがあまりにも仕事に圧倒されている私はGUI以外の処理をGUIスレッドから分離しようとしています。

答えて

3

UIスレッドでもUIコントロールを作成する必要があります。したがって、基本的にProcessPopupのすべてがあなたのケースのUIスレッド上で実行される必要があります。mainScreen.ShowPopup()

1

PopupTypeにコントロールが含まれている場合、それはメインのGUIスレッドで作成する必要があります。

2

あなたはです。ポストをバックグラウンドスレッドに作成しています。
これは動作しません。 UIスレッドでのみコントロールを作成できます。

高価な(遅い)ロジックをUIクラスから分離し、それをバックグラウンドスレッドで単独で実行する必要があります。

0

設計上、UIオブジェクト(メイン)を作成したスレッドのみがUIオブジェクトにアクセスできます。あなたの説明から "ソケットインターフェイスにはワーカースレッドがある"ので、インターフェイスはUIにアクセスできません。バックグラウンドワーカーからのコールバックは、UIにアクセスできる場所です。リスナーを熱くしておきたいので、UIへのアクセスに「進捗状況」がうまくいくと思います。

0

UIスレッドでUI要素を作成する必要があります。

private static UserControl CreatePopup(PopupModel model){ 
    switch (model.ScreenType) 
    { 
     case Screens.Type1: 
      popup = new PopupType1(); 
      break; 
     case Screens.Type2: 
      popup = new PopupType2(); 
      break; 
     case Screens.Type3: 
      popup = new PopupType3(); 
      break; 
     case Screens.Type4: 
      popup = new PopupType4(); 
      break; 
    } 
} 

をそしてProcessPopupに変更します:あなたは、たとえば次のことを行うことができます。また

public void ProcessPopup(PopupModel model) 
{ 
    viewModel.SetModel(model); 
    App.Current.Dispatcher.BeginInvoke(
       new Action(()=>{ 
          mainScreen.ShowPopup(CreatePopup(model)); 
          } 
      )); 
} 

、BeginInvokeメソッドの代わりに、呼び出しの使用を注意してください。これは、UIの更新を非同期で確実に行うため、一部のUIでワーカースレッドをブロックする必要がなくなります。