2012-02-25 31 views
8

Câu hỏiIn ấn BlockUIContainer để XpsDocument/FixedDocument

  1. Làm thế nào để bạn in một FlowDocument có BlockUIContainer?
  2. Làm cách nào để có thể đo lường/Cập nhật/Sắp xếp trên FlowDocument?

nền

Tôi đã một tạo FlowDocument với đoạn văn bản với một vài yếu tố Rectangle điền DrawingBrushes từ một cuốn từ điển tài nguyên và BlockUIContainer với các điều khiển tùy chỉnh. tài liệu

Các render một cách chính xác khi quan sát trong bất kỳ FlowDocument * khiển TUY NHIÊN khi tài liệu được chuyển đổi sang một FixedDocument/XpsDocument, không ai trong số các Rectangle hoặc BlockUIContainer yếu tố render.

Tôi gần như chắc chắn là do điều khiển có không được đo/sắp xếp, tuy nhiên không thể tìm ra cách ép buộc điều đó xảy ra trước khi nó được chuyển đổi thành XpsDocument.

  • tôi đã bước đi trên LogicalTree đệ quy và thực hiện những điều sau đây,

    UIElement element = (UIElement)d; 
    element.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); 
    element.Arrange(new Rect(element.DesiredSize)); 
    element.UpdateLayout(); 
    

    nơi d là một DependencyObject. Tôi có thể thấy rằng điều này đặt các thuộc tính ActualWidthActualHeight khi được chỉ định trong trình gỡ lỗi.

  • Tôi đã cố gắng buộc Dispatcher để hiển thị như được đề xuất bởi Will ♦.

Mã dùng để in các XpsDocument

public class XpsDocumentConverter 
{ 

    public static XpsDocumentReference CreateXpsDocument(FlowDocument document) 
    { 
     // Need to clone the document so that the paginator can work 
     FlowDocument clonedDocument = DocumentHelper.Clone<FlowDocument>(document); 

     Uri uri = new Uri(String.Format("pack://temp_{0}.xps/", Guid.NewGuid().ToString("N"))); 
     MemoryStream ms = new MemoryStream(); 

     Package pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); 
     PackageStore.AddPackage(uri, pkg); 
     XpsDocument xpsDocument = new XpsDocument(pkg, CompressionOption.Normal, uri.AbsoluteUri); 

     XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDocument), false); 
     DocumentPaginator paginator = new FixedDocumentPaginator(clonedDocument, A4PageDefinition.Default); 
     rsm.SaveAsXaml(paginator); 

     return new XpsDocumentReference(ms, xpsDocument); 
    } 

} 

Như bạn có thể thấy tôi cũng đang sử dụng một tùy chỉnh DocumentPaginator tên 'FixedDocumentPaginator'; tuy nhiên tôi sẽ không đăng mã đó vì tôi nghi ngờ vấn đề này là do thời điểm bắt đầu phân trang tài liệu trong GetPage(int pageNumber) mọi thứ đã được chuyển đổi thành Visual và đã quá muộn để bố cục.


Sửa

Hmm. Khi tôi đánh máy này, một ý nghĩ chỉ xảy ra với tôi rằng tài liệu nhân bản được sao chép có thể chưa hoàn thành được Measure/Arrange/UpdateLayout.

Câu hỏi: Làm cách nào để có thể đo lường/Cập nhật/sắp xếp trên FlowDocument?

Có thể một hack mà tôi có thể làm việc sẽ hiển thị tài liệu nhân bản trong một trong các FlowDocumentViewers (có lẽ ngoài màn hình).

Một giải pháp khả thi mà tôi chỉ học được về và đã không cố gắng sẽ được gọi: ContextLayoutManager.From(Dispatcher.CurrentDispatcher).UpdateLayout();

ContextLayoutManager đi cây hợp lý cho bạn và cập nhật trình bày.

Mã được sử dụng để nhân bản tài liệu

