Ros*_*oss 5 printing wpf multithreading printdialog documentviewer
在我的WPF应用程序中,我特别Window包含其中一个控件DocumentViewer.
打开并加载此窗口时,它会动态构建FixedDocument带有进度指示器的窗口,然后将其显示在DocumentViewer.它工作,并为了改善用户体验,我在自己的线程中运行此窗口,以便在构建文档时主应用程序窗口仍然响应.
基于此网页上的提示,我在一个新的线程中打开我的窗口,如下所示:
public void ShowDocumentViewerWindow(params object[] data) {
var thread = new Thread(() => {
var window = new MyDocumentViewerWindow(new MyObject(data));
window.Closed += (s, a) => window.Dispatcher.InvokeShutdown();
window.Show();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,我对这个设置很满意,但我刚遇到了一个问题.
MyDocumentViewerWindow 包含一个打印按钮,它引用内置的Print命令,以DocumentViewer为目标:
<Button Command="Print" CommandTarget="{Binding ElementName=MyDocumentViewer}">Print</Button>
Run Code Online (Sandbox Code Playgroud)
在我把窗口放在自己的线程之前,这很好用.但现在,当我点击它时,应用程序崩溃了.Visual Studio 2010将上面代码中的以下行突出显示为崩溃位置,并显示消息' 调用线程无法访问此对象,因为另一个线程拥有它.":
System.Windows.Threading.Dispatcher.Run();
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪如下所示:
at System.Windows.Threading.Dispatcher.VerifyAccess()
at MS.Internal.Printing.Win32PrintDialog.ShowDialog()
at System.Windows.Controls.PrintDialog.ShowDialog()
at System.Printing.PrintQueue.GatherDataFromPrintDialog(PrintDialog printDialog, XpsDocumentWriter&amp; writer, PrintTicket&amp; partialTrustPrintTicket, PrintQueue&amp; partialTrustPrintQueue, Double&amp; width, Double&amp; height, String jobDescription)
at System.Printing.PrintQueue.CreateXpsDocumentWriter(String jobDescription, PrintDocumentImageableArea&amp; documentImageableArea)
at System.Windows.Controls.Primitives.DocumentViewerBase.OnPrintCommand()
at System.Windows.Controls.Primitives.DocumentViewerBase.ExecutedRoutedEventHandler(Object target, ExecutedRoutedEventArgs args)
...
Run Code Online (Sandbox Code Playgroud)
我的预感是打印对话框在主UI线程中打开,并尝试访问由我自己的线程创建和拥有的文档,因此崩溃.
我有什么想法可以解决这个问题?我想把窗口保持在自己的线程中.
经过一些谷歌搜索后,我偶然发现了以下主题,这似乎是我遇到的确切问题.
在那个线程中,这个人最终使用了一个自定义的PrintDialog类(其源代码在这里找到),这与内置的PrintDialog非常相似,但是通过一些调整来修复这些跨线程的bug(它也是覆盖XPS文档编写器,它显然将自己与应用程序的主UI线程进一步联系起来)
我复制并粘贴了自定义PrintDialog的代码(并将类重命名为ThreadSafePrintDialog),删除了我的Print按钮的CommandTarget,而是使用我自己的Print方法:
private void Print_Executed(object sender, ExecutedRoutedEventArgs args) {
var printDialog = new ThreadSafePrintDialog();
if (!printDialog.ShowDialog(this)) return;
printDialog.PrintDocument(DocumentViewer.Document.DocumentPaginator, "My Document");
}
Run Code Online (Sandbox Code Playgroud)
完美的工作.