Sertan Pekel
Sertan Pekel

Reputation: 611

define a parameter in event

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

Answers (6)

SWeko
SWeko

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

Edper
Edper

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

srsyogesh
srsyogesh

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

Jan Dörrenhaus
Jan Dörrenhaus

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

Davio
Davio

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

Conrad Clark
Conrad Clark

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

Related Questions