Multiple message box showing in c# - c#

I am making a one form application and created a hard coded class for my GUI and event handlers.
At first the messagebox is showing once but when I click another button it is showing multiple times, increasing every click of a button.
I have not yet created a unhandled exception is that something to do with that? And if it is unhandled exception how can I do it?
private void btnInventoryAddFanbelt_click(object sender, EventArgs e)
{
// CONTENTS
// labels
lblFanbeltName.Name = "lblFanbeltName";
lblFanbeltName.Text = "Fanbelt name";
lblFanbeltName.Visible = true;
lblFanbeltName.Location = new Point(10, 10);
// textbox
txtFanbeltName.Name = "txtFanbeltName";
txtFanbeltName.Visible = true;
txtFanbeltName.Location = new Point(115, 8);
// buttons
btnInventorySaveFanbelt.Name = "btnInventorySaveFanbelt";
btnInventorySaveFanbelt.Text = "Add fanbelt";
btnInventorySaveFanbelt.Visible = true;
btnInventorySaveFanbelt.Location = new Point(125, 50);
// END OF CONTENTS
// REMOVE CONTROLS
split3.Panel2.Controls.Clear();
// ADD CONTROLS
split3.Panel2.Controls.Add(lblFanbeltName);
split3.Panel2.Controls.Add(txtFanbeltName);
split3.Panel2.Controls.Add(btnInventorySaveFanbelt);
// EVENTHANDLERS
btnInventorySaveFanbelt.Click += new EventHandler(btnInventorySaveFanbelt_click);
}
private void btnInventorySaveFanbelt_click(object sender, EventArgs e)
{
MessageBox.Show("Fanbelt added");
}

Every time you click on btnInventoryAddFanbelt, you are adding another click event:
btnInventorySaveFanbelt.Click += new EventHandler(btnInventorySaveFanbelt_click);
Only add it once, usually best to do that in the constructor or through the designer. It can also be shortened to just:
btnInventorySaveFanbelt.Click += btnInventorySaveFanbelt_click;
Also, split3.Panel2.Controls.Clear(); does not dispose of the controls, it just removes them, so you are leaking memory here. Try using:
while (split3.Panel2.Controls.Count > 0) {
split3.Panel2.Controls[0].Dispose();
}

Related

C# Event Handler is called multiple times when selecting a menu item

