Creating and submitting complex content to a GUI stream in WPF / C #

I know and use the xxx.Dispatcher.Invoke () method to get a background thread for managing GUI elements. I think I come across something similar, but a little different, where I need a long background task to create a tree of objects and when we pass it to the GUI for display.

Attempting to do this throws an InvalidOperationException, "because of the calling thread, it is not possible to access this object because it has a different thread." Curiously, this does not happen with a simple type.

Here is an example code that demonstrates a trivial case that throws an exception. Any idea how to get around this? I am sure that the problem is that the background thread owns the created factory object and that the front-end GUI thread cannot take responsibility, although it works for simpler types of systems.

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 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();
}

The big problem is that I have a large document that I create on the fly in the background, and I would like the GUI to display what has been created so far without waiting for completion.

How can a background worker act as a factory object and transfer content to the main thread?

Thank!

+3
2

Run , Run FrameworkContentElement, DispatcherObject , .

+5

, Run - DispatcherObject, , . , Dispatch.Invoke Dispatcher.BeginInvoke :

    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();
    }
+1

Source: https://habr.com/ru/post/1761992/


All Articles