【问题标题】:Removing anonymous event handlers with some parameters删除带有一些参数的匿名事件处理程序
【发布时间】:2012-05-16 14:18:47
【问题描述】:

我订阅了这样的活动:

private void CoupleOverlay(IMapVisual mapVisual)
{            
      overlay.DrawTilesProgressChanged += (s, e) => 
      {               
          mapVisual.DrawingProgress = e.ProgressPercentage;
      };
}

应用程序可能会多次调用 CoupleOverlay 事件,因此我需要取消订阅 DrawTilesProgressChanged 事件并再次订阅,但因为它是一个匿名事件,我无法取消订阅。我试图转换为

private void CoupleOverlay(IMapVisual mapVisual)
{
    overlay.DrawTilesProgressChanged -=overlay_DrawTilesProgressChanged;                 
    overlay.DrawTilesProgressChanged +=overlay_DrawTilesProgressChanged;                 
}

private void overlay_DrawTilesProgressChanged(object sender, DrawTilesProgressChangedTileOverlayEventArgs e)
{       
    mapVisual.DrawingProgress = e.ProgressPercentage;
}

它不起作用,因为mapVisualoverlay_DrawTilesProgressChanged 方法上不是有效变量。

如果我将代码更改为

private void CoupleOverlay(IMapVisual mapVisual)
{
    EventHandler<DrawTilesProgressChangedTileOverlayEventArgs> drawEvent = (s, e) =>
    {           
        mapVisual.DrawingProgress = e.ProgressPercentage;
    };

    overlay.DrawTilesProgressChanged -= drawEvent;
    overlay.DrawTilesProgressChanged += drawEvent;
}

它不起作用,因为drawEvent 是一个局部变量,下次我调用 CoupleOverlay 时,它会创建一个新变量。

那么我怎样才能取消订阅这个事件处理程序呢?或者我怎么知道我已经订阅了该活动,所以我不需要再次订阅?

【问题讨论】:

  • 一种解决方案是将drawEvent 设为字段而不是局部变量。
  • 为什么需要退订?只需在 Dispose() 订阅和删除订阅即可。
  • @IAbstract:我有一个包含子图层的图层,首先我为所有子图层调用 CoupleOverlay,如果用户更改子图层的定义,我需要再次为所有子图层调用 CoupleOverlay。当绘图有进度时事件正在引发,我只想为每个子层的progressPercentage 分配一个数字。问题是当我因为这个事件重新创建子层时,GC 无法从内存中删除旧的子层。

标签: c# events event-handling


【解决方案1】:

它不起作用,因为drawEvent是局部变量,下次我调用CoupleOverlay时,它会创建一个新的。

确实如此。您基本上需要保留一个实例变量而不是局部变量。实例变量实际上是“当前订阅的事件处理程序”。然后在CoupleOverlay 中删除该事件处理程序,创建一个新事件处理程序(将其存储在变量中)并使用它重新订阅。

另一种方法是使用单个事件处理程序,但将“当前”叠加层和地图视觉对象保留为实例变量,供事件处理程序使用。然后CoupleOverlay 方法只需要更新这些变量。

【讨论】:

  • 我在 for() CoupleOverlay (,) 之类的循环中调用了 CoupleOverlay,您能否给我一些关于如何使用单个事件处理程序的基本示例?
  • @Behnam:那么你想在那个循环中做什么?什么时候触发事件,你想在什么时候执行多少位代码?
  • 我有包含子图层的图层,首先我为所有子图层调用 CoupleOverlay,如果用户更改子图层的定义,我需要再次为该特定图层的所有子图层调用 CoupleOverlay。当绘图有进度时事件正在引发,我只想为每个子层的progressPercentage 分配一个数字。问题是当我因为这个事件重新创建子层时,GC 无法从内存中删除旧的子层。
  • @Behnam:在引发事件时,我仍然不清楚您想要运行多少个处理程序。想想
  • 我只是稍微简化了代码,考虑在 Photoshop 中,您希望在图层管理器​​中显示每个图层/子图层的绘制进度,因此我们需要在每个图层/子图层的每个绘制进度中引发事件。
【解决方案2】:

如何取消订阅此事件处理程序

你不能因为 lambda 是一个局部变量,并且不能超出它声明的范围(在你的情况下是函数本身)。要获得所需的灵活性,您需要使用delegates

我如何知道我已订阅并参加活动,所以我不需要 再次订阅

要获取订阅者列表,使用以下内容就足够了:

MulticastDelegate.GetInvocationList Method(事件和委托是多播的)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 2010-11-26
    • 2011-04-18
    • 2010-11-21
    • 1970-01-01
    • 2012-04-17
    相关资源
    最近更新 更多