2016-09-23 34 views
5

私はWPFを使用して印刷したい巨大なデータを持っています。私はWPFがVisualクラスから派生したWPFコントロールを印刷するためにPrintDialog.PrintVisualメソッドを提供することを発見しました。大きなWPFユーザーコントロールの印刷

PrintVisualは1ページしか印刷しないので、ページに収まるようにコントロールを拡大する必要があります。残念ながら、このレポートは時にはページに収まるように縮尺を変えても読みにくいので、私にとってはうまくいかないでしょう。

WPFによって提供される印刷の別のオプションは、FlowDocumentで別のビューを作成することです。これはおそらくドキュメントを印刷する最良の方法ですが、印刷したいと思っていた各コントロールのために維持しなければならない余計なビューはもちろん、ドキュメントに入れたいものよりも多くの作業が必要でした。

私はこのlinkで別の解決策を得ましたが、それは私にとっては複雑すぎるようです。

これにはより良い解決策がありますか?助けていただきありがとうございます

+0

既に持っているコントロールを印刷したいのですか、またはもう一度印刷するコントロールを作成しますか? – marbel82

+0

@ marbel82すでに持っているコントロールを印刷します –

答えて

2

報告書がDataGridまたはスクロール可能なもので表示されているとしますか?

私は確かにFlowDocumentはあなたが良い言葉の専門家の不足のために見えるものを印刷したい場合は、ここをクリックすることをお勧めします。しかし、何かがすばやく汚れていれば、RenderTargetBitmap.Renderを使って一連の操作を行うことができます。基本的なプロセスは次のようになります。

  1. はあなたがDataGridまたは含むだScrollViewerに1ページ
  2. コールRenderTargetBitmap.Renderに印刷することを可視領域を有するようにRenderTargetBitmap
  3. スクロールにビューを作成します。 「大」コントロール
  4. 印刷結果のビットマップ
  5. 次の「ページ」を繰り返し

"large"コントロールでRenderTargetBitmap.Renderを呼び出しないでください。 ScrollViewerに大きなコントロールをラップします(まだない場合)。それは基本的にあなたのページネーターになります。

あなたが結果に満足するかどうかわかりませんが、これは私が考えることができる最も簡単な方法です。毎回手動でPrintScreenを押すように見えます。それがあなたの望むものなのかどうかは分かりませんが、もっと見た目にしたい場合は、FlowDocumentを使う必要があると思います。

0

印刷用にPrintDialogとDocumentPaginatorを使用します。

私は何をすることです:

  • 選択プリンタ(ショーの印刷ダイアログまたはシステムデフォルトを使用)
  • ページ(用紙のサイズでWPFコントロール)
  • 印刷
を作成

私のテスト機能は次のとおりです。

public static void PrintTest1(Viewbox viewboxInWindowForRender) 
{ 
    FrameworkElement[] testContArr = PrepareTestContents(); 

    //========================= 
    PrintManager man = new PrintManager(); 

    // Show print dialog (or select default printer) 
    if (!man.SelectPrinter()) 
     return; 

    man.SetPageMargins(new Thickness(PrintManager.Size1cm * 2)); 

    //========================= 
    List<FrameworkElement> pagesForPrint = new List<FrameworkElement>(); 

    for (int i = 0; i < testContArr.Length; i++) 
    { 
     // Put the page content into the control of the size of paper 
     FrameworkElement whitePage = man.CreatePageWithContentStretched(testContArr[i]); 
     // Temporary put the page into window (need for UpdateLayout) 
     viewboxInWindowForRender.Child = whitePage; 
     // Update and render whitePage. 
     // Measure and Arrange will be used properly. 
     viewboxInWindowForRender.UpdateLayout(); 

     pagesForPrint.Add(whitePage); 
    } 
    viewboxInWindowForRender.Child = null; 
    //========================= 
    // Now you can show print preview to user. 
    // pagesForPrint has all pages. 
    // ... 
    //========================= 

    MyDocumentPaginator paginator = man.CreatePaginator(); 
    paginator.AddPages(pagesForPrint); 

    // Start printing 
    man.Print(paginator, "Printing Test"); 
} 

// For testing 
public static FrameworkElement[] PrepareTestContents() 
{ 
    StackPanel sp1 = new StackPanel(); 
    sp1.Width = PrintManager.PageSizeA4.Width - PrintManager.Size1cm * 2; 
    sp1.Children.Add(PrepareTestBorder("Alice has a cat.")); 
    sp1.Children.Add(PrepareTestBorder("Page number one.")); 

    StackPanel sp2 = new StackPanel(); 
    sp2.Width = sp1.Width/2; 
    sp2.Children.Add(PrepareTestBorder("Farmer has a dog.")); 
    sp2.Children.Add(PrepareTestBorder("Page number two.")); 

    return new FrameworkElement[] {sp1, sp2 }; 
} 

