Prevent printing blank pages - c#

I just need to reset "border" after print previewing. I preview the page I wantted to print correctly but when I do printing it gives blank pages because "border" wasnt reset. Where should I put "border=0"?("border" is no. rows in a datagridview)
private void button5_Click(object sender, EventArgs e)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);
PrintPreviewDialog ppd = new PrintPreviewDialog();
ppd.Document = pd;
ppd.ShowDialog();
}
private void pd_PrintPage(object sender, PrintPageEventArgs e)
{
prntt(sender, e);
}
public void prntt(object sender, PrintPageEventArgs e)
{
for (; border < ViewA.RowCount; border++)
{
if (ustsin + yuk > e.MarginBounds.Bottom - 400f)
{
e.HasMorePages = true;
return;
}
texts = ViewA.Rows[border].Cells["Persons"].Value.ToString();
...
graphics.DrawString(texts, font, Brushes.Black, new RectangleF(e.MarginBounds.Left, ustsin, 115f, 90f));
...
float hoho = (float)e.Graphics.MeasureString(texts, font, 115, StringFormat.GenericTypographic).Height;
...
var mesele = new float[] { hoho, koko, moko };
float kapa = mesele.OrderByDescending(s => s).First();
ustsin += kapa + yuk;
}
e.HasMorePages = false;
}
if I can close when we press the print button in print preview, can I reset in its closing event?
edit: I did this, it seems to work but when I send it to xps, it shows 2 pages in the screen. like this http://i.imgur.com/a9KnkA0.png . How can I make this show 1 page?
private void printDocument1_EndPrint(object sender, PrintEventArgs e)
{
border = 0;
}

