File: QuickInfo\LazyToolTip.cs
Web Access
Project: src\src\EditorFeatures\Core.Wpf\Microsoft.CodeAnalysis.EditorFeatures.Wpf_s3pc0hsu_wpftmp.csproj (Microsoft.CodeAnalysis.EditorFeatures.Wpf)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
 
namespace Microsoft.CodeAnalysis.Editor.QuickInfo
{
    internal partial class ContentControlService
    {
        /// <summary>
        /// Class which allows us to provide a delay-created tooltip for our reference entries.
        /// </summary>
        private sealed class LazyToolTip
        {
            private readonly Func<DisposableToolTip> _createToolTip;
            private readonly IThreadingContext _threadingContext;
            private readonly FrameworkElement _element;
 
            private DisposableToolTip _disposableToolTip;
 
            private LazyToolTip(
                IThreadingContext threadingContext,
                FrameworkElement element,
                Func<DisposableToolTip> createToolTip)
            {
                _threadingContext = threadingContext;
                _element = element;
                _createToolTip = createToolTip;
 
                _threadingContext.ThrowIfNotOnUIThread();
 
                // Set ourselves as the tooltip of this text block.  This will let WPF know that 
                // it should attempt to show tooltips here.  When WPF wants to show the tooltip 
                // though we'll hear about it "ToolTipOpening".  When that happens, we'll swap
                // out ourselves with a real tooltip that is lazily created.  When that tooltip
                // is the dismissed, we'll release the resources associated with it and we'll
                // reattach ourselves.
                _element.ToolTip = this;
 
                element.ToolTipOpening += this.OnToolTipOpening;
                element.ToolTipClosing += this.OnToolTipClosing;
            }
 
            public static void AttachTo(FrameworkElement element, IThreadingContext threadingContext, Func<DisposableToolTip> createToolTip)
                => new LazyToolTip(threadingContext, element, createToolTip);
 
            private void OnToolTipOpening(object sender, ToolTipEventArgs e)
            {
                try
                {
                    _threadingContext.ThrowIfNotOnUIThread();
 
                    Debug.Assert(_element.ToolTip == this);
                    Debug.Assert(_disposableToolTip == null);
 
                    _disposableToolTip = _createToolTip();
                    _element.ToolTip = _disposableToolTip.ToolTip;
                }
                catch (Exception ex) when (FatalError.ReportAndCatch(ex))
                {
                    // Do nothing, since this is a WPF event handler and propagating the exception would cause a crash
                }
            }
 
            private void OnToolTipClosing(object sender, ToolTipEventArgs e)
            {
                try
                {
                    _threadingContext.ThrowIfNotOnUIThread();
 
                    Debug.Assert(_disposableToolTip != null);
                    Debug.Assert(_element.ToolTip == _disposableToolTip.ToolTip);
 
                    _element.ToolTip = this;
 
                    _disposableToolTip.Dispose();
                    _disposableToolTip = null;
                }
                catch (Exception ex) when (FatalError.ReportAndCatch(ex))
                {
                    // Do nothing, since this is a WPF event handler and propagating the exception would cause a crash
                }
            }
        }
    }
}