WPF Printing Flow Document - wpf

Greetings,
I have a problem with printing in WPF.
I am creating a flow document and add some controls to that flow document.
Print Preview works ok and i have no problem with printing from a print preview window.
The problem exists when I print directly to the printer without a print preview. But what is more surprisingly - when I use XPS Document Writer as a printer
everyting is ok, when i use some physical printer, some controls on my flow document are not displayed.
Thanks in advance

Important thing to note : You can use XpsDocumentWriter even when printing directly to a physical printer. Don't make the mistake I did of avoiding it just because you're not creating an .xps file!
Anyway - I had this same problem, and none of the DoEvents() hacks seemed to work. I also wasn't particularly happy about having to use them in the first place. In my situation some of the databound controls printed fine, but some others (nested UserControls) didnt. It was as if only one 'level' was being databound and the rest wouldn't bind even with a 'DoEvents()' hack.
The solution was simple though. Use XpsDocumentWriter like this. it will open a dialog where you can choose whichever installed physical printer you want.
// 8.5 x 11 paper
Size sz = new Size(96 * 8.5, 96 * 11);
// create your visual (this is a WPF UserControl)
var template = new PackingSlipTemplate()
{
DataContext = new PackingSlipViewModel(order)
};
// arrange
template.Measure(sz);
template.Arrange(new Rect(sz));
template.UpdateLayout();
// print to XpsDocumentWriter
// this will open a dialog and you can print to any installed printer
// not just a 'virtual' .xps file
PrintDocumentImageableArea area = null;
XpsDocumentWriter xps = PrintQueue.CreateXpsDocumentWriter(ref area,);
xps.Write(template);
I found the OReilly book on 'Programming WPF' quite useful with its chapter on Printing - found through Google Books.
If you don't want a print dialog to appear, but want to print directly to the default printer you can do the following. (For me the application is to print packing slips in a warehouse environment - and I don't want a dialog popping up every time).
var template = new PackingSlipTemplate()
{
DataContext = new PackingSlipViewModel(orders.Single())
};
// arrange
template.Measure(sz);
template.Arrange(new Rect(sz));
template.UpdateLayout();
LocalPrintServer localPrintServer = new LocalPrintServer();
var defaultPrintQueue = localPrintServer.DefaultPrintQueue;
XpsDocumentWriter xps = PrintQueue.CreateXpsDocumentWriter(defaultPrintQueue);
xps.Write(template, defaultPrinter.DefaultPrintTicket);

XPS Document can be printed without a problem

i have noticed one thing:
tip: the controls that are not displayed are the controls I am binding some data, so the conclusion is that the binding doesn't work. Can it be the case that binding is not executing before sending the document to the printer?

Related

WPF Printing to Epson TM-H6000 Slip

I am trying to print to an Epson TM-H6000 Slip printer. I am able to print to the receipt printer but not the slip.
PrintDialog printDlg = new PrintDialog();
printDlg.ShowDialog();
FlowDocument doc = new FlowDocument(new Paragraph(new Run("Some text goes here")));
IDocumentPaginatorSource idpSource = doc;
printDlg.PrintDocument(idpSource.DocumentPaginator, "Testing");
Selecting the receipt will print the text to the receipt printer. Sending the same command to slip, it feeds the paper but does not print anything on it.
Edit: I should note that it does print a windows test page
I found a solution for this however it is not a good solution. Basically, if I set the font size 19 or larger it prints. If it is under 19 then it just feeds the page.
I don't know if this is an issue with MS PrintDocument or Epson's printer driver. If anyone has an idea please reply!

How to Render Panel control to Pdf and Excel file in Windows form

This a Panel Control Contain Invoice Bill:
I want to make this Panel in Pdf and Excel file,but not in image format as a regular pdf file. This code is Written in Windows c#.
Graphics grp = panel.CreateGraphics();
Size formSize = this.ClientSize;
bitmap = new Bitmap(formSize.Width, 610, grp);
grp = Graphics.FromImage(bitmap);
Point panelLocation = PointToScreen(panel.Location);
grp.CopyFromScreen(panelLocation.X, panelLocation.Y, 0, 0, formSize);
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.PrintPreviewControl.Zoom = 1;
printPreviewDialog1.ShowDialog();
but it makes screen shot and create pdf file..
There is nothing that I know of that will take your image and create a "nice" PDF (small, searchable, zoomable) automatically. There is just too much room for error.
You will need to use something that is report-specific or pdf-specific to create your document. Depending on your requirements Docmosis and iText are good at this. Docmosis lets you build your layout in a doc template so it's easier than building in code, but it will still take work specific to the report you are creating. Please note I work for Docmosis. If you prefer a code-approach, iText is very good.
I hope that helps.

Cloning a PathGeometry in Silverlight / WPF

