【问题标题】:Unsubscribing from anonymous delegate event退订匿名委托事件
【发布时间】:2012-06-07 22:11:09
【问题描述】:

我在想办法取消订阅一些匿名委托事件时遇到了一些麻烦,我在预先制作的帮助文件中找到了这些事件,该文件有助于在运行时移动控件。我想取消订阅这些事件的原因是控件(在这种情况下为按钮)将再次被锁定并且无法移动。这是帮助程序类中的方法:

 public static void Init(Control control)
    {
        Init(control, Direction.Any);
    }

    public static void Init(Control control, Direction direction)
    {
        Init(control, control, direction);
    }

 public static void Init(Control control, Control container, Direction direction)
    {
        bool Dragging = false;
        Point DragStart = Point.Empty;

        control.MouseDown += delegate(object sender, MouseEventArgs e)
        {
            Dragging = true;
            DragStart = new Point(e.X, e.Y);
            control.Capture = true;
        };
        control.MouseUp += delegate(object sender, MouseEventArgs e)
        {
            Dragging = false;
            control.Capture = false;
        };
        control.MouseMove += delegate(object sender, MouseEventArgs e)
        {
            if (Dragging)
            {
                if (direction != Direction.Vertical)
                    container.Left = Math.Max(0, e.X + container.Left - DragStart.X);
                if (direction != Direction.Horizontal)
                    container.Top = Math.Max(0, e.Y + container.Top - DragStart.Y);
            }
        };

    }

这是我通过调用方法订阅这些事件的方式;

    ControlMover.Init(this.Controls["btn" + i]);

我在 MSDN 上阅读了一些关于通过创建一个保存这些事件的局部变量然后通过这种方式取消订阅来取消订阅这些的方法,但我似乎无法在我自己的项目中使用它。如何取消订阅这些事件,以便我的控件再次固定到位?

【问题讨论】:

  • 您可以发布您的代码,将它们存储在变量中并使用它来取消订阅吗?
  • 但我个人会为此使用命名方法。更简单、更简洁的代码 IMO。
  • 我已将其删除,因为我什至无法远程工作。我会尝试检索一些或进一步的工作,但看起来不太好!
  • 您需要指定您的代理人才能取消订阅。以下讨论应该会有所帮助:*.com/questions/1362204/…*.com/questions/2051357/…

标签: c# events delegates anonymous


【解决方案1】:

不保证编译器创建的匿名委托是唯一的,当取消订阅时,相同代码缺乏唯一性将导致它无法取消订阅正确的处理程序。唯一安全的方法是保留对委托的引用并使用它来取消订阅,或将其更改为完整方法。

我相信,基于对象实例和方法签名,代表是平等的。

可能的重复:

How to remove a lambda event handler

基本上,保留一个参考:

MouseEventHandler handler = (sender, e) =>
        {
            Dragging = true;
            DragStart = new Point(e.X, e.Y);
            control.Capture = true;
        };

control.MouseDown += handler;
control.MouseDown -= handler;

或者把匿名方法变成合适的方法。

【讨论】:

  • 为您的意见喝彩。我认为从长远来看,为了让事情变得更容易,我会把它们变成适当的方法。
  • @Shane'Shamus'Coulter 我愿意,它还会让您的注册码更简洁:control.MouseDown += MouseDownHandler;
  • 所以事实证明,由于类中所有参数的传递,我实际上很难使它们成为正确的方法..
  • 在这种情况下,要么让这些参数成为类成员变量,要么让匿名方法引用类成员。
  • 是否可以取消订阅:control.MouseDown += new MouseEventHandler((sender, e) => MouseDown(sender, e, control)); ?或者这是同一件事..我有一种感觉..
【解决方案2】:

简而言之,您不能使用anonymous 委托来做到这一点。

如果您想从事件中取消订阅,请定义delegate/action 并遵循您引用的模式。

【讨论】: