Printing Canvas using PrintDialog in WPF - c#

I am trying to take the print of Canvas in A4 size by setting height and width to 29.7cm and 21cm respectively.
I am getting proper output on Windows 7 devices. But for Windows 10 devices, the print output is not same as Windows 7 devices.
The real problem is height and width is not maintained for Windows 10 devices.
Please Help and Suggest Me !!
Please find below code:
Xaml:
<Window x:Class="TestSolution.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Height="29.7cm"
Width="21cm"
ResizeMode="NoResize">
<Grid x:Name="grdTest"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Height="29.7cm"
Width="21cm">
<Canvas x:Name="cnvTest"
VerticalAlignment="Stretch"
Height="29.7cm"
Width="21cm"
HorizontalAlignment="Stretch">
</Canvas>
</Grid>
</window>
Code Behind
private void btn_Click(object sender, RoutedEventArgs e)
{
PrintDialog prnt = new PrintDialog();
if (prnt.ShowDialog() == true)
{
prnt.PrintVisual(cnvTest, "Printing Canvas");
}
this.Close();
}

Finally got the solution. courtesy Magnus (MM8)
Please find solution on the below link
https://social.msdn.microsoft.com/Forums/en-US/b26c7898-169a-4726-b582-e79dc63f8450/printing-canvas-using-printdialog-in-wpf?forum=wpf
Here is a copy of the answer from the site, assuming a canvas with the name cnvTest:
private void btn_Click(object sender, RoutedEventArgs e)
{
PrintDialog prnt = new PrintDialog();
if (prnt.ShowDialog() == true)
{
Size pageSize = new Size(prnt.PrintableAreaWidth, prnt.PrintableAreaHeight);
cnvTest.Measure(pageSize);
cnvTest.Arrange(new Rect(5, 5, pageSize.Width, pageSize.Height));
if (prnt.ShowDialog() == true)
{
prnt.PrintVisual(canvas, "Printing Canvas");
}
}
this.Close();
}

you can try this code
System.Windows.Controls.PrintDialog printDialog = new System.Windows.Controls.PrintDialog();
System.Drawing.Printing.PrinterSettings printer = new System.Drawing.Printing.PrinterSettings();
System.Printing.LocalPrintServer localPrintServer = new System.Printing.LocalPrintServer();
System.Printing.PrintTicket pt = new System.Printing.PrintTicket();
System.Printing.PrintQueue pq = new System.Printing.PrintQueue(localPrintServer, printer.PrinterName, System.Printing.PrintSystemDesiredAccess.AdministratePrinter);
System.Printing.PageMediaSize PMS = new System.Printing.PageMediaSize(canvas.ActualWidth + 20, canvas.ActualHeight + 20);
System.Windows.Size pageSize = new System.Windows.Size(canvas.ActualWidth+20, canvas.ActualHeight+20);
canvas.Arrange(new Rect(0, 0, pageSize.Width, pageSize.Height));
canvas.Measure(pageSize);
pt.PageMediaSize = PMS;
pt.PageMediaType = System.Printing.PageMediaType.Unknown;
pq.DefaultPrintTicket.PageMediaSize = PMS;
pq.DefaultPrintTicket.PageMediaType = System.Printing.PageMediaType.Unknown;
printDialog.PrintQueue = pq;
printDialog.PrintTicket = pt;
printDialog.PrintQueue.Commit();
if (printDialog.ShowDialog() == true)
{
printDialog.PrintVisual(canvas, "Test");
}

Related

How to center MDI child Form?

