WeakEventManager无法处理附加行为中的事件

时间:2017-03-19 17:06:11

标签: c# wpf weak-references attached-properties attachedbehaviors

我有一个WPF附加行为,处理UIElement的MouseEnter和MouseLeave事件。我试图通过切换使用WeakEventManager来防止内存泄漏,但现在代码不再处理事件。

当我使用时(见下文):

 _control.MouseEnter += OnMouseEnter;  
 _control.MouseLeave += OnMouseLeave;  

代码处理事件。

当我使用时(见下文):

  WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseEnter", OnMouseEnter);  
  WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseLeave", OnMouseLeave);  

代码不处理该事件。

如何在附加行为中使用WeakEventManager处理事件?

以下是我如何在XAML中使用附加行为的示例: 在这种情况下,两个控件在TreeView控件中显示为节点;我使用附加的行为是许多其他控件,它不起作用。

  <HierarchicalDataTemplate x:Key="EquipmentUnitTemplate" >
    <StackPanel 
      Orientation="Horizontal">
      <controls:EquipmentUnitBillboard 
        Width="22"
        Height="20"
        VerticalAlignment="Center"
        Style="{DynamicResource TreeViewNavigatorEquipmentUnitBillboardStyle}"
        behaviours:ToolTipEquipmentUnitHelper.TooltipMemberBinding="{Binding EquipmentUnitModel}"
        behaviours:ContextMenuEquipmentUnitHelper.ContextMenuMemberBinding="{Binding EquipmentUnitModel}"
        Visibility="{Binding HasIcon, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverterCollapsed}}"
        IconType="{Binding IconId, Mode=OneWay}"/>
      <Label 
        Margin="5,0,0,0"
        Padding="0,0,0,0"
        VerticalAlignment="Center"
        Style="{DynamicResource LabelInTreeStyle}"
        behaviours:ToolTipEquipmentUnitHelper.TooltipMemberBinding="{Binding EquipmentUnitModel}"
        behaviours:ContextMenuEquipmentUnitHelper.ContextMenuMemberBinding="{Binding EquipmentUnitModel}"
        Content="{Binding DisplayName}" 
        FontWeight="Bold" 
        />
    </StackPanel>
  </HierarchicalDataTemplate>

这是附加的行为,删除了大部分不需要的代码:

public class ToolTipHelper
{
private readonly UIElement _control = null;

public ToolTipHelper(UIElement control)
{
  this._control = control;
}

public static readonly DependencyProperty TooltipMemberBindingProperty
  = DependencyProperty.RegisterAttached("TooltipMemberBinding", typeof(object), typeof(ToolTipHelper), new PropertyMetadata(null, OnTooltipMemberBindingChanged));

public static void SetTooltipMemberBinding(DependencyObject dependencyObject, object tooltipMember)
{
  dependencyObject.SetValue(TooltipMemberBindingProperty, tooltipMember);
}

public static object GetTooltipMemberBinding(DependencyObject dependencyObject)
{
  return (object)dependencyObject.GetValue(TooltipMemberBindingProperty);
}

private static void OnTooltipMemberBindingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
  var control = dependencyObject as UIElement;
  if (control != null)
  {
    if ((object)e.NewValue != null)
    {
      var behavior = new ToolTipHelper(control);
      behavior.Attach();
    }

    if ((object)e.OldValue != null)
    {
      var behavior = new ToolTipHelper(control);
      behavior.Detach();
    }
  }
}

