[Updated, see below!]
In our WinForms application, where there is WPF FlowDocumentReader, there is a memory leak, in ElementHost. I recreated this problem in a simple project and added the code below.
What does the application do?
When I click button1:
- A
UserControl1, which contains only FlowDocumentReader, is created and set asElementHost Child - A
FlowDocumentis created from a text file (it contains only FlowDocumentwith StackPanela few thousand lines <TextBox/>) - Property
FlowDocumentReader Documentset toFlowDocument
At this point, the page displays correctly FlowDocument. A lot of memory is used, as expected.
Problem
button1, , ! GC , , ! , , :
button2, elementHost1.Child null GC (. ), - , , !
, . , ElementHost Controls, Disposing , null, GC, .
, , GC . .
VS, :
http://speedy.sh/8T5P2/WindowsFormsApplication7.zip
, . 2 . Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Documents;
using System.IO;
using System.Xml;
using System.Windows.Markup;
using System.Windows.Forms.Integration;
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
private ElementHost elementHost;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string rawXamlText = File.ReadAllText("in.txt");
using (var flowDocumentStringReader = new StringReader(rawXamlText))
using (var flowDocumentTextReader = new XmlTextReader(flowDocumentStringReader))
{
if (elementHost != null)
{
Controls.Remove(elementHost);
elementHost.Child = null;
elementHost.Dispose();
}
var uc1 = new UserControl1();
object document = XamlReader.Load(flowDocumentTextReader);
var fd = document as FlowDocument;
uc1.docReader.Document = fd;
elementHost = new ElementHost();
elementHost.Dock = DockStyle.Fill;
elementHost.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
Controls.Add(elementHost);
elementHost.Child = uc1;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (elementHost != null)
elementHost.Child = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
}
UserControl1.xaml
<UserControl x:Class="WindowsFormsApplication7.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<FlowDocumentReader x:Name="docReader"></FlowDocumentReader>
</UserControl>
:
, . ElementHost, , . , , , click1 , , - , , . , .
, , , :
1)
2) "",
3) "GO" -
4a) - .
4b) "CLEAN", , , , GC/
, 3) 4). "CLEAN" , , .
CLR "GO" ( ~ 350 ). , 16125 (5x ) Controls.TextBox 16125 Controls.TextBoxView, 16125 Documents.TextEditor, - . :
http://i.imgur.com/m28Aiux.png 
.
- ()
, WPF-, ElementHost FlowDocument, . , WPF TextBox, TextEditor.
, , , .
, TextBoxes, ( ):
var textBoxes = FindVisualChildren<TextBox>(this).ToList();
foreach (var textBox in textBoxes)
{
var type = textBox.GetType();
object textEditor = textBox.GetType().GetProperty("TextEditor", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(textBox, null);
var onDetach = textEditor.GetType().GetMethod("OnDetach", BindingFlags.NonPublic | BindingFlags.Instance);
onDetach.Invoke(textEditor, null);
}
FindVisualChildren:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
, , TextBox. GC.Collect() ( , ). , , , . TextEditors .