diff --git a/src/GraphNodeManagerViewExtension/GraphNodeManagerView.xaml.cs b/src/GraphNodeManagerViewExtension/GraphNodeManagerView.xaml.cs index f37bc8d0ea3..e3efc6edaaa 100644 --- a/src/GraphNodeManagerViewExtension/GraphNodeManagerView.xaml.cs +++ b/src/GraphNodeManagerViewExtension/GraphNodeManagerView.xaml.cs @@ -1,5 +1,9 @@ +using System; +using System.ComponentModel; +using System.Linq; using System.Windows; using System.Windows.Controls; +using System.Windows.Data; using System.Windows.Input; using Dynamo.GraphNodeManager.ViewModels; @@ -8,7 +12,7 @@ namespace Dynamo.GraphNodeManager /// /// Interaction logic for GraphNodeManagerView.xaml /// - public partial class GraphNodeManagerView : UserControl + public partial class GraphNodeManagerView : UserControl, IDisposable { /// /// A persistent handle of the currently selected row @@ -25,6 +29,9 @@ public partial class GraphNodeManagerView : UserControl /// private bool mouseHandled = false; + private GraphNodeManagerViewModel viewModel; + private bool disposedValue; + /// /// Constructor /// @@ -33,7 +40,38 @@ public GraphNodeManagerView(GraphNodeManagerViewModel viewModel) { InitializeComponent(); + this.viewModel = viewModel; this.DataContext = viewModel; + + viewModel.PropertyChanged += ViewModel_OnPropertyChanged; + viewModel.RequestExportGraph += ViewModel_RequestExportGraph; + } + + private void ViewModel_RequestExportGraph(object parameter) + { + if (parameter == null) return; + var type = parameter.ToString(); + var promptName = System.IO.Path.GetFileNameWithoutExtension(viewModel.CurrentWorkspace.FileName); + + var filteredNodes = NodesInfoDataGrid.ItemsSource.Cast().ToArray(); + + switch (type) + { + case "CSV": + Utilities.Utilities.ExportToCSV(filteredNodes, promptName); + break; + case "JSON": + Utilities.Utilities.ExportToJson(filteredNodes, promptName); + break; + } + } + + private void ViewModel_OnPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(GraphNodeManagerViewModel.IsAnyFilterOn)) + { + CollectionViewSource.GetDefaultView(NodesInfoDataGrid.ItemsSource).Refresh(); + } } /// @@ -118,5 +156,22 @@ private void ExportButton_OnClick(object sender, RoutedEventArgs e) e.Handled = true; } + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + viewModel.PropertyChanged -= ViewModel_OnPropertyChanged; + viewModel.RequestExportGraph -= ViewModel_RequestExportGraph; + + disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/GraphNodeManagerViewExtension/GraphNodeManagerViewExtension.cs b/src/GraphNodeManagerViewExtension/GraphNodeManagerViewExtension.cs index 79f708b121e..e56296b8106 100644 --- a/src/GraphNodeManagerViewExtension/GraphNodeManagerViewExtension.cs +++ b/src/GraphNodeManagerViewExtension/GraphNodeManagerViewExtension.cs @@ -64,6 +64,7 @@ private void MenuItemCheckHandler(object sender, RoutedEventArgs e) { AddToSidebar(); } + /// /// Close the Extension /// @@ -71,7 +72,6 @@ private void MenuItemCheckHandler(object sender, RoutedEventArgs e) /// private void MenuItemUnCheckedHandler(object sender, RoutedEventArgs e) { - this.Dispose(); viewLoadedParamsReference.CloseExtensioninInSideBar(this); } @@ -80,16 +80,11 @@ private void MenuItemUnCheckedHandler(object sender, RoutedEventArgs e) /// private void AddToSidebar() { + // Use late initialization for the GraphNodeManagerViewModel + this.ViewModel ??= new GraphNodeManagerViewModel(this.viewLoadedParamsReference, UniqueId, MessageLogged); // initialise the ViewModel and View for the window - this.ViewModel = new GraphNodeManagerViewModel(this.viewLoadedParamsReference, UniqueId, MessageLogged); - this.ManagerView = new GraphNodeManagerView(this.ViewModel); - - if (this.ManagerView == null) - { - return; - } - - this.ViewModel.GraphNodeManagerView = this.ManagerView; + // Use late initialization for the GraphNodeManagerView + this.ManagerView ??= new GraphNodeManagerView(this.ViewModel); this.viewLoadedParamsReference?.AddToExtensionsSideBar(this, this.ManagerView); } @@ -114,6 +109,7 @@ public override void Shutdown() /// public override void Dispose() { + this.ManagerView?.Dispose(); this.ViewModel?.Dispose(); this.ManagerView = null; this.ViewModel = null; diff --git a/src/GraphNodeManagerViewExtension/GraphNodeManagerViewModel.cs b/src/GraphNodeManagerViewExtension/GraphNodeManagerViewModel.cs index ea4e8bc2871..59f043f4720 100644 --- a/src/GraphNodeManagerViewExtension/GraphNodeManagerViewModel.cs +++ b/src/GraphNodeManagerViewExtension/GraphNodeManagerViewModel.cs @@ -44,7 +44,7 @@ public class GraphNodeManagerViewModel : NotificationObject, IDisposable private bool isAnyFilterOn = false; private Action logMessage; - private HomeWorkspaceModel CurrentWorkspace + internal HomeWorkspaceModel CurrentWorkspace { get { @@ -112,8 +112,6 @@ public string SearchText } } - public GraphNodeManagerView GraphNodeManagerView; - public string searchBoxPrompt = "Search.."; /// /// Search Box Prompt binding @@ -318,34 +316,16 @@ internal void ClearAllFilters(object obj) /// Export the current graph to CSV or JSON /// /// - /// internal void ExportGraph(object parameter) { - if (parameter == null) return; - var type = parameter.ToString(); - var promptName = System.IO.Path.GetFileNameWithoutExtension(currentWorkspace.FileName); - - var filteredNodes = FilteredNodesArray(); - - switch (type) - { - case "CSV": - Utilities.Utilities.ExportToCSV(filteredNodes, promptName); - break; - case "JSON": - Utilities.Utilities.ExportToJson(filteredNodes, promptName); - break; - } + RequestExportGraph?.Invoke(parameter); } /// - /// Helper method to return an Array of the currently active Nodes + /// This action is called on the export graph command. /// - /// - private GridNodeViewModel [] FilteredNodesArray() - { - return GraphNodeManagerView.NodesInfoDataGrid.ItemsSource.Cast().ToArray(); - } + /// + internal event Action RequestExportGraph; /// /// On changing a condition that affects the filter @@ -354,7 +334,6 @@ internal void NodesCollectionFilter_Changed() { // Refresh the view to apply filters. RaisePropertyChanged(nameof(IsAnyFilterOn)); - CollectionViewSource.GetDefaultView(GraphNodeManagerView.NodesInfoDataGrid.ItemsSource).Refresh(); } /// @@ -572,7 +551,6 @@ public void Dispose() viewLoadedParams.CurrentWorkspaceChanged -= OnCurrentWorkspaceChanged; viewLoadedParams.CurrentWorkspaceCleared -= OnCurrentWorkspaceCleared; NodesCollection.Filter -= NodesCollectionViewSource_Filter; - GraphNodeManagerView = null; } /// diff --git a/test/DynamoCoreWpfTests/ViewExtensions/GraphNodeManagerViewExtensionTests.cs b/test/DynamoCoreWpfTests/ViewExtensions/GraphNodeManagerViewExtensionTests.cs index a964df9eee3..7eff7b11e7f 100644 --- a/test/DynamoCoreWpfTests/ViewExtensions/GraphNodeManagerViewExtensionTests.cs +++ b/test/DynamoCoreWpfTests/ViewExtensions/GraphNodeManagerViewExtensionTests.cs @@ -22,8 +22,19 @@ namespace DynamoCoreWpfTests { public class GraphNodeManagerViewExtensionTests : DynamoTestUIBase { + private bool oldEnablePersistance = false; + private string PackagesDirectory { get { return Path.Combine(GetTestDirectory(this.ExecutingDirectory), "pkgs"); } } + protected override void GetLibrariesToPreload(List libraries) + { + libraries.Add("VMDataBridge.dll"); + libraries.Add("DesignScriptBuiltin.dll"); + libraries.Add("DSCoreNodes.dll"); + base.GetLibrariesToPreload(libraries); + } + + protected override DynamoModel.IStartConfiguration CreateStartConfiguration(IPathResolver pathResolver) { string settingDirectory = Path.Combine(GetTestDirectory(ExecutingDirectory), "settings"); @@ -53,13 +64,26 @@ private void LoadExtension(GraphNodeManagerViewExtension v) #endregion #region Tests + + [SetUp] + public void Setup() + { + oldEnablePersistance = ViewModel.PreferenceSettings.EnablePersistExtensions; + ViewModel.PreferenceSettings.EnablePersistExtensions = false; + } + + [TearDown] + public void Teardown() + { + ViewModel.PreferenceSettings.EnablePersistExtensions = oldEnablePersistance; + } + /// /// Test if the Extension loads correctly /// [Test] public void ViewExtensionOpenTest() { - RaiseLoadedEvent(this.View); var extensionManager = View.viewExtensionManager; var viewExtension = extensionManager.ViewExtensions .FirstOrDefault(x => x as GraphNodeManagerViewExtension != null) @@ -82,7 +106,6 @@ public void ViewExtensionOpenTest() [Test] public void CorrectNumberNodeItemsTest() { - RaiseLoadedEvent(this.View); var extensionManager = View.viewExtensionManager; var viewExt = extensionManager.ViewExtensions .FirstOrDefault(x => x as GraphNodeManagerViewExtension != null) @@ -102,7 +125,6 @@ public void CorrectNumberNodeItemsTest() Open(@"pkgs\Dynamo Samples\extra\ZoomNodeColorStates.dyn"); hwm = this.ViewModel.CurrentSpace as HomeWorkspaceModel; - Utility.DispatcherUtil.DoEvents(); int loadedGraphNodes = hwm.Nodes.Count(); int loadedExtensionNodes = dataGridItems.Count; @@ -121,13 +143,13 @@ public void CorrectNumberNodeItemsTest() Assert.AreEqual(loadedGraphNodes, loadedExtensionNodes); Assert.AreEqual(deleteGraphNodes, deleteExtensionNodes); } + /// /// Test if using the IsFrozen filter yields correct results /// [Test] public void FilterFrozenItemsTest() { - RaiseLoadedEvent(this.View); var extensionManager = View.viewExtensionManager; var viewExt = extensionManager.ViewExtensions .FirstOrDefault(x => x as GraphNodeManagerViewExtension != null) @@ -137,7 +159,6 @@ public void FilterFrozenItemsTest() LoadExtension(viewExt); Open(@"pkgs\Dynamo Samples\extra\ZoomNodeColorStates.dyn"); - Utility.DispatcherUtil.DoEvents(); // Get number of frozen Nodes in the graph var hwm = this.ViewModel.CurrentSpace as HomeWorkspaceModel; @@ -174,30 +195,25 @@ public void FilterFrozenItemsTest() [Test] public void ContainsEmptyListOrNullTest() { - RaiseLoadedEvent(this.View); var extensionManager = View.viewExtensionManager; var viewExt = extensionManager.ViewExtensions .FirstOrDefault(x => x as GraphNodeManagerViewExtension != null) as GraphNodeManagerViewExtension; - var hwm = this.ViewModel.CurrentSpace as HomeWorkspaceModel; - - // Arrange LoadExtension(viewExt); - var view = viewExt.ManagerView; - - Open(@"pkgs\Dynamo Samples\extra\GraphNodeManagerTestGraph_NullsEmptyLists.dyn"); - - hwm = this.ViewModel.CurrentSpace as HomeWorkspaceModel; - hwm.Run(); + OpenAndRun(@"pkgs\Dynamo Samples\extra\GraphNodeManagerTestGraph_NullsEmptyLists.dyn"); Utility.DispatcherUtil.DoEvents(); + var view = viewExt.ManagerView; + var images = WpfUtilities.ChildrenOfType(view.NodesInfoDataGrid); - + int nullNodesImageCount = GetImageCount(images, "Null"); - int emptyListNodesImageCount = GetImageCount(images, "EmptyList"); + int emptyListNodesImageCount = GetImageCount(images, "EmptyList"); + + var hwm = this.ViewModel.CurrentSpace; int nullNodesCount = hwm.Nodes.Count(ContainsAnyNulls); int emptyListNodesCount = hwm.Nodes.Count(ContainsAnyEmptyLists); @@ -214,7 +230,6 @@ public void ContainsEmptyListOrNullTest() [Test] public void ViewExtensionOpensWithDynamoWhenRememberedTest() { - RaiseLoadedEvent(this.View); ViewModel.PreferenceSettings.EnablePersistExtensions = true; //assert that option is enabled @@ -247,7 +262,6 @@ public void ViewExtensionOpensWithDynamoWhenRememberedTest() [Test] public void ViewExtensionDoesNotOpensWithDynamoWhenClosedTest() { - RaiseLoadedEvent(this.View); ViewModel.PreferenceSettings.EnablePersistExtensions = true; //assert that option is enabled @@ -284,7 +298,6 @@ public void ViewExtensionDoesNotOpensWithDynamoWhenClosedTest() [Test] public void ViewExtensionDoesNotOpenWhenNotRememberedTest() { - RaiseLoadedEvent(this.View); ViewModel.PreferenceSettings.EnablePersistExtensions = false; //assert that option is disabled