From 3b45327b379484a67d5e9558e64ba2c51e9b4ac4 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 4 Dec 2010 16:00:00 +0100 Subject: [PATCH] Fix SD-1787 - Memory Leak in ContextActionsBulbPopup --- .../AvalonEdit.AddIn/Src/CodeEditor.cs | 8 +++- .../AvalonEdit.AddIn/Src/CodeEditorView.cs | 7 ++- .../Src/ContextActionsRenderer.cs | 45 ++++++++----------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs index 2146d112ed..57c364d3d6 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs @@ -217,10 +217,11 @@ namespace ICSharpCode.AvalonEdit.AddIn TextCopied(this, e); } - protected virtual void DisposeTextEditor(TextEditor textEditor) + protected virtual void DisposeTextEditor(CodeEditorView textEditor) { // detach IconBarMargin from IconBarManager textEditor.TextArea.LeftMargins.OfType().Single().TextView = null; + textEditor.Dispose(); } void textEditor_GotFocus(object sender, RoutedEventArgs e) @@ -332,9 +333,9 @@ namespace ICSharpCode.AvalonEdit.AddIn // remove secondary editor this.Children.Remove(secondaryTextEditor); this.Children.Remove(gridSplitter); + secondaryTextEditorAdapter.Language.Detach(); DisposeTextEditor(secondaryTextEditor); secondaryTextEditor = null; - secondaryTextEditorAdapter.Language.Detach(); secondaryTextEditorAdapter = null; gridSplitter = null; this.RowDefinitions.RemoveAt(this.RowDefinitions.Count - 1); @@ -574,6 +575,9 @@ namespace ICSharpCode.AvalonEdit.AddIn if (errorPainter != null) errorPainter.Dispose(); this.Document = null; + DisposeTextEditor(primaryTextEditor); + if (secondaryTextEditor != null) + DisposeTextEditor(secondaryTextEditor); } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs index b467774c84..b47eabd56e 100755 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.AvalonEdit.AddIn /// There can be two CodeEditorView instances in a single CodeEditor if split-view /// is enabled. /// - public class CodeEditorView : SharpDevelopTextEditor + public class CodeEditorView : SharpDevelopTextEditor, IDisposable { public ITextEditor Adapter { get; set; } @@ -61,6 +61,11 @@ namespace ICSharpCode.AvalonEdit.AddIn SetupTabSnippetHandler(); } + public virtual void Dispose() + { + contextActionsRenderer.Dispose(); + } + protected override string FileName { get { return this.Adapter.FileName; } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs index a30362582a..6f1f1b2241 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActionsRenderer.cs @@ -18,7 +18,7 @@ namespace ICSharpCode.AvalonEdit.AddIn /// /// Renders Popup with context actions on the left side of the current line in the editor. /// - public class ContextActionsRenderer + public sealed class ContextActionsRenderer : IDisposable { readonly CodeEditorView editorView; ITextEditor Editor { get { return this.editorView.Adapter; } } @@ -36,12 +36,11 @@ namespace ICSharpCode.AvalonEdit.AddIn public bool IsEnabled { get { - try { - string fileName = this.Editor.FileName; - return fileName.EndsWith(".cs") || fileName.EndsWith(".vb"); - } catch { + string fileName = this.Editor.FileName; + if (String.IsNullOrEmpty(fileName)) return false; - } + return fileName.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) + || fileName.EndsWith(".vb", StringComparison.OrdinalIgnoreCase); } } @@ -59,10 +58,16 @@ namespace ICSharpCode.AvalonEdit.AddIn this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) }; this.delayMoveTimer.Stop(); this.delayMoveTimer.Tick += TimerMoveTick; - WorkbenchSingleton.Workbench.ViewClosed += WorkbenchSingleton_Workbench_ViewClosed; WorkbenchSingleton.Workbench.ActiveViewContentChanged += WorkbenchSingleton_Workbench_ActiveViewContentChanged; } - + + public void Dispose() + { + ClosePopup(); + WorkbenchSingleton.Workbench.ActiveViewContentChanged -= WorkbenchSingleton_Workbench_ActiveViewContentChanged; + delayMoveTimer.Stop(); + } + void ContextActionsRenderer_KeyDown(object sender, KeyEventArgs e) { if (this.popup == null) @@ -131,26 +136,14 @@ namespace ICSharpCode.AvalonEdit.AddIn this.popup.IsHiddenActionsExpanded = false; this.popup.ViewModel = null; } - - void WorkbenchSingleton_Workbench_ViewClosed(object sender, ViewContentEventArgs e) - { - try { - // prevent memory leaks - if (e.Content.PrimaryFileName == this.Editor.FileName) { - WorkbenchSingleton.Workbench.ViewClosed -= WorkbenchSingleton_Workbench_ViewClosed; - WorkbenchSingleton.Workbench.ActiveViewContentChanged -= WorkbenchSingleton_Workbench_ActiveViewContentChanged; - } - } catch {} - } - void WorkbenchSingleton_Workbench_ActiveViewContentChanged(object sender, EventArgs e) { - ClosePopup(); - try { - // open the popup again if in current file - if (((IViewContent)WorkbenchSingleton.Workbench.ActiveContent).PrimaryFileName == this.Editor.FileName) - CaretPositionChanged(this, EventArgs.Empty); - } catch {} + // open the popup again if in current file + IViewContent activeViewContent = WorkbenchSingleton.Workbench.ActiveViewContent; + if (activeViewContent != null && activeViewContent.PrimaryFileName == this.Editor.FileName) + CaretPositionChanged(this, EventArgs.Empty); + else // otherwise close popup + ClosePopup(); } } }