WPF Print Problem - c#

When i select Microsoft XPS Document Writer as Printer, my output is perfect but when i select my HP 1020 printer machine, the printer outputs blank copy...Following is the code....
private void printButton_Click(object sender, RoutedEventArgs e)
{
PrintInvoice pi = new PrintInvoice();
pi.DataContext = this.DataContext;
PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
if (printDlg.ShowDialog() == true)
{
pi.Margin = new Thickness(30);
//now print the visual to printer to fit on the one page.
printDlg.PrintVisual(pi, "First Fit to Page WPF Print");
}
}

This could be caused by a number of different things. There are a few steps that you can add which, when performed correctly, may cause the flying men to return with goods and knowledge.
First, you should scale to the printed page (code from a2zdotnet):
System.Printing.PrintCapabilities capabilities =
printDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);
//get scale of the print wrt to screen of WPF visual
double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / this.ActualWidth, capabilities.PageImageableArea.ExtentHeight /
this.ActualHeight);
//Transform the Visual to scale
this.LayoutTransform = new ScaleTransform(scale, scale);
//get the size of the printer page
Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
//update the layout of the visual to the printer page size.
this.Measure(sz);
this.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
//now print the visual to printer to fit on the one page.
printDlg.PrintVisual(this, "Code ganked from http://www.a2zdotnet.com/View.aspx?id=66");
The cargo-cult code is in the Measure and Arrange steps. Often, if you call Measure and pass in a new Size(Double.MaxValue, Double.MaxValue) that's all you need to do.
The second ritual involves bumping the Dispatcher.
visual.DataContext = foo;
Dispatcher.Invoke((Action)()=>{;}); // bamp
// print here
Try these and see if it helps.

this XAML does the trick in some situations
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<... Name="myPrintElement" />
</ScrollViewer >

Related

How to print WPF layout to not be dependent on the screen resolution?

I've been trying to use the following method to print a page on A4 paper. If my application runs on a laptop where the resolution is 1366x768 the printout scales down and I have no idea why? If I run it on a PC where the monitor resolution is higher, it prints as it should. I have tried to change PageMediaSize, ScaleTransform, LayoutTransform, Windows.Size with no success. What am I doing wrong?
The first 4 lines are there because I am sometimes using a 'print preview' where I'm scaling the page using a Viewbox, so the user can resize the preview. To not to affect the printing I am setting the Height and Width right before printing but outside of the PC's visible desktop area so it is not visible for the user.
var desktopWorkingArea = System.Windows.SystemParameters.WorkArea;
this.Top = desktopWorkingArea.Bottom + 100;
this.Height = 1250;
this.Width = 815;
System.Windows.Controls.PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
printDlg.PrintQueue = new System.Printing.PrintQueue(new System.Printing.PrintServer(), printerName);
System.Printing.PrintCapabilities capabilities = printDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);
//get scale of the print wrt to screen of WPF visual
double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / this.ActualWidth, capabilities.PageImageableArea.ExtentHeight / this.ActualHeight);
//Transform the Visual to scale
this.LayoutTransform = new ScaleTransform(scale, scale);
//get the size of the printer page
System.Windows.Size sz = new System.Windows.Size(this.ActualWidth, this.ActualHeight); //(8.5 * 96.0, 11.0 * 96.0);
//update the layout of the visual to the printer page size.
this.Measure(sz);
this.Arrange(new Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
//now print the visual to printer to fit on the one page.
printDlg.PrintVisual(this, "Certificate - " + serialNumberTextBlock.Text);

WPF Print canvas to fit page

I am trying to print a canvas to both printer and file with the help of PrintDialog. I want the canvas to fit the page. I was able to achieve it using the following code
private void Print(Visual v)
{
System.Windows.FrameworkElement e = v as System.Windows.FrameworkElement ;
if (e == null)
return;
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
//store original scale
Transform originalScale = e.LayoutTransform;
//get selected printer capabilities
System.Printing.PrintCapabilities capabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);
//get scale of the print wrt to screen of WPF visual
double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / e.ActualWidth, capabilities.PageImageableArea.ExtentHeight /
e.ActualHeight);
//Transform the Visual to scale
e.LayoutTransform = new ScaleTransform(scale, scale);
//get the size of the printer page
System.Windows.Size sz = new System.Windows.Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
//update the layout of the visual to the printer page size.
e.Measure(sz);
e.Arrange(new System.Windows.Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
//now print the visual to printer to fit on the one page.
pd.PrintVisual(v, "My Print");
//apply the original transform.
e.LayoutTransform = originalScale;
}
}
The above code seems to be working as expected but when I am writing it to a PDF file using a PDF writer, the canvas will be resized when the save dialog box shows up and it will be set back to normal. So there is a resizing happening in the UI as well.
This canvas is already a cloned one and this cannot be printed without showing it in the UI because there are some background operations happening to fill the elements in the canvas which can be started only after it's loaded. Hence the cloned canvas is shown as a print preview.
Does anyone know of a good solution, or perhaps improve on the existing one to solve the UI resizing issue?