I have this code, to add a new child:
private void Menu1_Click(object sender, RoutedEventArgs e)
{
Point centerPoint = new Point((Container.ActualWidth / 2) - (500/2), (Container.ActualHeight / 2) - (400 / 2));
MdiChild newForm = new MdiChild();
newForm.Title = "My Form";
newForm.Content = new MyForm1();
newForm.Width = 500;
newForm.Height = 400;
newForm.Resizable = false;
newForm.MaximizeBox = false;
newForm.Position = centerPoint;
Container.Children.Add(newForm);
}
This code is for the view:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
xmlns:mdi="clr-namespace:WPF.MDI;assembly=WPF.MDI"
Title="WPF.MDI Example" Height="362" Width="684" WindowState="Maximized">
<DockPanel>
<mdi:MdiContainer Name="Container" Background="#FF474040" >
<mdi:MdiContainer.Menu>
<Menu DockPanel.Dock="Top" Width="677">
<MenuItem Header="Menu1" click="Menu1_Click">
</mdi:MdiContainer.Menu>
</mdi:MdiContainer>
</DockPanel>
How can I center MDI child Form?
It always opens in the upper left side
I don't find the solution yet,
Thanks.
I also tried to put this code, in the code behind form child, but it doesn't works:
public partial class MyForm1: UserControl
{
BalanceEntities db = new BalanceEntities();
public MyForm1()
{
InitializeComponent();
this.HorizontalAlignment = HorizontalAlignment.Center;
this.VerticalAlignment = VerticalAlignment.Center;
}
}
You should use WindowStartupLocation property of the Window like this:
private void Menu1_Click(object sender, RoutedEventArgs e)
{
Point centerPoint = new Point((Container.ActualWidth / 2) - (500/2), (Container.ActualHeight / 2) - (400 / 2));
MdiChild newForm = new MdiChild();
newForm .Title = "My Form";
//The code omitted for the brevity
newForm.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
Container.Children.Add(newForm);
}
OR:
this.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
Thanks for James Thorpe, I solve my problem at this way:
private void Menu1_Click(object sender, RoutedEventArgs e)
{
MdiChild newForm = new MdiChild();
newForm.Title = "My Form";
newForm.Content = new MyForm1();
newForm.Width = 500;
newForm.Height = 400;
newForm.Resizable = false;
newForm.MaximizeBox = false;
Container.Children.Add(newForm);
// And then I add the position:
Point centerPoint = new Point((Container.ActualWidth / 2) - (newForm.Width / 2), (Container.ActualHeight / 2) - (newForm.Height / 2));
newForm.Position = centerPoint;
}
Thanks for the help.
Do the following , it worked for me
newForm.StartPosition = FormStartPosition.CenterScreen;

Print the entire area of the control with C#

