WPF列表框内存泄漏

本文关键字:泄漏 内存 列表 WPF | 更新日期: 2023-09-27 18:14:04

我的xaml:

<ListBox Grid.Row="4" HorizontalAlignment="Stretch" Margin="10,132,10,10"  ScrollViewer.VerticalScrollBarVisibility="Disabled" Name="lbStatus" VerticalAlignment="Stretch" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/>

和我的c#代码:

  public void DisplayStatusMessage(string msg)  
  {
       if (lbStatus.Dispatcher.CheckAccess())
       {
          AddMessage(msg, Brushes.Black);
       }
       else
       {
          this.Dispatcher.BeginInvoke((Action)(() =>
          {
            AddMessage(msg, Brushes.Black);
           }));
       }   
  }

  private void AddMessage(string msg)
  {
     ListBoxItem status = new ListBoxItem();
     status.Content = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss:fff ") + msg;
     lbStatus.Items.Add(status);
     lbStatus.ScrollIntoView(status);
     status = null;
   }

我在while (true)循环中调用DisplayStatusMessage来显示列表框上的状态。我的应用程序一夜之间增长了很多,这似乎表明列表框上有内存泄漏。是否有一个替代列表框来显示无限状态?

WPF列表框内存泄漏

这本身不是一个'泄漏'。如果您不断地向ListBox添加条目,甚至在一夜之间,您可能会有数千个条目,这当然需要内存来存储。

为了避免这种情况,您可以在添加新条目时删除旧条目:

if (listbox.Items.Count > 100)
    listbox.Items.RemoveAt(0); // 0 or 99, whichever is your oldest
listbox.Items.Add(status);
listbox.ScrollIntoView(status);

ListBox有一个泄漏,如果一个'DataTemplate'被分配。即使您只是在其中放入一个TextBox,您也可以测量到相当大的内存泄漏。我找到了一个解决方案,将其替换为"ListView"。"ListView"似乎已经注意到这个漏洞,微软的解决方案是添加一个受保护的方法"ClearContainerForItemOverride"。这将在每个不再使用的ListViewItem(数据项的容器)时调用。现在我们还可以使用它来清除所有分配的东西和附加的事件处理程序,这些处理程序会阻止DataTemplate的内容被垃圾收集器收集。这取决于DataTemplate里面有什么。我在那里为ListView的客户端调用了一个公共事件所以他/她可以把代码放在那里。在我的例子中,我只有一个TextBox,这导致了以下代码:

    private void lstLog_ClearListViewItemContainer(object sender,
        ClearListViewItemContainerEventArgs clearListViewItemContainerEventArgs)
    {
        ContentPresenter contentPresenter = VisualTree.FindChild<ContentPresenter>(
            clearListViewItemContainerEventArgs.ListViewItem, null, true);
        if (contentPresenter != null)
        {
            Control control = VisualTree.FindChild<Control>(contentPresenter, null, true);
            if (control != null)
            {
                TextBox txtLog = (TextBox)control;
                txtLog.GotFocus -= txtLog_GotFocus;
                txtLog.PreviewMouseDown -= txtLog_PreviewMouseDown;
                txtLog.SelectionChanged -= txtLog_SelectionChanged;
                txtLog.ContextMenu = null;  // cut the reference from the context menu back to the textbox
                BindingOperations.ClearBinding(txtLog, TextBox.TextProperty);
                BindingOperations.ClearBinding(txtLog, TextBox.ForegroundProperty);
                txtLog.Foreground = null;
                txtLog.Resources = null;
            }
            contentPresenter.DataContext = null;
            contentPresenter.ContentTemplate = null;
            contentPresenter.Content = null;
            contentPresenter.Resources = null;
        }
    }

To 'VisualTree':深入搜索类型T的第一个子元素。. net 'VisalTreeHelper'的自定义类型化版本。

我认为不是所有的清理代码都是必要的,但是太多总比太少好。对内存使用情况的测量表明,泄漏通过这种方式消失了。