PrintFixedDocument wpf print quality- Windows 10/8 vs Windows 7

I am currently trying to print the contents of a content container (it only contains datagrids with information) and an image using PrintFixedDocument. It prints flawlessly on my machine (windows 10) with full image quality and on another pc which is windows 8, the quality is the same.
However when this is done on a Windows 7 pc the image quality becomes very poor and the final result is very blurred. This is a problem as the computer cannot be updated from windows 7 for various reasons, so im wondering if anyone else has experienced this and if so is there a workaround? Also could be an issue with my GetFixedDocument method, though I cannot work out why this would work on both win 10 and 8 but not 7.
NOTE THIS IS RUNNING FROM AN INSTALLED VERSION OF THE APPLICATION ON EACH PC
ALSO BEEN TRIED ON MULTIPLE PRINTERS ON ALL 3 OPERATING SYSTEMS
Any help would be appreciated
Xaml:
<StackPanel Margin="-105,146,66,0" Height="900" VerticalAlignment="Top" x:Name="PrintImageContextMenu">
<Image Canvas.ZIndex="0" Source="{Binding Coupon.OverlayImagePath}" Margin="0,-21,-76,108" Stretch="Fill" />
<ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource DataViewerDataTemplateSelector}" />
</StackPanel>
C#:
public partial class CouponViewerView
{
public CouponViewerView()
{
InitializeComponent();
}
public void Print()
{
//Executes On Thread
Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (EventHandler)delegate
{
UpdateLayout();
var fixedDoc = PrintHelper.GetFixedDocument(StackPanelToPrint, new PrintDialog());
PrintHelper.ShowPrintPreview(fixedDoc);
}, null, null);
}
private void PrintCurrentForm(object sender, RoutedEventArgs e)
{
Print();
}
C# Print helper code:
public static void ShowPrintPreview(FixedDocument fixedDoc)
{
var wnd = new Window();
var viewer = new DocumentViewer();
viewer.Document = fixedDoc;
wnd.Content = viewer;
wnd.ShowDialog();
}
public static FixedDocument GetFixedDocument(FrameworkElement toPrint, PrintDialog printDialog)
{
var capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
var pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
var visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
var fixedDoc = new FixedDocument();
//If the toPrint visual is not displayed on screen we neeed to measure and arrange it
toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));
//
var size = toPrint.DesiredSize;
//Will assume for simplicity the control fits horizontally on the page
double yOffset = 0;
while (yOffset < size.Height)
{
var vb = new VisualBrush(toPrint)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Top,
ViewboxUnits = BrushMappingMode.Absolute,
TileMode = TileMode.None,
Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height)
};
var pageContent = new PageContent();
var page = new FixedPage();
((IAddChild)pageContent).AddChild(page);
fixedDoc.Pages.Add(pageContent);
page.Width = pageSize.Width;
page.Height = pageSize.Height;
var canvas = new Canvas();
FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
canvas.Width = visibleSize.Width;
canvas.Height = visibleSize.Height;
canvas.Background = vb;
page.Children.Add(canvas);
yOffset += visibleSize.Height;
}
return fixedDoc;
}
anyone else has experienced this and if so is there a workaround?
That's the only directly answerable question, yes, many. Keep in mind that you often substantially rescale an image on a printer, they are devices with very high dots-per-inch resolution compared to a monitor. A machine that boots Win7 often runs at 96dpi, later ones tend to have better monitors so are often run at higher dpi settings. First thing to watch out for is the source image. If it has a pixel size that's adequate for that Win7 PC then it can get very blurry when it is blown-up to 600 dpi.
Probably the most unintuitive scaling behavior in WPF is what happens when the image alignment does not perfectly match a target pixel after scaling. A problem described well in this blog post. Be sure to also read this SO question, an almost perfect fit for your usage of VisualBrush and its blurriness problem. This problem was addressed in .NET 4.0 with the added UseLayoutRounding property. You are not using it, you definitely should. Don't blindly apply the BitmapScalingMode that the dup recommends, the type of image (line-art vs photo) matters a lot.
I had a similar issue I ended up instead of directly printing to creating a PDF and having that open for the client and they could print it if they wanted just fine.
Windows 7 just seems broken with some of the WPF printing.

