diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/PopupControlService.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/PopupControlService.cs index 08c0e6c1e75..1f7664f9778 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/PopupControlService.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/PopupControlService.cs @@ -468,10 +468,21 @@ private void ShowToolTip(DependencyObject o, bool fromKeyboard) } _currentToolTip.SetValue(OwnerProperty, o); - _currentToolTip.Opened += OnToolTipOpened; _currentToolTip.Closed += OnToolTipClosed; _currentToolTip.FromKeyboard = fromKeyboard; - _currentToolTip.IsOpen = true; + + if (!_currentToolTip.IsOpen) + { + // open the tooltip, and finish the initialization when its popup window is available. + _currentToolTip.Opened += OnToolTipOpened; + _currentToolTip.IsOpen = true; + } + else + { + // If the tooltip is already open, initialize it now. This only happens when the + // app manages the tooltip directly. + SetSafeArea(_currentToolTip); + } CurrentToolTipTimer = new DispatcherTimer(DispatcherPriority.Normal); CurrentToolTipTimer.Interval = TimeSpan.FromMilliseconds(ToolTipService.GetShowDuration(o)); @@ -632,6 +643,7 @@ private void ClearServiceProperties(ToolTip tooltip) { tooltip.ClearValue(OwnerProperty); tooltip.FromKeyboard = false; + tooltip.Closed -= OnToolTipClosed; if ((bool)tooltip.GetValue(ServiceOwnedProperty)) { @@ -727,8 +739,27 @@ private void OnToolTipOpened(object sender, EventArgs e) private void OnToolTipClosed(object sender, EventArgs e) { ToolTip toolTip = (ToolTip)sender; - toolTip.Closed -= OnToolTipClosed; - ClearServiceProperties(toolTip); + if (toolTip != CurrentToolTip) + { + // If we manage the tooltip (the normal case), the current tooltip closes via + // 1. DismissCurrentToolTip sets _currentToolTip=null and calls CloseToolTip + // 2. CloseToolTip sets toolTip.IsOpen=false, and returns + // 3. Asynchronously, the tooltip raises the Closed event (after popup animations have run) + // 4. our event handler OnToolTipClosed gets here + // It's now time to do the final cleanup, which includes removing this event handler. + ClearServiceProperties(toolTip); + } + else + { + // We get here if the app closes the current tooltip or its popup directly. + // Do nothing (i.e. ignore the event). This leaves the service properties in place - + // eventually DismissCurrentToolTip will call CloseToolTip, which needs them + // (in particular the Owner property). When that happens, either + // a. tooltip.IsOpen==false. CloseToolTip clears the service properties immediately. + // b. tooltip.IsOpen==true. (This can happen if the app re-opens the tooltip directly.) + // CloseToolTip proceeds as in step 2 of the normal case. + // Either way, the final cleanup happens. + } } // The previous tooltip hasn't closed and we are trying to open a new one