2016-05-13 6 views
1

[Я извиняюсь за мой плохой английский]WPF: ObservableCollection утечка памяти

В моей MainWindow у меня есть некоторые ContentControl и я поставил его Content в какой-то точки зрения называется SimpleView. Если у SimpleView есть ListBox, ограниченный коллекцией, вид живой, даже если я удалю SimpleView.

Все мои режимы просмотра реализуют INotifyPropertyChanged. Это мой код:

MainWindow.xaml

<Window x:Class="WpfMemory.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"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 

     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 
      <Button Content="Set view" Click="SetView" /> 
      <Button Content="Clear view" Click="ClearView" /> 
     </StackPanel> 

     <ContentControl x:Name="ViewContainer" Grid.Row="1" Margin="4" /> 
    </Grid> 
</Window> 

В коде позади

private void SetView(object sender, RoutedEventArgs e) 
{ 
    var simpleViewModel = new ViewModels.SimpleViewModel(); 
    var simpleview = new Views.SimpleView() { DataContext = simpleViewModel }; 
    ViewContainer.Content = simpleview; 
} 

private void ClearView(object sender, RoutedEventArgs e) 
{ 
    ViewContainer.Content = null; 
    System.GC.Collect(); 
} 

SampleView.xaml

<UserControl x:Class="WpfMemory.Views.SimpleView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition/> 
      <ColumnDefinition MinWidth="60"/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 

     <TextBlock Text="SomeText" /> 
     <TextBox Text="{Binding SomeText}" Grid.Column="1"/> 

     <TextBlock Text="Large data" Grid.Row="1"/> 
     <ListBox ItemsSource="{Binding LargeData,Mode=OneTime}" 
       Grid.Row="2" Grid.Column="1" 
       DisplayMemberPath="Name" /> 

    </Grid> 
</UserControl> 

Посмотреть модели

public sealed class SimpleViewModel : ViewModelBase 
{ 
    public SimpleViewModel() 
    { 
     var items = Enumerable.Range(1, 10000) 
      .Select(x => new SimpleItem() 
      { 
       Id = x, 
       Name = "Item " + x 
      }) 
      .ToArray(); 

     LargeData = new ObservableCollection<SimpleItem>(items); 
    } 

    public string SomeText{ get; set; } = "yehudah"; 

    ObservableCollection<SimpleItem> largeData; 
    public ObservableCollection<SimpleItem> LargeData 
    { 
     get { return largeData; } 
     set { SetProperty(ref largeData, value); } 
    } 
} 

public sealed class SimpleItem : ViewModelBase 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

я запустить приложение и нажмите на SetView, а затем на ClearView. Теперь, против диагностических инструментов я нажимаю на «Сделать снимок» И это результат:

Memory snapshot

Спасибо за любую помощь.

+0

Вы не можете узнать, когда соберется GarbageCollector. Используйте SetView и ClearView несколько раз и проверьте состояние памяти. – nkoniishvt

+0

Даже если я вызову GC.Collect явно? Итак, как я могу обнаружить утечки памяти? Если я удалю список, он будет собран немедленно. –

+0

Я был неправ. Это первый раз, когда я использую SetProperty, это необходимо? это единственная «странная» вещь, которую я вижу здесь. – nkoniishvt

ответ

0

Я думаю, вы должны сбросить simpleview.DataContext, когда управление содержимым выгружено.

Вы можете сделать

simpleview.Unloaded += (_, __) => simpleview.DataContext = null; 

когда SetView.

+0

Ваша идея замечательная, но она решает только половину проблемы. '' 'ViewModel'' собирается немедленно, но' '' View''' является стальным. –

+0

Не уверен, что мы должны беспокоиться об этом, потому что _ViewModel_ он не будет собран немедленно. Если вы сохраняете _ViewContainer.Content = null_ на _ClearView_, _ViewModel_ будет собран в какой-то момент (вы можете проверить, вызывая GC.Collect() несколько раз). –

Смежные вопросы