public static FlowDocument Clone(FlowDocument originalDocument) 
{ 
    FlowDocument clonedDocument = new FlowDocument(); 
    TextRange sourceDocument = new TextRange(originalDocument.ContentStart, originalDocument.ContentEnd); 
    TextRange clonedDocumentRange = new TextRange(clonedDocument.ContentStart, clonedDocument.ContentEnd); 
    try 
    { 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      sourceDocument.Save(ms, DataFormats.XamlPackage); 
      clonedDocumentRange.Load(ms, DataFormats.XamlPackage); 
     } 

     clonedDocument.ColumnWidth = originalDocument.ColumnWidth; 
     clonedDocument.PageWidth = originalDocument.PageWidth; 
     clonedDocument.PageHeight = originalDocument.PageHeight; 
     clonedDocument.PagePadding = originalDocument.PagePadding; 
     clonedDocument.LineStackingStrategy = clonedDocument.LineStackingStrategy; 

     return clonedDocument; 
    } 
    catch (Exception) 
    {    
    } 

    return null; 
} 

Trả lời

9

gửi bài tham khảo này là tương lai cho những người khác đang gặp vấn đề tương tự vẽ với FlowDocument/FixedDocument/XpsDocument.

Một số điều cần lưu ý:

  • BlockUIContainers không nhân bản khi bạn sử dụng các phương pháp trên. Điều này là không rõ ràng ngay lập tức cho đến khi tôi in cây logic ra khỏi cửa sổ gỡ lỗi bằng cách sử dụng một số phương pháp trợ giúp (các phương pháp này được đăng bên dưới - chúng cực kỳ hữu ích).
  • Bạn cần hiển thị tài liệu trong trình xem và hiển thị nhanh trên tài liệu. Dưới đây là phương pháp trợ giúp mà tôi đã viết để làm điều này cho tôi.

ForceRenderFlowDocument

private static string ForceRenderFlowDocumentXaml = 
@"<Window xmlns=""http://schemas.microsoft.com/netfx/2007/xaml/presentation"" 
      xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> 
     <FlowDocumentScrollViewer Name=""viewer""/> 
    </Window>"; 

public static void ForceRenderFlowDocument(FlowDocument document) 
{ 
    using (var reader = new XmlTextReader(new StringReader(ForceRenderFlowDocumentXaml))) 
    { 
     Window window = XamlReader.Load(reader) as Window; 
     FlowDocumentScrollViewer viewer = LogicalTreeHelper.FindLogicalNode(window, "viewer") as FlowDocumentScrollViewer; 
     viewer.Document = document; 
     // Show the window way off-screen 
     window.WindowStartupLocation = WindowStartupLocation.Manual; 
     window.Top = Int32.MaxValue; 
     window.Left = Int32.MaxValue; 
     window.ShowInTaskbar = false; 
     window.Show(); 
     // Ensure that dispatcher has done the layout and render passes 
     Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Loaded, new Action(() => {})); 
     viewer.Document = null; 
     window.Close(); 
    } 
} 

Edit: Tôi chỉ cần thêm window.ShowInTaskbar = false để phương pháp này như thể bạn đang nhanh chóng bạn có thể thấy cửa sổ xuất hiện trong thanh tác vụ.

Người dùng sẽ không bao giờ "nhìn thấy" cửa sổ khi nó được đặt ở vị trí ngoài màn hình tại Int32.MaxValue - một mẹo đã trở lại phổ biến trong ngày với tác giả đa phương tiện sớm (ví dụ: Macromedia/Adobe Director).

Đối với những người đang tìm kiếm và tìm câu hỏi này, tôi có thể cho bạn biết rằng không có cách nào khác để buộc tài liệu hiển thị.

thị giác và logic Tree Helpers

public static string WriteVisualTree(DependencyObject parent) 
{ 
    if (parent == null) 
     return "No Visual Tree Available. DependencyObject is null."; 

    using (var stringWriter = new StringWriter()) 
    using (var indentedTextWriter = new IndentedTextWriter(stringWriter, " ")) 
    {    
     WriteVisualTreeRecursive(indentedTextWriter, parent, 0); 
     return stringWriter.ToString(); 
    } 
} 

