I'm building a WPF app that connects to a SQL Server database using LINQ to SQL.
The main window of the app contains a ListView
containing a series of detail views.
The ItemSource
of the ListView
is bound to a collection of detail view model objects exposed as a property on the root view model.
Each detail view model object composes several ICommand
properties as well as a property exposing a detail model object, which in turn exposes the various data fields shown in the UI.
Analysis with the ANTS memory profiler shows that the objects being leaked are those contained in the detail model object, and some UI classes to which they are bound.
Instances of these objects from previous refreshes are not being garbage collected.
ANTS has a tool that allows the user to trace chains of reference to identify why unwanted memory is being retained. When I use it, I find that all of the chains that show up have an ICommand
in them. Accordingly, I've removed the offending ICommand
, and found that
the memory leak disappears.
Unfortunately, I need the ICommand
to implement some important functionality. What is really confusing me is how it has a reference to the detail model object in the first place- they are two completely separate instance variables in the detail view model object.
Here is the constructor of the detail view model object (The reference to the RootViewModel is used for callbacks in some of the methods connected to the ICommands. I originally suspected that this might be causing a circular chain of references that might be the cause of the problem, but removing it doesn't seem to have any effect.)
public CarDataViewModel(CarData carDataItem, RootViewModel parentViewModel)
{
_parentViewModel = parentViewModel;
CarDataModel = carDataItem;
CompetingCheckboxStatus = CarDataModel.CurrentCar.Competing;
AcknowledgeAlarm = new ParameterlessCommand(AcknowledgeAlarmClicked);
Acknowledge = new ParameterlessCommand(AcknowledgeClicked);
ShowReport = new ParameterlessCommand(ShowReportClicked);
Cancel = new ParameterlessCommand(CancelClicked);
}
Here's the xaml where the bindings are set up - AcknowledgeAlarm is the ICommand, CarDataModel is the detail model object:
<ListView x:Name="itemGridView"Grid.Row="1"ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding CarDataViewModels}" IsSynchronizedWithCurrentItem="True" Margin="0,0,0,0">
<ListView.ItemTemplate>
<DataTemplate>
</DataTemplate.Resources>
<Button Command="{Binding AcknowledgeAlarm}">
<Border DataContext="{Binding CarDataModel}" BorderBrush="{StaticResource GrayFadeBrush}" Background="White" BorderThickness="5">
<Grid> . . .
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…