9

XamlReader.Load()WPF アプリには、メソッドを使用して別のファイルからユーザー コントロールを読み込む操作があります。

StreamReader mysr = new StreamReader(pathToFile);
DependencyObject rootObject = XamlReader.Load(mysr.BaseStream) as DependencyObject;
ContentControl displayPage = FindName("displayContentControl") as ContentControl;
displayPage.Content = rootObject;

ファイルのサイズが原因でプロセスに時間がかかるため、UI が数秒間フリーズします。

アプリの応答性を維持するために、UI の更新に直接関与しない操作の一部を実行するために、バックグラウンド スレッドを使用しようとしています。

使用しようとするBackgroundWorkerと、エラーが発生しました:多くの UI コンポーネントがこれを必要とするため、呼び出し元のスレッドは STA でなければなりません

だから、私は別の方法に行きました:

 private Thread _backgroundThread;
 _backgroundThread = new Thread(DoReadFile);
 _backgroundThread.SetApartmentState(ApartmentState.STA);
 _backgroundThread.Start();
 void DoReadFile()
 {
   StreamReader mysr3 = new StreamReader(path2);
   Dispatcher.BeginInvoke(
           DispatcherPriority.Normal,
           (Action<StreamReader>)FinishedReading,
           mysr3);
 }

 void FinishedReading(StreamReader stream)
    {            
        DependencyObject rootObject = XamlReader.Load(stream.BaseStream) as DependencyObject;
        ContentControl displayPage = FindName("displayContentControl") as ContentControl;
        displayPage.Content = rootObject;
    }

時間のかかる操作はすべて UI スレッドに残っているため、これでは何も解決しません。

このようにしようとすると、すべての解析がバックグラウンドで行われます:

private Thread _backgroundThread;
_backgroundThread = new Thread(DoReadFile);
_backgroundThread.SetApartmentState(ApartmentState.STA);
_backgroundThread.Start();
 void DoReadFile()
 {
  StreamReader mysr3 = new StreamReader(path2);      
  DependencyObject rootObject3 = XamlReader.Load(mysr3.BaseStream) as DependencyObject;
        Dispatcher.BeginInvoke(
           DispatcherPriority.Normal,
           (Action<DependencyObject>)FinishedReading,
           rootObject3);
  }

  void FinishedReading(DependencyObject rootObject)
  {            
    ContentControl displayPage = FindName("displayContentControl") as ContentControl;
    displayPage.Content = rootObject;
  } 

例外が発生しました:別のスレッドがこのオブジェクトを所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。(ロードされた UserControl には、エラーを引き起こす可能性のある他のコントロールが存在します)

UI が応答するような方法でこの操作を実行する方法はありますか?

4

5 に答える 5

7

XAML を取得してバックグラウンド スレッドを読み込むことは、基本的に非スターターです。WPF コンポーネントにはスレッド アフィニティがあり、一般的に言えば、作成されたスレッドからのみ使用できます。そのため、バックグラウンド スレッドでロードすると、UI はレスポンシブになりますが、UI スレッドにプラグインできないコンポーネントが作成されます。

ここでの最良のオプションは、XAML ファイルを小さな断片に分割し、それらを UI スレッドに段階的に読み込み、すべての読み込み操作の間にメッセージ ポンプを確実に許可することです。オブジェクトを使用BeginInvokeDispatcherてロードをスケジュールする可能性があります。

于 2011-03-22T17:25:10.943 に答える
2

わかったように、スレッドが STA でない限り使用できません。XamlReader.Loadたとえそうであっても、メッセージ ポンプを開始し、それを介して作成されたコントロールへのすべてのアクセスを集中させる必要があります。これは WPF の動作の基本的な方法であり、反対することはできません。

したがって、唯一の実際のオプションは次のとおりです。

  1. XAML をより小さな部分に分割します。
  2. 呼び出しごとに新しい STA スレッドを開始しLoadます。リターン後Load、スレッドはメッセージ ループを開始し、作成したコントロールを管理する必要があります。アプリケーションでは、さまざまなコントロールがさまざまなスレッドによって所有されているという事実を考慮する必要があります。
于 2011-03-22T17:29:08.723 に答える
1

正確な解決策はありませんが、次のリンクからある程度の方向性を得ることができます。

http://www.codehosting.net/blog/BlogEngine/post/Opening-WPF-Windows-on-a-new-thread.aspx

http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/

于 2011-03-22T19:13:05.090 に答える
-1

別のスレッドに制御を渡すことができるメソッドを呼び出すことができます:

http://msdn.microsoft.com/en-us/library/ms748331.aspx

それは .Freeze() と呼ばれます

于 2011-08-01T15:55:03.030 に答える