Reputation: 611
I have a TableLayoutPanel (tlp) with rows. I add rows manually with a button. Every row which I created below the last one, has a button that will remove the row from tlp. Here is the code:
private void btnTSatirEkle_Click(object sender, EventArgs e)
{
tlpTDersRows = tlpTDers.RowCount;
tlpTDers.RowCount++;
DateTimePicker dtp = new DateTimePicker();
dtp.Name = "dtpTR" + (tlpTDersRows).ToString();
DateTimePicker dtp2 = (DateTimePicker)tlpTDers.Controls["dtpTR" + (tlpTDersRows - 1).ToString()];
dtp.Value = dtp2.Value.AddDays(1);
dtp.Dock = DockStyle.Fill;
tlpTDers.Controls.Add(dtp, 0, tlpTDersRows);
ComboBox comb = new ComboBox();
comb.Name = "cbxTR" + (tlpTDersRows).ToString();
comb.Dock = DockStyle.Fill;
comb.Items.AddRange(devamDur);
tlpTDers.Controls.Add(comb, 1, tlpTDersRows);
TextBox txtr = new TextBox();
txtr.Name = "txtTR" + (tlpTDersRows).ToString();
txtr.Dock = DockStyle.Fill;
txtr.Multiline = true;
tlpTDers.Controls.Add(txtr, 2, tlpTDersRows);
oldX = btnTSatirEkle.Location.X;
oldY = btnTSatirEkle.Location.Y;
Button buttonNew = new Button();
buttonNew.Name = "btnDelTR" + (tlpTDersRows - 1).ToString();
buttonNew.Text = "-";
buttonNew.Location = new Point(oldX, oldY);
buttonNew.Size = btnTSatirEkle.Size;
this.Controls.Add(buttonNew);
buttonNew.Click += new EventHandler(SatirSil); //I get error here, even I write SatirSil(sender, e, tlpTDersRows - 1)..
btnTSatirEkle.Location = new Point(644, tlpTDers.Controls["dtpTR" + tlpTDersRows.ToString()].Location.Y + 12);
tlpTDersRows++;
}
private void SatirSil(object sender, EventArgs e, int rowNo)
{
//codes
}
I want to send the row number as parameter to SatirSil method (which will be called when I click on buttonNew_Click event).
Any ideas?
Upvotes: 3
Views: 233
Reputation: 30882
The Button.Click
event is defined as
public event EventHandler Click
where EventHandler
is defined by
public delegate void EventHandler(Object sender, EventArgs e);
This means that for a method to be assignable as a handler for an event, it must have the exact signature defined by a delegate, i.e. it must take two parameters, an object
and an EventArgs
instance, and it must return void
. The signature of your SatirSil
method
void SatirSil(object sender, EventArgs e, int rowNo)
does not match, because it has an additional integer parameter. As mentioned in the other answers, you have two common solutions to this problem:
Somehow embed the extra parameter in the sender
parameter, because the EventArgs
by itself is pretty much useless. Since most of the time the sender parameter will in fact be a Control
object, it is common to use the Control.Tag
property to store extra data about the sender, that will be taken out by the handler and used as required. That will look like:
Button buttonNew = new Button();
...
buttonNew.Tag = (tlpTDersRows - 1);
buttonNew.Click = SatirSil;
....
void SatirSil(object sender, EventArgs e)
{
int rowNumber = (int)(sender as Control).Tag;
//rest of code
}
Somehow create a specialized version of the handler that will have the row number "hardcoded". Starting from C# 3.0 this is relatively easy to accomplish using the lambda syntax, that generates an inline "method" for you, e.g.
EventHandler handler = (sender, e) => {...code here ...}
is code that creates a delegate instance called "handler" that you can attach to an event, using
someButton.Click += handler;
or you can even invoke, using
handler(senderValue, eValue);
Note that the "...code here..." block is still contained in the original method where you write the declaration, so whatever is accessible to the method, is accessible to the body of the lambda expression. Knowing that you can make a separate handler for each button using code like:
Button buttonNew = new Button();
...
buttonNew.Click = (_, __) => SatirSil(rowNumber);
//if you do not care about parameters,
//it's customary to use _, __, etc for the names
//instead of the more verbose
//buttonNew.Click = (sender, e) => SatirSil(rowNumber);
....
void SatirSil(int rowNumber)
{
//actual implementation
}
I personally prefer the second option, because it neatly separated the code that is concerned with the creation and wire-up of the button, from the code that does the actual work. For example, if the SatirSil
method was needed in another part of the code, the calls would respectively be:
Control dummy = new Control();
dummy.Tag = myRowNumber;
SatirSil(dummy, null);
vs
SatirSil(myRowNumber);
Upvotes: 2
Reputation: 9322
Change:
buttonNew.Click += new EventHandler(SatirSil);
to
buttonNew.Click += new EventHandler((snd, ev)=>SatirSil(snd,ev,rowno));
or using your own variable (i.e. tlpTDersRows
) it could be like this:
buttonNew.Click += new EventHandler((snd, ev)=>SatirSil(snd,ev,tlpTDersRows-1));
Upvotes: 2
Reputation: 609
There is no way that you can modify the delgate signature for Button click event which was defined already. If you do what you're trying to do then you will get compiler error. How you can achieve in other way is while creating the button name , append it with the row number , so that in the event handler you can cast the sender object to button and get the name and extract the row number from it.
buttonNew.Name = "btnDelTR_" + rowNumber
private void SatirSil(object sender, EventArgs e, int rowNo)
{
int rowNo = //split the string to get the number.
}
Upvotes: 0
Reputation: 6717
The button is the sender
of your event. So if you store your row number in the Tag
property of your button, like so:
buttonNew.Tag = tlpTDersRows;
you could then do something like:
private void SatirSil(object sender, EventArgs e)
{
Button button = (Button)sender;
int rowNo = (int)button.Tag;
// ... delete row here.
}
Upvotes: 1
Reputation: 4737
How about:
Button buttonNew = new Button();
buttonNew.Name = "btnDelTR" + (tlpTDersRows - 1).ToString();
buttonNew.Text = "-";
buttonNew.Location = new Point(oldX, oldY);
buttonNew.Size = btnTSatirEkle.Size;
this.Controls.Add(buttonNew);
buttonNew.Tag = tlpTDersRows - 1;
buttonNew.Click += SatirSil;
private void SatirSil(object sender, EventArgs e)
{
//codes
var btn = (Button)sender;
var row = (int)btn.Tag;
}
Upvotes: 0
Reputation: 4526
I got one idea:
buttonNew.Click += new EventHandler((sender,args)=>SatirSil(sender,args,rowNo));
This way you'll still be setting buttonNew.Click
with a compatible EventHandler
, but the body of the anonymous method will be using your method SatirSil
which uses your row number as a parameter.
Upvotes: 1