diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/WeakReferenceTests.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/WeakReferenceTests.cs index 29ae3be832..2925945ce4 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/WeakReferenceTests.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/WeakReferenceTests.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Windows.Threading; using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Rendering; @@ -45,7 +46,6 @@ namespace ICSharpCode.AvalonEdit } [Test] - [Ignore] public void DocumentDoesNotHoldReferenceToTextArea() { TextDocument textDocument = new TextDocument(); @@ -61,7 +61,6 @@ namespace ICSharpCode.AvalonEdit } [Test] - [Ignore] public void DocumentDoesNotHoldReferenceToTextEditor() { TextDocument textDocument = new TextDocument(); @@ -102,9 +101,12 @@ namespace ICSharpCode.AvalonEdit static void GarbageCollect() { - GC.WaitForPendingFinalizers(); - GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); - GC.WaitForPendingFinalizers(); + for (int i = 0; i < 3; i++) { + GC.WaitForPendingFinalizers(); + GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); + // pump WPF messages so that WeakEventManager can unregister + Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(delegate {})); + } } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs index 4d995f5ee8..036e57f59d 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs @@ -73,6 +73,8 @@ namespace ICSharpCode.AvalonEdit.Editing AddBinding(EditingCommands.SelectToDocumentEnd, Ctrl | Shift, Key.End, OnMoveCaretExtendSelection(CaretMovementType.DocumentEnd)); CommandBindings.Add(new CommandBinding(ApplicationCommands.SelectAll, OnSelectAll)); + + TextAreaDefaultInputHandler.WorkaroundWPFMemoryLeak(InputBindings); } static void OnSelectAll(object target, ExecutedRoutedEventArgs args) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs index 77d4d5f5b9..239a32fdbe 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs @@ -75,6 +75,8 @@ namespace ICSharpCode.AvalonEdit.Editing CommandBindings.Add(new CommandBinding(AvalonEditCommands.ConvertLeadingTabsToSpaces, OnConvertLeadingTabsToSpaces)); CommandBindings.Add(new CommandBinding(AvalonEditCommands.ConvertLeadingSpacesToTabs, OnConvertLeadingSpacesToTabs)); CommandBindings.Add(new CommandBinding(AvalonEditCommands.IndentSelection, OnIndentSelection)); + + TextAreaDefaultInputHandler.WorkaroundWPFMemoryLeak(InputBindings); } static TextArea GetTextArea(object target) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs index 2494fc6766..24d8175244 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs @@ -2,7 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.Linq; +using System.Collections.Generic; using System.Windows; using System.Windows.Input; @@ -54,6 +54,16 @@ namespace ICSharpCode.AvalonEdit.Editing return kb; } + internal static void WorkaroundWPFMemoryLeak(List inputBindings) + { + // Work around WPF memory leak: + // KeyBinding retains a reference to whichever UIElement it is used in first. + // Using a dummy element for this purpose ensures that we don't leak + // a real text editor (which a potentially large document). + UIElement dummyElement = new UIElement(); + dummyElement.InputBindings.AddRange(inputBindings); + } + #region Undo / Redo UndoStack GetUndoStack() {