private static void WriteVisualTreeRecursive(IndentedTextWriter writer, DependencyObject parent, int indentLevel) 
{ 
    if (parent == null) 
     return; 

    int childCount = VisualTreeHelper.GetChildrenCount(parent); 
    string typeName = parent.GetType().Name; 
    string objName = parent.GetValue(FrameworkElement.NameProperty) as string; 

    writer.Indent = indentLevel; 
    writer.WriteLine(String.Format("[{0:000}] {1} ({2}) {3}", indentLevel, 
                   String.IsNullOrEmpty(objName) ? typeName : objName, 
                   typeName, childCount) 
        ); 

    for (int childIndex = 0; childIndex < childCount; ++childIndex) 
     WriteVisualTreeRecursive(writer, VisualTreeHelper.GetChild(parent, childIndex), indentLevel + 1); 
} 

public static string WriteLogicalTree(DependencyObject parent) 
{ 
    if (parent == null) 
     return "No Logical Tree Available. DependencyObject is null."; 

    using (var stringWriter = new StringWriter()) 
    using (var indentedTextWriter = new IndentedTextWriter(stringWriter, " ")) 
    { 
     WriteLogicalTreeRecursive(indentedTextWriter, parent, 0); 
     return stringWriter.ToString(); 
    } 
} 

private static void WriteLogicalTreeRecursive(IndentedTextWriter writer, DependencyObject parent, int indentLevel) 
{ 
    if (parent == null) 
     return; 

    var children = LogicalTreeHelper.GetChildren(parent).OfType<DependencyObject>(); 
    int childCount = children.Count(); 

    string typeName = parent.GetType().Name; 
    string objName = parent.GetValue(FrameworkElement.NameProperty) as string; 

    double actualWidth = (parent.GetValue(FrameworkElement.ActualWidthProperty) as double?).GetValueOrDefault(); 
    double actualHeight = (parent.GetValue(FrameworkElement.ActualHeightProperty) as double?).GetValueOrDefault(); 

    writer.Indent = indentLevel; 
    writer.WriteLine(String.Format("[{0:000}] {1} ({2}) {3}", indentLevel, 
                   String.IsNullOrEmpty(objName) ? typeName : objName, 
                   typeName, 
                   childCount) 
        ); 

    foreach (object child in LogicalTreeHelper.GetChildren(parent)) 
    { 
     if (child is DependencyObject) 
      WriteLogicalTreeRecursive(writer, (DependencyObject)child, indentLevel + 1); 
    } 

} 

Cách sử dụng

#if DEBUG 
    Debug.WriteLine("--- Start -------"); 
    Debug.WriteLine(VisualAndLogicalTreeHelper.WriteLogicalTree(document)); 
    Debug.WriteLine("--- End -------"); 
#endif 
+0

Cảm ơn rất nhiều vì điều này, chỉ thông qua địa ngục này, bạn đã giúp rất nhiều =) – JMK

+0

Điều gì đang xảy ra trong 'XpsDocumentReference'? Tôi tiếp tục cố gắng in từ một 'PrintDialog' bằng cách kéo' DocumentPaginator' từ tài liệu XPS qua 'GetFixedDocumentSequence(). DocumentPaginator'. Tôi nhận được một ngoại lệ phân tích Xaml kết quả từ một ngoại lệ InvalidURI. Rõ ràng URI tài liệu cố định bị xáo trộn bằng cách nào đó. –

+1

@AustinMullins xem xét câu trả lời của tôi tại http://stackoverflow.com/questions/9647401/documentviewer-to-richtextbox-binding-error Nó cho thấy việc triển khai 'XpsDocumentReference'. Đã một vài năm kể từ khi tôi nhìn vào XPS. Rất vui được xem lại và trợ giúp.Nó sẽ là một cơ hội tốt để tạo ra một thư viện nguồn mở. – Dennis

4

tôi tìm thấy giải pháp này here, và nó đã giúp tôi có được việc in ấn của FlowDocment mà không cần phải làm cho nó đi màn hình ... Vì vậy, tôi hy vọng nó có thể giúp bạn !!

String copyString = XamlWriter.Save(flowDocViewer.Document); 
FlowDocument copy = XamlReader.Parse(copyString) as FlowDocument; 
+0

Tôi chạy vào vòng lặp đệ quy vô hạn khi nhúng 'ItemsControl' vào' BlockUIElement' trong 'XamlWriter.Save'. Tôi nghĩ rằng vấn đề là một số tài sản của các ItemsControl tham chiếu container của nó, và 'MarkupWriter.RecordNamespaces' chức năng đệ quy điều hướng mỗi tài sản của mục để tiết kiệm. –