From c5c5df293c1c72fad4bb94ffec3a1d4a7eede542 Mon Sep 17 00:00:00 2001 From: DimitarVen Date: Thu, 13 Feb 2025 13:03:07 +0200 Subject: [PATCH 01/10] delay preview control creation till when it is actually needed --- src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 61 +++++++++++++++---- .../Views/Core/WorkspaceView.xaml.cs | 10 +++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index 125bd48cba3..233a44cdbb4 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -41,7 +41,6 @@ public partial class NodeView : IViewModelView /// Old ZIndex of node. It's set, when mouse leaves node. /// private int oldZIndex; - private bool nodeWasClicked; public NodeView TopControl @@ -73,6 +72,14 @@ private void NodeView_MouseLeave(object sender, MouseEventArgs e) viewModel.OnMouseLeave(); } + /// + /// This is a dispatcher timer that ensures a preview control is only initialized + /// when it is absolutely needed. It is static so that it can be shared for all + /// node views, instead of each having its own timer with additional overhead. + /// + private static DispatcherTimer delayPreviewControlTimer = null; + private static NodeView previewControlHost = null; + internal PreviewControl PreviewControl { get @@ -132,6 +139,34 @@ public NodeView() Panel.SetZIndex(this, 1); } + private static void DelayPreviewControlAction(object sender, EventArgs e) + { + delayPreviewControlTimer.Stop(); + // potentially initialize the preview control only if the node is still in focus + if (previewControlHost?.IsMouseOver == true) + { + delayPreviewControlTimer.Dispatcher.BeginInvoke(previewControlHost.TryShowPreviewBubbles, DispatcherPriority.Loaded); + } + + previewControlHost = null; + } + + private void InitialTryShowPreviewBubble() + { + if (delayPreviewControlTimer == null) // prepare the shared timer + { + delayPreviewControlTimer = new DispatcherTimer(DispatcherPriority.Background, Dispatcher); + delayPreviewControlTimer.Interval = TimeSpan.FromMilliseconds(300); + delayPreviewControlTimer.Tick += DelayPreviewControlAction; + } + + // Always set old ZIndex to the last value, even if mouse is not over the node. + oldZIndex = NodeViewModel.StaticZIndex; + + previewControlHost = this; + delayPreviewControlTimer.Start(); + } + private void OnNodeViewUnloaded(object sender, RoutedEventArgs e) { ViewModel.NodeLogic.DispatchedToUI -= NodeLogic_DispatchedToUI; @@ -226,10 +261,7 @@ private void NodeModel_ConnectorAdded(Graph.Connectors.ConnectorModel obj) { // If the mouse does not leave the node after the connector is added, // try to show the preview bubble without new mouse enter event. - if (IsMouseOver) - { - Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded); - } + if (IsMouseOver) InitialTryShowPreviewBubble(); } void NodeLogic_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) @@ -506,16 +538,13 @@ private void OnNodeViewMouseEnter(object sender, MouseEventArgs e) // if the node is located under "Hide preview bubbles" menu item and the item is clicked, // ViewModel.DynamoViewModel.ShowPreviewBubbles will be updated AFTER node mouse enter event occurs // so, wait while ShowPreviewBubbles binding updates value - Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded); + InitialTryShowPreviewBubble(); } private void TryShowPreviewBubbles() { nodeWasClicked = false; - // Always set old ZIndex to the last value, even if mouse is not over the node. - oldZIndex = NodeViewModel.StaticZIndex; - // There is no need run further. if (IsPreviewDisabled()) return; @@ -541,21 +570,29 @@ private bool IsPreviewDisabled() // Or preview is disabled for this node // Or preview shouldn't be shown for some nodes (e.g. number sliders, watch nodes etc.) // Or node is frozen. + // Or we are panning the view return !ViewModel.DynamoViewModel.ShowPreviewBubbles || ViewModel.WorkspaceViewModel.IsConnecting || ViewModel.WorkspaceViewModel.IsSelecting || !previewEnabled || - !ViewModel.IsPreviewInsetVisible || ViewModel.IsFrozen; + !ViewModel.IsPreviewInsetVisible || ViewModel.IsFrozen || + ViewModel.WorkspaceViewModel.IsPanning; } private void OnNodeViewMouseLeave(object sender, MouseEventArgs e) { ViewModel.ZIndex = oldZIndex; + delayPreviewControlTimer.Stop(); - //Watch nodes doesn't have Preview so we should avoid to use any method/property in PreviewControl class due that Preview is created automatically + // The preview hasn't been instantiated yet, we should stop here + if (previewControl == null) return; + + // Watch nodes doesn't have Preview so we should avoid to use any method/property in PreviewControl class due that Preview is created automatically if (ViewModel.NodeModel != null && ViewModel.NodeModel is CoreNodeModels.Watch) return; // If mouse in over node/preview control or preview control is pined, we can not hide preview control. - if (IsMouseOver || PreviewControl.IsMouseOver || PreviewControl.StaysOpen || IsMouseInsidePreview(e) || + // check the field and not the property because that will trigger the instantiation + if (IsMouseOver || previewControl?.IsMouseOver == true || + previewControl?.StaysOpen == true || IsMouseInsidePreview(e) || (Mouse.Captured is DragCanvas && IsMouseInsideNodeOrPreview(e.GetPosition(this)))) return; // If it's expanded, then first condense it. diff --git a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs index a64660908c0..b592aaa13a2 100644 --- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs @@ -810,6 +810,11 @@ private void OnCanvasMouseDown(object sender, MouseButtonEventArgs e) GeoScalingPopup.IsOpen = false; if(PortContextMenu.IsOpen) DestroyPortContextMenu(); + + if (!ViewModel.IsPanning && e.MiddleButton == MouseButtonState.Pressed) + { + ViewModel.RequestTogglePanMode(); + } } /// @@ -846,6 +851,11 @@ private void OnMouseRelease(object sender, MouseButtonEventArgs e) // (not node, note, not buttons from viewControlPanel such as zoom, pan and so on) ContextMenuPopup.IsOpen = true; } + + if (ViewModel.IsPanning && e.MiddleButton == MouseButtonState.Released) + { + ViewModel.RequestTogglePanMode(); + } } private void OnMouseMove(object sender, MouseEventArgs e) From 4d1631edf84ce8d6b9804ee2b1c54db351fd502c Mon Sep 17 00:00:00 2001 From: DimitarVen Date: Fri, 14 Feb 2025 11:38:50 +0200 Subject: [PATCH 02/10] unload and dereference --- src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 10 ++++++++++ src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index 233a44cdbb4..d7e15855f75 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -167,6 +167,16 @@ private void InitialTryShowPreviewBubble() delayPreviewControlTimer.Start(); } + /// + /// Used to unload and dereference any stored node view preview data and events + /// + public static void ClearPreviewDelayTimer() + { + delayPreviewControlTimer.Tick -= DelayPreviewControlAction; + delayPreviewControlTimer = null; + previewControlHost = null; + } + private void OnNodeViewUnloaded(object sender, RoutedEventArgs e) { ViewModel.NodeLogic.DispatchedToUI -= NodeLogic_DispatchedToUI; diff --git a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs index b592aaa13a2..1c2be16ef72 100644 --- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs @@ -149,6 +149,8 @@ private void RemoveViewModelsubscriptions(WorkspaceViewModel ViewModel) ViewModel.Model.CurrentOffsetChanged -= vm_CurrentOffsetChanged; DynamoSelection.Instance.Selection.CollectionChanged -= OnSelectionCollectionChanged; infiniteGridView.DetachFromZoomBorder(zoomBorder); + + NodeView.ClearPreviewDelayTimer(); } /// From 03017abfb6a7c4134217b54db2e2672c0392dd09 Mon Sep 17 00:00:00 2001 From: DimitarVen Date: Fri, 14 Feb 2025 12:19:52 +0200 Subject: [PATCH 03/10] implement ActionDebouncer --- src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 38 +++++++------------ .../Views/Core/WorkspaceView.xaml.cs | 2 +- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index d7e15855f75..8670f0b4867 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -77,8 +77,7 @@ private void NodeView_MouseLeave(object sender, MouseEventArgs e) /// when it is absolutely needed. It is static so that it can be shared for all /// node views, instead of each having its own timer with additional overhead. /// - private static DispatcherTimer delayPreviewControlTimer = null; - private static NodeView previewControlHost = null; + private static ActionDebouncer delayPreviewControl = null; internal PreviewControl PreviewControl { @@ -139,42 +138,33 @@ public NodeView() Panel.SetZIndex(this, 1); } - private static void DelayPreviewControlAction(object sender, EventArgs e) + private void DelayPreviewControlAction() { - delayPreviewControlTimer.Stop(); - // potentially initialize the preview control only if the node is still in focus - if (previewControlHost?.IsMouseOver == true) - { - delayPreviewControlTimer.Dispatcher.BeginInvoke(previewControlHost.TryShowPreviewBubbles, DispatcherPriority.Loaded); - } + if (!IsMouseOver) return; - previewControlHost = null; + TryShowPreviewBubbles(); } private void InitialTryShowPreviewBubble() { - if (delayPreviewControlTimer == null) // prepare the shared timer - { - delayPreviewControlTimer = new DispatcherTimer(DispatcherPriority.Background, Dispatcher); - delayPreviewControlTimer.Interval = TimeSpan.FromMilliseconds(300); - delayPreviewControlTimer.Tick += DelayPreviewControlAction; - } - // Always set old ZIndex to the last value, even if mouse is not over the node. oldZIndex = NodeViewModel.StaticZIndex; - previewControlHost = this; - delayPreviewControlTimer.Start(); + if (delayPreviewControl == null) + { + delayPreviewControl = new ActionDebouncer(null); + } + + delayPreviewControl.Debounce(300, DelayPreviewControlAction); } /// /// Used to unload and dereference any stored node view preview data and events /// - public static void ClearPreviewDelayTimer() + public static void ResetPreviewControlDelay() { - delayPreviewControlTimer.Tick -= DelayPreviewControlAction; - delayPreviewControlTimer = null; - previewControlHost = null; + delayPreviewControl?.Dispose(); + delayPreviewControl = null; } private void OnNodeViewUnloaded(object sender, RoutedEventArgs e) @@ -591,7 +581,7 @@ private bool IsPreviewDisabled() private void OnNodeViewMouseLeave(object sender, MouseEventArgs e) { ViewModel.ZIndex = oldZIndex; - delayPreviewControlTimer.Stop(); + delayPreviewControl.Cancel(); // The preview hasn't been instantiated yet, we should stop here if (previewControl == null) return; diff --git a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs index 1c2be16ef72..b783bcd9414 100644 --- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs @@ -150,7 +150,7 @@ private void RemoveViewModelsubscriptions(WorkspaceViewModel ViewModel) DynamoSelection.Instance.Selection.CollectionChanged -= OnSelectionCollectionChanged; infiniteGridView.DetachFromZoomBorder(zoomBorder); - NodeView.ClearPreviewDelayTimer(); + NodeView.ResetPreviewControlDelay(); } /// From 65e3da20312da894c1c77bd1f31bff031c145a91 Mon Sep 17 00:00:00 2001 From: DimitarVen Date: Fri, 14 Feb 2025 12:24:33 +0200 Subject: [PATCH 04/10] update comments o\ --- src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index 8670f0b4867..cc66ff420f7 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -73,9 +73,9 @@ private void NodeView_MouseLeave(object sender, MouseEventArgs e) } /// - /// This is a dispatcher timer that ensures a preview control is only initialized - /// when it is absolutely needed. It is static so that it can be shared for all - /// node views, instead of each having its own timer with additional overhead. + /// This ensures that a preview control is initialized only when it is absolutely + /// needed. It is static so that it can be shared for all node views, instead of + /// each node having its own debouncer with additional overhead. /// private static ActionDebouncer delayPreviewControl = null; From c1606be3aa295a422ed9c100974d27378d124393 Mon Sep 17 00:00:00 2001 From: DimitarVen Date: Tue, 18 Feb 2025 16:16:08 +0200 Subject: [PATCH 05/10] move preview debouncer to workspaceviewmodel --- .../ViewModels/Core/WorkspaceViewModel.cs | 11 ++++++++ src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 25 ++----------------- .../Views/Core/WorkspaceView.xaml.cs | 2 -- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs index 209a89ea37b..564cbd12227 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs @@ -560,6 +560,14 @@ internal GeometryScalingViewModel GeoScalingViewModel } } + /// + /// Ensures that a preview control is initialized only when it is + /// absolutely needed. It lives here so that it can be shared by + /// all node views for reduced overhead and better management. + /// + internal Wpf.Utilities.ActionDebouncer DelayNodePreviewControl + = new Wpf.Utilities.ActionDebouncer(null); + #endregion public WorkspaceViewModel(WorkspaceModel model, DynamoViewModel dynamoViewModel) @@ -721,6 +729,9 @@ public override void Dispose() InCanvasSearchViewModel?.Dispose(); NodeAutoCompleteSearchViewModel.LuceneUtility?.DisposeAll(); NodeAutoCompleteSearchViewModel?.Dispose(); + + DelayNodePreviewControl?.Dispose(); + DelayNodePreviewControl = null; } internal void ZoomInInternal() diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index cc66ff420f7..d08d5da9549 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -72,13 +72,6 @@ private void NodeView_MouseLeave(object sender, MouseEventArgs e) viewModel.OnMouseLeave(); } - /// - /// This ensures that a preview control is initialized only when it is absolutely - /// needed. It is static so that it can be shared for all node views, instead of - /// each node having its own debouncer with additional overhead. - /// - private static ActionDebouncer delayPreviewControl = null; - internal PreviewControl PreviewControl { get @@ -150,21 +143,7 @@ private void InitialTryShowPreviewBubble() // Always set old ZIndex to the last value, even if mouse is not over the node. oldZIndex = NodeViewModel.StaticZIndex; - if (delayPreviewControl == null) - { - delayPreviewControl = new ActionDebouncer(null); - } - - delayPreviewControl.Debounce(300, DelayPreviewControlAction); - } - - /// - /// Used to unload and dereference any stored node view preview data and events - /// - public static void ResetPreviewControlDelay() - { - delayPreviewControl?.Dispose(); - delayPreviewControl = null; + viewModel.WorkspaceViewModel.DelayNodePreviewControl.Debounce(300, DelayPreviewControlAction); } private void OnNodeViewUnloaded(object sender, RoutedEventArgs e) @@ -581,7 +560,7 @@ private bool IsPreviewDisabled() private void OnNodeViewMouseLeave(object sender, MouseEventArgs e) { ViewModel.ZIndex = oldZIndex; - delayPreviewControl.Cancel(); + viewModel.WorkspaceViewModel.DelayNodePreviewControl.Cancel(); // The preview hasn't been instantiated yet, we should stop here if (previewControl == null) return; diff --git a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs index b783bcd9414..b592aaa13a2 100644 --- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs @@ -149,8 +149,6 @@ private void RemoveViewModelsubscriptions(WorkspaceViewModel ViewModel) ViewModel.Model.CurrentOffsetChanged -= vm_CurrentOffsetChanged; DynamoSelection.Instance.Selection.CollectionChanged -= OnSelectionCollectionChanged; infiniteGridView.DetachFromZoomBorder(zoomBorder); - - NodeView.ResetPreviewControlDelay(); } /// From 2bbd299cf5981c4a12977799aeb899b6a9e8551a Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Mon, 9 Jun 2025 20:24:10 -0700 Subject: [PATCH 06/10] Update NodeView.xaml.cs --- src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index c5c2328df56..a1a6401eecc 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -295,6 +295,9 @@ public Grid PresentationGrid #region constructors static NodeView() { + //Set bitmap scaling mode to low quality for default node icon. + RenderOptions.SetBitmapScalingMode(_defaultNodeIcon, BitmapScalingMode.LowQuality); + //Freeze the static resource to reduce memory overhead _frozenImageSource.Freeze(); _transientImageSource.Freeze(); @@ -640,6 +643,8 @@ public NodeView() Source = _frozenImageSource }; + RenderOptions.SetBitmapScalingMode(FrozenImage, BitmapScalingMode.LowQuality); + FrozenImage.SetBinding(Grid.VisibilityProperty, new Binding("IsFrozen") { Converter = _boolToVisibilityCollapsedConverter, @@ -658,6 +663,8 @@ public NodeView() Source = _transientImageSource }; + RenderOptions.SetBitmapScalingMode(TransientImage, BitmapScalingMode.LowQuality); + TransientImage.SetBinding(Grid.VisibilityProperty, new Binding("IsTransient") { Converter = _boolToVisibilityCollapsedConverter, @@ -676,6 +683,8 @@ public NodeView() Source = _hiddenEyeImageSource }; + RenderOptions.SetBitmapScalingMode(HiddenEyeImage, BitmapScalingMode.LowQuality); + HiddenEyeImage.SetBinding(Grid.VisibilityProperty, new Binding("IsVisible") { Converter = _inverseBooleanToVisibilityCollapsedConverter, @@ -1030,6 +1039,7 @@ public NodeView() UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, TargetNullValue = null }); + RenderOptions.SetBitmapScalingMode(zoomStateImgOne, BitmapScalingMode.LowQuality); zoomGlyphRowZero.Children.Add(zoomStateImgOne); @@ -1061,6 +1071,7 @@ public NodeView() Converter = _emptyToVisibilityCollapsedConverter, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); + RenderOptions.SetBitmapScalingMode(zoomStateImgTwo, BitmapScalingMode.LowQuality); // Image in column 1 var zoomStateImgThree = new Image @@ -1084,6 +1095,7 @@ public NodeView() Converter = _emptyToVisibilityCollapsedConverter, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); + RenderOptions.SetBitmapScalingMode(zoomStateImgThree, BitmapScalingMode.LowQuality); zoomGlyphRowOne.Children.Add(zoomStateImgTwo); zoomGlyphRowOne.Children.Add(zoomStateImgThree); From 814dbe935e060abe8866bfbed84599c9af53eccb Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:47:57 -0700 Subject: [PATCH 07/10] Update PreviewBubbleTests.cs --- test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs b/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs index 2ca88df7760..b8868136b30 100644 --- a/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs +++ b/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs @@ -630,6 +630,7 @@ public void PreviewBubble_ShownForColorRange() // open preview bubble RaiseMouseEnterOnNode(nodeView, () => !nodeView.PreviewControl.IsHidden); + DispatcherUtil.DoEvents(); Assert.IsFalse(nodeView.PreviewControl.IsHidden, "Preview bubble for color range should be shown"); } From 6d16f92a4f1c70c840b1091316f4de905731fbcd Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:24:22 -0700 Subject: [PATCH 08/10] Update PreviewBubbleTests.cs --- test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs b/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs index b8868136b30..0ee70e5f5da 100644 --- a/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs +++ b/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs @@ -630,7 +630,7 @@ public void PreviewBubble_ShownForColorRange() // open preview bubble RaiseMouseEnterOnNode(nodeView, () => !nodeView.PreviewControl.IsHidden); - DispatcherUtil.DoEvents(); + DispatcherUtil.DoEventsLoop(); Assert.IsFalse(nodeView.PreviewControl.IsHidden, "Preview bubble for color range should be shown"); } From aad4c8d271c15c7cd5b18eabcb0e355557ed5240 Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Tue, 17 Jun 2025 08:06:58 -0700 Subject: [PATCH 09/10] add test mode condition --- src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs index 51c4f242c93..5f1224c942f 100644 --- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs @@ -1786,7 +1786,17 @@ private void NodeModel_ConnectorAdded(Graph.Connectors.ConnectorModel obj) { // If the mouse does not leave the node after the connector is added, // try to show the preview bubble without new mouse enter event. - if (IsMouseOver) InitialTryShowPreviewBubble(); + if (IsMouseOver) + { + if (DynCmd.IsTestMode) + { + Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded); + } + else + { + InitialTryShowPreviewBubble(); + } + } } void NodeLogic_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) @@ -2087,7 +2097,14 @@ private void OnNodeViewMouseEnter(object sender, MouseEventArgs e) // if the node is located under "Hide preview bubbles" menu item and the item is clicked, // ViewModel.DynamoViewModel.ShowPreviewBubbles will be updated AFTER node mouse enter event occurs // so, wait while ShowPreviewBubbles binding updates value - InitialTryShowPreviewBubble(); + if (DynCmd.IsTestMode) + { + Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded); + } + else + { + InitialTryShowPreviewBubble(); + } } private void TryShowPreviewBubbles() From 0b4a88e1cd40b74708c82f34c014a5e4d1d7b2c7 Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Tue, 17 Jun 2025 08:15:04 -0700 Subject: [PATCH 10/10] Update PreviewBubbleTests.cs --- test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs b/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs index 0ee70e5f5da..2ca88df7760 100644 --- a/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs +++ b/test/DynamoCoreWpf3Tests/PreviewBubbleTests.cs @@ -630,7 +630,6 @@ public void PreviewBubble_ShownForColorRange() // open preview bubble RaiseMouseEnterOnNode(nodeView, () => !nodeView.PreviewControl.IsHidden); - DispatcherUtil.DoEventsLoop(); Assert.IsFalse(nodeView.PreviewControl.IsHidden, "Preview bubble for color range should be shown"); }