I have following code.
So basically it executes command (DelegateCommand based on weak reference delegates), when Selector.SelectionChanged event is raised.
public static readonly DependencyProperty SelectionCommandProperty
= DependencyProperty.RegisterAttached(
"SelectionCommand",
typeof(ICommand),
typeof(CommonUtilities),
new PropertyMetadata(null, OnSelectionCommandPropertyChanged));
private static void OnSelectionCommandPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as Selector;
var command = e.NewValue as ICommand;
if (selector != null && command != null)
{
selector.SelectionChanged
+= (o, args) => command.Execute(selector.SelectedItem);
}
}
public static ICommand GetSelectionCommand(DependencyObject d)
{
return d.GetValue(SelectionCommandProperty) as ICommand;
}
public static void SetSelectionCommand(DependencyObject d, ICommand value)
{
d.SetValue(SelectionCommandProperty, value);
}
Note that the context is static.
Does this cause leak? I can guess that it doesnt because as far as I know, the anonymous handler would be in effect until the scope of all “outer” variables (i.e. selector, command here) is not applicable for GC. Once they are GCed which would happen when the View (that has selector) and ViewModel (that is supplying command) are unloaded from parent GUI, the anonymous delegate would also be unhooked.
Am I right here?
Here are the references in this example:
This means the view and view-model can be garbage collected, leaving the
SelectorandICommandalive.The garbage collector is capable of dealing with circular references; so even though the
Selectorreferences the delegate, and the delegate references theSelectorthese can still be garbage collected.The
ICommandhowever, will be kept alive as long as this anonymous delegate is kept alive, which is determined solely by the lifetime of theSelectorinstance. As long as theSelectoris being garbage collected, the delegate andICommandwill eventually be garbage collected too.So in simple situations, no, your code does not cause a leak.
There is however a situation where your code does leak handlers, I am assuming your view-model has a property like so:
Which is then bound in the view, if you change the value of this
OnSelectionChangedcommand, your attached property will leak event handlers, as you never unsubscribe the delegate which executes the old command.So rather than just one command being executed, all of the previous values of this property will be executed.
I would go for an implementation more like the following: