Nella mia app WPF, ho un particolare Window
che contiene, tra gli altri controlli, un DocumentViewer
.Stampa del contenuto di un DocumentViewer in un thread dell'interfaccia utente diverso
Quando questa finestra viene aperta e caricata, crea dinamicamente un FixedDocument
con un indicatore di avanzamento, quindi lo visualizza nello DocumentViewer
. Funziona e, per migliorare l'esperienza dell'utente, eseguo questa finestra nella sua stessa thread, in modo che la finestra principale dell'applicazione sia ancora reattiva mentre il documento è in fase di costruzione.
Sulla base delle punte a this web page, apro la mia finestra in un nuovo thread come questo:
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();
}
Sono stato felice con questa configurazione fino ad ora, ma ho appena incontrato un problema.
MyDocumentViewerWindow
contiene un pulsante di stampa, che fa riferimento al comando built-in di stampa, destinato al DocumentViewer:
<Button Command="Print" CommandTarget="{Binding ElementName=MyDocumentViewer}">Print</Button>
Prima ho avuto la finestra nel proprio thread, questo ha funzionato bene. Ma ora, quando faccio clic, l'applicazione si arresta in modo anomalo. Visual Studio 2010 evidenzia la seguente riga dal codice precedente come posizione di arresto anomalo, con il messaggio 'Il thread chiamante non può accedere a questo oggetto perché lo possiede un thread diverso. ':
System.Windows.Threading.Dispatcher.Run();
L'analisi dello stack inizia così:
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)
...
mia impressione è che la finestra di dialogo di stampa si sta aprendo nel thread principale dell'interfaccia utente, e cercando di accedere al documento che viene creato e di proprietà dalla mia stessa discussione, da qui l'incidente.
Qualche idea su come posso risolvere questo problema? Mi piacerebbe mantenere la finestra con il suo thread.
Grazie per quello. La creazione del mio documento implica l'istanziazione di un oggetto FixedDocument, l'aggiunta di oggetti FixedPage, il riempimento di controlli, ecc. Poiché il componente FixedDocument è DispatcherObject, non è stato possibile crearlo in un thread in background e quindi impostarlo come origine per DocumentViewer, così come creato una violazione cross-thread. Ho scoperto che devo creare il mio documento nello stesso thread del mio DocumentViewer - cioè su un thread dell'interfaccia utente :-(Ma ho appena trovato una soluzione al mio problema - lo posterò ora. – Ross