From 9581b801bcf3f165e83dcea46b73dad6cd880a65 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Sat, 2 May 2026 10:37:40 -0400 Subject: [PATCH] =?UTF-8?q?Fix=20#916=20(Lite)=20=E2=80=94=20Memory=20tab?= =?UTF-8?q?=20tooltip=20stops=20working=20after=20returning=20to=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors Dashboard fix in 4e58e8a. WPF Popup with PlacementTarget = chart can wedge when the user navigates away from a TabItem mid-hover: WPF 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. Lite has the same nested TabControl pattern (parent Memory tab hosting Memory Overview / Memory Clerks / Memory Grants / Memory Pressure Events sub-tabs) so the bug surfaces the same way. - 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) --- Lite/Helpers/ChartHoverHelper.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Lite/Helpers/ChartHoverHelper.cs b/Lite/Helpers/ChartHoverHelper.cs index 28241eb..1e0514d 100644 --- a/Lite/Helpers/ChartHoverHelper.cs +++ b/Lite/Helpers/ChartHoverHelper.cs @@ -53,6 +53,16 @@ public ChartHoverHelper(ScottPlot.WPF.WpfPlot chart, string unit) chart.MouseMove += OnMouseMove; chart.MouseLeave += OnMouseLeave; + + /* Tab switching can leave the popup wedged: WPF unloads the parent TabItem + without firing MouseLeave, so IsOpen stays true with a stale anchor. + When the chart becomes visible again, OnMouseMove sets IsOpen = true + but it is already true, so the popup never re-anchors and never shows. + Force-close on every visibility/load transition so the next mouse move + re-opens cleanly. */ + chart.IsVisibleChanged += OnChartVisibilityChanged; + chart.Unloaded += OnChartUnloaded; + chart.Loaded += OnChartLoaded; } public string Unit { get => _unit; set => _unit = value; } @@ -61,11 +71,23 @@ public void Dispose() { _chart.MouseMove -= OnMouseMove; _chart.MouseLeave -= OnMouseLeave; + _chart.IsVisibleChanged -= OnChartVisibilityChanged; + _chart.Unloaded -= OnChartUnloaded; + _chart.Loaded -= OnChartLoaded; _popup.IsOpen = false; _scatters.Clear(); _barPlots.Clear(); } + private void OnChartVisibilityChanged(object sender, DependencyPropertyChangedEventArgs e) => + _popup.IsOpen = false; + + private void OnChartUnloaded(object sender, RoutedEventArgs e) => + _popup.IsOpen = false; + + private void OnChartLoaded(object sender, RoutedEventArgs e) => + _popup.IsOpen = false; + public void Clear() { _scatters.Clear(); @@ -193,6 +215,11 @@ private void OnMouseMove(object sender, MouseEventArgs e) _text.Text = $"{bestLabel}\n{valueFormatted} {_unit}\n{time:HH:mm:ss}"; _popup.HorizontalOffset = pos.X + 15; _popup.VerticalOffset = pos.Y + 15; + /* Toggle if already open so WPF re-evaluates the placement target. + Without this, a popup that was IsOpen = true when its TabItem was + unloaded stays "open" with a stale anchor and never appears on + return — the assignment below is a no-op. */ + if (_popup.IsOpen) _popup.IsOpen = false; _popup.IsOpen = true; } else