WeakEventManager 无法处理附加行为中的事件
WeakEventManager fails to handle event in attached behavior
我有一个 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)
{
}
}
}
您应该等到控件加载完成后再添加处理程序。
这个有效:
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);
}
}
我有一个 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)
{
}
}
}
您应该等到控件加载完成后再添加处理程序。
这个有效:
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);
}
}