Consider the reference Josh Smith’ article WPF Apps With The Model-View-ViewModel Design Pattern, specifically the example implementation of a RelayCommand (In Figure 3). (No need to read through the entire article for this question.)
In general, I think the implementation is excellent, but I have a question about the delegation of CanExecuteChanged subscriptions to the CommandManager‘s RequerySuggested event. The documentation for RequerySuggested states:
Since this event is static, it will
only hold onto the handler as a weak
reference. Objects that listen for
this event should keep a strong
reference to their event handler to
avoid it being garbage collected. This
can be accomplished by having a
private field and assigning the
handler as the value before or after
attaching to this event.
Yet the sample implementation of RelayCommand does not maintain any such to the subscribed handler:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
- Does this leak the weak reference up to the
RelayCommand‘s client, requiring that the user of theRelayCommandunderstand the implementation ofCanExecuteChangedand maintain a live reference themselves? -
If so, does it make sense to, e.g., modify the implementation of
RelayCommandto be something like the following to mitigate the potential premature GC of theCanExecuteChangedsubscriber:// This event never actually fires. It's purely lifetime mgm't. private event EventHandler canExecChangedRef; public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; this.canExecChangedRef += value; } remove { this.canExecChangedRef -= value; CommandManager.RequerySuggested -= value; } }
I too believe this implementation is flawed, because it definitely leaks the weak reference to the event handler. This is something actually very bad.
I am using the MVVM Light toolkit and the
RelayCommandimplemented therein and it is implemented just as in the article.The following code will never invoke
OnCanExecuteEditChanged:However, if I change it like this, it will work:
The only difference? Just as indicated in the documentation of
CommandManager.RequerySuggestedI am saving the event handler in a field.