diff --git a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs
index 703b2594680..4793222f40c 100644
--- a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs
+++ b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs
@@ -583,6 +583,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)
@@ -746,6 +754,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 5a2d7c14d46..171f53342f5 100644
--- a/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs
+++ b/src/DynamoCoreWpf/Views/Core/NodeView.xaml.cs
@@ -49,7 +49,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
@@ -296,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();
@@ -641,6 +643,8 @@ public NodeView()
Source = _frozenImageSource
};
+ RenderOptions.SetBitmapScalingMode(FrozenImage, BitmapScalingMode.LowQuality);
+
FrozenImage.SetBinding(Grid.VisibilityProperty, new Binding("IsFrozen")
{
Converter = _boolToVisibilityCollapsedConverter,
@@ -659,6 +663,8 @@ public NodeView()
Source = _transientImageSource
};
+ RenderOptions.SetBitmapScalingMode(TransientImage, BitmapScalingMode.LowQuality);
+
TransientImage.SetBinding(Grid.VisibilityProperty, new Binding("IsTransient")
{
Converter = _boolToVisibilityCollapsedConverter,
@@ -677,6 +683,8 @@ public NodeView()
Source = _hiddenEyeImageSource
};
+ RenderOptions.SetBitmapScalingMode(HiddenEyeImage, BitmapScalingMode.LowQuality);
+
HiddenEyeImage.SetBinding(Grid.VisibilityProperty, new Binding("IsVisible")
{
Converter = _inverseBooleanToVisibilityCollapsedConverter,
@@ -1031,6 +1039,7 @@ public NodeView()
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
TargetNullValue = null
});
+ RenderOptions.SetBitmapScalingMode(zoomStateImgOne, BitmapScalingMode.LowQuality);
zoomGlyphRowZero.Children.Add(zoomStateImgOne);
@@ -1062,6 +1071,7 @@ public NodeView()
Converter = _emptyToVisibilityCollapsedConverter,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
+ RenderOptions.SetBitmapScalingMode(zoomStateImgTwo, BitmapScalingMode.LowQuality);
// Image in column 1
var zoomStateImgThree = new Image
@@ -1085,6 +1095,7 @@ public NodeView()
Converter = _emptyToVisibilityCollapsedConverter,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
+ RenderOptions.SetBitmapScalingMode(zoomStateImgThree, BitmapScalingMode.LowQuality);
zoomGlyphRowOne.Children.Add(zoomStateImgTwo);
zoomGlyphRowOne.Children.Add(zoomStateImgThree);
@@ -1536,6 +1547,21 @@ private static Style GetCodeBlockPortItemControlStyle()
#endregion
+ private void DelayPreviewControlAction()
+ {
+ if (!IsMouseOver) return;
+
+ TryShowPreviewBubbles();
+ }
+
+ private void InitialTryShowPreviewBubble()
+ {
+ // Always set old ZIndex to the last value, even if mouse is not over the node.
+ oldZIndex = NodeViewModel.StaticZIndex;
+
+ viewModel.WorkspaceViewModel.DelayNodePreviewControl.Debounce(300, DelayPreviewControlAction);
+ }
+
private void OnNodeViewUnloaded(object sender, RoutedEventArgs e)
{
ViewModel.NodeLogic.DispatchedToUI -= NodeLogic_DispatchedToUI;
@@ -1763,7 +1789,14 @@ private void NodeModel_ConnectorAdded(Graph.Connectors.ConnectorModel obj)
// try to show the preview bubble without new mouse enter event.
if (IsMouseOver)
{
- Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded);
+ if (DynCmd.IsTestMode)
+ {
+ Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded);
+ }
+ else
+ {
+ InitialTryShowPreviewBubble();
+ }
}
}
@@ -2065,16 +2098,20 @@ 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);
+ if (DynCmd.IsTestMode)
+ {
+ Dispatcher.BeginInvoke(new Action(TryShowPreviewBubbles), DispatcherPriority.Loaded);
+ }
+ else
+ {
+ 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;
@@ -2099,23 +2136,30 @@ private bool IsPreviewDisabled()
// Or the user is selecting nodes
// 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 node is transient state.
+ // 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.IsTransient;
+ !ViewModel.IsPreviewInsetVisible || ViewModel.IsFrozen ||
+ ViewModel.WorkspaceViewModel.IsPanning;
}
private void OnNodeViewMouseLeave(object sender, MouseEventArgs e)
{
ViewModel.ZIndex = oldZIndex;
+ viewModel.WorkspaceViewModel.DelayNodePreviewControl.Cancel();
- //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 8288bc2d22a..ce312622cf8 100644
--- a/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs
+++ b/src/DynamoCoreWpf/Views/Core/WorkspaceView.xaml.cs
@@ -901,6 +901,11 @@ private void OnCanvasMouseDown(object sender, MouseButtonEventArgs e)
GeoScalingPopup.IsOpen = false;
if(PortContextMenu.IsOpen) DestroyPortContextMenu();
+
+ if (!ViewModel.IsPanning && e.MiddleButton == MouseButtonState.Pressed)
+ {
+ ViewModel.RequestTogglePanMode();
+ }
}
///
@@ -937,6 +942,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)