I'm using PrintDocument to print out multiple pages that each have one control on. So far I'm able to print them all out on individual sheets as desired, however I'm unable to center the controls in the middle of the pages and it always shows in the top corner of the page. I'll post my code below.
var dialog = new PrintDialog();
var queue = GetPrinterQueue(pPrinterId);
if (queue == null)
return;
dialog.PrintQueue = queue;
dialog.PrintTicket.PageOrientation = paperOrientation
? PageOrientation.Portrait
: PageOrientation.Landscape;
var document = new FixedDocument();
var fixedPage = new FixedPage();
fixedPage.Children.Add(front);
//fixedPage.Measure(size);
//fixedPage.Arrange(new Rect());
//fixedPage.UpdateLayout();
var pageContent = new PageContent();
((IAddChild)pageContent).AddChild(fixedPage);
document.Pages.Add(pageContent);
dialog.PrintDocument(document.DocumentPaginator, "Badge");
That is the bare minimum to make it print out a control per sheet, to make it simpler I have taken out the parts that print to different pages, for the sake of this it only needs to print one.
I've tried changing what is passed into .Arrange() and it makes no difference, what am I missing?
Thanks
Related
I have a WPF application in which I have 3 forms of prints. In 2 ways, I use directly a window's visual and use PrintVisual(myPanel, "Title") to print it. And in 3rd, I got to print multiple pages so I am using FlowDocument, StackPanel and finally IDocumentPaginatorSource and call PrintDocument to print.
All the code is working perfectly on my system. I can perform Print on OneNote and XPS and it works as expected. But the same app, when I try to run on other system it shows blank page for all 3 prints. PrintVisual is supported on .NET 3.0, 3.5, 4.0, 4.5, so I can't find a reason for it not to work.
I will also share my some code, for better clarity :
// 1 PRINT
public void PrintRegister()
{
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
pd.PrintVisual(this, "Register Window");
return;
}
// 2 PRINT
public static void PrintAttendanceOf(System.Data.DataRow r1) {
PrintLayoutWindowPORT plw = PrintUtility.CreatePrintLayoutWindowPORTObject(r1); // PORTRAIT
Canvas p1 = PrintUtility.CloneCanvas(plw._PrintCanvas, 5);
Grid myPanel = new Grid();
myPanel.Margin = new Thickness(10);
myPanel.Children.Add(p1);
PrintDialog pd = new PrintDialog();
pd.PageRangeSelection = PageRangeSelection.AllPages;
PrintQueue pq = pd.PrintQueue;
pq.DefaultPrintTicket.PageOrientation = PageOrientation.Portrait;
pd.PrintTicket = pq.DefaultPrintTicket;
double pageWidth = pd.PrintableAreaWidth;
double pageHeight = pd.PrintableAreaHeight;
myPanel.Measure(new Size(pageWidth, pageHeight));
//myPanel.Arrange(new Rect(new Point(1, 1), myPanel.DesiredSize));
myPanel.UpdateLayout();
if (pd.ShowDialog().GetValueOrDefault(false))
{
pd.PrintVisual(myPanel, "Attendance Chart");
}
pd = null;
plw.Close();
plw = null;
myPanel = null;
p1 = null;
return;
}
Code for the 3rd Print i.e. Multiple Pages is quiet long, hence have not added it now here. If required, can post it.
Can anyone help me know the reason for printing blank page and no contents on other system. I feel some sort of compatibility or system or resource may be required or what else?
Any help is highly appreciated.
Thanks
Below is the process I worked in Windows forms for printing.
I used PrintDocument class. It contains PrintPage event and I used that to draw the graphics of what I need to print and obtained the result successfully as I expected.
Below is the code:
public PrintDocument Printing
{
m_printDocument = new PrintDocument();
m_printDocument.PrintPage += new PrintPageEventHandler(OnPrintPage);
}
The code for OnPrintPage as follows:
protected virtual void OnPrintPage(object sender, PrintPageEventArgs e)
{
//Image img = I have the things to be printing in the form of image.
e.Graphics.DrawImage(img, new Point(0,0));
}
In WPF:
I am working with Fixed document and by using the below code I can print
PrintDialog print = new PrintDialog();
print.PrintDocument(FixedDocument.DocumentPaginator, "Print") //Where Fixed document contains the data to be printed.
This results is insufficient memory to continue the execution of the program.
But I got Fixed document without any problem.
Any solutions ...?
I hope the similar thing as like Windows form would be there in WPF too...
I used to get this when my pages contained lots of visual elements (drawings/images/ complex diagrams). Instead of printing the complete document at once (which can lead to out of memory)
print.PrintDocument(FixedDocument.DocumentPaginator, "Print")
I printed one of its page.
PrintQueue selectedPrntQueue = printDialog.PrintQueue;
XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(selectedPrntQueue);
SerializerWriterCollator collator = writer.CreateVisualsCollator();
collator.BeginBatchWrite();
var paginator = FixedDocument.DocumentPaginator;
FixedPage fixedPage = paginator.GetFixedPage(printedPageCount)
ContainerVisual newPage = new ContainerVisual();
Size sz = new Size(pageSize.Height.Value, pageSize.Width.Value);
fixedPage.Measure(sz);
fixedPage.Arrange(new Rect(new Point(), sz));
fixedPage.UpdateLayout();
newPage.Children.Add(fixedPage);
collator.Write(newPage);
I had to do GC after printing few pages (my magic number was 10).
You may need to tweak the this up to your requirement.
So I am printing out some text from a textbox, which has wordwrapping enabled, but when I print out the document, the string that should be wordwrapped does not, and cuts offs on the page. I'd like to simply enable word wrapping for my printed document. Also is there a way to set the margins for the printed document, some of the text gets cut off from both the top and left margins. Thanks! Code attached below.
FixedDocument document = new FixedDocument();
document.DocumentPaginator.PageSize = new Size(printDlg.PrintableAreaWidth, printDlg.PrintableAreaHeight);
FixedPage page1 = new FixedPage();
page1.Width = document.DocumentPaginator.PageSize.Width;
page1.Height = document.DocumentPaginator.PageSize.Height;
MessageBox.Show(page1.Height.ToString() + page1.Width);
GridType.Children.Remove(Textbox);
page1.Children.Add(Textbox);
PageContent page1Content = new PageContent();
((IAddChild)page1Content).AddChild(page1);
document.Pages.Add(page1Content);
printDlg.PrintDocument(document.DocumentPaginator, "My first document");
page1.Children.Remove(Textbox);
GridType.Children.Add(Textbox);
Your textbox setting won't applied in PrintDoc .. you must recalculate all in your printdoc printpage event
We've got a large stock of paper forms that we need to fill out. It's very tedious to do this by hand, so we're building an application. It should provide a form to fill in data, be able to show print preview, print the data on the paper form, and keep the history.
Currently, we have a FixedPage which we print like this:
var dlg = new PrintDialog();
if (dlg.ShowDialog() == true)
{
var doc = new FixedDocument();
doc.DocumentPaginator.PageSize = new Size(11.69 * 96, 8.27 * 96); // A4 Landscape
var fp = Application.LoadComponent(new Uri("/FixedPage.xaml", UriKind.Relative)) as FixedPage;
fp.DataContext = this;
fp.UpdateLayout();
var pc = new PageContent();
((IAddChild)pc).AddChild(fp);
doc.Pages.Add(pc);
dlg.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
dlg.PrintDocument(doc.DocumentPaginator, string.Format("Form #{0}", FormNumber));
}
For the print preview we have a custom UserControl with scanned image of the paper form on background and the data on foreground. Basically, it's repeating the FixedPage layout, and all this makes us think there's a flaw in our design.
Is there a better way to do what we want?
I was tasked with the same problem and wanted to avoid writing my own templating system to save time, unit testing, and my sanity.
I ended up writing a hybrid to did some cool things. First, I wrote my templates using HTML and CSS. It was very easy to do and allowed for great flexibility when making minor adjustments from our Marketing department.
I filled the template with my own tags (e.g [code_type/], [day_list]...[/day_list]) and string replaced the text with a dictionary of tags that could be a single or multivalued.
After generating the html, I would use an html to pdf library I found that uses the open-source webkit engine to render and create the generated pdf. It turned out very stable and took around 2 weeks to write the initial program. Everyone was very pleased and testing was a breeze.
If you want more details, send me a message or reply to this.
We have managed to find a solution, which allows us to throw away a bunch of renundant code. It is still ugly:
public class CustomDocumentViewer : DocumentViewer
{
public static readonly DependencyProperty BackgroundImageProperty =
DependencyProperty.Register("BackgroundImage", typeof(Image), typeof(CustomDocumentViewer), new UIPropertyMetadata(null));
public Image BackgroundImage
{
get { return GetValue(BackgroundImageProperty) as Image; }
set { SetValue(BackgroundImageProperty, value); }
}
protected override void OnDocumentChanged()
{
(Document as FixedDocument).Pages[0].Child.Children.Insert(0, BackgroundImage);
base.OnDocumentChanged();
}
protected override void OnPrintCommand()
{
var printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
(Document as FixedDocument).Pages[0].Child.Children.RemoveAt(0);
printDialog.PrintDocument(Document.DocumentPaginator, "Test page");
(Document as FixedDocument).Pages[0].Child.Children.Insert(0, BackgroundImage);
}
}
}
...
<local:CustomDocumentViewer x:Name="viewer" BackgroundImage="{StaticResource PaperFormImage}"/>
...
InitializeComponent();
viewer.Document = Application.LoadComponent(new Uri("/PaperFormDocument.xaml", UriKind.Relative)) as IDocumentPaginatorSource;
The reason why we're using Application.LoadComponent instead of binding is a five years old bug: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=293646
I am trying to print the content of RichTextBox including the Adorner Layers inside.
I am using this code to print
double w = Editor.ExtentWidth; // Editor is the RichTextBox
double h = Editor.ExtentHeight;
LocalPrintServer ps = new LocalPrintServer();
PrintQueue pq = ps.DefaultPrintQueue;
XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq);
PrintTicket pt = pq.UserPrintTicket;
if (xpsdw != null)
{
pt.PageOrientation = PageOrientation.Portrait;
PageMediaSize pageMediaSize = new PageMediaSize(w, h);
pt.PageMediaSize = pageMediaSize;
xpsdw.Write(Editor);
}
The problem I'm facing is that this code only prints the content that is visible on the screen, not the whole content of the Editor.
EDIT
The pictures are adorner layers, If I print using the method above, it only prints the visible part on the screen not the whole document.
Edit
I'm trying to print each page separately but I cant force Editor.InvalidateVisual(); after doing a Editor.PageDown(); Is there a way I can do that in my method ?
When controls draw on the adorner layer, they search up the tree until they find an adorner layer. Often times this is a the window level. In some cases, you'll want an adorner layer closer to the control, or directly around the control. In this case, wrap the control with an <AdornerDecorator><RichTextBox /></AdornerDecorator>
In your case, you'd probably want to pass a parent element of adorner decorator, or the decorator itself to the print logic. This way the print logic would include the adorner layer as part of the visual. Maybe something like this:
<Grid Name="EditorWrapper">
<AdornerDecorator>
<RichTextBox />
</AdornerDecorator>
</Grid>
Then, pass "EditorWrapper" to the print logic.
EDIT
If you just want to print the contents of the RichTextBox, then you might be best to use the built-in pagination capabilities of the FlowDocument. FlowDocument implements IDocumentPaginatorSource, which will return a paginator that can print the document. Pass that paginator to the XpsDocumentWriter and it should dump the content properly.
var doc = Editor.Document;
var src = doc as IDocumentPaginatorSource;
var pag = src.DocumentPaginator;
xpsdw.Write(pag);
I found this code here:
// Serialize RichTextBox content into a stream in Xaml or XamlPackage format. (Note: XamlPackage format isn't supported in partial trust.)
TextRange sourceDocument = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
MemoryStream stream = new MemoryStream();
sourceDocument.Save(stream, DataFormats.Xaml);
// Clone the source document's content into a new FlowDocument.
FlowDocument flowDocumentCopy = new FlowDocument();
TextRange copyDocumentRange = new TextRange(flowDocumentCopy.ContentStart, flowDocumentCopy.ContentEnd);
copyDocumentRange.Load(stream, DataFormats.Xaml);
// Create a XpsDocumentWriter object, open a Windows common print dialog.
// This methods returns a ref parameter that represents information about the dimensions of the printer media.
PrintDocumentImageableArea ia = null;
XpsDocumentWriter docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia);
if (docWriter != null && ia != null)
{
DocumentPaginator paginator = ((IDocumentPaginatorSource)flowDocumentCopy).DocumentPaginator;
// Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device.
paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
Thickness pagePadding = flowDocumentCopy.PagePadding;
flowDocumentCopy.PagePadding = new Thickness(
Math.Max(ia.OriginWidth, pagePadding.Left),
Math.Max(ia.OriginHeight, pagePadding.Top),
Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), pagePadding.Right),
Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), pagePadding.Bottom));
flowDocumentCopy.ColumnWidth = double.PositiveInfinity;
// Send DocumentPaginator to the printer.
docWriter.Write(paginator);
}
Adorner layers are are drawing oriented. So one option left is to convert the entire RichTextBox into a drawing and print that as an Image in XPS.
Although this poses multiple issues...
It will print the external and internal contents that occupy or occupied by the richtextbox i.e. editor toolbar (if it is part of the control template of the rich text box), internal scroll bars etc.
If there are scrollbars then the content out of the scrollbars are not going to be printed as the image will be the exact "snapshot" of the textbox (with remaining text clipped by srollbars).
Will you be happy with that?
I didn't find any way that works 100% for this problem, so I'm trying to transform all my adorner layers to actual images. I'll update the question once I get a 100% working solution.