How to create Smart ToolTip in WPF Application

No.of Views4503
Bookmarked0 times
Downloads 
Votes0
By  Prabu   On  13 Dec 2010 09:12:15
Tag : WPF , ToolTips
In this article I will show how to create smart tooltip in WPF Application. For example, in Microsoft Word 2007, when you mouse over the Paste icon, the "Paste" tooltip appears with its description.
emailbookmarkadd commentsprint

Images in this article missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at info@codegain.com

 

Introduction

In this article I will show how to create smart tooltip in WPF Application. For example, in Microsoft Word 2007, when  you mouse over the Paste icon, the "Paste" tooltip appears with its description.

The Smart Tooltips are displayed when user hovers the cursor over an item, without clicking it, and a tooltip may appear. It may take a second or two to display the tooltip, but when it does appear, it usually is a small box with a yellow background explaining what the icon represents

Example of Smart Tooltip 

Image Loading

Implementation

In my project application, I thought of to show the Smart tooltip in my Enrolment module. My application is WPF XBAP application; hence I am not able to customize the Tooltip with my own style using shapes. Because internally Tooltips are showing using Popup, the customized tooltip are showing with black colored shadow in smart tooltip. Then I have search through the internet about this issue and come to know about Adorners and its feature from this link then decided to use Adorner for Smart Tooltip. Here is the adorner control source.

C# Code

ControlAdorner.cs