// For testing 
public static FrameworkElement PrepareTestBorder(string text) 
{ 
    Border b = new Border(); 
    b.BorderBrush = Brushes.Black; 
    b.BorderThickness = new Thickness(1); 
    b.Margin = new Thickness(0, 0, 0, 5); 

    TextBlock t = new TextBlock(); 
    t.Text = text; 

    b.Child = t; 
    return b; 
} 

ウィンドウ内のどこかに一時的なレイアウトの更新とレンダリングのためのViewboxが必要です。

<Window ...> 
    <Grid> 
     <Viewbox x:Name="forRender" Visibility="Hidden" Width="100" Height="100"/> 
     ... 
    </Grid> 
</Window> 

そして、あなたがテストを実行することができますより:PrintTest1(forRender);


ここに私のPrintManagerクラスです:

public class PrintManager 
{ 
    public static readonly Size PageSizeA4 = new Size(21 * 96/2.54, 29.7 * 96/2.54); // (793.700787401575, 1122.51968503937) 
    public static readonly double Size1cm = 96/2.54; // 37.7952755905512 

    private PrintDialog _printDialog; 

    public PrintTicket PrintTicket { get; private set; } 
    public PrintCapabilities TicketCapabilities { get; private set; } 

    // Page size selected in print dialog (may not be exactly as paper size) 
    public Size PageSize { get; private set; } 
    public Thickness PageMargins { get; private set; } 

    public Rect PageContentRect { 
     get { 
      return new Rect(PageMargins.Left, PageMargins.Top, 
       PageSize.Width - PageMargins.Left - PageMargins.Right, 
       PageSize.Height - PageMargins.Top - PageMargins.Bottom); 
     } 
    } 

    public PrintManager() 
    { 
    } 

    /// <summary> 
    /// Show print dialog or try use default printer when useDefaultPrinter param set to true. 
    /// <para/> 
    /// Return false on error or when user pushed Cancel. 
    /// </summary> 
    public bool SelectPrinter(bool useDefaultPrinter = false) 
    { 
     if (_printDialog == null) 
      _printDialog = new PrintDialog(); 

     try 
     { 
      if (useDefaultPrinter) 
       _printDialog.PrintQueue = LocalPrintServer.GetDefaultPrintQueue(); 

      // pDialog.PrintQueue == null when default printer is not selected in system 
      if (_printDialog.PrintQueue == null || !useDefaultPrinter) 
      { 
       // Show print dialog 
       if (_printDialog.ShowDialog() != true) 
        return false; 
      } 

      if (_printDialog.PrintQueue == null) 
       throw new Exception("Printer error"); 

      // Get default printer settings 
      //_printDialog.PrintTicket = _printDialog.PrintQueue.DefaultPrintTicket; 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
      return false; 
     } 

     PrintTicket = _printDialog.PrintTicket; 
     TicketCapabilities = _printDialog.PrintQueue.GetPrintCapabilities(PrintTicket); 
     PageSize = new Size((double)TicketCapabilities.OrientedPageMediaWidth, 
      (double)TicketCapabilities.OrientedPageMediaHeight); 
     SetPageMargins(PageMargins); // Update margins if too small 

     return true; 
    } 

    /// <summary> 
    /// Start printing pages from paginator. 
    /// </summary> 
    public void Print(MyDocumentPaginator paginator, string printTaskDescription) 
    { 
     if (_printDialog == null) 
      return; 

     // Start printing document 
     _printDialog.PrintDocument(paginator, printTaskDescription); 
    } 

    /// <summary> 
    /// Set page margins and return true. 
    /// <para/> 
    /// If new page margins are too small (unprinted area) then set minimum and return false. 
    /// </summary> 
    public bool SetPageMargins(Thickness margins) 
    { 
     PageImageableArea pia = TicketCapabilities.PageImageableArea; 

     PageMargins = new Thickness(Math.Max(margins.Left, pia.OriginWidth), 
      Math.Max(margins.Top, pia.OriginHeight), 
      Math.Max(margins.Right, PageSize.Width - pia.OriginWidth - pia.ExtentWidth), 
      Math.Max(margins.Bottom, PageSize.Height - pia.OriginHeight - pia.ExtentHeight)); 

     return PageMargins == margins; 
    } 

