Printing in WPF similar to Winforms - c#

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.

Related

WPF RichTexBox printing is creating unexpected line breaks

In RichTextBox of my WPF app, following print method is creating unexpected line breaks. Question: What I may be missing here, and how can we fix the issue?
For example, when I enter the following text in the RichTextBox (RTB), the RTB looks like as shown in image 1. But when I call the following two print methods the first one does not create the unexpected line breaks, but the second method does create unexpected line breaks:
MainWindow.xaml
<StackPanel>
<RichTextBox Name="richTB" />
<Button Click="PrintCommand1">Print RTB Content</Button>
<Button Click="PrintCommand2">Print RTB Content</Button>
</StackPanel>
Method 1
private void PrintCommand1(Object sender, RoutedEventArgs args)
{
PrintDialog pd = new PrintDialog();
if ((pd.ShowDialog() == true))
{
pd.PrintVisual(richTB as Visual, "printing as visual");
}
}
Method 2
private void PrintCommand2(Object sender, RoutedEventArgs args)
{
PrintDialog pd = new PrintDialog();
if ((pd.ShowDialog() == true))
{
pd.PrintDocument((((IDocumentPaginatorSource)richTB.Document).DocumentPaginator), "printing as paginator");
}
}
The text I enter [Note: There is only one line break]
This is a test for testing purpose only. Another test: x6. Let us do some background and foreground colors.
This is a new line with formatting, as well.
Snapshot of the RichTexBox with above text
Snapshot of "Print to PDF" (on Windows 10) using Method 1 [Printed correctly with one real line break]
Snapshot of "Print to PDF" (on Windows 10) using Method 2 [Printed incorrectly with unexpected line breaks]
Because of the DocumentPaginator class takes context of the FlowDocument and split in into multiple pages to get desired result some of FlowDocument parameters should be configured before printing:
private void PrintCommand2(Object sender, RoutedEventArgs args)
{
var pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
FlowDocument doc = richTB.Document;
// Save all settings that will be configured for printing.
double pageHeight = doc.PageHeight;
double pageWidth = doc.PageWidth;
double columnGap = doc.ColumnGap;
double columnWidth = doc.ColumnWidth;
// Make the FlowDocument page match the printed page.
doc.PageHeight = pd.PrintableAreaHeight;
doc.PageWidth = pd.PrintableAreaWidth;
doc.ColumnGap = 5;
// Set the minimum desired width of the column in the System.Windows.Documents.FlowDocument.
doc.ColumnWidth = doc.PageWidth - doc.ColumnGap - doc.PagePadding.Left - doc.PagePadding.Right;
pd.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator, "A Flow Document");
// Reapply the old settings.
doc.PageHeight = pageHeight;
doc.PageWidth = pageWidth;
doc.ColumnGap = columnGap;
doc.ColumnWidth = columnWidth;
}
}
With respect to Matthew MacDonald this way of the flow document content printing and more advanced techniques described in his book Pro WPF 4.5 in C# Windows Presentation Foundation in .NET 4.5 (Chapter 29).

Center printing PrintDocument

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

WPF Printing prints on 1 system and not on other

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

Print preview issue in Steema Teechart with graphics3d

I am using tchart with graphics 3d for real time chart plotting. whenever I try to call print preview for the chart, the preview page is just a blank page and the actual chart background becomes black. I tried different tricks and i found this printpreview works in normal canvas. but as soon as i write the line
Chart1.Graphics3D = new Graphics3DDirect2D(Chart1.Chart);
print preview does not work .
If I call export function, e.g. export to pdf functionality then the pdf file has exported chart in it and alternate route can be I can print the pdf.
But I want to use print preview and give user a functionality to change margins and other things as per their need.
Link for the demo project is http://www.filedropper.com/sampleprojecttchartprint
Link for the Video describing issue is http://tinypic.com/r/2ufg7f5/5
What am I doing wrong here?
There is a limitation with the wrapper TeeChart uses, a limitation documented here:
http://bugs.teechart.net/show_bug.cgi?id=356
As suggested, the workaround is to use the GDI+ canvas for image exportation, e.g.
private void InitializeChart()
{
tChart1.Graphics3D = new Graphics3DDirect2D(tChart1.Chart);
tChart1.Aspect.View3D = false;
FastLine series = new FastLine(tChart1.Chart);
series.FillSampleValues(1000);
}
TChart tChart2;
private void button1_Click(object sender, EventArgs e)
{
if(tChart2 == null) tChart2 = new TChart();
MemoryStream ms = new MemoryStream();
tChart1.Export.Template.Save(ms);
ms.Position = 0;
tChart2.Import.Template.Load(ms);
tChart2.Export.Image.PNG.Width = tChart1.Width;
tChart2.Export.Image.PNG.Height = tChart1.Height;
tChart2.Export.Image.PNG.Save(#"C:\tmp\direct2d.png");
}

Printing on a paper form with preview

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

Categories

Resources