Creating FlowDocument on BackgroundWorker thread

2019-07-29 19:03发布

I have the need to generate dynamically generate a FlowDocument from a large set of data. Because the process takes several minutes, I'd like to perform the operation on a background thread rather than have the UI hang.

However, I can't generate the FlowDocument on a non-UI thread otherwise attempts to insert rectangles and images cause run-time errors complaining that it's not STA thread.

There are a couple of threads on StackOverflow which seem to involve the same problem I'm having:

In the first link someone suggests the following:

"What I'd do: use a XamlWriter and serialize the FlowDocument into an XDocument. The serialization task involves the Dispatcher, but once it's done, you can run as many wacky parallel analyses of the data as you want and nothing in the UI will affect it. (Also once it's an XDocument you query it with XPath, which is a pretty good hammer, so long as your problems are actually nails.)"

Can someone elaborate on what does the author mean by this?

2条回答
Ridiculous、
2楼-- · 2019-07-29 19:30

For any future visitors I faced the same problem and solved all thanks to this article article

What ended up doing is creating the object on a background thread

            Thread loadingThread = new Thread(() =>
        {
            //Load the data
            var documant = LoadReport(ReportTypes.LoadOffer, model, pageWidth);

            MemoryStream stream = new MemoryStream();
            //Write the object in the memory stream
            XamlWriter.Save(documant, stream);
            //Move to the UI thread
            Dispatcher.BeginInvoke(
               DispatcherPriority.Normal,
               (Action<MemoryStream>)FinishedGenerating,
               stream);
        });

        // set the apartment state  
        loadingThread.SetApartmentState(ApartmentState.STA);

        // make the thread a background thread  
        loadingThread.IsBackground = true;

        // start the thread  
        loadingThread.Start();

And then wrote the result in the memory stream as xaml so we can read it back in the main thread

void FinishedGenerating(MemoryStream stream)
    {
        //Read the data from the memory steam
        stream.Seek(0, SeekOrigin.Begin);
        FlowDocument result = (FlowDocument)XamlReader.Load(stream);

        FlowDocumentScrollViewer = new FlowDocumentScrollViewer
        {
            Document = result
        };
    //your code...

Wish it could save others some time :)

查看更多
你好瞎i
3楼-- · 2019-07-29 19:31

While not realy an answer to elaborating on what the author of your quote means, maybe this can be a solution for your problem: If you hook yourself into the Application.Idle Event, you can build your FlowDocument one by one there. This event still is in the UI Thread so you won't get problems like in a background worker. Altho you have to be carefull not to do too much work at once, otherwise you will block your application. If it is possible to seperate your generation process into small chunks you can process those chunks one by one in this event.

查看更多
登录 后发表回答