Skip to content

Commit d27bdba

Browse files
Fix #916 — Memory tab tooltip stops working after returning to tab
WPF Popup with PlacementTarget = chart can wedge when the user navigates away from a TabItem mid-hover: TabControl unloads the parent without firing MouseLeave on the chart, so _popup.IsOpen stays true with a stale anchor. On return, OnMouseMove sets IsOpen = true but it is already true — the assignment is a no-op and the popup never re-anchors or appears. Memory tab is the most visible victim because it has 6 charts inside a nested TabControl, multiplying the chance of a wedged popup, but the bug is general to ChartHoverHelper. - Force _popup.IsOpen = false on chart Loaded / Unloaded / IsVisibleChanged. - In OnMouseMove, toggle IsOpen off then on so WPF re-evaluates placement even when the popup believes it is already open. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7cc2265 commit d27bdba

1 file changed

Lines changed: 27 additions & 0 deletions

File tree

Dashboard/Helpers/ChartHoverHelper.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ public ChartHoverHelper(ScottPlot.WPF.WpfPlot chart, string unit)
5353

5454
chart.MouseMove += OnMouseMove;
5555
chart.MouseLeave += OnMouseLeave;
56+
57+
/* Tab switching can leave the popup wedged: WPF unloads the parent TabItem
58+
without firing MouseLeave, so IsOpen stays true with a stale anchor.
59+
When the chart becomes visible again, OnMouseMove sets IsOpen = true
60+
but it is already true, so the popup never re-anchors and never shows.
61+
Force-close on every visibility/load transition so the next mouse move
62+
re-opens cleanly. */
63+
chart.IsVisibleChanged += OnChartVisibilityChanged;
64+
chart.Unloaded += OnChartUnloaded;
65+
chart.Loaded += OnChartLoaded;
5666
}
5767

5868
public string Unit { get => _unit; set => _unit = value; }
@@ -61,11 +71,23 @@ public void Dispose()
6171
{
6272
_chart.MouseMove -= OnMouseMove;
6373
_chart.MouseLeave -= OnMouseLeave;
74+
_chart.IsVisibleChanged -= OnChartVisibilityChanged;
75+
_chart.Unloaded -= OnChartUnloaded;
76+
_chart.Loaded -= OnChartLoaded;
6477
_popup.IsOpen = false;
6578
_scatters.Clear();
6679
_barPlots.Clear();
6780
}
6881

82+
private void OnChartVisibilityChanged(object sender, DependencyPropertyChangedEventArgs e) =>
83+
_popup.IsOpen = false;
84+
85+
private void OnChartUnloaded(object sender, RoutedEventArgs e) =>
86+
_popup.IsOpen = false;
87+
88+
private void OnChartLoaded(object sender, RoutedEventArgs e) =>
89+
_popup.IsOpen = false;
90+
6991
public void Clear()
7092
{
7193
_scatters.Clear();
@@ -207,6 +229,11 @@ pick the series closest in Y (nearest line to cursor). */
207229
_text.Text = $"{bestLabel}\n{valueFormatted} {_unit}\n{time:HH:mm:ss}";
208230
_popup.HorizontalOffset = pos.X + 15;
209231
_popup.VerticalOffset = pos.Y + 15;
232+
/* Toggle if already open so WPF re-evaluates the placement target.
233+
Without this, a popup that was IsOpen = true when its TabItem was
234+
unloaded stays "open" with a stale anchor and never appears on
235+
return — the assignment below is a no-op. */
236+
if (_popup.IsOpen) _popup.IsOpen = false;
210237
_popup.IsOpen = true;
211238
}
212239
else

0 commit comments

Comments
 (0)