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

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.

Related

How can i call a flowLayoutPanel to remove a button control via name, that was is nested inside that same flowLayoutPanel

class RTB
{
Form1 f = new Form1();
Button bt = new Button();
RichTextBox r = new RichTextBox();
public RichTextBox addPanel(string Task)
{
bt.Text = "X";
bt.Click += new EventHandler(btnButton_Click);
r.Controls.Add(bt);
return r;
}
void btnButton_Click(object sender, EventArgs e)
{
f.rem(r.Name);
}
}
class Form1 : Form
{
public void rem(string name)
{
flowLayoutPanel1.Controls.RemoveByKey(name);
}
}
In the RTB class, I am creating a RichRextBox, that contains a button control, and adding the Richtexbox with the button straight into a FlowLayoutPanel,
the button is subscribed to btnButton_Click so when it is clicked it will run f.rem(r.Name).
now when I click the button inside the RichTextBox to remove it from the FlowLayoutPanel it doesn't work. Any help will be greatly appreciated.
Note: I am able to create and add them to the FlowLayoutPanel, I did not include that code because i think it is irrelevant to this specific problem.
you need to assign name for RichTextBox that you need to remove at create
RichTextBox r = new RichTextBox();
r.Name = "Any_Unique_Name";
or other way without use ram function :
void btnButton_Click(object sender, EventArgs e)
{
//delete parent of clicked `Button` will be target `RichTextBox`
((Button)sender).Parent.Dispose();
}
You have the r variable available to you in the button click handler. You can simplify even more with an anonymous handler:
btn.Click += new EventHandler((s, e) => {
r.Dispose();
});
Now the control will disappear when the button is clicked.

Multiple message box showing in 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();
}

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).

C# mouse event for class object

First - I'm a graphics designer - not a programmer :/
I'm trying create simple aplication (C# windows Form application) with option to add some objects (PictureBox) and allow user to drag those PicturesBoxes on form (change their positon after adding to form).
I can do it for one PictureBox, but can't add function to all dinamic created objects :/
I have something like that for standard Picturebox4
public bool moveDetect = false;
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
private void pictureBox4_MouseUp(object sender, MouseEventArgs e)
{
if (moveDetect)
{
Point pozycja = new Point();
this.Cursor = new Cursor(Cursor.Current.Handle);
pozycja = this.PointToClient(Cursor.Position);
pictureBox4.Location = pozycja;
}
}
Does anyone know any tutorial showing how to add function like above to my simple class "myPictureBox : Picturebox"
My class is:
class myPictureBox : PictureBox
{
public bool moveDetect = false;
// constructor
public myPictureBox(int w, int h, string name)
{
this.Width = w;
this.Height = h;
this.Image = Image.FromFile("../../Resources/" + name + ".png");
Debug.WriteLine("Created ...");
}
}
Constructor works good and show "Created..." in output. Cant add function to all objects :/
Thanks and Regards ;)
If I understand correctly, your code works fine with the event handlers MouseUp and MouseDown when you are working with PictureBoxes that you create at design time using the designer.
You can add these same event handlers to controls that are created dynamically when you instantiate them:
MyPictureBox dynamicPicBox = new MyPictureBox(800, 600, "JustATest");
dynamicPicBox.MouseDown += pictureBox_MouseDown;
this adds an event handler that maps to the method pictureBox_MouseDown
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
Since your custom class is derived from PictureBox, it should recognize this type of event handler.

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
}

Categories