WPF的悬停工具栏实现方案

解决方法:参照ToolTip控件实现一个功能更为强大的ToolTip(命名为RichToolTip)

1、目标:仿照Word2007的悬停工具栏,如下图实现上下文工具栏。

2、虽然ToolTip的控件模板可以定义为包含可交互操作的控件(如Button,TextBox等),然而却无法接受焦点(鼠标移到ToolTip上内容立即就消失),所以无法用此办法实现;

3、使用方法与ToolTipService类似,参见如下代码:

<TextBox x:Name="_txtWords" BorderThickness="1" BorderBrush="Black" Margin="5">
    <controls:RichToolTip.PopupContent>
        <controls:RichToolTip
                PlacementTarget="{Binding RelativeSource={RelativeSource Self}, Path=RelatedObject}"
                Placement="MousePoint" 
                HorizontalOffset="0"
                VerticalOffset="0">
            <Border BorderBrush="Black" BorderThickness="1" Margin="5" Background="DarkKhaki">
                <utils:HoverOverToolBarView />
            </Border>
        </controls:RichToolTip>
    </controls:RichToolTip.PopupContent>
</TextBox>

4、应用效果如下所见:

 5、代码实现:

RichToolTip Control's Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Windows;
  5 using System.Windows.Controls;
  6 using System.Windows.Controls.Primitives;
  7 using System.Windows.Data;
  8 using System.Windows.Documents;
  9 using System.Windows.Input;
 10 using System.Windows.Media;
 11 using System.Windows.Media.Imaging;
 12 using System.Windows.Shapes;
 13 using System.Windows.Threading;
 14 using System.Runtime.InteropServices;
 15 using System.Windows.Interop;
 16 using System.Reflection;
 17 using System.Diagnostics;
 18 using System.Security;
 19 using System.Security.Permissions;
 20 using System.Windows.Navigation;
 21 using System.Windows.Media.Animation;
 22 
 23 namespace JetSun.Presentation.Controls
 24 {
 25     /// <summary>
 26     /// A kind-of Tooltip implementation that stays open once element is hovered and the content inside is responsive
 27     /// 
 28     /// It corresponds to most of the TooltipService attached properties so use them as you wish
 29     /// Known Issues:
 30     /// 1 - I didn't have the time nor the strength to care about repositioning. I simply hide the popup whenever it would need repositioning. (Window movement, etc..) But it's ok since it's the default behavior of popup overall.
 31     /// 2 - XBap mode sets transparency through a hack! supported only in full trust.
 32     /// 3 - In XBap mode, moving the mouse slowly towards the popup will cause it to hide
 33     /// 4 - In XBap mode, moving the mouse over the element shows the tooltip even when the browser isn't the active window
 34     /// </summary>
 35     /// 
 36     public partial class RichToolTip : ContentControl
 37     {
 38         #region Fields
 39         const int _animationDurationInMs = 200;
 40         const int _showDeferredMilliseconds = 500;
 41         const bool _animationEnabledDefault = true;
 42 
 43         delegate void Action();
 44         Popup _parentPopup;
 45 
 46         static RichToolTip _lastShownPopup = null;
 47         #endregion
 48 
 49         #region Properties
 50         UIElement _relatedObject;
 51         /// <summary>
 52         /// 关联控件
 53         /// </summary>
 54         public UIElement RelatedObject
 55         {
 56             get { return _relatedObject; }
 57         }
 58 
 59         private bool _enableAnimation = _animationEnabledDefault;
 60         /// <summary>
 61         /// 是否显示动画
 62         /// </summary>
 63         public bool EnableAnimation
 64         {
 65             get { return _enableAnimation; }
 66             set { _enableAnimation = value; }
 67         }
 68         #endregion
 69 
 70         #region Instancing
 71         static RichToolTip()
 72         {
 73             EventManager.RegisterClassHandler(typeof(UIElement), UIElement.MouseDownEvent, new MouseButtonEventHandler(OnElementMouseDown), true);
 74             EventManager.RegisterClassHandler(typeof(RichToolTip), ButtonBase.ClickEvent, new RoutedEventHandler(OnButtonBaseClick), false);
 75             EventManager.RegisterClassHandler(typeof(Selector), Selector.SelectionChangedEvent, new SelectionChangedEventHandler(selector_SelectionChangedEvent), true);
 76 
 77             if (BrowserInteropHelper.IsBrowserHosted)
 78             {
 79                 EventManager.RegisterClassHandler(typeof(NavigationWindow), UIElement.MouseLeaveEvent, new RoutedEventHandler(OnNavigationWindowMouseLeaveEvent), true);
 80             }
 81             else
 82             {
 83                 EventManager.RegisterClassHandler(typeof(Window), Window.SizeChangedEvent, new RoutedEventHandler(OnWindowSizeChanged), true);
 84             }
 85 
 86             CommandManager.RegisterClassCommandBinding(typeof(RichToolTip), new CommandBinding(CloseCommand, ExecuteCloseCommand));
 87             InitStoryboards();
 88         }
 89         /// <summary>
 90         /// 
 91         /// </summary>
 92         public RichToolTip()
 93         {
 94             Loaded += new RoutedEventHandler(ContentTooltip_Loaded);
 95             Unloaded += new RoutedEventHandler(ContentTooltip_Unloaded);
 96         }
 97         /// <summary>
 98         /// 
 99         /// </summary>
100         /// <param name="relatedObject"></param>
101         public RichToolTip(UIElement relatedObject)
102             : this()
103         {
104             Load(relatedObject);
105         }
106         #endregion
107 
108         #region Loading
109         void Load(UIElement relatedObject)
110         {
111             _relatedObject = relatedObject;
112 
113             FrameworkElement fe = relatedObject as FrameworkElement;
114 
115             if (fe == null)
116             {
117                 throw new InvalidOperationException("The element is not supported");
118             }
119 
120             _relatedObject.MouseEnter += element_MouseEnter;
121             _relatedObject.MouseLeave += element_MouseLeave;
122 
123             fe.Unloaded += new RoutedEventHandler(RelatedObject_Unloaded);
124 
125             BindRootVisual();
126 
127             this.MouseLeave += new MouseEventHandler(RichToolTip_MouseLeave);
128         }
129 
130         void RichToolTip_MouseLeave(object sender, MouseEventArgs e)
131         {
132             if (IsShown() && this == _lastShownPopup)
133             {
134                 Hide(true);
135             }
136         }
137 
138         void RelatedObject_Unloaded(object sender, RoutedEventArgs e)
139         {
140             _relatedObject.MouseEnter -= element_MouseEnter;
141             _relatedObject.MouseLeave -= element_MouseLeave;
142         }
143 
144         void ContentTooltip_Unloaded(object sender, RoutedEventArgs e)
145         {
146             UnbindRootVisual();
147         }
148 
149         void ContentTooltip_Loaded(object sender, RoutedEventArgs e)
150         {
151             BindRootVisual();
152         }
153         #endregion
154 
155         #region Popup Creation
156         private static readonly Type PopupType = typeof(Popup);
157         private static readonly Type PopupSecurityHelperType = PopupType.GetNestedType("PopupSecurityHelper", BindingFlags.Public | BindingFlags.NonPublic);
158 
159         private static readonly FieldInfo Popup_secHelper = PopupType.GetField("_secHelper", BindingFlags.Instance | BindingFlags.NonPublic);
160         private static readonly FieldInfo PopupSecurityHelper_isChildPopupInitialized = PopupSecurityHelperType.GetField("_isChildPopupInitialized", BindingFlags.Instance | BindingFlags.NonPublic);
161         private static readonly FieldInfo PopupSecurityHelper_isChildPopup = PopupSecurityHelperType.GetField("_isChildPopup", BindingFlags.Instance | BindingFlags.NonPublic);
162 
163         void HookupParentPopup()
164         {
165             _parentPopup = new Popup();
166 
167             if (BrowserInteropHelper.IsBrowserHosted)
168             {
169                 try
170                 {
171                     new ReflectionPermission(PermissionState.Unrestricted).Demand();
172 
173                     DoPopupHacks();
174                 }
175                 catch (SecurityException) { }
176             }
177 
178             _parentPopup.AllowsTransparency = true;
179             Popup.CreateRootPopup(_parentPopup, this);
180         }
181 
182         void DoPopupHacks()
183         {
184             object secHelper = Popup_secHelper.GetValue(_parentPopup);
185             PopupSecurityHelper_isChildPopupInitialized.SetValue(secHelper, true);
186             PopupSecurityHelper_isChildPopup.SetValue(secHelper, false);
187         }
188         #endregion
189 
190         #region Commands
191         /// <summary>
192         /// 
193         /// </summary>
194         public static RoutedCommand CloseCommand = new RoutedCommand("Close", typeof(RichToolTip));
195         static void ExecuteCloseCommand(object sender, ExecutedRoutedEventArgs e)
196         {
197             HideLastShown(true);
198         }
199         #endregion
200 
201         #region Dependency Properties
202         /// <summary>
203         /// 
204         /// </summary>
205         public static readonly DependencyProperty PlacementProperty = ToolTipService.PlacementProperty.AddOwner(typeof(RichToolTip));
206         /// <summary>
207         /// 
208         /// </summary>
209         public PlacementMode Placement
210         {
211             get { return (PlacementMode)GetValue(PlacementProperty); }
212             set { SetValue(PlacementProperty, value); }
213         }
214         /// <summary>
215         /// 
216         /// </summary>
217         /// <param name="obj"></param>
218         /// <returns></returns>
219         public static PlacementMode GetPlacement(DependencyObject obj)
220         {
221             return (PlacementMode)obj.GetValue(PlacementProperty);
222         }
223         /// <summary>
224         /// 
225         /// </summary>
226         /// <param name="obj"></param>
227         /// <param name="value"></param>
228         public static void SetPlacement(DependencyObject obj, PlacementMode value)
229         {
230             obj.SetValue(PlacementProperty, value);
231         }
232         /// <summary>
233         /// 
234         /// </summary>
235         public static readonly DependencyProperty PlacementTargetProperty = ToolTipService.PlacementTargetProperty.AddOwner(typeof(RichToolTip));
236         /// <summary>
237         /// 
238         /// </summary>
239         public UIElement PlacementTarget
240         {
241             get { return (UIElement)GetValue(PlacementTargetProperty); }
242             set { SetValue(PlacementTargetProperty, value); }
243         }
244         /// <summary>
245         /// 
246         /// </summary>
247         /// <param name="obj"></param>
248         /// <returns></returns>
249         public static UIElement GetPlacementTarget(DependencyObject obj)
250         {
251             return (UIElement)obj.GetValue(PlacementTargetProperty);
252         }
253         /// <summary>
254         /// 
255         /// </summary>
256         /// <param name="obj"></param>
257         /// <param name="value"></param>
258         public static void SetPlacementTarget(DependencyObject obj, UIElement value)
259         {
260             obj.SetValue(PlacementTargetProperty, value);
261         }
262         /// <summary>
263         /// 
264         /// </summary>
265         public static readonly DependencyProperty PlacementRectangleProperty = ToolTipService.PlacementRectangleProperty.AddOwner(typeof(RichToolTip));
266         /// <summary>
267         /// 
268         /// </summary>
269         public Rect PlacementRectangle
270         {
271             get { return (Rect)GetValue(PlacementRectangleProperty); }
272             set { SetValue(PlacementRectangleProperty, value); }
273         }
274         /// <summary>
275         /// 
276         /// </summary>
277         /// <param name="obj"></param>
278         /// <returns></returns>
279         public static Rect GetPlacementRectangle(DependencyObject obj)
280         {
281             return (Rect)obj.GetValue(PlacementRectangleProperty);
282         }
283         /// <summary>
284         /// 
285         /// </summary>
286         /// <param name="obj"></param>
287         /// <param name="value"></param>
288         public static void SetPlacementRectangle(DependencyObject obj, Rect value)
289         {
290             obj.SetValue(PlacementRectangleProperty, value);
291         }
292         /// <summary>
293         /// 
294         /// </summary>
295         public static readonly DependencyProperty HorizontalOffsetProperty = ToolTipService.HorizontalOffsetProperty.AddOwner(typeof(RichToolTip));
296         /// <summary>
297         /// 
298         /// </summary>
299         public double HorizontalOffset
300         {
301             get { return (double)GetValue(HorizontalOffsetProperty); }
302             set { SetValue(HorizontalOffsetProperty, value); }
303         }
304         /// <summary>
305         /// 
306         /// </summary>
307         /// <param name="obj"></param>
308         /// <returns></returns>
309         public static double GetHorizontalOffset(DependencyObject obj)
310         {
311             return (double)obj.GetValue(HorizontalOffsetProperty);
312         }
313         /// <summary>
314         /// 
315         /// </summary>
316         /// <param name="obj"></param>
317         /// <param name="value"></param>
318         public static void SetHorizontalOffset(DependencyObject obj, double value)
319         {
320             obj.SetValue(HorizontalOffsetProperty, value);
321         }
322         /// <summary>
323         /// 
324         /// </summary>
325         public static readonly DependencyProperty VerticalOffsetProperty = ToolTipService.VerticalOffsetProperty.AddOwner(typeof(RichToolTip));
326         /// <summary>
327         /// 
328         /// </summary>
329         public double VerticalOffset
330         {
331             get { return (double)GetValue(VerticalOffsetProperty); }
332             set { SetValue(VerticalOffsetProperty, value); }
333         }
334         /// <summary>
335         /// 
336         /// </summary>
337         /// <param name="obj"></param>
338         /// <returns></returns>
339         public static double GetVerticalOffset(DependencyObject obj)
340         {
341             return (double)obj.GetValue(VerticalOffsetProperty);
342         }
343         /// <summary>
344         /// 
345         /// </summary>
346         /// <param name="obj"></param>
347         /// <param name="value"></param>
348         public static void SetVerticalOffset(DependencyObject obj, double value)
349         {
350             obj.SetValue(VerticalOffsetProperty, value);
351         }
352         /// <summary>
353         /// 
354         /// </summary>
355         public static readonly DependencyProperty IsOpenProperty =
356                 Popup.IsOpenProperty.AddOwner(typeof(RichToolTip), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnIsOpenChanged)));
357         /// <summary>
358         /// 
359         /// </summary>
360         public bool IsOpen
361         {
362             get { return (bool)GetValue(IsOpenProperty); }
363             set { SetValue(IsOpenProperty, value); }
364         }
365 
366         private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
367         {
368             RichToolTip ctrl = (RichToolTip)d;
369 
370             if ((bool)e.NewValue)
371             {
372                 if (ctrl._parentPopup == null)
373                 {
374                     ctrl.HookupParentPopup();
375                 }
376             }
377         }
378 
379         #endregion
380 
381         #region Attached Properties
382 
383         #region HideOnClick
384         /// <summary>
385         /// 
386         /// </summary>
387         /// <param name="obj"></param>
388         /// <returns></returns>
389         public static bool GetHideOnClick(DependencyObject obj)
390         {
391             return (bool)obj.GetValue(HideOnClickProperty);
392         }
393         /// <summary>
394         /// 
395         /// </summary>
396         /// <param name="obj"></param>
397         /// <param name="value"></param>
398         public static void SetHideOnClick(DependencyObject obj, bool value)
399         {
400             obj.SetValue(HideOnClickProperty, value);
401         }
402         /// <summary>
403         /// 
404         /// </summary>
405         public static readonly DependencyProperty HideOnClickProperty =
406             DependencyProperty.RegisterAttached("HideOnClick", typeof(bool), typeof(RichToolTip), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
407         #endregion
408 
409         #region PopupContent
410         /// <summary>
411         /// 
412         /// </summary>
413         /// <param name="obj"></param>
414         /// <returns></returns>
415         public static object GetPopupContent(DependencyObject obj)
416         {
417             return obj.GetValue(PopupContentProperty);
418         }
419         /// <summary>
420         /// 
421         /// </summary>
422         /// <param name="obj"></param>
423         /// <param name="value"></param>
424         public static void SetPopupContent(DependencyObject obj, object value)
425         {
426             obj.SetValue(PopupContentProperty, value);
427         }
428         /// <summary>
429         /// 
430         /// </summary>
431         public static readonly DependencyProperty PopupContentProperty =
432             DependencyProperty.RegisterAttached("PopupContent", typeof(object), typeof(RichToolTip), new FrameworkPropertyMetadata(OnPopupContentChanged));
433 
434         private static void OnPopupContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
435         {
436             UIElement element = o as UIElement;
437             if (element == null)
438             {
439                 throw new InvalidOperationException("Can't hook to events other than UI Element");
440             }
441 
442             if (e.NewValue != null)
443             {
444                 RichToolTip popup = e.NewValue as RichToolTip;
445 
446                 if (popup != null)
447                 {
448                     popup.Load(element);
449                 }
450                 else
451                 {
452                     popup = new RichToolTip(element);
453 
454                     Binding binding = new Binding
455                     {
456                         Path = new PropertyPath(PopupContentProperty),
457                         Mode = BindingMode.OneWay,
458                         Source = o,
459                     };
460                     popup.SetBinding(ContentProperty, binding);
461                 }
462 
463                 SetContentTooltipWrapper(o, popup);
464             }
465         }
466         #endregion
467 
468         #region ContentTooltipWrapper
469         internal static RichToolTip GetContentTooltipWrapper(DependencyObject obj)
470         {
471             return (RichToolTip)obj.GetValue(ContentTooltipWrapperProperty);
472         }
473 
474         internal static void SetContentTooltipWrapper(DependencyObject obj, RichToolTip value)
475         {
476             obj.SetValue(ContentTooltipWrapperProperty, value);
477         }
478 
479         internal static readonly DependencyProperty ContentTooltipWrapperProperty =
480             DependencyProperty.RegisterAttached("ContentTooltipWrapper", typeof(RichToolTip), typeof(RichToolTip));
481         #endregion
482 
483         #endregion
484 
485         #region Root Visual Binding
486         bool _boundToRoot = false;
487         bool _hasParentWindow = false;
488         Window _parentWindow = null;
489 
490         void BindRootVisual()
491         {
492             if (!_boundToRoot)
493             {
494                 if (!BrowserInteropHelper.IsBrowserHosted)
495                 {
496                     _parentWindow = UIHelpers.FindLogicalAncestorByType<Window>(_relatedObject)
497                         ?? UIHelpers.FindVisualAncestorByType<Window>(_relatedObject);
498 
499                     if (_parentWindow != null)
500                     {
501                         _hasParentWindow = true;
502 
503                         _parentWindow.Deactivated += window_Deactivated;
504                         _parentWindow.LocationChanged += window_LocationChanged;
505                     }
506                 }
507 
508                 _boundToRoot = true;
509             }
510         }
511 
512         void UnbindRootVisual()
513         {
514             if (_boundToRoot)
515             {
516                 if (_parentWindow != null)
517                 {
518                     _parentWindow.Deactivated -= window_Deactivated;
519                     _parentWindow.LocationChanged -= window_LocationChanged;
520                 }
521 
522                 _boundToRoot = false;
523             }
524         }
525         #endregion
526 
527         #region Animations & Intervals
528         static DispatcherTimer _timer;
529         static Storyboard _showStoryboard;
530         static Storyboard _hideStoryboard;
531         bool setRenderTransform;
532 
533         static void InitStoryboards()
534         {
535             _showStoryboard = new Storyboard();
536             _hideStoryboard = new Storyboard();
537 
538             TimeSpan duration = TimeSpan.FromMilliseconds(_animationDurationInMs);
539 
540             DoubleAnimation animation = new DoubleAnimation(1, duration, FillBehavior.Stop);
541             Storyboard.SetTargetProperty(animation, new PropertyPath(UIElement.OpacityProperty));
542             _showStoryboard.Children.Add(animation);
543 
544             animation = new DoubleAnimation(0.1, 1, duration, FillBehavior.Stop);
545             Storyboard.SetTargetProperty(animation, new PropertyPath("(0).(1)", FrameworkElement.RenderTransformProperty, ScaleTransform.ScaleXProperty));
546             _showStoryboard.Children.Add(animation);
547 
548             animation = new DoubleAnimation(0.1, 1, duration, FillBehavior.Stop);
549             Storyboard.SetTargetProperty(animation, new PropertyPath("(0).(1)", FrameworkElement.RenderTransformProperty, ScaleTransform.ScaleYProperty));
550             _showStoryboard.Children.Add(animation);
551 
552             animation = new DoubleAnimation(0, duration, FillBehavior.Stop);
553             Storyboard.SetTargetProperty(animation, new PropertyPath(UIElement.OpacityProperty));
554             _hideStoryboard.Children.Add(animation);
555 
556             _hideStoryboard.Completed += delegate { OnAnimationCompleted(); };
557         }
558 
559         static void InitTimer()

560         {
561             _timer = new DispatcherTimer();
562             _timer.Interval = TimeSpan.FromMilliseconds(_showDeferredMilliseconds);
563         }
564 
565         static void ResetTimer(RichToolTip tooltip)
566         {
567             if (_timer != null)
568             {
569                 _timer.Tick -= tooltip.ShowDeferred;
570                 _timer.Stop();
571             }
572         }
573 
574         void Animate(bool show)
575         {
576             if (show)
577             {
578                 if (!setRenderTransform)
579                 {
580                     RenderTransform = new ScaleTransform();
581 
582                     setRenderTransform = true;
583                 }
584 
585                 _showStoryboard.Begin(this);
586             }
587             else
588             {
589                 _hideStoryboard.Begin(this);
590             }
591         }
592 
593         static void OnAnimationCompleted()
594         {
595             HideLastShown(false);
596         }
597         #endregion
598 
599         #region Event Invocations
600         void element_MouseEnter(object sender, MouseEventArgs e)
601         {
602             if (!IsShown() && this != _lastShownPopup)
603             {
604                 if (!_hasParentWindow || _parentWindow.IsActive)
605                 {
606                     Show(true);
607                 }
608             }
609         }
610 
611         void element_MouseLeave(object sender, MouseEventArgs e)
612         {
613             ResetTimer(this);
614 
615             if (IsShown() && this == _lastShownPopup)
616             {
617                 Hide(true);
618             }
619         }
620 
621         static void OnNavigationWindowMouseLeaveEvent(object sender, RoutedEventArgs e)
622         {
623             Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
624             new Action(() =>
625             {
626                 if (_lastShownPopup != null && !_lastShownPopup.IsMouseOver)
627                 {
628                     HideLastShown(false);
629                 }
630             }));
631         }
632 
633         void window_LocationChanged(object sender, EventArgs e)
634         {
635             if (IsShown())
636             {
637                 HideLastShown(false);
638             }
639         }
640 
641         void window_Deactivated(object sender, EventArgs e)
642         {
643             if (IsShown())
644             {
645                 HideLastShown(false);
646             }
647         }
648 
649         static void OnWindowSizeChanged(object sender, RoutedEventArgs e)
650         {
651             HideLastShown();
652         }
653 
654         static void OnElementMouseDown(object sender, MouseButtonEventArgs e)
655         {
656             if (_lastShownPopup != null && _lastShownPopup.IsShown())
657             {
658                 RichToolTip popup;
659 
660                 DependencyObject o = e.OriginalSource as DependencyObject;
661                 if (!TryFindPopupParent(e.OriginalSource, out popup))
662                 {
663                     HideLastShown(true);
664                 }
665             }
666         }
667 
668         static void OnButtonBaseClick(object sender, RoutedEventArgs e)
669         {
670             if (_lastShownPopup != null && _lastShownPopup.IsShown())
671             {
672                 DependencyObject o = e.OriginalSource as DependencyObject;
673 
674                 bool hide = GetHideOnClick(o);
675                 if (hide)
676                 {
677                     HideLastShown(true);
678 
679                     e.Handled = true;
680                 }
681             }
682         }
683 
684         static void selector_SelectionChangedEvent(object sender, SelectionChangedEventArgs e)
685         {
686             HideLastShown();
687         }
688 
689         static bool TryFindPopupParent(object source, out RichToolTip popup)
690         {
691             popup = null;
692             UIElement element = source as UIElement;
693 
694             if (element != null)
695             {
696                 popup = UIHelpers.FindVisualAncestorByType<RichToolTip>(element);
697 
698                 if (popup == null)
699                 {
700                     popup = UIHelpers.FindLogicalAncestorByType<RichToolTip>(element);
701                 }
702 
703                 return popup != null;
704             }
705 
706             return false;
707         }
708         #endregion
709 
710         #region Show / Hide
711         bool _showAnimate = _animationEnabledDefault;
712 
713         bool IsShown()
714         {
715             return IsOpen;
716         }
717 
718         public void Show(bool animate)
719         {
720             _showAnimate = animate;
721 
722             if (_timer == null)
723             {
724                 InitTimer();
725             }
726 
727             _timer.Tick += ShowDeferred;
728 
729             if (!_timer.IsEnabled)
730             {
731                 _timer.Start();
732             }
733         }
734 
735         private void ShowDeferred(object sender, EventArgs e)
736         {
737             ResetTimer(this);
738 
739             HideLastShown(false);
740 
741             ShowInternal();
742 
743             if (_showAnimate && EnableAnimation)
744             {
745                 Animate(true);
746             }
747             else
748             {
749                 this.Opacity = 1;
750             }
751 
752             _lastShownPopup = this;
753         }
754 
755         private void ShowInternal()
756         {
757             Visibility = Visibility.Visible;
758 
759             IsOpen = true;
760         }
761 
762         static void HideLastShown()
763         {
764             HideLastShown(false);
765         }
766 
767         static void HideLastShown(bool animate)
768         {
769             if (_lastShownPopup != null)
770             {
771                 _lastShownPopup.Hide(animate);
772             }
773         }
774 
775         /// <summary>
776         /// 
777         /// </summary>
778         /// <param name="animate"></param>
779         public void Hide(bool animate)
780         {
781             Point pt = Mouse.GetPosition(this);
782             if (pt.X >= 0 && pt.Y >= 0 && pt.X <= this.ActualWidth && pt.Y <= this.ActualHeight) return;
783 
784             if (animate && EnableAnimation)
785             {
786                 Animate(false);
787             }
788             else
789             {
790                 HideInternal();
791             }
792         }
793 
794         private void HideInternal()
795         {
796             this.Visibility = Visibility.Collapsed;
797             this.IsOpen = false;
798 
799             _lastShownPopup = null;
800         }
801 
802         #endregion
803     }
804 }
原文地址:https://www.cnblogs.com/chriskwok/p/2623161.html