I have a simple handler that adds an ellipse to an empty Silverlight canvas
private void UCLoaded(object sender, RoutedEventArgs e)
{
var geometry = MakeElipse(20, 15, new Point(100, 100));
var ellipsePath = new Path
{
Data = geometry,
Fill = new SolidColorBrush(Colors.DarkGray),
StrokeThickness = 4,
Stroke = new SolidColorBrush(Colors.Gray)
};
LayoutRoot.Children.Add(ellipsePath);
//
var duplicateEllipsePath = new Path();
//duplicateEllipsePath.Data = ellipsePath.Data;
duplicateEllipsePath.Data = geometry;
duplicateEllipsePath.Fill = ellipsePath.Fill;
duplicateEllipsePath.StrokeThickness = ellipsePath.StrokeThickness;
duplicateEllipsePath.Stroke = ellipsePath.Stroke;
LayoutRoot.Children.Add(duplicateEllipsePath);
}
The first ellipse, ellipsePath, is fine and renders as expected. But the line duplicateEllipsePath.Data = ellipsePath.Data or the alternative duplicateEllipsePath.Data = geometry each throw the System.ArgumentException "Value does not fall within the expected range". How can it be in range once, and out-of-range immediately afterwards? What is the correct way of duplicating a path in code like this?
It looks like the only way to clone a path is to do so manually. To quote this answer from Yi-Lun Luo:
The Data property is actually a Geometry. While not noticeable in Silverlight, A Geometry actually relies on an underlying system resource (because it needs to draw something). If you need to draw another Geometry, you'll need another system resource. So you must clone it before you assign it to a new Path. In WPF, we do have a Clone method on Geometry, unfortunately this is not supported in Silverlight. So you have to manually do the clone.
Another post above Yi-Lun's claims to contain reflective code to clone a geometry, and the same code seems to appear here, although the latter is more clearly formatted. However, in your case, it seems overkill to use a method such as this. The geometry you use is created by your MakeElipse [sic] method. Extracting the common code to generate the geometries into a method seems about the best way to proceed here.
The error message 'Value does not fall within the expected range' is a bit misleading. I don't see anything 'out of range', given that the exact same object was supposedly in range for your first ellipse. I can't say exactly why this error message is reported, but I can speculate. Silverlight is implemented in native code, and I believe that because the native code can't throw exceptions it instead returns numeric error codes. Perhaps there's a limited number of error codes and the one for 'Value does not fall within the expected range' was the one chosen for this error?

Snapshots of Control in time using VisualBrush stored in one Fixed(Flow)Document

I need to take snapshots of Control in time and store them in one FixedDocument. Problem is that VisualBrush is somehow "lazy" and do not evaluate itself by adding it to document. When I finaly create the document, all pages contains the same (last) state of Control. While VisualBrush cannot be Freezed, is there any other chance to do it? I would like to have more snapshots on one page so generate document page by page isn't solution for me. Aswel as converting VisualBrush to Bitmap (I want to keep it in vectors). In short - I need to somehow Freeze() VisualBrush
for(;;)
{
FixedPage page = new FixedPage();
...
Rectangle rec = new Rectangle();
...
rec.Fill = vb;
page.Children.Add(rec);
PageContent content = new PageContent();
((IAddChild)content).AddChild(page);
doc.Pages.Add(content);
}
I used serialization:
string svb = XamlWriter.Save(vb.CloneCurrentValue());
// Replace all "Name" attributes (I don't need them already and deserialization would crash on them) with "Tag" - not best practice but it's fast :)
svb = svb.Replace("Name", "Tag");
rect.Fill((VisualBrush)XamlReader.Parse(svb));
EDIT
Better way is to save Visual as XPS document and then take the Visual back. (De)serialization has some problems with SharedSizeGroups and many other "reference like" things.
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
control.InvalidateArrange();
UpdateLayout();
writer.Write(control);
Visual capture = doc.GetFixedDocumentSequence().DocumentPaginator.GetPage(0).Visual;

WPF image vector format export (XPS?)