This is not a duplicat question- the diffenece beetween my question an the others one is my Controler contail a scroller, so they are more informations can't be printed.
I have a C# application that contains a main form name MainForms. This MainForms has a control mainDisplay. I want to print the entire information what we found on the mainDisplay to the printer.
The problem is the information on the the control is too big, and I have to scroll to see all information.
Someone have any function that allow me to print this control MainDisplay with entire information in it?
This the printscreen of the area of my MainDisplay at the right you see the scrollbar:
I use this Function (Source : Printing a control)
private static void PrintControl(Control control)
{
var bitmap = new Bitmap(control.Width, control.Height);
control.DrawToBitmap(bitmap, new Rectangle(0, 0, control.Width, control.Height));
var pd = new PrintDocument();
pd.PrintPage += (s, e) => e.Graphics.DrawImage(bitmap, 100, 100);
pd.Print();
}
But my problem still can't print all the informations contain in my control, it's just print a small erea, still need print more informations which are not printed.
I find the solution. This is the steps i do :
1 - We have a mainForm, and this main form contain a control mainDisplay with a specific dimension and area, let's say this dimensions is smaller and we get scroll.
2- What i do is i make this mainDisplay Empty.
3- i create an other Control myControlToDisplay. I draw and i put all fields i want without scroll, so this one myControlToDisplay will have a big dimension.
4- on the star-up of my application, i tell to the mainDisplay to load myControlToDisplay. This time all the content of myControlToDisplay will be display on mainDisplay with a scroll. Because mainDisplay have a small area.
5- I write this functions :
Bitmap MemoryImage;
PrintDocument printDoc = new PrintDocument();
PrintDialog printDialog = new PrintDialog();
PrintPreviewDialog printDialogPreview = new PrintPreviewDialog();
Control panel = null;
public void Print(Control pnl)
{
DateTime saveNow = DateTime.Now;
string datePatt = #"yyyy-M-d_hh-mm-ss tt";
panel = pnl;
GetPrintArea(pnl);
printDialog.AllowSomePages = true;
printDoc.PrintPage += new PrintPageEventHandler(Print_Details);
printDialog.Document = printDoc;
printDialog.Document.DocumentName = "Document Name";
//printDialog.ShowDialog();
if (printDialog.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
public void PrintPreview(Control pnl)
{
DateTime saveNow = DateTime.Now;
string datePatt = #"yyyy-M-d_hh-mm-ss tt";
panel = pnl;
GetPrintArea(pnl);
printDoc.PrintPage += new PrintPageEventHandler(Print_Details);
printDialogPreview.Document = printDoc;
printDialogPreview.Document.DocumentName = "Document Name";
//printDialog.ShowDialog();
if (printDialogPreview.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
private void Print_Details(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
RectangleF marginBounds = e.MarginBounds;
DateTime saveNow = DateTime.Now;
string datePatt = #"M/d/yyyy hh:mm:ss tt";
//String dtString = saveNow.ToString(datePatt);
// create header and footer
string header = "Put all information you need to display on the Header";
string footer = "Print date : " + saveNow.ToString(datePatt);
Font font = new Font("times new roman", 10, System.Drawing.FontStyle.Regular);
Brush brush = new SolidBrush(Color.Black);
// measure them
SizeF headerSize = e.Graphics.MeasureString(header, font);
SizeF footerSize = e.Graphics.MeasureString(footer, font);
// draw header
RectangleF headerBounds = new RectangleF(marginBounds.Left-80, marginBounds.Top-80, marginBounds.Width, headerSize.Height);
e.Graphics.DrawString(header, font, brush, headerBounds);
// draw footer
RectangleF footerBounds = new RectangleF(marginBounds.Left-80, marginBounds.Bottom - footerSize.Height+80, marginBounds.Width, footerSize.Height);
e.Graphics.DrawString(footer, font, brush, footerBounds);
// dispose objects
font.Dispose();
brush.Dispose();
}
public void GetPrintArea(Control pnl)
{
MemoryImage = new Bitmap(pnl.Width, pnl.Height);
Rectangle rect = new Rectangle(0, 0, pnl.Width, pnl.Height);
pnl.DrawToBitmap(MemoryImage, new Rectangle(0, 0, pnl.Width, pnl.Height));
}
protected override void OnPaint(PaintEventArgs e)
{
if (MemoryImage != null)
{
e.Graphics.DrawImage(MemoryImage, 0, 0);
base.OnPaint(e);
}
}
void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
{
Rectangle pageArea = e.PageBounds;
Rectangle m = e.MarginBounds;
if ((double)MemoryImage.Width / (double)MemoryImage.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)MemoryImage.Height / (double)MemoryImage.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)MemoryImage.Width / (double)MemoryImage.Height * (double)m.Height);
}
e.Graphics.DrawImage(MemoryImage, m);
}
6 -And finally we suppose that we have two buttons, one to Print and the other one to print preview.
You just have to call this function :
private void PrintButton_Click(object sender, EventArgs e)
{
try
{
Print(mainDisplay.getCurentPanel());
}
catch (Exception exp)
{
MessageBox.Show("Error: \n" + exp.Message);
}
}
private void PrintPreviewButton_Click(object sender, EventArgs e)
{
try
{
PrintPreview(mainDisplay.getCurentPanel());
}
catch (Exception exp)
{
MessageBox.Show("Error: \n" + exp.Message);
}
}
Hope it will help someone :)
good luck

Print WPF in Letter size