initially set it to 0 and reset it after ppd.ShowDialog();
ppd.ShowDialog();
border = 0;
UPDATE
Looks like PrintPreviewDialog doesn't support much as you (and many others expect), it's up to the user (not to programmer). You can try this a little hacky stuff:
//code in your button5_Click
ToolStripButton onePageButton = ((ToolStrip)ppd.Controls[1]).Items[3] as ToolStripButton;
BeginInvoke((Action)(() => onePageButton.PerformClick()));
ppd.ShowDialog();
UPDATE
To intercept the Clicking on the Print button, you have to add a little much more code. You have to detect the click before the Click is fired on the item (print button), show the message box asking for confirmation and re-click the item if user agrees. Here is the code for you:
//Use this class to add message interceptor into your ToolStrip message loop
public class NativeToolStrip : NativeWindow {
ToolStrip ts;
bool letClicked;
protected override void OnHandleChange() {
base.OnHandleChange();
Control c = Control.FromHandle(Handle);
ts = c as ToolStrip;
}
protected override void WndProc(ref Message m) {
if (m.Msg == 0x202&&!letClicked) {//WM_LBUTTONUP = 0x202
int x = m.LParam.ToInt32() & 0x00ff;
int y = m.LParam.ToInt32() >> 16;
ToolStripItem item = ts.GetItemAt(new Point(x, y));
//check if the first item (the Print Button) is clicked
if (item != null && ts.Items.IndexOf(item) == 0) {
if (MessageBox.Show("Do you want to print?", "Print confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
return;//discard message
else {
letClicked = true;
item.PerformClick();
}
}
}
base.WndProc(ref m);
if (letClicked) letClicked = false;
}
}
//This code should be done somewhere like in your form constructor
//BUT your PrintPreviewDialog should also be declared once in the form scope
//You can also place this in your button5_Click BUT it's not recommended
ToolStrip ts = (ToolStrip)ppd.Controls[1];
new NativeToolStrip().AssignHandle(ts.Handle);

Related

How to close a Print Preview Dialog?

I have a document printing function. I am trying to close the Print Preview Dialog form after the user presses the Print button. Once the print button in the print preview dialog is pressed, the event starts the function below to print the document. I am expecting the form to close when I call printPreviewDialog1.Close() but it just goes over the line and nothing happens.
But it doesn't close the print preview dialog form after the print job is done.
public void _start_Print(object sender, EventArgs e)
{
printDocument1.Print();
}
Added as requested in the comments. Initializing Print Preview Dialog
private void btnPrint_Click(object sender, EventArgs e)
{
PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog();
printPreviewDialog1.Document = printDocument1;
ToolStrip ts = new ToolStrip();
ts.Name = "wrongToolStrip";
foreach (Control ctl in printPreviewDialog1.Controls)
{
if (ctl.Name.Equals("toolStrip1"))
{
ts = ctl as ToolStrip;
break;
}
}
ToolStripButton printButton = new ToolStripButton();
ToolStripButton closeButton = new ToolStripButton();
foreach (ToolStripItem tsi in ts.Items)
{
if (tsi.Name.Equals("printToolStripButton"))
{
printButton = tsi as ToolStripButton;
}
else if (tsi.Name.Equals("closeToolStripButton")) // idk if this is the name of the close button im trying to programmatically close it after printing
{
closeButton = tsi as ToolStripButton;
}
}
ts.Items.Remove(printButton);
ToolStripButton b = new ToolStripButton();
b.ImageIndex = printButton.ImageIndex;
b.Visible = true;
ts.Items.Insert(0, b);
b.Click += new EventHandler(this._start_Print);
printPreviewDialog1.WindowState = FormWindowState.Maximized;
printPreviewDialog1.ShowDialog();
printPreviewDialog1.Dispose(); //< doesnt do anything
closeButton.PerformClick(); // < doesn't do anything, possibly using wrong name for toolstripbutton
}
Initializing Print Document as requested in the comments
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawRectange(Pens.Black, 60, 60, 60,60);
}
Solved.
I created a Global ToolStripButton and initialized this button with the closeToolStripButton in the printPreviewDialog.
Then I programmatically clicked this button after the print job was done.
private ToolStripButton closeButton = new ToolStripButton(); <-- global variable
private void btnPrint_Click(object sender, EventArgs e)
{
foreach (ToolStripItem tsi in ts.Items)
{
if (tsi.Name.Equals("closeToolStripButton"))
{
closeButton = tsi as ToolStripButton;
}
else if (tsi.Name.Equals("printToolStripButton"))
{
printButton = tsi as ToolStripButton;
}
}
ts.Items.Remove(printButton);
ToolStripButton b = new ToolStripButton();
b.ImageIndex = printButton.ImageIndex;
b.Visible = true;
ts.Items.Insert(0, b);
b.Click += new EventHandler(this._start_Printer); //<-- this starts the printer event where i "PerformClick() on the initialized closeButton"
printprevDialog.WindowState = FormWindowState.Maximized;
printprevDialog.ShowDialog();
}
public void _start_Printer(object sender, EventArgs e) // <--- then i just performed the close click here right after i hit the print button
{
printDocument1.Print();
closeButton.PerformClick(); // <-- this way im not violating cross thread operations
}

C# - How to find out which dynamic button was clicked?

I am writing a program where I dynamically add buttons, I do that by storing them in a Dictionary to get a certain value from them later on (the color of the background).
I need to set a Click event on every one of them, but every Click event has to be a little different, as by clicking the button, a ColorDialog pops up and changes the background of the button.
Is there a way to know which button I clicked? In the following code, the button1 click event adds the other buttons and sets the EventHandler for each of them, what should be the code for the EventHandler? Thank you so much in advance guys.
int i = 0;
Dictionary<int, Button> buttonDictionary = new Dictionary<int, Button>();
Dictionary<int, ColorDialog> colorsDictionary = new Dictionary<int ColorDialog>();
public void button1_Click(object sender, EventArgs e)
{
i++;
buttonDictionary.Add(i, new Button());
buttonDictionary[i].Click += new EventHandler(Click);
this.Controls.Add(buttonDictionary[i]);
}
public void Click(object sender, EventArgs e)
{
//Somehow get the int key of the button that was clicked???? (in this case: int j)
int j;
if (!colorsDictionary.ContainsKey(j))
{
colorsDictionary.Add(j, new ColorDialog());
}
if (colorsDictionary[j].ShowDialog() == DialogResult.OK)
{
buttonDictionary[j].BackColor = colorsDictionary[j].Color;
}
}
The code is made just for adding the buttons, I will be glad for any kind of help, thank you guys!
Well, a direct answer to your question is: cast the sender to a Button
Button pressedButton = (Button) sender;
and then check to which button of the dictionary it matches:
foreach (var entry in buttonDictionary)
{
if (entry.Value == pressedButton)
{
j = entry.Key;
break;
}
}
However, that's overly complex for what you want to achieve. It would be much easier if you had a direct relationship between the button and the color picker:
Dictionary<Button, ColorDialog> buttonDictionary = new Dictionary<Button, ColorDialog>();
Then fill it like this:
public void button1_Click(object sender, EventArgs e)
{
i++;
var button = new Button();
this.Controls.Add(button);
button.Click += new EventHandler(Click);
buttonDictionary.Add(button, null);
}
And later access it with
public void Click(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
ColorDialog dialog = buttonDictionary[pressedButton];
if (dialog == null)
{
dialog = new ColorDialog();
buttonDictionary[pressedButton] = dialog;
}
if (dialog.ShowDialog() == DialogResult.OK)
{
pressedButton.BackColor = dialog.Color;
}
}
Even more, the question is why you would need so many ColorDialgos, since it should be possible with one dialog only. You can get rid of i, j, all dictionaries and most handling as well. IMHO, the following should be sufficient:
public void button1_Click(object sender, EventArgs e)
{
var button = new Button();
Controls.Add(button);
button.Click += Click;
}
public void Click(object sender, EventArgs e)
{
Button pressedButton = (Button) sender;
ColorDialog dialog = new ColorDialog {Color = pressedButton.BackColor};
if (dialog.ShowDialog() == DialogResult.OK)
{
pressedButton.BackColor = dialog.Color;
}
}
Bonus info:
I don't exactly know what you want to achieve. But your buttons will all be in the same place, overlapping each other. To avoid this, drag a flow layout panel onto the form and then add the buttons to the flow layout:
flowLayoutPanel1.Controls.Add(button);
This will ensure that your buttons are nicely arranged.

ToolStripDropDown catches MouseeDown before underlying control

I have created my own ComboBox-like control where the dropdown part contains a tree. I have seen those solutions using an ordinary ComboBox and overwriting the WndProc, but there was always some odd behavior despite lots and lots of code. So I decided to make it simple: just a label with a ToolStripDropDown/ToolStripControlHost that is opened when mouse goes down on the label. The missing ComboBox triangle doesn't hurt.
Everything works perfectly, except one tiny thing: like with the stock ComboBox I would like the dropdown to hide when I click on the label again. But when I click on it, the dropdown hides for a split second, just to appear again. If I click outside the label, the dropdown just hides, like it should be.
public class RepoNodeComboBox: Label
{
RepoTreeView repoTreeView;
ToolStripControlHost treeViewHost;
ToolStripDropDown dropDown;
bool isDropDownOpen;
public int DropDownHeight;
public RepoNodeComboBox()
{
repoTreeView = new RepoTreeView();
repoTreeView.BorderStyle = BorderStyle.None;
repoTreeView.LabelEdit = false;
treeViewHost = new ToolStripControlHost(repoTreeView);
treeViewHost.Margin = Padding.Empty;
treeViewHost.Padding = Padding.Empty;
treeViewHost.AutoSize = false;
dropDown = new ToolStripDropDown();
dropDown.CanOverflow = true;
dropDown.AutoClose = true;
dropDown.DropShadowEnabled = true;
dropDown.Items.Add(treeViewHost);
dropDown.Closing += dropDownClosing;
TextAlign = ContentAlignment.MiddleLeft;
BackColor = SystemColors.Window;
BorderStyle = BorderStyle.FixedSingle;
DropDownHeight = 400;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (dropDown != null)
{
dropDown.Dispose();
dropDown = null;
}
}
base.Dispose(disposing);
}
// when mouse goes down on the label, this is executed first
void dropDownClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
// just to test if I can get more out of it than with dropdown.Visible
isDropDownOpen = false;
}
// this is subsidiary to the Closing event of the dropdown
protected override void OnMouseDown(MouseEventArgs e)
{
if (dropDown != null)
{
if (isDropDownOpen)
{
dropDown.Hide();
}
else
{
repoTreeView.Size = new Size(Width, DropDownHeight);
treeViewHost.Width = Width;
treeViewHost.Height = DropDownHeight;
dropDown.Show(this, 0, Height);
isDropDownOpen = true;
}
}
base.OnMouseDown(e);
}
}
As far as I can see (breakpoints), the dropdown catches the MOUSEDOWN event first in order to close itself. Only after that my label gets passed through the MOUSEDOWN event, and since it sees the dropdown is closed, it thinks the label has been clicked like for the first time - and opens the dropdown again.
So it seems the label has no chance of knowing if the MOUSEDOWN was the result of closing the dropdown item. I could open it every other event, but that would require no other closing events to happen.
Is there any way to make sure that an open dropdown item just closes even if I click on the label?
Try checking for the Mouse position when the floating host closes:
void dropDownClosing(object sender, CancelEventArgs e) {
isDropDownOpen = this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition));
}
On the MouseDown code, make sure to set isDropDownOpen to false in the true block:
protected override void OnMouseDown(MouseEventArgs e) {
if (dropDown != null) {
if (isDropDownOpen) {
isDropDownOpen = false;
dropDown.Hide();
} else {
isDropDownOpen = true;
repoTreeView.Size = new Size(Width, DropDownHeight);
treeViewHost.Width = Width;
treeViewHost.Height = DropDownHeight;
dropDown.Show(this, 0, Height);
}
}
base.OnMouseDown(e);
}