Our tool allows export to PNG, which works very nicely.
Now, I would like to add export to some vector format. I tried XPS, but the results are not satisfying at all.
Take a look at a comparison http://www.jakubmaly.cz/xps-vs-png.png.
The picture on the left comes from an XPS export, the picture on the right from PNG export, the XPS picture is visibly blurred when opened in XPS Viewer and zoomed 100%.
Are there any settings that I am missing or why is it so?
Thanks,
Jakub.
A sample xps output can be found here: http://www.jakubmaly.cz/files/a.xps.
This is the code that does the XPS export:
if (!boundingRectangle.HasValue)
{
boundingRectangle = new Rect(0, 0, frameworkElement.ActualWidth, frameworkElement.ActualHeight);
}
// Save current canvas transorm
Transform transform = frameworkElement.LayoutTransform;
// Temporarily reset the layout transform before saving
frameworkElement.LayoutTransform = null;
// Get the size of the canvas
Size size = new Size(boundingRectangle.Value.Width, boundingRectangle.Value.Height);
// Measure and arrange elements
frameworkElement.Measure(size);
frameworkElement.Arrange(new Rect(size));
// Open new package
System.IO.Packaging.Package package = System.IO.Packaging.Package.Open(filename, FileMode.Create);
// Create new xps document based on the package opened
XpsDocument doc = new XpsDocument(package);
// Create an instance of XpsDocumentWriter for the document
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
// Write the canvas (as Visual) to the document
writer.Write(frameworkElement);
// Close document
doc.Close();
// Close package
package.Close();
// Restore previously saved layout
frameworkElement.LayoutTransform = transform;
Interesting (and annoying) issue - you may want to check out the lengthy answer from Jo0815 to Printing XpsDocument causes resampled images (96dpi?) - FixedDocument prints sharp, quoting a Microsoft support response - a couple of excerpts:
Some vector features from WPF cannot be emulated in our GDI code and
we resort to converting subsets of the scene to GDI bitmaps. These
bitmaps are the cause of the blurred zooming.
[...]
These bitmaps are the cause of the blurred zooming. The problem is
that the WPF is being rasterised to a bitmap at the -wrong resolution.
The print path is designed to rasterise unsupported features into a
bitmap, but it is supposed to do it at device resolution. Instead the
rasterisation is always being done at 96dpi. That's fine for a screen
but produces blurred output for a 600dpi printer. [emphasis mine]
Please note that the latter will apply for nowadays higher DPI screens as well of course, I've encountered blurring like this various times already - do you by chance use a high DPI monitor?
Now, apparently Microsoft is not entirely in control of the apparatus regarding this:
Additionally the problem only occurs when printing XPS and isn't a
problem when printing XAML directly. I'm pretty sure there is
documentation somewhere that says XPS will print at device resolution.
[...] It is something we
plan to improve in the next version of the product but not for Win 7.
The problem is that when printing XAML it will correctly render the
image at 600dpi, but when printing XPS it will still render the image
at 96dpi. Since XAML is converted to XPS before printing it seems
highly odd that one method of printing XPS produces different results
to another method of printing XPS. [emphasis mine]
[...]
There is no UI to configure the XPS Document Writer DPI. If you later
print a generated XPS document at a different DPI from the writers
internal default you may get poor results for bitmap content. With GDI
printers you can control the final DPI and your final desitination is
usally paper - no chance to reprint the document.
Conclusion
In conclusion, I'd still try to adjust PrintTicket.PageResolution Property within Néstor Sánchez' approach (+1), if your use case does allow this (though I remotely recall reading somewhere, that this doesn't have any effect as well); section Bitmap Resolution and Pixel Format in Using the XPS Rasterization Service confirms the issue he encountered with FixedDocument:
XPS rasterizer object for a fixed page must know the resolution at
which the page will be rendered. The XPSDrv filter specifies this
resolution, in dots per inch (DPI), as an input parameter [...] For example, if a display device has a resolution
of 600 DPI, and a fixed page describes a standard letter-size page, a
bitmap image of the entire page has the following dimensions [...]
Workaround
As a potential workaround you might want to explore alexandrud's solution for the related question How to convert a XPS file to an image in high quality (rather than blurry low resolution)?, which recommends using xps2img, a XPS (XML Paper Specification) document to set of images conversion utility. In particular it Allows to specify images size or DPI, which might help depending on the print path solution applied in turn.
Good luck!
I've had a similar problem. My image was very blurry when passed to XPS intermediated thru a FixedDocument.
The solution was to write the image directly to the XPS...
/// <summary>
/// Saves the supplied visual Source, within the specified Bounds, as XPS in the specified File-Name.
/// Returns error message or null when succeeded.
/// </summary>
public static string SaveVisualAsXPS(Visual Source, Size Bounds, string FileName)
{
string ErrorMessage = null;
try
{
using (var Container = Package.Open(FileName, FileMode.Create))
{
using (var TargetDocument = new XpsDocument(Container, CompressionOption.Maximum))
{
var Writer = XpsDocument.CreateXpsDocumentWriter(TargetDocument);
var Ticket = GetPrintTicketFromPrinter();
if (Ticket == null)
return "No printer is defined.";
Ticket.PageMediaSize = new PageMediaSize(Bounds.Width, Bounds.Height);
var SourceVisual = Source;
Writer.Write(SourceVisual, Ticket);
}
}
}
catch (Exception Problem)
{
ErrorMessage = "Cannot export document to XPS.\nProblem: " + Problem.Message;
}
return ErrorMessage;
}
Giving a print-ticket with the exact width and height avoids scaling (that was I wanted in my case).
Get the function from the example in:
http://msdn.microsoft.com/en-us/library/system.printing.printticket.aspx

Resources