I try to print a letter for making a simple letter merge application.
But I'm struggled on how to set the printer options within WPF and .NET 4.
Here's my code:
private void button_Print_Click(object sender, RoutedEventArgs e)
{
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
pd.PrintTicket.PageOrientation = PageOrientation.Landscape;
pd.PrintTicket.PageMediaSize = new PageMediaSize(865, 612);
pd.PrintVisual(canvas_Letter, "Letter Canvas");
}
}
In the PrintDialog I choose the MP tray, which is feeded with letters of C5 size. Its printing my WPF, but not with the correct positions of the elements. Its like the Margin detects the paper size of a A4 paper.
Even if I choose paper size of C5 in the PrintDialog, the print is still out of bounds.
Any idea how to fit the size of C5 to my visual print? It seems like my pd.PrintTicket.PageMediaSize set to 865px width and 612px height doesn't work :/
Not sure if I'm understanding your question right. Do you want to print out your canvas_Letter adjusted to the selected paper size?
In this case I think you have to use the 'PrintCapabilities' and further you have to call Measure() and Arrange() on your canvas_Letter.
Something like this:
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
Rect printableArea = GetPrintableArea(printDlg);
// I'm using here a viewbox for easily adjust the canvas_Letter to the desired size
Viewbox viewBox = new Viewbox { Child = canvas_Letter };
viewBox.Measure(printableArea.Size);
viewBox.Arrange(printableArea);
printDlg.PrintVisual(viewBox, "Letter Canvas");
}
private static Rect GetPrintableArea(PrintDialog printDialog)
{
PrintCapabilities cap;
try
{
cap = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
}
catch (PrintQueueException)
{
return Rect.Empty;
}
if (cap.PageImageableArea == null)
{
return Rect.Empty;
}
var leftMargin = cap.OrientedPageMediaWidth.HasValue ? (cap.OrientedPageMediaWidth.Value - cap.PageImageableArea.ExtentWidth) / 2 : 0;
var topMargin = cap.OrientedPageMediaHeight.HasValue ? (cap.OrientedPageMediaHeight.Value - cap.PageImageableArea.ExtentHeight) / 2 : 0;
var width = cap.PageImageableArea.ExtentWidth;
var height = cap.PageImageableArea.ExtentHeight;
return new Rect(leftMargin, topMargin, width, height);
}

C# How to create a label onClick on a canvas

What I am looking for is for the user to
1. click on the canvas
2. a new label show up and the user can enter text.
3. When the user clicks elsewhere or hit enter the labels is finished editing.
This is what I have so far...
private void DrawingCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
var canvas = (Canvas)sender;
var point = e.GetPosition(canvas);
Label lbl = new Label();
lbl.Content = "start typing";
//lbl.Left = location.X;
//lbl.Top = location.Y;
//lbl.Focus = Boolean.TrueString;
canvas.Children.Add(lbl);
}
Any help would be greatly appreciated, thanks!
Try like this
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas x:Name="cnvs" PreviewMouseLeftButtonUp="cnvs_MouseLeftButtonUp" Background="Transparent"></Canvas>
private void cnvs_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var canvas = (Canvas)sender;
var point = e.GetPosition(canvas);
TextBox txtBox = new TextBox() {Width=80,AcceptsReturn=false };
canvas.Children.Add(txtBox);
Canvas.SetLeft(txtBox, point.X);
Canvas.SetTop(txtBox, point.Y);
txtBox.Focus();
}
I hope this will help.
UPDaTE:
var canvas = (Canvas)sender;
var point = e.GetPosition(canvas);
TextBox txtBox = new TextBox() {AcceptsReturn=false ,BorderThickness=new Thickness(0)};
Binding b = new Binding("Text") { RelativeSource = new RelativeSource(RelativeSourceMode.Self) };
txtBox.SetBinding(TextBox.WidthProperty, b);
canvas.Children.Add(txtBox);
Canvas.SetLeft(txtBox, point.X);
Canvas.SetTop(txtBox, point.Y);
txtBox.Focus();
Try setting the textbox width to Double.NaN. This will give you an "Auto" width. To get rid of the border, set the textbox's borderthickness to 0. See below:
private void cnvs_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var canvas = (Canvas)sender;
var point = e.GetPosition(canvas);
var txtBox = new TextBox() { Width=Double.NaN, AcceptsReturn=false }; // auto width
txtBox.BorderThickness = new Thickness(0); // no border
canvas.Children.Add(txtBox);
Canvas.SetLeft(txtBox, point.X);
Canvas.SetTop(txtBox, point.Y);
txtBox.Focus();
}

Panel in a panel, autoscroll

