3

我有一个带有行的 TableLayoutPanel (tlp)。我使用按钮手动添加行。我在最后一行下方创建的每一行都有一个按钮,可以从 tlp.xml 中删除该行。这是代码:

    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
    }

我想将行号作为参数发送给 SatirSil 方法(单击 buttonNew_Click 事件时将调用该方法)。

有任何想法吗?

4

6 回答 6

2

事件Button.Click定义为

public event EventHandler Click

其中EventHandler定义为

public delegate void EventHandler(Object sender, EventArgs e);

这意味着,对于可分配为事件处理程序的方法,它必须具有委托定义的确切签名,即它必须接受两个参数,一个object和一个EventArgs实例,并且它必须返回voidSatirSil你方法的签名

void SatirSil(object sender, EventArgs e, int rowNo)

不匹配,因为它有一个额外的整数参数。如其他答案中所述,您有两种常见的解决方案来解决此问题:

  • 以某种方式将额外的参数嵌入到参数中sender,因为EventArgs它本身几乎没有用。由于大多数情况下 sender 参数实际上是一个Control对象,因此通常使用该Control.Tag属性来存储有关发送者的额外数据,这些数据将由处理程序取出并根据需要使用。这看起来像:

    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
    }
    
  • 以某种方式创建一个专用版本的处理程序,该版本将具有“硬编码”的行号。从 C# 3.0 开始,使用 lambda 语法相对容易完成,它会为您生成一个内联“方法”,例如

    EventHandler handler = (sender, e) => {...code here ...}
    

    是创建一个称为“处理程序”的委托实例的代码,您可以将其附加到事件,使用

    someButton.Click += handler;
    

    或者你甚至可以调用,使用

    handler(senderValue, eValue); 
    

    请注意,“...code here...”块仍然包含在您编写声明的原始方法中,因此该方法可以访问的任何内容都可以访问 lambda 表达式的主体。知道您可以使用以下代码为每个按钮创建一个单独的处理程序:

    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
    }
    

我个人更喜欢第二种选择,因为它巧妙地将与按钮的创建和连接有关的代码与实际工作的代码分开。例如,如果SatirSil代码的另一部分需要该方法,则调用将分别为:

Control dummy = new Control();
dummy.Tag = myRowNumber;
SatirSil(dummy, null);

对比

SatirSil(myRowNumber);
于 2013-06-28T13:13:29.707 回答
2

改变:

buttonNew.Click += new EventHandler(SatirSil);

buttonNew.Click += new EventHandler((snd, ev)=>SatirSil(snd,ev,rowno));

或使用您自己的变量(即tlpTDersRows)它可能是这样的:

buttonNew.Click += new EventHandler((snd, ev)=>SatirSil(snd,ev,tlpTDersRows-1));
于 2013-06-28T12:47:43.083 回答
1

我有一个想法:

buttonNew.Click += new EventHandler((sender,args)=>SatirSil(sender,args,rowNo));

这样,您仍将buttonNew.Click使用 compatible进行设置EventHandler,但匿名方法的主体将使用您的方法SatirSil,该方法使用您的行号作为参数。

于 2013-06-28T12:44:17.883 回答
1

该按钮是sender您的事件。因此,如果您将行号存储在Tag按钮的属性中,如下所示:

buttonNew.Tag = tlpTDersRows;

然后您可以执行以下操作:

private void SatirSil(object sender, EventArgs e)
{
    Button button = (Button)sender;
    int rowNo = (int)button.Tag;
    // ... delete row here.
}
于 2013-06-28T12:47:02.720 回答
0

怎么样:

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;

}
于 2013-06-28T12:46:55.760 回答
0

您无法修改已定义的按钮单击事件的委托签名。如果你做你想做的事,那么你会得到编译器错误。您如何以其他方式实现是在创建按钮名称时,将其附加到行号,以便在事件处理程序中您可以将发送者对象转换为按钮并获取名称并从中提取行号。

    buttonNew.Name = "btnDelTR_" + rowNumber

    private void SatirSil(object sender, EventArgs e, int rowNo)
    {
             int rowNo =   //split the string to get the number.
    }
于 2013-06-28T12:51:09.480 回答