Microsoft Report page orientation (VS 2013, C#)

I am printing labels with MS Report (c#/VS2013). The labels are 8 cm wide and 4 cm high. The printer sees and feeds them as portrait (no rotation) but the report viewer prints them landscape because the width is greater than the hight. Printer specific page orientation change before printing are ignored (!), so the labels are always printed in a 90° rotation against the label orientation. printer is an industial thermo transfer printer.
I don't understand why the page orientation is bound to the relation between hight and width and cannot be set indepenently! I already tried to change the orientation right before printing - this caused the labes be printed in several pieces but did not rotate them.
The only thing that helped was changing the paper size to 8 width and 8.1 height. Then the labels print correctly but this leads to a lot of empty pages (labels) and is no good solution.
The only way I see currently is redesigning all the labels rotated by 90° which is quite some effort, so I would be grateful if someone had a solution for this stange behaviour!
I solved this issue by rendering to an image and printing that through a PrintDocument object. This way I am able to send the landscape-formed label (8cm width, 4cm height) to the printer in portrait.
I am sure this can be done more elegant but due to time pressure I now go with this solution:
String tempDir = Path.GetTempFileName();
File.Delete(tempDir);
Directory.CreateDirectory(tempDir);
tempDir = Utils.addBackslash(tempDir);
ExportToPNG(tempDir);
String imageFile = Utils.FindFirstFile(tempDir, "*.png");
if (imageFile != "")
{
PrintDocument pd = new PrintDocument();
try
{
pd.DefaultPageSettings.PrinterSettings.PrinterName = DB.Instance.getSetting("label.printername");
}
catch
{
// This is just a preset, it may fail without consequences
}
pd.DefaultPageSettings.Landscape = false; // Now I can do it!
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile(imageFile);
Point p = new Point(100, 100);
args.Graphics.DrawImage(i, 0, 0, i.Width, i.Height);
};
PrintDialog pdi = new PrintDialog();
pdi.Document = pd;
if (pdi.ShowDialog() == DialogResult.OK)
pd.Print();
pd.Dispose();
}

C# Printvisual, can not fit to page

I want to use printvisual to print this gridcontroll:
<Grid Name="printingkvitto2" Margin="0" Height="900" Width="842" VerticalAlignment="Top">
//stuff
</Grid>
Got this code:
PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
//if (printDlg.ShowDialog() == true)
{
LocalPrintServer localPrintServer = new LocalPrintServer();
PrintQueue pq = localPrintServer.GetPrintQueue(Properties.Settings.Default.valdskrivarenamn);
printDlg.PrintQueue = pq;
//get selected printer capabilities
System.Printing.PrintCapabilities capabilities = printDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);
//get scale of the print wrt to screen of WPF visual
double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / printingkvitto2.ActualWidth, capabilities.PageImageableArea.ExtentHeight /
printingkvitto2.ActualHeight);
//Transform the Visual to scale
printingkvitto2.LayoutTransform = new ScaleTransform(scale, scale);
//get the size of the printer page
Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
//update the layout of the visual to the printer page size.
printingkvitto2.Measure(sz);
printingkvitto2.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
//now print the visual to printer to fit on the one page.
printDlg.PrintVisual(printingkvitto2, "print");
}
But I cant get it to fit the printed page (A4). It's always outside of the frame on the right side.
I want to send a "fit to page" setting to the printer.
What am I doing wrong?

Categories