diff --git a/src/DocumentationBrowserViewExtension/DocumentationBrowserView.xaml.cs b/src/DocumentationBrowserViewExtension/DocumentationBrowserView.xaml.cs index 5303c40e909..ca451bc2aae 100644 --- a/src/DocumentationBrowserViewExtension/DocumentationBrowserView.xaml.cs +++ b/src/DocumentationBrowserViewExtension/DocumentationBrowserView.xaml.cs @@ -109,6 +109,13 @@ protected virtual void Dispose(bool disposing) // Cleanup this.viewModel.LinkChanged -= NavigateToPage; this.documentationBrowser.NavigationStarting -= ShouldAllowNavigation; + this.documentationBrowser.DpiChanged -= DocumentationBrowser_DpiChanged; + + if (this.documentationBrowser.CoreWebView2 != null) + { + this.documentationBrowser.CoreWebView2.WebMessageReceived -= CoreWebView2OnWebMessageReceived; + } + // Note to test writers // Disposing the document browser will cause future tests // that uses the Browser component to crash @@ -116,17 +123,6 @@ protected virtual void Dispose(bool disposing) { this.documentationBrowser.Dispose(); } - this.documentationBrowser.DpiChanged -= DocumentationBrowser_DpiChanged; - try - { - if (this.documentationBrowser.CoreWebView2 != null) - this.documentationBrowser.CoreWebView2.WebMessageReceived -= CoreWebView2OnWebMessageReceived; - - } - catch (Exception) - { - return; - } } async void InitializeAsync() diff --git a/src/DocumentationBrowserViewExtension/DocumentationBrowserViewExtension.cs b/src/DocumentationBrowserViewExtension/DocumentationBrowserViewExtension.cs index 0601cf567e4..7e293c1d00a 100644 --- a/src/DocumentationBrowserViewExtension/DocumentationBrowserViewExtension.cs +++ b/src/DocumentationBrowserViewExtension/DocumentationBrowserViewExtension.cs @@ -436,6 +436,8 @@ protected virtual void Dispose(bool disposing) { this.pmExtension.PackageLoader.PackgeLoaded -= OnPackageLoaded; } + + PackageDocumentationManager.Instance.MessageLogged -= OnMessageLogged; PackageDocumentationManager.Instance.Dispose(); } diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index 5253492237b..a46e0216ba2 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -873,8 +873,8 @@ protected DynamoModel(IStartConfiguration config) if (!IsServiceMode) { SearchModel = new NodeSearchModel(Logger); - SearchModel.ItemProduced += - node => ExecuteCommand(new CreateNodeCommand(node, 0, 0, true, true)); + SearchModel.ItemProduced += SearchModel_ItemProduced; + } NodeFactory = new NodeFactory(); @@ -1021,6 +1021,11 @@ protected DynamoModel(IStartConfiguration config) DynamoReady(new ReadyParams(this)); } + private void SearchModel_ItemProduced(NodeModel node) + { + ExecuteCommand(new CreateNodeCommand(node, 0, 0, true, true)); + } + /// /// It returns a PathManager instance based on the mode in order to reuse it's Singleton instance or create a new one /// @@ -1476,6 +1481,10 @@ public void Dispose() FeatureFlags.MessageLogged -= LogMessageWrapper; } DynamoUtilities.DynamoFeatureFlagsManager.FlagsRetrieved -= CheckFeatureFlagTest; + if (!IsServiceMode) + { + SearchModel.ItemProduced -= SearchModel_ItemProduced; + } } private void InitializeCustomNodeManager() @@ -2886,7 +2895,7 @@ public void RemoveWorkspace(WorkspaceModel workspace) { OnWorkspaceRemoveStarted(workspace); if (_workspaces.Remove(workspace)) - { + { if (workspace is HomeWorkspaceModel) { workspace.Dispose(); diff --git a/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs b/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs index 4168958d142..d7ddfd9c860 100644 --- a/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs +++ b/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs @@ -24,7 +24,7 @@ namespace Dynamo.UI.Controls /// Notice this control shares a lot of logic with InCanvasSearchControl for now /// But they will diverge eventually because of UI improvements to auto complete. /// - public partial class NodeAutoCompleteSearchControl + public partial class NodeAutoCompleteSearchControl : IDisposable { ListBoxItem HighlightedItem; @@ -45,7 +45,10 @@ public NodeAutoCompleteSearchControl() if (Application.Current != null) { Application.Current.Deactivated += CurrentApplicationDeactivated; - Application.Current.MainWindow.Closing += NodeAutoCompleteSearchControl_Unloaded; + if (Application.Current.MainWindow != null) + { + Application.Current.MainWindow.Closing += NodeAutoCompleteSearchControl_Unloaded; + } } HomeWorkspaceModel.WorkspaceClosed += this.CloseAutoCompletion; } @@ -55,8 +58,12 @@ private void NodeAutoCompleteSearchControl_Unloaded(object sender, System.Compon if (Application.Current != null) { Application.Current.Deactivated -= CurrentApplicationDeactivated; - Application.Current.MainWindow.Closing -= NodeAutoCompleteSearchControl_Unloaded; + if (Application.Current.MainWindow != null) + { + Application.Current.MainWindow.Closing -= NodeAutoCompleteSearchControl_Unloaded; + } } + HomeWorkspaceModel.WorkspaceClosed -= this.CloseAutoCompletion; } private void CurrentApplicationDeactivated(object sender, EventArgs e) @@ -388,5 +395,10 @@ private void OnSuggestion_Click(object sender, RoutedEventArgs e) } ViewModel.PopulateAutoCompleteCandidates(); } + + public void Dispose() + { + NodeAutoCompleteSearchControl_Unloaded(this,null); + } } } diff --git a/src/DynamoCoreWpf/Extensions/ViewExtensionCommandExecutive.cs b/src/DynamoCoreWpf/Extensions/ViewExtensionCommandExecutive.cs index 20204d670dc..a9cc8910ace 100644 --- a/src/DynamoCoreWpf/Extensions/ViewExtensionCommandExecutive.cs +++ b/src/DynamoCoreWpf/Extensions/ViewExtensionCommandExecutive.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dynamo.Extensions; using Dynamo.Logging; using Dynamo.Models; @@ -7,14 +7,19 @@ namespace Dynamo.Wpf.Extensions { - internal class ViewExtensionCommandExecutive : ICommandExecutive + internal class ViewExtensionCommandExecutive : ICommandExecutive,IDisposable { private readonly DynamoViewModel dynamoViewModel; public ViewExtensionCommandExecutive(DynamoViewModel model) { dynamoViewModel = model; - MessageLogged += (message) => { dynamoViewModel.Model.Logger.Log(message); }; + MessageLogged += ViewExtensionCommandExecutive_MessageLogged; + } + + private void ViewExtensionCommandExecutive_MessageLogged(ILogMessage message) + { + dynamoViewModel.Model.Logger.Log(message); } public void ExecuteCommand(DynamoModel.RecordableCommand command, string uniqueId, string extensionName) @@ -42,5 +47,10 @@ private void Log(ILogMessage obj) var handler = MessageLogged; if (handler != null) handler(obj); } + + public void Dispose() + { + MessageLogged -= ViewExtensionCommandExecutive_MessageLogged; + } } } diff --git a/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs b/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs index 387be24c45c..09d11ca2a65 100644 --- a/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs +++ b/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; @@ -120,7 +120,7 @@ public void AddExtensionMenuItem(MenuItem menuItem) /// public void AddToExtensionsSideBar(IViewExtension viewExtension, ContentControl contentControl) { - bool added = dynamoView.AddOrFocusExtensionControl(viewExtension, contentControl); + bool added = dynamoView.AddOrFocusExtensionControl(viewExtension, contentControl); if (added) { @@ -223,7 +223,7 @@ public void OpenViewExtension(string extensionName) { dynamoViewModel.OnViewExtensionOpenRequest(extensionName); } - + /// /// Event raised when a component inside Dynamo raises a request to open a view extension. /// @@ -247,6 +247,13 @@ public event Action ViewExtensionOpenRequestWithParameter remove => dynamoViewModel.ViewExtensionOpenWithParameterRequest -= value; } + public new void Dispose() + { + if (CommandExecutive is IDisposable disposable) + { disposable.Dispose(); } + base.Dispose(); + } + } /// /// An enum that represents the different possible diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index 1f13e7a687d..a128f518531 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -3421,6 +3421,10 @@ public bool PerformShutdownSequence(ShutdownParams shutdownParams) BackgroundPreviewViewModel.Dispose(); + foreach (var wsvm in workspaces) + { + wsvm.Dispose(); + } MainGuideManager?.CloseRealTimeInfoWindow(); model.ShutDown(shutdownParams.ShutdownHost); diff --git a/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs index dac21d0b0c7..146e5850afd 100644 --- a/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs @@ -403,6 +403,7 @@ public override void Dispose() { cate.DisposeTree(); } + Model.EntryAdded += AddEntry; Model.EntryUpdated -= UpdateEntry; Model.EntryRemoved -= RemoveEntry; @@ -425,12 +426,7 @@ private void InitializeCore() searchIconAlignment = System.Windows.HorizontalAlignment.Left; // When Library changes, sync up - Model.EntryAdded += entry => - { - InsertEntry(MakeNodeSearchElementVM(entry), entry.Categories); - RaisePropertyChanged("BrowserRootCategories"); - }; - + Model.EntryAdded += AddEntry; Model.EntryUpdated += UpdateEntry; Model.EntryRemoved += RemoveEntry; @@ -440,6 +436,12 @@ private void InitializeCore() InsertClassesIntoTree(LibraryRootCategories); } + private void AddEntry(NodeSearchElement entry) + { + InsertEntry(MakeNodeSearchElementVM(entry), entry.Categories); + RaisePropertyChanged("BrowserRootCategories"); + } + private IEnumerable CategorizeEntries(IEnumerable entries, bool expanded) { var tempRoot = entries.GroupByRecursive( diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs index 86d6e6b481d..ea55d5c62ba 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs @@ -2892,7 +2892,13 @@ public void Dispose() dynamoViewModel.SideBarTabItems.CollectionChanged -= this.OnCollectionChanged; if (fileTrustWarningPopup != null) + { fileTrustWarningPopup.CleanPopup(); + } + //TODO code smell. + var workspaceView = this.ChildOfType(); + workspaceView?.Dispose(); + (workspaceView?.NodeAutoCompleteSearchBar?.Child as IDisposable)?.Dispose(); } } } diff --git a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs index ffe021f61cf..d684a58f7cf 100644 --- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs @@ -33,7 +33,7 @@ namespace Dynamo.Views /// /// Interaction logic for WorkspaceView.xaml /// - public partial class WorkspaceView + public partial class WorkspaceView: IDisposable { public enum CursorState { @@ -1134,5 +1134,10 @@ private void OnGeometryScaling_Click(object sender, RoutedEventArgs e) } GeoScalingPopup.IsOpen = true; } + + public void Dispose() + { + RemoveViewModelsubscriptions(ViewModel); + } } } diff --git a/src/DynamoManipulation/DynamoManipulationExtension.cs b/src/DynamoManipulation/DynamoManipulationExtension.cs index 89c10ed3fe3..23d138803da 100644 --- a/src/DynamoManipulation/DynamoManipulationExtension.cs +++ b/src/DynamoManipulation/DynamoManipulationExtension.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; @@ -174,6 +174,13 @@ private void UnregisterEventHandlers() BackgroundPreviewViewModel.CanNavigateBackgroundPropertyChanged -= Watch3DViewModelNavigateBackgroundPropertyChanged; BackgroundPreviewViewModel.ViewMouseDown -= Watch3DViewModelOnViewMouseDown; } + + var settings = GetRunSettings(WorkspaceModel); + if (settings != null) + { + settings.PropertyChanged -= OnRunSettingsPropertyChanged; + } + } private void Watch3DViewModelOnViewMouseDown(object o, MouseButtonEventArgs mouseButtonEventArgs) diff --git a/src/GraphMetadataViewExtension/GraphMetadataViewModel.cs b/src/GraphMetadataViewExtension/GraphMetadataViewModel.cs index b06466b33df..ee2151b8308 100644 --- a/src/GraphMetadataViewExtension/GraphMetadataViewModel.cs +++ b/src/GraphMetadataViewExtension/GraphMetadataViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.ObjectModel; using System.IO; using System.Windows.Media.Imaging; @@ -266,6 +266,7 @@ private void MarkCurrentWorkspaceModified() public void Dispose() { this.viewLoadedParams.CurrentWorkspaceChanged -= OnCurrentWorkspaceChanged; + this.viewLoadedParams.CurrentWorkspaceCleared += OnCurrentWorkspaceChanged; if (linterManager != null) { linterManager.PropertyChanged -= OnLinterManagerPropertyChange; diff --git a/src/LibraryViewExtensionWebView2/LibraryViewController.cs b/src/LibraryViewExtensionWebView2/LibraryViewController.cs index 1bfc43befbe..d00bfa47dc0 100644 --- a/src/LibraryViewExtensionWebView2/LibraryViewController.cs +++ b/src/LibraryViewExtensionWebView2/LibraryViewController.cs @@ -622,7 +622,6 @@ public void Dispose() protected void Dispose(bool disposing) { if (!disposing) return; - if (observer != null) observer.Dispose(); observer = null; if (this.dynamoWindow != null) @@ -636,11 +635,15 @@ protected void Dispose(bool disposing) } if (this.browser != null) { + browser.CoreWebView2.RemoveHostObjectFromScript("bridgeTwoWay"); browser.SizeChanged -= Browser_SizeChanged; browser.Loaded -= Browser_Loaded; browser.Dispose(); browser = null; } + twoWayScriptingObject.Dispose(); + dynamoViewModel = null; + commandExecutive = null; } public static async Task ExecuteScriptFunctionAsync(WebView2 webView2, string functionName, params object[] parameters) diff --git a/src/LibraryViewExtensionWebView2/ScriptingObject.cs b/src/LibraryViewExtensionWebView2/ScriptingObject.cs index 6642105bace..e143df61cb1 100644 --- a/src/LibraryViewExtensionWebView2/ScriptingObject.cs +++ b/src/LibraryViewExtensionWebView2/ScriptingObject.cs @@ -11,7 +11,7 @@ namespace Dynamo.LibraryViewExtensionWebView2 [ClassInterface(ClassInterfaceType.AutoDual)] [ComVisible(true)] - public class ScriptingObject + public class ScriptingObject: IDisposable { private LibraryViewController controller; @@ -20,6 +20,11 @@ public ScriptingObject(LibraryViewController controller) this.controller = controller; } + public void Dispose() + { + controller = null; + } + /// /// Used to get access to the iconResourceProvider and return a base64encoded string version of an icon. ///