I'm doing a minimalist test app after encountering an issue with my real program, using WinForms. I put a small panel (child) inside a bigger panel (parent). The bigger panel has AutoScroll set to true. The child panel has the default Anchors set to Top and Left. The child panel is not docked.
The behavior I want is for scrollbars to appear whenever the smaller panel's location is too offset, either top, bottom, left or right. The problem is that it only works when it's too far right, or too far in the bottom. No scrollbars appear when it's too much in the top or too much in the left directions.
I use two simple buttons to force the child panel's location 200 pixels to the left, or 200 pixels to the right to have a quick way of easily modifying its position.
Here's my Form1() code:
private void button1_Click(object sender, EventArgs e)
{
childPanel.Location = new Point(childPanel.Location.X - 200, childPanel.Location.Y);
hostPanel.Invalidate();
}
private void button2_Click(object sender, EventArgs e)
{
childPanel.Location = new Point(childPanel.Location.X + 200, childPanel.Location.Y);
hostPanel.Invalidate();
}
Here's the designer code:
private void InitializeComponent()
{
this.hostPanel = new System.Windows.Forms.Panel();
this.childPanel = new System.Windows.Forms.Panel();
this.moveChildLeft = new System.Windows.Forms.Button();
this.moveChildRight = new System.Windows.Forms.Button();
this.hostPanel.SuspendLayout();
this.SuspendLayout();
//
// hostPanel
//
this.hostPanel.AutoScroll = true;
this.hostPanel.BackColor = System.Drawing.SystemColors.AppWorkspace;
this.hostPanel.Controls.Add(this.childPanel);
this.hostPanel.Location = new System.Drawing.Point(239, 48);
this.hostPanel.Name = "hostPanel";
this.hostPanel.Size = new System.Drawing.Size(400, 400);
this.hostPanel.TabIndex = 0;
//
// childPanel
//
this.childPanel.BackColor = System.Drawing.SystemColors.ButtonHighlight;
this.childPanel.Location = new System.Drawing.Point(29, 62);
this.childPanel.Name = "childPanel";
this.childPanel.Size = new System.Drawing.Size(342, 259);
this.childPanel.TabIndex = 0;
//
// moveChildLeft
//
this.moveChildLeft.Location = new System.Drawing.Point(61, 81);
this.moveChildLeft.Name = "moveChildLeft";
this.moveChildLeft.Size = new System.Drawing.Size(75, 23);
this.moveChildLeft.TabIndex = 1;
this.moveChildLeft.Text = "Left 200";
this.moveChildLeft.UseVisualStyleBackColor = true;
this.moveChildLeft.Click += new System.EventHandler(this.button1_Click);
//
// moveChildRight
//
this.moveChildRight.Location = new System.Drawing.Point(61, 111);
this.moveChildRight.Name = "moveChildRight";
this.moveChildRight.Size = new System.Drawing.Size(75, 23);
this.moveChildRight.TabIndex = 2;
this.moveChildRight.Text = "Right 200";
this.moveChildRight.UseVisualStyleBackColor = true;
this.moveChildRight.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1018, 549);
this.Controls.Add(this.moveChildRight);
this.Controls.Add(this.moveChildLeft);
this.Controls.Add(this.hostPanel);
this.Name = "Form1";
this.Text = "Form1";
this.hostPanel.ResumeLayout(false);
this.ResumeLayout(false);
}
Yet - Another Winforms incapability quickly solved by WPF:
XAML:
<Window x:Class="WpfApplication4.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" WindowState="Maximized">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button Content="Left" Click="MoveLeft"/>
<Button Content="Right" Click="MoveRight"/>
</StackPanel>
<Border BorderBrush="Blue" BorderThickness="1" Width="300" Height="300">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" x:Name="Scr">
<Grid Background="Green" Width="100" Height="100" x:Name="Grid"/>
</ScrollViewer>
</Border>
</DockPanel>
</Window>
Code behind:
using System.Windows;
namespace WpfApplication4
{
public partial class Window3 : Window
{
public Window3()
{
InitializeComponent();
}
private void MoveRight(object sender, RoutedEventArgs e)
{
if (Grid.Margin.Right <= 0)
{
Grid.Margin = new Thickness(Grid.Margin.Left + 100,0,0,0);
}
else
{
Grid.Margin = new Thickness(0, 0, Grid.Margin.Right - 100, 0);
Scr.ScrollToHorizontalOffset(Scr.HorizontalOffset - 100);
}
}
private void MoveLeft(object sender, RoutedEventArgs e)
{
if (Grid.Margin.Left > 0)
{
Grid.Margin = new Thickness(Grid.Margin.Left - 100, 0, 0, 0);
}
else
{
Grid.Margin = new Thickness(0, 0, Grid.Margin.Right + 100, 0);
Scr.ScrollToHorizontalOffset(Scr.HorizontalOffset + 100);
}
}
}
}
Copy and paste my code in a File -> New -> WPF Application and see the results for yourself.
Eventually, you might want to convert your app to WPF. Since, Winform is condemned to a small death.

Categories

Resources