印刷用に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クラスです:
は、
あなたは既に持っているコントロールを印刷したいと言ってきました。
私のソリューションでこれを印刷することができます。
例:
UserCtrl
がParentBorder
であるとします。 親コントロールから削除してから使用する必要があります。あなたがページを準備することができるよりも
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。 私のために測定し、アレンジしないでください。適切なレイアウトの更新とレンダリングのために、コントロールをウィンドウにドッキングする必要があります。
既に持っているコントロールを印刷したいのですか、またはもう一度印刷するコントロールを作成しますか? – marbel82
@ marbel82すでに持っているコントロールを印刷します –