patterncsharpMinor
Possible memory leak with WPF Custom Control?
Viewed 0 times
controlwithwpfcustompossibleleakmemory
Problem
I might have a potential memory leak with my custom control. Do I actually have one?
```
public interface IAlertable : INotifyPropertyChanged { ... }
public sealed class AlertButton : Button
{
private static readonly DependencyPropertyKey HasAlertPropertyKey = DependencyProperty.RegisterReadOnly("HasAlert", typeof(bool), typeof(AlertButton),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, null));
public static readonly DependencyProperty HasAlertProperty = HasAlertPropertyKey.DependencyProperty;
public static readonly DependencyProperty AlertContextProperty = DependencyProperty.Register("AlertContext", typeof(IAlertable), typeof(AlertButton),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, OnAlertContextChanged, null, false, UpdateSourceTrigger.PropertyChanged));
static AlertButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AlertButton), new FrameworkPropertyMetadata(typeof(AlertButton)));
}
private PropertyChangedEventHandler PropertyChangedEventHandler { get; set; }
public bool HasAlert
{
get { return (bool)GetValue(HasAlertProperty); }
protected set { SetValue(HasAlertPropertyKey, value); }
}
public IAlertable AlertContext
{
get { return (IAlertable )GetValue(AlertContextProperty); }
set { SetValue(AlertContextProperty, value); }
}
private static void OnAlertContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = (AlertButton)d;
obj.OnAlertContextChanged((IAlertable)e.OldValue, (IAlertable)e.NewValue);
}
private void OnAlertContextChanged(IAlertable prev, IAlertable curr)
{
if (prev != null)
{
UnhookEvents(prev);
}
if (curr != null)
{
HookEvents(curr);
}
}
private void UnhookEvents(IAlertable context)
{
var handler = PropertyC
```
public interface IAlertable : INotifyPropertyChanged { ... }
public sealed class AlertButton : Button
{
private static readonly DependencyPropertyKey HasAlertPropertyKey = DependencyProperty.RegisterReadOnly("HasAlert", typeof(bool), typeof(AlertButton),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, null));
public static readonly DependencyProperty HasAlertProperty = HasAlertPropertyKey.DependencyProperty;
public static readonly DependencyProperty AlertContextProperty = DependencyProperty.Register("AlertContext", typeof(IAlertable), typeof(AlertButton),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, OnAlertContextChanged, null, false, UpdateSourceTrigger.PropertyChanged));
static AlertButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AlertButton), new FrameworkPropertyMetadata(typeof(AlertButton)));
}
private PropertyChangedEventHandler PropertyChangedEventHandler { get; set; }
public bool HasAlert
{
get { return (bool)GetValue(HasAlertProperty); }
protected set { SetValue(HasAlertPropertyKey, value); }
}
public IAlertable AlertContext
{
get { return (IAlertable )GetValue(AlertContextProperty); }
set { SetValue(AlertContextProperty, value); }
}
private static void OnAlertContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = (AlertButton)d;
obj.OnAlertContextChanged((IAlertable)e.OldValue, (IAlertable)e.NewValue);
}
private void OnAlertContextChanged(IAlertable prev, IAlertable curr)
{
if (prev != null)
{
UnhookEvents(prev);
}
if (curr != null)
{
HookEvents(curr);
}
}
private void UnhookEvents(IAlertable context)
{
var handler = PropertyC
Solution
Yes, you are correct, in some cases
In your case the simplest solution would probably be to additionally
Alternatively, you can use weak events pattern as Zache suggested.
ICommand can leak memory too! Usually it does not happen, because most implementations of ICommand either utilize CommandManager (which uses weak references) or do not care about CanExecute state and therefore use empty CanExecuteChanged event, which does not hold any references at all. But if you implement CanExecuteChanged as strong event, ICommand will cause memory leak.In your case the simplest solution would probably be to additionally
UnhookEvents when control is unloaded, and to HookEvents when it is loaded.Alternatively, you can use weak events pattern as Zache suggested.
Context
StackExchange Code Review Q#54191, answer score: 3
Revisions (0)
No revisions yet.