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>`
Use dispatcher class in this case. the Dispatcher class has invoke and beginInvoke methods. which allow to send the request to the current thread using dispatchment process. what you need to do is create a call like below using delegate
the begin invoke call process your call asynchronously.
I tied this some time ago - and I think found the problem to be that the printpreview dialog needs to be on the mainthread.
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. :)
The easiest way would be.
There is also another "trick"...
Often I run into the same problems. For example I try bind a
FrameworkElement
to anContentPresenter
. My solution for this, I use aItemsControl
in place of theContentPresenter
and bind my singleFrameworkElement
over anObservableCollection<FrameworkElement>
with only the one item. After this, no problemsI've wrote this simple snippet, I do not have any experiences with it, but I tested it for few things, and it seems to be working fine.
And here is the usage: