【问题标题】:C# Delegation is not being removedC# 委派没有被删除
【发布时间】:2011-10-23 16:56:09
【问题描述】:

在程序中,我使用图片框创建了多个面板。图片框被委派为可点击。我希望用户可以选择从订单中删除其中一个面板/图片框。现在,如果它被删除并且订单被重新排列,那么在被删除的图片框保留其委托顺序之后的所有图片框。因此,在被删除的那个之后单击其中的任何一个,会跳到它旁边的那个(即单击#9,它将转到#10)。我需要删除重新排序的委托并正确地重新委托它们。我试过了:

int z2 = z;
var myClickDelegate = (EventHandler)delegate { clicked(z2, null); };
PicBx[z].Click += myClickDelegate;

创造和

PicBx[z].Click -= myClickDelegate;

删除

还有

int z2 = z;
PicBx[z].Click -= delegate { clicked(z2, null); };

但他们都没有删除原始委托。

【问题讨论】:

  • 这就是您要避免匿名代表的原因。
  • Ω 是有效标识符,无需满足 z2。
  • 我假设 Ω,你的意思是 z?如果是这样,那是因为它在循环中,您需要在循环中声明一个单独的变量。
  • @Claus - 根本不应该避免使用匿名委托作为事件处理程序。使用(非匿名)方法作为事件处理程序是不好的 OO - 它不会封装您的逻辑。此外,由于事件处理程序签名,您可以将错误的事件处理程序连接到事件等。使用匿名委托允许您编写可以使用局部变量的内联事件处理程序,不要破坏代码流,并且对其他班级隐藏。他们太棒了。
  • 是的,那是在您不想想再次删除它们时使用的。

标签: c# delegation


【解决方案1】:

您的第一种方法应该有效,但后一种方法不应该有效。
因为当您执行 PicBx[z].Click -= delegate { clicked(z2, null); }; 方法时,您并没有删除旧的委托,而是创建了一个新的委托,然后将其移除。

在您的第一次尝试中应该可以:

private void SomeMethod()
{
    var myClickDelegate = (EventHandler)delegate { clicked(z2, null); };
    PicBx[z].Click += myClickDelegat;
    //Do extra work
    PicBx[z].Click -= mayClickDelegat;
}

编辑:与您的评论配对: 我注意到您只是在您的委托中添加clicked(z2, null),所以我假设您只是首先创建委托只是为了传递该int z2 来表示图片框索引。
您可以使用pictureBox.Tag 将该索引与图片框本身放在一起,并在点击事件中从标签中获取int

int z2 = z;
picBx[z].Tag = z2;//here we embedded the number with the picture box.
PicBx[z].Click += clicked;
...
PicBx[z].Click -= clicked;

所以在点击事件中:

private void clicked(object sender, EventArgs e)
{
    PictureBox pictureBox = sender as PictureBox;

    if (pictureBox != null)
    {
        int number = Convert.ToInt32(pictureBox.Tag);
        ...
    }
}

Edit2:与您的 cmets 配对,您似乎拥有不同的 clicked 方法签名:

private void clicked(int tes,..
{
    Pnl[tes].BackColor = Color.Red;
}

这里我们只改成:

private void clicked(object sender, EventArgs e)
{
    PictureBox pictureBox = sender as PictureBox;//when user clicks on picture box it will be the sender parameter.

    if (pictureBox != null)
    {
        //we add number to each of picture boxes at there tags. "picBx[z].Tag = z2"
        int tes = Convert.ToInt32(pictureBox.Tag);
        pnl[tes].BackColor = Color.Red;
    }
}

【讨论】:

  • 这是问题所在。删除是在原始函数之外的不同区域调用的。即private void createpicbx() 将创建委托,但是当单击删除按钮private void Button14_click() 时,它会尝试将其删除。
  • 那你应该在你的课堂上引用图片框的处理程序,我会更新答案告诉你怎么做。
  • 所以在int number = Convert.ToInt32(pictureBox.Tag); 下的点击事件中,我是否只需输入'int z2 = tt; var myClickDelegate = (EventHandler)delegate { clicked(z2, null); }; PicBx[tt].Click -= myClickDelegate;'
  • @user 我们摆脱了var myClickDelegate = (EventHandler)delegate { clicked(z2, null); };,只需将所有图片框附加到clicked事件。不要在这里混淆名称number,它只是代表您的z“或z2”,因此请随意填写以将其重命名为您认为相关的名称。所以:每个pitureBox.Click都分配给clicked事件,当事件发生时,我们只需检查发送者,并从中获取底层图片框“当用户点击任何图片框时,发送者将是图片框用户默认点击”,然后从其标签中获取z
  • 好吧,这是有道理的。我收到了No overload for 'clicked' matches delegate 'System.EventHandler'
【解决方案2】:

您没有尝试删除同一个委托。您应该尝试将您的代表存储在某个地方:

this.MyDelegate = delegate { clicked(z2, null); };

PicBx[z].Click += this.MyDelegate;


...

...


PicBx[z].Click -= this.MyDelegate;

但是像这样玩代理可能会导致糟糕的设计选择。您应该定义一个bool,您将在其中确定是否执行您的委托。

public void OnClick(object sender, ...)
{
    if(myBool)
    {
        ...
    }
}

【讨论】:

    【解决方案3】:

    从您对 Jalal 的回答看来,您实际上可能需要这样的东西

    How to remove all event handlers from a control

    【讨论】:

      【解决方案4】:

      这里有两个问题。

      首先,正如其他人所指出的,您需要删除添加到事件处理程序中的同一委托实例。

      第二个是您使用数组来存储图片框,并且您的处理程序使用索引来查找图片框,因此当您从数组中删除图片框时,所有图片框的事件处理程序数组将指向错误的图片框。

      这是怎么做的:

      第 1 步:更改您的事件处理程序以获取图片框的实例,而不是数组的索引。

      第 2 步:创建一个类级字典,以通过图片框保存您的委托引用:

      Dictionary<PictureBox, EventHandler> _pictureBoxHandlers =
          new Dictionary<PictureBox, EventHandler>();
      

      第 3 步:编写您的订阅代码,如下所示:

      //After the picture box is added to `PicBx`
      var pb = PicBx[z];
      var myClickDelegate = (EventHandler)delegate { clicked(pb, null); };
      _pictureBoxHandlers[pb] = myClickDelegate;
      pb.Click += myClickDelegate;
      

      第 4 步:编写您的退订代码,如下所示:

      //Before the picture box is removed from `PicBx`
      var pb = PicBx[z];
      if (_pictureBoxHandlers.ContainsKey(pb))
      {
          var myClickDelegate = _pictureBoxHandlers[pb];
          pb.Click -= myClickDelegate;
          _pictureBoxHandlers.Remove(pb);
      }
      

      看看情况如何。

      【讨论】:

      • On clicked(pb, null) pb 是 int 的位置(通常是 z2)...'private void clicked(int tes, EventArgs e)'。那不会抛出错误吗?
      • @user770344 - 是的,它会的。这就是为什么我的“步骤 1”是更改事件处理程序的签名以获取图片框而不是索引。如果您的图片框列表发生更改,则在事件处理程序中使用整数将不起作用。
      猜你喜欢
      • 1970-01-01
      • 2016-02-14
      • 2020-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-25
      相关资源
      最近更新 更多