How to prevent contexmenustrip closing?

I have a listbox with unnumbered items and a contexmenustrip. I wrote this code ( I know it seems too primitive, because of my inexpertness) It works fine but I have a little problem.
I want to make cms open at near your mouse position when you click on an item in listbox. and It will be opened at previous position when you click on blank. It is ok but cms is reopening by your each click. Is it posible to make it stay open when you click on blank not an item?
public Form1()
{
InitializeComponent();
}
int a, b, tx, ty;
int mx=0;
private void listBox1_MouseClick(object sender, MouseEventArgs e)
{
b = a;
a = listBox1.SelectedIndex;
if (listBox1.SelectedIndex != -1)
{
if (a!= b)
{
contextMenuStrip1.Show(MousePosition.X + 10, MousePosition.Y);
tx = MousePosition.X;
ty = MousePosition.Y;
mx =1;
}
else if (a==0 && b==0 && mx== 0)
{
tx = MousePosition.X;
ty = MousePosition.Y;
contextMenuStrip1.Show(tx + 10, ty);
mx = 1;
}
else
{
contextMenuStrip1.Show(tx + 10, ty);
}
}
}
Use AutoClose property of ContextMenuStrip to prevent it automatically closing.
ContextMenuStrip cms = new ContextMenuStrip();
cms.AutoClose = false;
Then call Close method to manually close it
cms.Close();
Or handle the Closing event of contextmenustrip and set e.Cancel = true based on your condition
void cms_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
if(your condition)
{
e.Cancel = true;
}
}