public class ControlAdorner : Adorner
    {
        private Control _child;

        public ControlAdorner(UIElement adornedElement)
            : base(adornedElement) { }

        protected override int VisualChildrenCount
        {
            get
            {
                return 1;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            if (index != 0) throw new ArgumentOutOfRangeException();
            return _child;
        }

        public Control Child
        {
            get { return _child; }
            set
            {
                if (_child != null)
                {
                    RemoveVisualChild(_child);
                }
                _child = value;
                if (_child != null)
                {
                    AddVisualChild(_child);
                }
            }
        }

        protected override Size MeasureOverride(Size constraint)
        {
            Size max = new Size(double.PositiveInfinity, double.PositiveInfinity);
            this._child.Measure(max);
            this.InvalidateArrange();
            return this._child.DesiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            FrameworkElement target = AdornedElement as FrameworkElement;
            Point location = new Point(target.ActualWidth + 2, -((_child.ActualHeight - target.ActualHeight) / 2));
            Rect rect = new Rect(location, finalSize);
            this._child.Arrange(rect);
            return this._child.RenderSize;
        }
    }

    public class Adorners : ContentControl
    {
        #region Attached Properties

        // Template attached property
        public static readonly DependencyProperty TemplateProperty =
            DependencyProperty.RegisterAttached("Template", typeof(ControlTemplate), typeof(Adorners), new PropertyMetadata(TemplateChanged));

        public static ControlTemplate GetTemplate(UIElement target)
        {
            return (ControlTemplate)target.GetValue(TemplateProperty);
        }
        public static void SetTemplate(UIElement target, ControlTemplate value)
        {
            target.SetValue(TemplateProperty, value);
        }
        private static void TemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UpdateAdroner((UIElement)d, GetIsVisible((UIElement)d), (ControlTemplate)e.NewValue);
        }

        // IsVisible attached property
        public static readonly DependencyProperty IsVisibleProperty =
            DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(Adorners), new PropertyMetadata(IsVisibleChanged));

        public static bool GetIsVisible(UIElement target)
        {
            return (bool)target.GetValue(IsVisibleProperty);
        }
        public static void SetIsVisible(UIElement target, bool value)
        {
            target.SetValue(IsVisibleProperty, value);
        }
        private static void IsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UserControl rootPage = FindVisualParent<UserControl>((UIElement)d);
            Control ctrl = GetChildWindow(rootPage) as Control;
            if (ctrl != null)
                UpdateAdroner((UIElement)d, (bool)e.NewValue, ctrl);
            else
                UpdateAdroner((UIElement)d, (bool)e.NewValue, GetTemplate((UIElement)d));
        }

        // ChildWindow attached property
        public static readonly DependencyProperty ChildWindowProperty =
            DependencyProperty.RegisterAttached("ChildWindow", typeof(DependencyObject), typeof(Adorners));

        public static DependencyObject GetChildWindow(DependencyObject target)
        {
            return (DependencyObject)target.GetValue(ChildWindowProperty);
        }
        public static void SetChildWindow(UIElement target, DependencyObject value)
        {
            target.SetValue(ChildWindowProperty, value);
        }

        // InternalAdorner attached property
        public static readonly DependencyProperty InternalAdornerProperty =
            DependencyProperty.RegisterAttached("InternalAdorner", typeof(ControlAdorner), typeof(Adorners));

        public static ControlAdorner GetInteranlAdorner(DependencyObject target)
        {
            return (ControlAdorner)target.GetValue(InternalAdornerProperty);
        }
        public static void SetInternalAdorner(DependencyObject target, ControlAdorner value)
        {
            target.SetValue(InternalAdornerProperty, value);
        }

        #endregion

        #region Implementation

        // Actually do all the work:
        private static void UpdateAdroner(UIElement adorned)
        {
            UpdateAdroner(adorned, GetIsVisible(adorned), GetTemplate(adorned));
        }

        private static void UpdateAdroner(UIElement adorned, bool isVisible, ControlTemplate controlTemplate)
        {
            var layer = AdornerLayer.GetAdornerLayer(adorned);

            if (layer == null)
            {
                // if we don't have an adorner layer it's probably because it's too early in the window's construction.
                Dispatcher.CurrentDispatcher.BeginInvoke( DispatcherPriority.Loaded,
                    new Action(() => { UpdateAdroner(adorned); }));
                return;
            }

            var existingAdorner = GetInteranlAdorner(adorned);

            if (existingAdorner == null)
            {
                if (controlTemplate != null && isVisible)
                {
                    // show
                    var newAdorner = new ControlAdorner(adorned);
                    newAdorner.Child = new Control() { Template = controlTemplate, Focusable = false, };
                    layer.Add(newAdorner);
                    SetInternalAdorner(adorned, newAdorner);
                }
            }
            else
            {
                if (controlTemplate != null && isVisible)
                {
                    // switch template
                    Control ctrl = existingAdorner.Child;
                    ctrl.Template = controlTemplate;
                }
                else
                {
                    // hide
                    existingAdorner.Child = null;
                    layer.Remove(existingAdorner);
                    SetInternalAdorner(adorned, null);
                }
            }
        }

        private static void UpdateAdroner(UIElement adorned, bool isVisible, Control childControl)
        {
            var layer = AdornerLayer.GetAdornerLayer(adorned);

            if (layer == null)
            {
                // if we don't have an adorner layer it's probably because it's too early in the window's construction.
                Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Loaded,
                    new Action(() => { UpdateAdroner(adorned); }));
                return;
            }

            var existingAdorner = GetInteranlAdorner(adorned);
            if (existingAdorner == null)
            {
                if (childControl != null && isVisible)
                {
                    // show
                    var newAdorner = new ControlAdorner(adorned);
                    newAdorner.Child = childControl;
                    layer.Add(newAdorner);
                    SetInternalAdorner(adorned, newAdorner);
                }
            }
            else
            {
                if (childControl != null && isVisible)
                {
                    // switch template
                    Control ctrl = childControl;
                }
                else
                {
                    // hide
                    existingAdorner.Child = null;
                    layer.Remove(existingAdorner);
                    SetInternalAdorner(adorned, null);
                }
            }
        }

        public static T FindVisualParent<T>(UIElement element) where T : UIElement
        {
            UIElement parent = element;
            while (parent != null)
            {
                T correctlyTyped = parent as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }

                parent = VisualTreeHelper.GetParent(parent) as UIElement;
            }

            return null;
        }

        #endregion
    }

 

That's all  in code, just use this in application

Output 

Image Loading

Download Sample Project

Download source files -17 kb

Conlcusion

In this article you have learned how to create smart tooltip in WPF Application.hopes help.thank you for reading.

 
Sign Up to vote for this article
 
About Author
 
Prabu
Occupation-Software Engineer
Company-
Member Type-Fresh
Location-India
Joined date-23 Jun 2010
Home Page-
Blog Page-http://prabu-guru.blogspot.com/
 
 
Other popularSectionarticles
Comments
There is no comments for this articles.
Leave a Reply
Title:
Display Name:
Email:
(not display in page for the security purphase)
Website:
Message:
Please refresh your screen using Ctrl+F5
If you can't read this number refresh your screen
Please input the anti-spam code that you can read in the image.
^ Scroll to Top