3

xxx.Dispatcher.Invoke() メソッドを使用してバックグラウンド スレッドを取得し、GUI 要素を操作することを認識しています。私は、オブジェクトのツリーを構築するために長時間実行されるバックグラウンド タスクが必要であり、表示のために GUI に渡す必要がある、似たようなものにぶつかっていると思いますが、わずかに異なります。

これを実行しようとすると、「別のスレッドがこのオブジェクトを所有しているため、呼び出し元のスレッドがこのオブジェクトにアクセスできないため」、InvalidOperationException が発生します。不思議なことに、これは単純型では起こりません。

例外をスローする単純なケースを示すコード例を次に示します。これを回避する方法はありますか?バックグラウンド スレッドがファクトリで構築されたオブジェクトを所有しており、フォアグラウンド GUI スレッドが所有権を取得できないことが問題であると確信していますが、より単純なシステム タイプでは機能します。

private void button1_Click(object sender, RoutedEventArgs e) 
{  
   // These two objects are created on the GUI thread
   String abc = "ABC";  
   Paragraph p = new Paragraph();

   BackgroundWorker bgw = new BackgroundWorker();

   // These two variables are place holders to give scoping access
   String def = null;
   Run r = null;

   // Initialize the place holders with objects created on the background thread
   bgw.DoWork += (s1,e2) =>
     {
       def = "DEF";
       r = new Run("blah");
     };

   // When the background is done, use the factory objects with the GUI
   bgw.RunWorkerCompleted += (s2,e2) =>
     {
        abc = abc + def;         // WORKS: I suspect there's a new object
        Console.WriteLine(abc);  // Console emits 'ABCDEF'

        List<String> l = new List<String>();  // How about stuffing it in a container?
        l.Add(def);                           // WORKS: l has a reference to def

        // BUT THIS FAILS.
        p.Inlines.Add(r);  // Calling thread cannot access this object
     };

   bgw.RunWorkerAsync();
}

問題の範囲は、バックグラウンドでオンザフライで構築している大きなドキュメントがあり、完了を待たずにこれまでに生成されたものを GUI に表示したいということです。

バックグラウンド ワーカーがオブジェクト ファクトリとして機能し、コンテンツをメイン スレッドに渡すにはどうすればよいでしょうか。

ありがとう!

4

2 に答える 2

5

Runバックグラウンド スレッドでを作成しようとしていますが、RunFrameworkContentElementから継承DispatcherObjectされているため、それを作成したスレッドにバインドされています。

于 2010-08-27T21:00:23.767 に答える
1

As Franci said, Run is a DispatcherObject, so it is only updatable on the thread that created it. The code should run if it calls Dispatch.Invoke or Dispatcher.BeginInvoke like this:

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        var button = sender as Button;

        string abc = "ABC";
        var p = new Paragraph();

        var bgw = new BackgroundWorker();

        String def = null;
        Run r = null;

        bgw.DoWork += (s1, e2) =>
          {
              def = "DEF";
              button.Dispatcher.BeginInvoke(new Action(delegate{r = new Run("blah");}));
          };

        bgw.RunWorkerCompleted += (s2, e2) =>
          {
              abc = abc + def;
              Console.WriteLine(abc); 
              var l = new List<String> { def };
              p.Inlines.Add(r);  // Calling thread can now access this object because 
                                 // it was created on the same thread that is updating it.
          };

        bgw.RunWorkerAsync();
    }
于 2010-08-28T04:29:03.640 に答える