Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access separate thread generated WPF UI elements from the Dispatcher thread?

I need to generate a print preview (a long one) using wpf UI elements like FixedDocument, FlowDocument, PageContent, BlockUIContainer and all those. To keep my UI responsive i'm doing this part on a separate Thread class thread (BackgroundWorker won't work since i need an STA thread). Everything is OK upto this point.
But after displaying the print preview now i need to print, and clicking Print icon on the generated preview throws the infamous "The calling thread cannot access this object because a different thread owns it." exception. So, is there any way around?

EDIT (CODE):

Dispatcher.CurrentDispatcher.Invoke(new Action(() =>  
    {  
        Thread thread = new Thread(() =>  
            {  
                FixedDocument document = renderFlowDocumentTemplate(report);  
                PrintPreview preview = new PrintPreview();  
                preview.WindowState = WindowState.Normal;  
                preview.documentViewer.Document = document;  
                preview.ShowDialog();  
            });  
        thread.SetApartmentState(ApartmentState.STA);  
        thread.Start();  
    }));`

Ok here, the RenderFlowDocumentTemplate() generates the print preview (which contains the UI elements) and fills the them with Report data. PrintPreview is a custom window that contains a DocumentViewer element that actually holds and displays the preview, and contains the Print icon, upon clicking which i'm supposd to get the PrintDialog window.

EDIT (XAML):

<cw:CustomWindow x:Class="MyApp.Reports.PrintPreview"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cw="clr-namespace:MyApp.UI.CustomWindows;assembly=MyApp.UI.CustomWindows">    
    <DocumentViewer Margin="0,30,0,0" Name="documentViewer"></DocumentViewer>
</cw:CustomWindow>`
like image 921
atiyar Avatar asked Jul 06 '12 08:07

atiyar


3 Answers

The easiest way would be.

Action a = () =>
{
    //Code from another thread.
};
Dispatcher.BeginInvoke(a);
like image 131
Silvermind Avatar answered Oct 17 '22 13:10

Silvermind


I tied this some time ago - and I think found the problem to be that the printpreview dialog needs to be on the mainthread.

like image 1
Rune Andersen Avatar answered Oct 17 '22 13:10

Rune Andersen


Found another guy with exactly the same problem - Printing the content of a DocumentViewer in a different UI thread. Just followed the same path. The code here was a real savior.
Now I'm NOT trying to access the secondary thread generated UI element from the Dispatcher thread, instead now the rest of the printing procedure is executed on the secondary thread. No cross-thread "VerifyAccess" of UI elements, and It's working smoothly. :)

like image 1
atiyar Avatar answered Oct 17 '22 14:10

atiyar