CollectionView.View.Refresh上的内存泄漏

时间:2010-03-12 10:27:45

标签: c# .net wpf data-binding memory-leaks

我已经定义了我的约束力:

<TreeView
        ItemsSource="{Binding UsersView.View}"
        ItemTemplate="{StaticResource MyDataTemplate}"
/>

因此定义了CollectionViewSource:

private ObservableCollection<UserData> users;
public CollectionViewSource UsersView{get;set;}
UsersView=new CollectionViewSource{Source=users};
UsersView.SortDescriptions.Add(
          new SortDescription("IsLoggedOn",ListSortDirection.Descending);
UsersView.SortDescriptions.Add(
          new SortDescription("Username",ListSortDirection.Ascending);

到目前为止,这很好,这可以按预期工作:视图首先显示按字母顺序登录的用户,然后显示那些不按字母顺序登录的用户。

但是,UserData的IsLoggedIn属性每隔几秒由后台工作线程更新一次,然后代码调用:

UsersView.View.Refresh();

在UI线程上。

这再次按预期工作:登录的用户从视图底部移动到顶部,反之亦然。但是:每次我在视图上调用Refresh方法时,应用程序都会保留3.5MB的额外内存,这只在应用程序关闭后(或者在OutOfMemoryException之后发布...)

< p>

我做了一些研究,下面列出了一些不起作用的修复:

  • UserData类实现INotifyPropertyChanged
  • 更改基础用户集合根本没有任何区别:任何IENumerable <UserData&gt;作为CollectionViewSource的来源导致问题 - 将ColletionViewSource更改为列表<UserData&gt; (并刷新绑定)或从ObservableCollection继承以访问基础Items集合以对其进行排序不起作用。

我没有想法!帮助

编辑: 我找到了: Resource MyDataTemplate包含一个绑定到UserData对象的Label,以显示其属性之一,即由TreeView的ItemsSource传递的UserData对象。 Label具有ContextMenu,因此定义:

 <ContextMenu Background="Transparent" Width="325" Opacity=".8" HasDropShadow="True">

      <PrivateMessengerUI:MyUserData IsReadOnly="True" >

          <PrivateMessengerUI:MyUserData.DataContext>

              <Binding Path="."/>

          </PrivateMessengerUI:MyUserData.DataContext>

     </PrivateMessengerUI:MyUserData>

</ContextMenu>

MyUserData对象是UserControl,它显示UserData对象的所有属性。通过这种方式,用户首先只能看到用户的一条数据,而在右键单击时可以看到所有数据。

当我从DataTemplate中删除MyUserData UserControl时,内存泄漏消失了!我怎样才能实现上面指定的行为?

2 个答案:

答案 0 :(得分:2)

排除内存泄漏问题的第一步是找到明确的来源。这并不总是显而易见的,偶尔会违背你的直觉。根据您的解释,如果您删除了用户控件,问题就会消失,但是当您将其放回时,您会再次开始泄漏。这很可能表明该控件内存泄漏(尽管不一定)。也许你的控件符合one of the many types of WPF memory leaks,或者你有一个更经典的订阅事件的问题,但在不再需要时没有正确地解开它(the weak event pattern在这里很有用)。

你最好的办法就是抓住像.NET Memory ProfilerANTS Memory Profiler这样的工具(两者都非常出色且免费试用)。使用这些工具之一找到它们应该消失后悬挂的物体。这些工具可帮助您跟踪挂在对象上的对象链。在their sites上有很多关于内存分析的好文章,这里有关于SO和广泛开放的网页。

答案 1 :(得分:1)

你可以尝试两件事:

首先,DropShadow存在一些问题,因为它包含一些应该收集garbadge的引用。有关更多信息,请参阅此文章: http://blog.ramondeklein.nl/index.php/2009/02/20/memory-leak-with-wpf-resources-in-rare-cases/

您可以尝试将HasDropShadow设置为false,并查看您的记忆会发生什么。

其次,如果我们有相同菜单的多个ContextMenu对象,您可能想在资源中创建一个ContextMenu资源,并使用StaticResource扩展名引用它,如下所示:

<ContextMenu Background="Transparent" Width="325" Opacity=".8" x:Key="MyAwesomeContextMenu">

      <PrivateMessengerUI:MyUserData IsReadOnly="True" >

          <PrivateMessengerUI:MyUserData.DataContext>

              <Binding Path="."/>

          </PrivateMessengerUI:MyUserData.DataContext>

     </PrivateMessengerUI:MyUserData>

</ContextMenu>

在您定义上下文菜单的地方使用它:

ContextMenu="{StaticResource MyAwesomeContextMenu}"

希望这有点帮助!