I want to implement some Pictureboxes and when one of them is clicked, a MessageBox should appear and tell which Box is clicked.
However, I want to implement a choice how many Pictureboxes should appear. When I choose another MenuItem, then the click event will be called multiple times. I tried unsubscribing, but it doesn't work.
Here is my code:
public partial class Form1 : Form
{
PictureBox Pbox1;
PictureBox Pbox2;
PictureBox Pbox3;
PictureBox Pbox4;
public Form1()
{
InitializeComponent();
this.Text = "Picturebox";
Pbox1 = new PictureBox();
Pbox2 = new PictureBox();
Pbox3 = new PictureBox();
Pbox4 = new PictureBox();
}
private void Pbox_Click(object sender, EventArgs e, int nr)
{
MessageBox.Show("Picture number " + nr.ToString() + " is clicked");
}
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
Pbox1.Image = new Bitmap(#"Picture.png");
Pbox1.Location = new Point(20, 40);
Pbox1.Size = new Size(160, 120);
Pbox1.SizeMode = PictureBoxSizeMode.StretchImage;
Pbox1.Click += (sender2, e2) => Pbox_Click(sender2, e2, 1);
this.Controls.Add(Pbox1); }
The rest is the same as toolStripMenuItem2.
Can you help me with this problem?
When will it be called multiple times? I guess when switching to another menu item everything should work fine. But when switching back to an item that was already clicked before, then another click handler will be registered in addition to the existing one and will call the Pbox_Click method twice.
You can try to put the event registration in the constructor method or release other click-events before re-registering them.

Datagridview shall disappear when clicking on the Form in the background

As described in the title, I have a Form with a Datagridview on the front. The datagridview is smaller than my form in the back and I want the Datagridview to disappear whenever I click anywhere else but the Datagridview.
My code looks like this:
this.dataGridView1.Leave += new System.EventHandler(this.focus);
and the Eventhandler is defined like this:
private void focus(object sender, EventArgs e)
{
if(dataGridView1.Focused == false)
{
dataGridView1.Visible = false;
}
}
My problem is that my Datagridview only disappears when a new event in my form is activated but not when I click for example in a textbox on my form.
Can anyone help me?
The Leave event will not raise if you click on Form, or a ToolStripButton, PictureBox or any other non-selectable control.
If you expect a behavior like a dropdown, you can host DataGridView in a ToolStripControlHost and show it using a ToolStripDropDown. This way when you click anywhere outside the `DataGridView, it will disappear. It will act like a dropdown menu. Also the grid can be larger than your form:
private void button1_Click(object sender, EventArgs e)
{
this.dataGridView1.Margin = new Padding(0);
var host = new ToolStripControlHost(this.dataGridView1);
this.dataGridView1.MinimumSize = new Size(200, 100);
host.Padding = new Padding(0);
var dropdown = new ToolStripDropDown();
dropdown.Padding = new Padding(0);
dropdown.Items.Add(host);
dropdown.Show(button1, 0,button1.Height);
}
Important Note: It's an example. It's better to pay attention to disposing of objects in a real world application. For example, use just a single ToolStripdropDown and dispose it when closing the form.
Change the event handler assigning to:
this.dataGridView1.Leave += new System.EventHandler(fokussiert);
Worked for me when focusing on a textbox
you want your dgv also to disapear when you click on your textbox? is that what you mean?
private void dataGridView1_Leave(object sender, EventArgs e)
{
dataGridView1.Visible = false;
}
private void Form1_Click(object sender, EventArgs e)
{
dataGridView1.Visible = false;
}

NullReferenceException dynamically created controls, object seems to exist

In Win Forms I have these three test methods. First to create a button, second to create a tab control with two tabs and third to move created button to first tab.
private void button1_Click(object sender, EventArgs e)
{
Button przycisk = new Button();
przycisk.Location = new Point(24, 250);
przycisk.Name = "nowy";
przycisk.Text = "utworzony";
przycisk.Width = 131;
przycisk.Height = 23;
Controls.Add(przycisk);
}
private void button2_Click(object sender, EventArgs e)
{
TabControl zakladki = new TabControl();
zakladki.Location = new Point(208, 160);
zakladki.Name = "zakl";
zakladki.Height = 150;
zakladki.Width = 208;
zakladki.TabPages.Add("zakladka1", "pierwsza");
zakladki.TabPages.Add("zakladka2", "druga");
Controls.Add(zakladki);
}
private void button3_Click(object sender, EventArgs e)
{
TabControl zakladki = (TabControl)Controls.Find("zakl", false).FirstOrDefault();
int numerZakladki = 1;
foreach (TabPage zakladka in zakladki.TabPages)
{
Control kt = Controls["nowy"];
kt.Location = new Point(10, 10); // System.NullReferenceException
zakladka.Controls.Add(kt);
numerZakladki++;
}
}
I'm having a hard time to understand the behavior upon trying to change the referenced button location. The code above throws System.NullReferenceException, but when I do
if (kt != null)
{
kt.Location = new Point(10, 10);
}
it works as expected. Can anyone explain it to me ?
The new TabControl contains two Tabs.
If you move the button to the first Tab, the control at the Main form is null.
Code without Loop:
private void button3_Click(object sender, EventArgs e)
{
TabControl zakladki = (TabControl)Controls.Find("zakl", false).FirstOrDefault();
Control kt = Controls["nowy"];
kt.Location = new Point(10, 10);
zakladki.TabPages[0].Controls.Add(kt);
}
Your nowy controls are added to the root control (Form I guess), but you are trying to find them in the tab pages under zakl. You have to either add the controls to the tab page, or find them in the root control, just like you did with zakl.
You move the "nowy" button from the Form.Controls to the first TabPage's Controls collection. This removes the control from the first collection, so the code throws the exception on the next iteration. A Control can have only a singleParent.
Either create the Button for each tab separately (instead of moving it), or add the Button to the first tab only (without the foreach loop).

Event handler for a dynamically added button

Code :
public partial class Form3 : Form
{
...
...
private void button1_Click(object sender, EventArgs e)
{
Panel p = new Panel();
TextBox diaryName = new TextBox();
Button b = new Button();
Label l = new Label();
diaryName.Font = new Font("Consolas", 12, FontStyle.Bold);
b.Font = buttonFont;
l.Font = buttonFont;
b.BackColor = Color.Wheat;
l.Text = "Diary Name : ";
b.Text = "Add Diary";
Point lbl = l.Location;
diaryName.Location = new Point(l.Location.X + l.Width + 5, lbl.Y);
Point txtbox = diaryName.Location;
b.Location = new Point(txtbox.X + diaryName.Width + 20, txtbox.Y);
p.Controls.Add(l);
p.Controls.Add(diaryName);
p.Controls.Add(b);
p.Location = new Point(12,272);
p.Size = new Size(20 + 20 + 20 + diaryName.Width + l.Width + b.Width, diaryName.Height);
// I need help here..
// b.Click += new EventHandler(); ???
this.Controls.Add(p);
this.Height += 50;
this.Width += 30;
this.FormBorderStyle = FormBorderStyle.Fixed3D;
}
...
}
The above code adds a panel that contains a label,a textBox and a button to the form , that's all working fine, my problem is that I want to handle click event of the dynamically added button (b) , In my event handling code I should be able to access the dynamically added TextBox (diaryName) for validation purposes, but I don't know how to do It. I tried adding another function within the same class Form3 , but since The textbox t is created within the button1_Click function, I am unable to access the textbox , so How can I get around this ?
I am new to c#, I have a Java background so is there any way in c# to declare event handlers like this
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
System.out.println("You clicked the button");
}
});
You can easy assign a handler to the button's event this way:
b.Click += new EventHandler(newButtonClick);
where
protected void newButtonClick(object sender, EventArgs e)
{
//Access your textbox like this
var myTextBox = this.Controls.OfType<TextBox>().FirstOrDefault(tb=>tb.Name == "diaryName");
if(myTextBox!=null)
{
//rest of your code here
}
}
However it's a poor practice. Your button will depend heavily on the objects created dynamically somewhere outside - that breaks encapsulation rule of OOP. Secondly - did you think what will happen if you'll click your original button (the one you showed your handler for) twice?
edit: When I've come to think about it, your method is not that dynamic really. It creates those controls on the fly, but they're not generic in any way - it's a static piece of code, that creates always the same result. So in this case I'd think about putting your new panel, textbox and button in the form as a public items and then initialize them inside your method.
It'd be even better to create them in the visual studio's designer already, hide them using Visible properties and then in button1_Click you could only change their sizes and show them up.
Ok, need to add event for button click,
1) So after you create new Button
Button b = new Button();
2) next add click event for that
b.Click += new EventHandler(b_Click);
3) and then write the actual function body for click event in your code
void b_Click(object sender, EventArgs e)
{
//Your code for click operation
}

Custom button in C#: How to remove hover background?

I'm trying to do a custom button to my form (which has FormBorderStyle = none) using Visual Studio 2005. I have my 3 states button images in an ImageList linked to the button.
this.btnClose.AutoSize = false;
this.btnClose.BackColor = System.Drawing.Color.Transparent;
this.btnClose.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
this.btnClose.FlatAppearance.BorderSize = 0;
this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnClose.ForeColor = System.Drawing.Color.Transparent;
this.btnClose.ImageKey = "Disabled";
this.btnClose.ImageList = this.imageList1;
this.btnClose.Location = new System.Drawing.Point(368, -5);
this.btnClose.Margin = new System.Windows.Forms.Padding(0);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(31, 31);
this.btnClose.TabIndex = 0;
this.btnClose.UseVisualStyleBackColor = false;
this.btnClose.MouseLeave += new System.EventHandler(this.btnClose_MouseLeave);
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
this.btnClose.MouseDown += new System.Windows.Forms.MouseEventHandler(this.btnClose_MouseDown);
this.btnClose.MouseHover += new System.EventHandler(this.btnClose_MouseHover);
private void btnClose_MouseHover(object sender, EventArgs e)
{
btnClose.ImageKey = "enabled";
}
private void btnClose_MouseDown(object sender, MouseEventArgs e)
{
btnClose.ImageKey = "down";
}
private void btnClose_MouseLeave(object sender, EventArgs e)
{
btnClose.ImageKey = "disabled";
}
All is working, but there's one catch. Whenever I move the mouse hover the button I get a really annoying grey background.
How can I remove that?
btnClose.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent;
The grey background is due to the setting of "System.Windows.Forms.FlatStyle.Flat", it's the default behaviour, since it need to highlight the button when you hover. To eliminate that, you might have to write a custom button class, inherit from the original button and do some custom painting to achieve that.
Btw, instead of setting "enabled" in MouseHover, you should do it in MouseEnter. MouseEnter and MouseLeave is a pair which indicate whether is the mouse is within the button or not, and it's fired once per entry/exit. Where as MouseHover is fire whenever the mouse moved within the button, which create unnessecery repeated setting of "enabled".
I've solved this using a label instead of a button.
//
// imageListButtons
//
this.imageListButtons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListButtons.ImageStream")));
this.imageListButtons.TransparentColor = System.Drawing.Color.Transparent;
this.imageListButtons.Images.SetKeyName(0, "close_normal");
this.imageListButtons.Images.SetKeyName(1, "close_hover");
//
// lblClose
//
this.lblClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.lblClose.BackColor = System.Drawing.Color.Transparent;
this.lblClose.ImageKey = "close_normal";
this.lblClose.ImageList = this.imageListButtons;
this.lblClose.Location = new System.Drawing.Point(381, 7);
this.lblClose.Margin = new System.Windows.Forms.Padding(0);
this.lblClose.Name = "lblClose";
this.lblClose.Size = new System.Drawing.Size(12, 12);
this.lblClose.TabIndex = 0;
this.lblClose.MouseLeave += new System.EventHandler(this.lblClose_MouseLeave);
this.lblClose.MouseClick += new System.Windows.Forms.MouseEventHandler(this.lblClose_MouseClick);
this.lblClose.MouseEnter += new System.EventHandler(this.lblClose_MouseEnter);
private void lblClose_MouseEnter(object sender, EventArgs e)
{
lblClose.ImageKey = "close_hover";
}
private void lblClose_MouseLeave(object sender, EventArgs e)
{
lblClose.ImageKey = "close_normal";
}
private void lblClose_MouseClick(object sender, MouseEventArgs e)
{
this.Close();
}
PS: notice that I'm using now a two state button, instead of three. It is intended (I know that I still can use three).
create Mouse Enter event which is given below.
private void forAllButtons_MouseEnter(object sender, EventArgs e)
{
Button b = (Button)sender;
b.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent;
}
then assign this event to all the buttons.
Happy programming :)
I have got one suggestion.Create your own button class deriving from Button.Then override the MouseEnter event in that.Just remove the code for calling the base implementaion.
base.OnMouseEnter(e)
PS: You won't be able to use the MouseEnter event outside the derived class (e.g. a project using this control)
Hi you simply can apply these changes to your button easily using these two lines of codes.
Set the button's FlatStyle to Flat
this.btnClose.FlatStyle = FlatStyle.Flat;
Set the button's MouseOverBackColor to Transparent
this.btnClose.FlatAppearance.MouseOverBackColor = Color.Transparent;
Hope this will help. Thanks
You can also stop changing color of button by deselecting IsHitTestVisible option in Button Properties>common> IsHitTestVisible
Maybe this can also help ...
To solve the problem, Set the MouseOverBackColor to transparent inorder to remove the grey backgroud.

Categories