    /// <summary> 
    /// Set pate margins with minimal 
    /// </summary> 
    public void SetMinimalPageMargins() 
    { 
     PageImageableArea pia = TicketCapabilities.PageImageableArea; 

     // Set minimal page margins to bypass the unprinted area. 
     PageMargins = new Thickness(pia.OriginWidth, pia.OriginHeight, 
      (double)TicketCapabilities.OrientedPageMediaWidth - - pia.OriginWidth - pia.ExtentWidth, 
      (double)TicketCapabilities.OrientedPageMediaHeight - pia.OriginHeight - pia.ExtentHeight); 
    } 

    /// <summary> 
    /// Create page control witch pageContent ready to print. 
    /// Content is stretched to the margins. 
    /// </summary> 
    public FrameworkElement CreatePageWithContentStretched(FrameworkElement pageContent) 
    { 
     // Place the content inside the page (without margins) 
     Viewbox pageInner = new Viewbox(); 
     pageInner.VerticalAlignment = VerticalAlignment.Top; // From the upper edge 
     pageInner.Child = pageContent; 

     // Printed control - the page with content 
     Border whitePage = new Border(); 
     whitePage.Width = PageSize.Width; 
     whitePage.Height = PageSize.Height; 
     whitePage.Padding = PageMargins; 
     whitePage.Child = pageInner; 

     return whitePage; 
    } 

    /// <summary> 
    /// Create page control witch pageContent ready to print. 
    /// <para/> 
    /// Content is aligned to the top-center and must have 
    /// a fixed size (max PageSize-PageMargins). 
    /// </summary> 
    public FrameworkElement CreatePageWithContentSpecSize(FrameworkElement contentSpecSize) 
    { 
     // Place the content inside the page 
     Decorator pageInner = new Decorator(); 
     pageInner.HorizontalAlignment = HorizontalAlignment.Center; 
     pageInner.VerticalAlignment = VerticalAlignment.Top; 
     pageInner.Child = contentSpecSize; 

     // Printed control - the page with content 
     Border whitePage = new Border(); 
     whitePage.Width = PageSize.Width; 
     whitePage.Height = PageSize.Height; 

     // We align to the top-center only, because padding will cut controls 
     whitePage.Padding = new Thickness(0, PageMargins.Top, 0, 0); 

     whitePage.Child = pageInner; 
     return whitePage; 
    } 

    /// <summary> 
    /// Create paginator for pages created by CreatePageWithContent(). 
    /// </summary> 
    public MyDocumentPaginator CreatePaginator() 
    { 
     return new MyDocumentPaginator(PageSize); 
    } 
} 

そして、ここでは私のMyDocumentPaginatorクラスです:

は、

あなたは既に持っているコントロールを印刷したいと言ってきました。
私のソリューションでこれを印刷することができます。

例:
UserCtrlParentBorderであるとします。 親コントロールから削除してから使用する必要があります。あなたがページを準備することができるよりも

ParentBorder.Child = null; 
// Or you can use my function 
RemoveFromParent(UserCtrl); 

FrameworkElement whitePage = man.CreatePageWithContentStretched(UserCtrl); 
viewboxInWindowForRender.Child = whitePage; 
viewboxInWindowForRender.UpdateLayout(); 

MyDocumentPaginator paginator = man.CreatePaginator(); 
paginator.AddPages(whitePage); 

man.Print(paginator, "Printing UserControl"); 

// After print you can restore UserCtrl 
RemoveFromParent(UserCtrl); 
ParentBorder.Child = UserCtrl; 

ここだがRemoveFromParent機能である:私は窓にUpdateLayoutとビューボックスを使用する理由の代わりに計量、

public static void RemoveFromParent(FrameworkElement child) 
{ 
    DependencyObject parent = child.Parent; 

    if (parent == null) 
     return; 
    if (parent is Panel) 
     ((Panel)parent).Children.Remove(child); 
    else if (parent is Decorator) 
     ((Decorator)parent).Child = null; 
    else if (parent is ContentControl) 
     ((ContentControl)parent).Content = null; 
    else if (parent is ContentPresenter) 
     ((ContentPresenter)parent).Content = null; 
    else 
     throw new Exception("RemoveFromParent: Unsupported type " + parent.GetType().ToString()); 
} 

と他の例で人々のように配置する?

私は試してみましたが、私はこれに多くの問題がありました。私は、私はalredy持っているコントロールを使用して、私は印刷のためのスタイルを変更し、私もexport to PDF。 私のために測定し、アレンジしないでください。適切なレイアウトの更新とレンダリングのために、コントロールをウィンドウにドッキングする必要があります。

関連する問題