Change ItemIndex in a Comobox when drop down list is open

In Compact Framework, I want to change the ItemIndex of a ComboBox when the drop down list is open. I am trying to change it from LostFocus or KeyPress events, and it seems to work, but when the drop down list is closed, the value returns to the original value.
For example:
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Tab)
return;
if (e.KeyChar == 'A')
{
e.Handled = true;
comboBox1.SelectedIndex = 2;
}
}
When I press A, effectively the item #2 is selected and the text, but when I move to th next control or simply close the drop-down list, the combobox changes the value the previous one.
Thank you
I just tried to replicate your issue (but running on FF) with the following code and it is working fine:
using System;
using System.Windows.Forms;
namespace combotest
{
class MainClass
{
public static void Main (string[] args)
{
WinForm form = new WinForm ();
Application.Run (form);
//Console.WriteLine("Hello World!");
}
}
public class WinForm : Form
{
public WinForm ()
{
InitializeComponent ();
}
ComboBox comboBox1;
TextBox textBox1;
private void InitializeComponent ()
{
this.Width = 400;
this.Height = 300;
this.Text = "My Dialog";
Button btnOK = new Button ();
btnOK.Text = "OK";
btnOK.Location = new System.Drawing.Point (10, 10);
btnOK.Size = new System.Drawing.Size (80, 24);
this.Controls.Add (btnOK);
btnOK.Click += new EventHandler (btnOK_Click);
comboBox1=new ComboBox();
comboBox1.Location = new System.Drawing.Point (10, 50);
comboBox1.Size = new System.Drawing.Size (80, 24);
comboBox1.DropDownStyle=ComboBoxStyle.DropDownList;
this.Controls.Add (comboBox1);
textBox1=new TextBox();
textBox1.Location = new System.Drawing.Point (100, 50);
textBox1.Size = new System.Drawing.Size (80, 24);
this.Controls.Add (textBox1);
this.SuspendLayout();
String[] iList=new String[]{"text0","text1","text2","text3","text4"};
comboBox1.Items.AddRange(iList);
comboBox1.SelectedIndex=0;
this.ResumeLayout();
comboBox1.KeyPress+=new KeyPressEventHandler(comboBox1_KeyPress);
}
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Tab)
return;
if (e.KeyChar.ToString().ToUpper() == "A")
{
e.Handled = true;
comboBox1.SelectedIndex = 2;
textBox1.Text=comboBox1.SelectedItem.ToString();
}
}
private void btnOK_Click (object sender, System.EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close ();
}
}
}
So I assume you are having some additional code or event attached to the comboBox or it really behaves different within FF.
You may test your app also running within FF by just going to the bin\Debug dir within your PC's file explorer and then start your SmartDevice application on the PC by double clicking the exe file. Normally (no special DLLs referenced) it should run on PC too as the CF is downside compatible to FF.
If you still have an issue please post a minimized code sample that demonstrates your issue.

Categories