我已经定义了我的约束力:
<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
&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时,内存泄漏消失了!我怎样才能实现上面指定的行为?
答案 0 :(得分:2)
排除内存泄漏问题的第一步是找到明确的来源。这并不总是显而易见的,偶尔会违背你的直觉。根据您的解释,如果您删除了用户控件,问题就会消失,但是当您将其放回时,您会再次开始泄漏。这很可能表明该控件内存泄漏(尽管不一定)。也许你的控件符合one of the many types of WPF memory leaks,或者你有一个更经典的订阅事件的问题,但在不再需要时没有正确地解开它(the weak event pattern在这里很有用)。
你最好的办法就是抓住像.NET Memory Profiler或ANTS 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}"
希望这有点帮助!