private void Button_Click(object sender, RoutedEventArgs e) { PrintDialog dialog = new PrintDialog(); if (dialog.ShowDialog() == true) { dialog.PrintVisual(控件名, "Print Test"); } }
上述方法确实能打印了,但是发现不能居中打印,不能打印多页。
以下是网上找到的方法:(https://www.cnblogs.com/naliang/p/wpfprint.html)
public void print(FrameworkElement ViewContainer) { FrameworkElement objectToPrint = ViewContainer as FrameworkElement; PrintDialog printDialog = new PrintDialog(); printDialog.PrintTicket.PageOrientation = PageOrientation.Landscape; if ((bool)printDialog.ShowDialog().GetValueOrDefault()) { Mouse.OverrideCursor = Cursors.Wait; PrintCapabilities capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket); double dpiScale = 300.0 / 96.0; FixedDocument document = new FixedDocument(); try { objectToPrint.Width = capabilities.PageImageableArea.ExtentWidth; objectToPrint.UpdateLayout(); objectToPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); Size size = new Size(capabilities.PageImageableArea.ExtentWidth, objectToPrint.DesiredSize.Height); objectToPrint.Measure(size); size = new Size(capabilities.PageImageableArea.ExtentWidth, objectToPrint.DesiredSize.Height); objectToPrint.Measure(size); objectToPrint.Arrange(new Rect(size)); // Convert the UI control into a bitmap at 300 dpi double dpiX = 300; double dpiY = 300; RenderTargetBitmap bmp = new RenderTargetBitmap(Convert.ToInt32( capabilities.PageImageableArea.ExtentWidth * dpiScale), Convert.ToInt32(objectToPrint.ActualHeight * dpiScale), dpiX, dpiY, PixelFormats.Pbgra32); bmp.Render(objectToPrint); // Convert the RenderTargetBitmap into a bitmap we can more readily use PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(bmp)); System.Drawing.Bitmap bmp2; using (MemoryStream memoryStream = new MemoryStream()) { png.Save(memoryStream); bmp2 = new System.Drawing.Bitmap(memoryStream); } document.DocumentPaginator.PageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight); // break the bitmap down into pages int pageBreak = 0; int previousPageBreak = 0; int pageHeight = Convert.ToInt32(capabilities.PageImageableArea.ExtentHeight * dpiScale); while (pageBreak < bmp2.Height - pageHeight) { pageBreak += pageHeight; // Where we thing the end of the page should be // Keep moving up a row until we find a good place to break the page while (!IsRowGoodBreakingPoint(bmp2, pageBreak)) pageBreak--; PageContent pageContent = generatePageContent(bmp2, previousPageBreak, pageBreak, document.DocumentPaginator.PageSize.Width, document.DocumentPaginator.PageSize.Height, capabilities); document.Pages.Add(pageContent); previousPageBreak = pageBreak; } // Last Page PageContent lastPageContent = generatePageContent(bmp2, previousPageBreak, bmp2.Height, document.DocumentPaginator.PageSize.Width, document.DocumentPaginator.PageSize.Height, capabilities); document.Pages.Add(lastPageContent); } finally { // Scale UI control back to the original so we don't effect what is on the screen objectToPrint.Width = double.NaN; objectToPrint.UpdateLayout(); objectToPrint.LayoutTransform = new ScaleTransform(1, 1); Size size = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight); objectToPrint.Measure(size); objectToPrint.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), size)); Mouse.OverrideCursor = null; } printDialog.PrintDocument(document.DocumentPaginator, "Print Document Name"); } } private PageContent generatePageContent(System.Drawing.Bitmap bmp, int top, int bottom, double pageWidth, double PageHeight, System.Printing.PrintCapabilities capabilities) { FixedPage printDocumentPage = new FixedPage(); printDocumentPage.Width = pageWidth; printDocumentPage.Height = PageHeight; int newImageHeight = bottom - top; System.Drawing.Bitmap bmpPage = bmp.Clone(new System.Drawing.Rectangle(0, top, bmp.Width, newImageHeight), System.Drawing.Imaging.PixelFormat.Format32bppArgb); // Create a new bitmap for the contents of this page Image pageImage = new Image(); BitmapSource bmpSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( bmpPage.GetHbitmap(), IntPtr.Zero, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(bmp.Width, newImageHeight)); pageImage.Source = bmpSource; pageImage.VerticalAlignment = VerticalAlignment.Top; // Place the bitmap on the page printDocumentPage.Children.Add(pageImage); PageContent pageContent = new PageContent(); ((System.Windows.Markup.IAddChild)pageContent).AddChild(printDocumentPage); FixedPage.SetLeft(pageImage, capabilities.PageImageableArea.OriginWidth); FixedPage.SetTop(pageImage, capabilities.PageImageableArea.OriginHeight); pageImage.Width = capabilities.PageImageableArea.ExtentWidth; pageImage.Height = capabilities.PageImageableArea.ExtentHeight; return pageContent; } private bool IsRowGoodBreakingPoint(System.Drawing.Bitmap bmp, int row) { double maxDeviationForEmptyLine = 1627500; bool goodBreakingPoint = false; if (rowPixelDeviation(bmp, row) < maxDeviationForEmptyLine) goodBreakingPoint = true; return goodBreakingPoint; } private double rowPixelDeviation(System.Drawing.Bitmap bmp, int row) { int count = 0; double total = 0; double totalVariance = 0; double standardDeviation = 0; System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat); int stride = bmpData.Stride; IntPtr firstPixelInImage = bmpData.Scan0; unsafe { byte* p = (byte*)(void*)firstPixelInImage; p += stride * row; // find starting pixel of the specified row for (int column = 0; column < bmp.Width; column++) { count++; //count the pixels byte blue = p[0]; byte green = p[1]; byte red = p[3]; int pixelValue = System.Drawing.Color.FromArgb(0, red, green, blue).ToArgb(); total += pixelValue; double average = total / count; totalVariance += Math.Pow(pixelValue - average, 2); standardDeviation = Math.Sqrt(totalVariance / count); //go to next pixel p += 3; } } bmp.UnlockBits(bmpData); return standardDeviation; }
基于上述代码逻辑,修改了一个版本,由横版改为纵版,增加距边值的设定
public void print(FrameworkElement ViewContainer, double spaceH = 120, double spaceV = 100) { FrameworkElement objectToPrint = ViewContainer as FrameworkElement; PrintDialog printDialog = new PrintDialog(); printDialog.PrintTicket.PageOrientation = PageOrientation.Portrait; if ((bool)printDialog.ShowDialog().GetValueOrDefault()) { Mouse.OverrideCursor = Cursors.Wait; PrintCapabilities capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket); double dpiScale = 300.0 / 96.0; FixedDocument document = new FixedDocument(); try { Rect caprect = new Rect(spaceH, spaceV, capabilities.PageImageableArea.ExtentWidth - spaceH * 2, capabilities.PageImageableArea.ExtentHeight - spaceV * 2); objectToPrint.Width = caprect.Width; objectToPrint.UpdateLayout(); objectToPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); var size = new Size(objectToPrint.DesiredSize.Width, objectToPrint.DesiredSize.Height); objectToPrint.Measure(size); objectToPrint.Arrange(new Rect(size)); // Convert the UI control into a bitmap at 300 dpi double dpiX = 300; double dpiY = 300; RenderTargetBitmap bmp = new RenderTargetBitmap(Convert.ToInt32( caprect.Width * dpiScale), Convert.ToInt32(objectToPrint.ActualHeight * dpiScale), dpiX, dpiY, PixelFormats.Pbgra32); bmp.Render(objectToPrint); // Convert the RenderTargetBitmap into a bitmap we can more readily use PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(bmp)); System.Drawing.Bitmap bmp2; using (MemoryStream memoryStream = new MemoryStream()) { png.Save(memoryStream); bmp2 = new System.Drawing.Bitmap(memoryStream); } document.DocumentPaginator.PageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight); // break the bitmap down into pages int pageBreak = 0; int previousPageBreak = 0; int pageHeight = Convert.ToInt32(caprect.Height * dpiScale); while (pageBreak < bmp2.Height - pageHeight) { pageBreak += pageHeight; // Where we thing the end of the page should be // Keep moving up a row until we find a good place to break the page while (!IsRowGoodBreakingPoint(bmp2, pageBreak)) pageBreak--; PageContent pageContent = generatePageContent(bmp2, previousPageBreak, pageBreak, document.DocumentPaginator.PageSize.Width, document.DocumentPaginator.PageSize.Height, caprect); document.Pages.Add(pageContent); previousPageBreak = pageBreak; } // Last Page PageContent lastPageContent = generatePageContent(bmp2, previousPageBreak, bmp2.Height, document.DocumentPaginator.PageSize.Width, document.DocumentPaginator.PageSize.Height, caprect); document.Pages.Add(lastPageContent); } finally { Rect caprect = new Rect(spaceH, spaceV, capabilities.PageImageableArea.ExtentWidth - spaceH * 2, capabilities.PageImageableArea.ExtentHeight - spaceV * 2); // Scale UI control back to the original so we don't effect what is on the screen objectToPrint.Width = double.NaN; objectToPrint.UpdateLayout(); objectToPrint.LayoutTransform = new ScaleTransform(1, 1); Size size = new Size(caprect.Width, caprect.Height); objectToPrint.Measure(size); var ppp = new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), size); objectToPrint.Arrange(new Rect(caprect.TopLeft, size)); Mouse.OverrideCursor = null; } printDialog.PrintDocument(document.DocumentPaginator, "打印报表"); } } private PageContent generatePageContent(System.Drawing.Bitmap bmp, int top, int bottom, double pageWidth, double PageHeight, Rect rect) { FixedPage printDocumentPage = new FixedPage(); printDocumentPage.Width = pageWidth; printDocumentPage.Height = PageHeight; int newImageHeight = bottom - top; System.Drawing.Bitmap bmpPage = bmp.Clone(new System.Drawing.Rectangle(0, top, bmp.Width, newImageHeight), System.Drawing.Imaging.PixelFormat.Format32bppArgb); // Create a new bitmap for the contents of this page Image pageImage = new Image(); BitmapSource bmpSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( bmpPage.GetHbitmap(), IntPtr.Zero, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(bmp.Width, newImageHeight)); pageImage.Source = bmpSource; pageImage.VerticalAlignment = VerticalAlignment.Top; // Place the bitmap on the page printDocumentPage.Children.Add(pageImage); PageContent pageContent = new PageContent(); ((System.Windows.Markup.IAddChild)pageContent).AddChild(printDocumentPage); FixedPage.SetLeft(pageImage, rect.Left); FixedPage.SetTop(pageImage, rect.Top); pageImage.Width = rect.Width; pageImage.Height = rect.Height; return pageContent; } private bool IsRowGoodBreakingPoint(System.Drawing.Bitmap bmp, int row) { double maxDeviationForEmptyLine = 1627500; bool goodBreakingPoint = false; if (rowPixelDeviation(bmp, row) < maxDeviationForEmptyLine) goodBreakingPoint = true; return goodBreakingPoint; } private double rowPixelDeviation(System.Drawing.Bitmap bmp, int row) { int count = 0; double total = 0; double totalVariance = 0; double standardDeviation = 0; System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat); int stride = bmpData.Stride; IntPtr firstPixelInImage = bmpData.Scan0; unsafe { byte* p = (byte*)(void*)firstPixelInImage; p += stride * row; // find starting pixel of the specified row for (int column = 0; column < bmp.Width; column++) { count++; //count the pixels byte blue = p[0]; byte green = p[1]; byte red = p[3]; int pixelValue = System.Drawing.Color.FromArgb(0, red, green, blue).ToArgb(); total += pixelValue; double average = total / count; totalVariance += Math.Pow(pixelValue - average, 2); standardDeviation = Math.Sqrt(totalVariance / count); //go to next pixel p += 3; } } bmp.UnlockBits(bmpData); return standardDeviation; }