I just finished desktop apps written in WPF and c# using MVVM pattern. In this app I used Delegate Command implementation to wrap the ICommands properties exposed in my ModelView. The problem is these DelegateCommands prevent my ModelView and View from being garbage collected after closing the view. So it stays larking until I terminate the whole application. I profile the application I find it’s all about delegatecommand that keeping the modelview in memory. How could I avoid this situation and is this in nature of mvvm pattern, or it’s about my implantation of the pattern?. Thanks.
Edit: this is small but complete portion of how i implement MVVM pattern
First: CommandDelegte class
class DelegateCommand:ICommand
{
private Action<object> execute;
private Predicate<object> canExcute;
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
this.execute = execute;
this.canExcute = canExecute;
}
public bool CanExecute(object parameter)
{
if (this.canExcute != null)
{
return canExcute(parameter);
}
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
Second: ModelView Class
public class ViewModel:DependencyObject, INotifyPropertyChanged
{
private DelegateCommand printCommand;
public ICommand PrintCommand
{
get
{
if (printCommand == null)
{
printCommand = new DelegateCommand(Print, CanExecutePrint);
}
return printCommand;
}
}
void Print(object obj)
{
Console.WriteLine("Print Command");
}
bool CanExecutePrint(object obj)
{
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnProeprtyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Third: Window code behind
public MainWindow()
{
InitializeComponent();
base.DataContext = new ViewModel();
}
Forth: My XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.InputBindings>
<KeyBinding Key="P" Modifiers="Control" Command="{Binding Path=PrintCommand}"/>
</Window.InputBindings>
<StackPanel>
<Button Content="Print - Ctrl+P" Width="75" Height="75" Command="{Binding Path=PrintCommand}"/>
</StackPanel>
In your case, what contains a reference to what?
DelegateCommand
contains a reference to ViewModel
- its execute
and canExecute
properties contain references to a methods of the ViewModel
instance.
ViewModel
contains a reference to DelegateCommand
- its PrintCommand
property.
The view contains any number of references to the ViewModel
.
The CommandManager
contains a reference to DelegateCommand
in its RequerySuggested
event.
That last reference is a special case: CommandManager
uses a WeakReference
in its RequerySuggested
event, so despite the fact that DelegateCommand
registers for that event, it can still be garbage-collected.
Given all this, you shouldn't be having a problem. If the view gets disposed, neither the ViewModel
nor the DelegateCommand
should be reachable.
You say you've profiled the application and DelegateCommand
is holding a reference to ViewModel
. It seems to me that the logical next question should be: what's holding a reference to DelegateCommand
? It shouldn't be CommandManager
. Do you have something else in your application that's referencing your commands?