private void Attach()
{
  if (_control != null)
  {
    var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
    var applicationServices = container.Resolve<IApplicationServices>();
    var applicationSettings = container.Resolve<IApplicationSettings>();
    var realtimeObjectModel = container.Resolve<IRealtimeObjectModel>();
    var kpiEngine = container.Resolve<IKPIEngine>();
    var wcmSettings = container.Resolve<WencoConfigurationSettingsModel>();

    var val = _control.GetValue(TooltipMemberBindingProperty);

    if (val is HaulingUnit)
    {
      HaulingUnitToolTipViewModel huvm = new HaulingUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, wcmSettings, val as HaulingUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, huvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("HaulingUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);

    }
    else if (val is LoadingUnit)
    {
      LoadingUnitToolTipViewModel luvm = new LoadingUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, kpiEngine, wcmSettings, val as LoadingUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, luvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("LoadingUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);
    }
    else if (val is DrillUnit)
    {
      DrillUnitToolTipViewModel luvm = new DrillUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, wcmSettings, val as DrillUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, luvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("DrillUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);
    }
    else if (val is ScraperUnit)
    {
      ScraperUnitToolTipViewModel scvm = new ScraperUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, wcmSettings, val as ScraperUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, scvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("ScraperUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);
    }
    else if (val is AuxiliaryUnit)
    {
      AuxiliaryUnitToolTipViewModel auvm = new AuxiliaryUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, wcmSettings, val as AuxiliaryUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, auvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("OtherUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);
    }
    else if (val is FuelTruckUnit)
    {
      FuelTruckUnitToolTipViewModel auvm = new FuelTruckUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, wcmSettings, val as FuelTruckUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, auvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("OtherUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);
    }
    else if (val is CrusherUnit)
    {
      CrusherUnitToolTipViewModel auvm = new CrusherUnitToolTipViewModel(applicationServices, applicationSettings, realtimeObjectModel, wcmSettings, val as CrusherUnit);
      _control.SetValue(RadToolTipService.ToolTipContentProperty, auvm);

      DataTemplate template = (DataTemplate)Application.Current.FindResource("OtherUnitTooltipTemplate");
      _control.SetValue(RadToolTipService.ToolTipContentTemplateProperty, template);
    }
    //else if (val is DumpLocationDispatchConfigurationViewModel)
    //{

    //}

    int initial = Convert.ToInt32(SharedConstants.TooltipInitialShowDelayDuration.TotalMilliseconds);
    _control.SetValue(RadToolTipService.InitialShowDelayProperty, initial);
    int between = Convert.ToInt32(SharedConstants.TooltipBetweenShowDelayDuration.TotalMilliseconds);
    _control.SetValue(RadToolTipService.BetweenShowDelayProperty, between);
    int duration = Convert.ToInt32(applicationSettings.ProgramSettings.ToolTips.ToolTipOpenDuration.TotalMilliseconds);
    _control.SetValue(RadToolTipService.ShowDurationProperty, duration);

    // using this code the event never gets handled
    WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseEnter", OnMouseEnter);
    WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseLeave", OnMouseLeave);
    // if I uncomment these two lines the event gets handled.
    //_control.MouseEnter += OnMouseEnter;
    //_control.MouseLeave += OnMouseLeave;
  }
}

private void Detach()
{
  if (_control != null)
  {
    WeakEventManager<UIElement, RoutedEventArgs>.RemoveHandler(_control, "MouseEnter", OnMouseEnter);
    WeakEventManager<UIElement, RoutedEventArgs>.RemoveHandler(_control, "MouseLeave", OnMouseLeave);
    //_control.MouseEnter -= OnMouseEnter;
    //_control.MouseLeave -= OnMouseLeave;
  }
}

private void OnMouseEnter(object sender, RoutedEventArgs routedEventArgs)
{
  try
  {
    if ((sender is UIElement))
    {
      UIElement control = sender as UIElement;
    }
  }
  catch (Exception ex)
  {
  }
}

private void OnMouseLeave(object sender, RoutedEventArgs routedEventArgs)
{
  try
  {
    if ((sender is UIElement))
    {
      UIElement control = sender as UIElement;
    }
  }
  catch (Exception ex)
  {
  }
}

}

1 个答案:

答案 0 :(得分:1)

在添加处理程序之前,您应该等到控件加载完毕。

这有效:

private void Attach()
{
    if (_control != null)
    {
        FrameworkElement fe = _control as FrameworkElement;
        if (fe != null)
        {
            if (fe.IsLoaded)
            {
                WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseEnter", OnMouseEnter);
                WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseLeave", OnMouseLeave);
            }
            else
            {
                fe.Loaded += Fe_Loaded;
            }
        }
    }
}

private void Fe_Loaded(object sender, RoutedEventArgs e)
{
    WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseEnter", OnMouseEnter);
    WeakEventManager<UIElement, RoutedEventArgs>.AddHandler(_control, "MouseLeave", OnMouseLeave);
}

private void Detach()
{
    if (_control != null)
    {
        FrameworkElement fe = _control as FrameworkElement;
        if (fe != null)
            fe.Loaded += Fe_Loaded;
        WeakEventManager<UIElement, RoutedEventArgs>.RemoveHandler(_control, "MouseEnter", OnMouseEnter);
        WeakEventManager<UIElement, RoutedEventArgs>.RemoveHandler(_control, "MouseLeave", OnMouseLeave);
    }
}