diff --git a/src/DynamoCore/Graph/Nodes/NodeModel.cs b/src/DynamoCore/Graph/Nodes/NodeModel.cs index 7a08b3f0fee..b7e1edaf75a 100644 --- a/src/DynamoCore/Graph/Nodes/NodeModel.cs +++ b/src/DynamoCore/Graph/Nodes/NodeModel.cs @@ -411,6 +411,10 @@ internal ObservableHashSet Infos get { return infos; } } + /// + /// BlockInfoBubbleUpdates is flag used to block InfoBubble updates during (or immediately after) graph execution. + /// + internal bool BlockInfoBubbleUpdates = false; /// /// A publicly accessible collector of all Info/Warning/Error data diff --git a/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs b/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs index 412a2e00891..ed38fdf765a 100644 --- a/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs +++ b/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs @@ -698,7 +698,11 @@ private void OnUpdateGraphCompleted(AsyncTask task) var node = workspace.Nodes.FirstOrDefault(n => n.GUID == guid); if (node == null) continue; + + // Block Infos updates during the many errors/warnings/notifications added here + // InfoBubbles will be updated on NodeViewModel's EvaluationCompleted handler. using (node.PropertyChangeManager.SetPropsToSuppress(nameof(NodeModel.Infos), nameof(NodeModel.State))) + using (Disposable.Create(() => { node.BlockInfoBubbleUpdates = true; }, () => { node.BlockInfoBubbleUpdates = false; })) { node.Warning(warning.Value); // Update node warning message. } @@ -711,7 +715,11 @@ private void OnUpdateGraphCompleted(AsyncTask task) var node = workspace.Nodes.FirstOrDefault(n => n.GUID == guid); if (node == null) continue; + + // Block Infos updates during the many errors/warnings/notifications added here + // InfoBubbles will be updated on NodeViewModel's EvaluationCompleted handler. using (node.PropertyChangeManager.SetPropsToSuppress(nameof(NodeModel.Infos), nameof(NodeModel.State))) + using (Disposable.Create(() => { node.BlockInfoBubbleUpdates = true; }, () => { node.BlockInfoBubbleUpdates = false; })) { node.Info(string.Join(Environment.NewLine, info.Value.Select(w => w.Message))); } diff --git a/src/DynamoCoreWpf/ViewModels/Core/NodeViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/NodeViewModel.cs index ef89e10d916..2291b983757 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/NodeViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/NodeViewModel.cs @@ -1256,10 +1256,17 @@ private void UpdateErrorBubbleWidth() /// private void BuildErrorBubble() { - if (ErrorBubble == null) ErrorBubble = new InfoBubbleViewModel(this) + if (ErrorBubble == null) { - IsCollapsed = this.IsCollapsed - }; + ErrorBubble = new InfoBubbleViewModel(this) + { + IsCollapsed = this.IsCollapsed, + // The Error bubble sits above the node in ZIndex. Since pinned notes sit above + // the node as well and the ErrorBubble needs to display on top of these, the + // ErrorBubble's ZIndex should be the node's ZIndex + 2. + ZIndex = ZIndex + 2 + }; + } ErrorBubble.NodeInfoToDisplay.CollectionChanged += UpdateOverlays; ErrorBubble.NodeWarningsToDisplay.CollectionChanged += UpdateOverlays; @@ -1273,14 +1280,8 @@ private void BuildErrorBubble() WorkspaceViewModel.Errors.Add(ErrorBubble); }); } - - // The Error bubble sits above the node in ZIndex. Since pinned notes sit above - // the node as well and the ErrorBubble needs to display on top of these, the - // ErrorBubble's ZIndex should be the node's ZIndex + 2. - ErrorBubble.ZIndex = ZIndex + 2; // The Node displays a count of dismissed messages, listening to that collection in the node's ErrorBubble - ErrorBubble.DismissedMessages.CollectionChanged += DismissedNodeMessages_CollectionChanged; } @@ -1464,7 +1465,15 @@ private void DisposeErrorBubble() public void UpdateBubbleContent() { - if (DynamoViewModel == null) return; + if (NodeModel.BlockInfoBubbleUpdates) + { + return; + } + + if (DynamoViewModel == null) + { + return; + } bool hasErrorOrWarning = NodeModel.IsInErrorState || NodeModel.State == ElementState.Warning; bool isNodeStateInfo = NodeModel.State == ElementState.Info || NodeModel.State == ElementState.PersistentInfo; diff --git a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs index 89c7fce8982..c48f4adc246 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs @@ -885,7 +885,8 @@ void Model_NodeRemoved(NodeModel node) lock (Nodes) { nodeViewModel = Nodes.First(x => x.NodeLogic == node); - Errors.Remove(nodeViewModel.ErrorBubble); + if (nodeViewModel.ErrorBubble != null) + Errors.Remove(nodeViewModel.ErrorBubble); Nodes.Remove(nodeViewModel); } //unsub the events we attached below in NodeAdded. @@ -904,8 +905,9 @@ void Model_NodeAdded(NodeModel node) { Nodes.Add(nodeViewModel); } - Errors.Add(nodeViewModel.ErrorBubble); - + if (nodeViewModel.ErrorBubble != null) + Errors.Add(nodeViewModel.ErrorBubble); + PostNodeChangeActions(); } diff --git a/src/DynamoCoreWpf/Views/Preview/InfoBubbleView.xaml b/src/DynamoCoreWpf/Views/Preview/InfoBubbleView.xaml index ad3c07cdeed..3a26ecf151c 100644 --- a/src/DynamoCoreWpf/Views/Preview/InfoBubbleView.xaml +++ b/src/DynamoCoreWpf/Views/Preview/InfoBubbleView.xaml @@ -63,7 +63,7 @@ Margin="-10,-900,0,8" HorizontalAlignment="Left" LastChildFill="False" - Visibility="{Binding DoesNodeDisplayMessages, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}"> + Visibility="{Binding DoesNodeDisplayMessages, FallbackValue=Collapsed, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}"> + Visibility="{Binding DoesNodeDisplayMessages, FallbackValue=Collapsed, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}" /> + Visibility="{Binding NodeErrorsVisible, FallbackValue=Collapsed, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}"> @@ -126,7 +126,7 @@ FontSize="15" Foreground="Black" Text="{x:Static p:Resources.InfoBubbleError}" - Visibility="{Binding NodeErrorsSectionExpanded, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}" /> + Visibility="{Binding NodeErrorsSectionExpanded, FallbackValue=Collapsed, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}" /> + Visibility="{Binding NodeErrorsSectionExpanded, FallbackValue=Collapsed, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}">