代码之家  ›  专栏  ›  技术社区  ›  Dabblernl

CollectionView.View.Refresh内存泄漏

  •  3
  • Dabblernl  · 技术社区  · 15 年前

    我这样定义了我的约束:

    <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);
    

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

    但是,用户数据的IsLoggedin属性每隔几秒钟由BackgroundWorker线程更新一次,然后代码调用:

    UsersView.View.Refresh();
    

    在UI线程上。

    同样,这也可以按预期工作:登录的用户将从视图的底部移动到顶部,反之亦然。然而: 每次我对视图调用刷新方法时,应用程序都会存储3,5MB的额外内存,这些内存只有在应用程序关闭后(或在OutOfMemoryException…)才会释放。

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

    • UserData类实现InotifyPropertyChanged
    • 更改基础用户集合根本没有任何区别:任何IEnumerable <UserData >作为CollectionViewSource的源导致问题。
      -将CollectionViewSource更改为列表 <用户数据 >(和刷新绑定)或从ObservableCollection继承以获取对基础项集合的访问,从而对就地不起作用的项进行排序。

    我没主意了!帮助?

    编辑: 我发现了: 资源mydatatemplate包含一个绑定到userdata对象的标签,以显示其属性之一,userdata对象由treeview的itemssource传递。标签具有这样定义的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对象是一个显示UserData对象的所有属性的用户控件。这样,用户首先只看到一个用户的一段数据,右键单击可以看到所有数据。

    当我从数据模板中删除myuserdata用户控件时,内存泄漏将消失!我如何仍然可以实现上面指定的行为?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Community CDub    8 年前

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

    你最好的选择是 .NET Memory Profiler ANTS Memory Profiler (两者都很好,都有免费试用)。使用这些工具中的一个,找到应该消失后挂在周围的对象。这些工具提供了跟踪挂在对象上的对象链的帮助。有许多关于内存分析的好文章 their sites 在广开的网络上。

        2
  •  1
  •   Arcturus    15 年前

    你可以尝试两件事:

    首先,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}"
    

    希望这有点帮助!