2

I have a PDF Export in my Application (migradoc). To avoid freezing the GUI i want to run this Export as seperate Thread. The PDF has also Charts embedded in it. To make those Charts look like the ones i use in my application i create and render them in Code. (visifire) My Thread is already STA, but i get an Exception when running the WPF render Commands:

The calling thread cannot access this object because a different thread owns it

My Code:

         chart.Measure(new Size(311, 180));
            chart.Arrange(new Rect(0, 0, 311, 180));
            chart.UpdateLayout();
            ExportToPng(new Uri("C:\\" + i + "c.png"), chart);

  public void ExportToPng(Uri path, Chart surface)

    {
        if (path == null) return;


        // Save current canvas transform

        Transform transform = surface.LayoutTransform;


        // reset current transform (in case it is scaled or rotated)

        surface.LayoutTransform = null;


        // Create a render bitmap and push the surface to it

        var renderBitmap =
            new RenderTargetBitmap(
                (int) surface.Width,
                (int) surface.Height,
                96d,
                96d,
                PixelFormats.Pbgra32);


        renderBitmap.Render(surface);


        // Create a file stream for saving image

        using (var outStream = new FileStream(path.LocalPath, FileMode.Create))

        {
            // Use png encoder for our data

            var encoder = new PngBitmapEncoder();


            // push the rendered bitmap to it

            encoder.Frames.Add(BitmapFrame.Create(renderBitmap));


            // save the data to the stream

            encoder.Save(outStream);
        }


        // Restore previously saved layout

        surface.LayoutTransform = transform;
    }

I already tried to dispatch this Commands, but i still keep getting the same Error.

  DispatcherHelper.UIDispatcher.BeginInvoke((Action)(() =>
        {
                        chart.Measure(new Size(311, 180));
                        chart.Arrange(new Rect(0, 0, 311, 180));
                        chart.UpdateLayout();
                        ExportToPng(new Uri("C:\\" + i + "c.png"), chart);
                    }));
TheJoeIaut
  • 1,522
  • 2
  • 26
  • 59
  • 1
    AFAIK you can only render GUI on GUI thread, and on no other thread. – Tony The Lion Mar 13 '13 at 11:04
  • I know i already tried to Dispatch it, but i still get the same error ( see edit) – TheJoeIaut Mar 13 '13 at 11:08
  • Does your UI thread create the chart object? You can only update WPF objects from the same thread in which they were created on. So if you created your chart from another thread, then any updates to that chart object also needs to be on that specific other thread. – Rachel Mar 13 '13 at 14:51

1 Answers1

0

you need to pass copy of any object which is the part of GUI thread as the GUI thread own them and that's why they can't be access in other thread. like you chart object you need to create a copy of chart object and then pass it into the thread so the owner of the object is your new thread.

If you need to render these on the same GUI thread then only chance is to render these on the same thread and wait to operation to complete.

JSJ
  • 5,653
  • 3
  • 25
  • 32
  • @TheJoeIaut you cannot create it on another thread an pass it back, you should just create GUI elements on GUI thread. – Tony The Lion Mar 13 '13 at 11:13
  • Back to back is only work under GUI thread. but you can create one way shots from this way. – JSJ Mar 13 '13 at 11:17
  • The goal i try to achieve is rendering The Charts Save them to a file and then include them in the Report, without freezing my GUI. Is there a way to render the charts on a different gui thread. – TheJoeIaut Mar 13 '13 at 11:21
  • No you can't render any item which is type of visual on other thread, You need GUI Thread. A fuzy thing you can do. is run you app on main thread and run another app and render you chart then just copy it and use it as you like to use. – JSJ Mar 13 '13 at 11:34