2011-09-07 24 views
5

WPF uygulamasında, diğer denetimler arasında, bir DocumentViewer bulunan belirli bir Window var.Farklı bir UI iş parçacığı içinde bir DocumentViewer içeriğini yazdırma

Bu pencere açıldığında ve yüklendiğinde, bir ilerleme göstergesiyle FixedDocument dinamik olarak oluşturur ve ardından DocumentViewer içinde görüntüler. Çalışır ve kullanıcı deneyimini geliştirmek için, bu pencereyi kendi iş parçacığıyla çalıştırıyorum, böylece ana uygulama penceresi belge oluşturulurken hala yanıt veriyor.

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(); 
} 

Ben şimdiye kadar bu kurulum ile mutlu olmuştur, ama sadece bir sorun ile karşılaştım: this web page bahşişlere dayanarak

, böyle yeni bir iş parçacığı benim pencere açmak. Ben kendi iş parçacığı pencere vardı önce

<Button Command="Print" CommandTarget="{Binding ElementName=MyDocumentViewer}">Print</Button> 

, bu iyi çalıştı:

MyDocumentViewerWindow

Baskı yerleşik komutu, DocumentViewer hedefleyen başvuran bir yazdır düğmesi içerir. Ancak şimdi, tıkladığımda uygulama çöküyor. Visual Studio 2010, yukarıdaki koddan, ' ' iletisiyle, yukarıdaki koddan kilitlenme konumu olarak şu satırı vurgular: Çağıran iş parçacığı, farklı bir iş parçacığının sahip olduğu için bu nesneye erişemez. ':

System.Windows.Threading.Dispatcher.Run(); 

yığın izleme böyle başlıyor:

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;amp; writer, PrintTicket&amp;amp; partialTrustPrintTicket, PrintQueue&amp;amp; partialTrustPrintQueue, Double&amp;amp; width, Double&amp;amp; height, String jobDescription) 
at System.Printing.PrintQueue.CreateXpsDocumentWriter(String jobDescription, PrintDocumentImageableArea&amp;amp; documentImageableArea) 
at System.Windows.Controls.Primitives.DocumentViewerBase.OnPrintCommand() 
at System.Windows.Controls.Primitives.DocumentViewerBase.ExecutedRoutedEventHandler(Object target, ExecutedRoutedEventArgs args) 
... 

Benim önsezi yazdırma iletişim ana UI iş parçacığı açılıyor ve oluşturulan belgeyi erişmeye çalışıyor ve olunan olmasıdır kendi iş parçacığım, dolayısıyla kaza.

Bunu nasıl çözebilirim? Pencereyi kendi ipliğinde tutmak istiyorum.

cevap

6

Bazı daha Googling'lerden sonra, aşağıdaki konuya rastladım. Bu, sahip olduğum tam sorun gibi görünüyor.bu iş parçacığı olarak

PrintDialog and a secondary UI thread severe problem

, adam sonunda yerleşik olarak PrintDialog hemen aynı olduğu bir özel PrintDialog sınıfını (kaynak kodu olan here bulunursa), kullanır, ancak birkaç tweaks ile düzeltmek için Bu çapraz işlenen hatalar (ve aynı zamanda uygulamanın ana UI iş parçacığı içine daha da kendini bağlayan XPS Belge Yazıcısı'nı geçersiz kılar)

Bu özel PrintDialog için kodu kopyalayıp yapıştırdım (ve sınıfı ThreadSafePrintDialog olarak yeniden adlandırdım) , Yazdır düğmesinin CommandTarget'ını kaldırdım ve bunun yerine kendi Yazdırma yöntemimi kullan:

Kusursuz çalışır.

1

Önseziniz doğru. Başka bir iş parçacığı tarafından oluşturulduğunda, bu nesneyi UI iş parçacığına erişemezsiniz.

1) belki bir arka plan iş parçacığı ihtiyaç ve daha sonra aslında UI iş parçacığı üzerinde nesne oluşturmak bilgi toplamak, UI iş parçacığı üzerinde bu belgeyi oluşturabilir:

Ben birkaç seçenek olduğuna inanıyoruz. Belgenizin oluşturulmasının gerektirdiği şeye bağlıdır.

public void CreateDocument(T inputDataForDocumentCreation) { 
var uiDispatcher = Dispatcher.CurrentDispatcher; 
ThreadPool.QueueUserWorkItem(_ => { 
     // Load and create document components with yourDataForDocumentCreation 

     dispatcher.BeginInvoke(DispatcherPriority.Normal,() => { 
     //Actually create the document (this will happen on the UI thread, so it may be accessed from the UI thread) 
     }); 
    }); 
} 

2) Bu komutu, bu belgeyi oluşturan konuya gönderebilirdiniz? Bu iş parçacığı üzerinde tutun ve thread.Invoke(printMethod)

3) Freezable Objects'a bakabilirsiniz. Bu sayfanın alt kısmına bakın, "Kendi Dondurulabilir Sınıfınızı Oluşturma" başlığına gidin. Bu, belgenizin güvenliğini, onu oluşturandan farklı bir iş parçacığından erişmesini sağlar.

+0

Bunun için teşekkürler. Belge oluşturma, bir FixedDocument örneğini oluşturmayı, FixedPage nesneleri eklemeyi, bunları denetimleriyle doldurmayı vb. Içerir. FixedDocument bir DispatcherObject olduğundan, bir arka plan iş parçacığı içinde oluşturamadım ve sonra da bunu oluşturulduğu gibi DocumentViewer için kaynak olarak ayarlayamadım. çapraz iş parçacığı ihlali. Belgeimi, Document Viewer'ımla aynı konuya, yani bir UI iş parçacığıyla oluşturmam gerektiğini buldum :-(Ama sorunumun bir geçici çözümünü buldum - şimdi göndereceğim. – Ross

İlgili konular