/// <summary>
        /// 淡入
        /// </summary>
        /// <param name="notifyBox"></param>
        static void FadeIn(PopupNotify notifyBox)
        {
            DoubleAnimation aniTop = new DoubleAnimation();

            aniTop.Duration       = new Duration(TimeSpan.FromMilliseconds(600));
            aniTop.From           = notifyBox.Top + 15;
            aniTop.To             = notifyBox.Top;
            aniTop.EasingFunction = new QuarticEase()
            {
                EasingMode = EasingMode.EaseOut
            };
            Storyboard.SetTargetProperty(aniTop, new PropertyPath(Window.TopProperty));
            Storyboard.SetTarget(aniTop, notifyBox);

            DoubleAnimation aniOpacity = new DoubleAnimation();

            aniOpacity.Duration       = new Duration(TimeSpan.FromMilliseconds(1000));
            aniOpacity.From           = 0;
            aniOpacity.To             = 1;
            aniOpacity.EasingFunction = new QuarticEase()
            {
                EasingMode = EasingMode.EaseOut
            };
            Storyboard.SetTargetProperty(aniOpacity, new PropertyPath(Window.OpacityProperty));
            Storyboard.SetTarget(aniOpacity, notifyBox);

            Storyboard sbIn = new Storyboard();

            sbIn.Children.Add(aniTop);
            sbIn.Children.Add(aniOpacity);
            sbIn.Begin();
        }
        public static void NotifyCustom(object content, FrameworkElement placeTarget)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                PopupNotify bx = new PopupNotify();
                DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(FrameworkElement)).AddValueChanged(bx, (sender, e) =>
                {
                    (sender as PopupNotify).Left = CalcElementRight(placeTarget) - (sender as PopupNotify).ActualWidth;
                });
                DependencyPropertyDescriptor.FromProperty(ActualHeightProperty, typeof(FrameworkElement)).AddValueChanged(bx, (sender, e) =>
                {
                    (sender as PopupNotify).Top = (sender as PopupNotify)._bottom - (sender as PopupNotify).ActualHeight;
                });
                bx.Content     = content;
                bx.Title       = "";
                bx._bottom     = CalcBoxBottom(placeTarget);
                bx._notifyInfo = new NotifyInfo {
                    IsScreenNotify = false, IsText = false, PlaceTarget = placeTarget
                };
                lock (_boxes)
                {
                    _boxes.Add(bx);
                }
                bx.Loaded += (s, e) =>
                {
                    PopupNotify self = s as PopupNotify;
                    self.UpdateLayout();
                    SystemSounds.Asterisk.Play();//播放提示声

                    self.Top  = self._bottom - self.ActualHeight;
                    self.Left = CalcElementRight(self._notifyInfo.PlaceTarget) - self.ActualWidth;
                    if (self.Top < 0)
                    {
                        self.Visibility = Visibility.Hidden;
                    }
                    else
                    {
                        FadeIn(self);
                        Task.Factory.StartNew((box1) =>
                        {
                            System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(_boxLife));
                            lock (_boxes)
                            {
                                if (_boxes.Contains(box1))
                                {
                                    Application.Current.Dispatcher.Invoke(() =>
                                    {
                                        FadeOut(box1 as PopupNotify);
                                    });
                                }
                            }
                        }, self);
                    }
                };
                bx.Show();
            });
        }
        /// <summary>
        /// 显示消息提示(指定屏幕的右下角
        /// </summary>
        /// <param name="content">消息内容</param>
        /// <param name="title">消息标题</param>
        /// <param name="screenIndex">屏幕序号</param>
        public static void Notify(DependencyObject content, string title, int screenIndex)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                PopupNotify bx = new PopupNotify();
                DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(FrameworkElement)).AddValueChanged(bx, (sender, e) =>
                {
                    (sender as PopupNotify).Left = GetScrRight(screenIndex) - (sender as PopupNotify).ActualWidth;
                });
                DependencyPropertyDescriptor.FromProperty(ActualHeightProperty, typeof(FrameworkElement)).AddValueChanged(bx, (sender, e) =>
                {
                    (sender as PopupNotify).Top = (sender as PopupNotify)._bottom - (sender as PopupNotify).ActualHeight;
                });
                bx.MessageObj  = content;
                bx.Title       = title == null ? "" : title;
                bx._bottom     = CalcBoxBottom(screenIndex);
                bx._notifyInfo = new NotifyInfo {
                    IsScreenNotify = true, IsText = false, ScreenIndex = screenIndex
                };
                lock (_boxes)
                {
                    _boxes.Add(bx);
                }
                bx.Loaded += (s, e) =>
                {
                    try
                    {
                        PopupNotify self = s as PopupNotify;
                        self.UpdateLayout();
                        SystemSounds.Asterisk.Play();//播放提示声

                        self.Top  = self._bottom - self.ActualHeight;
                        self.Left = GetScrRight(screenIndex) - self.ActualWidth;
                        if (self.Top < 0)
                        {
                            self.Visibility = Visibility.Hidden;
                        }
                        else
                        {
                            FadeIn(self);
                            Task.Factory.StartNew((box1) =>
                            {
                                System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(_boxLife));
                                Application.Current.Dispatcher.Invoke(() =>
                                {
                                    FadeOut(box1 as PopupNotify);
                                });
                            }, self);
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                };
                bx.Show();
            });
        }
        /// <summary>
        /// 淡出
        /// </summary>
        /// <param name="notifyBox"></param>
        static void FadeOut(PopupNotify notifyBox)
        {
            DoubleAnimation aniTop = new DoubleAnimation();

            aniTop.Duration       = new Duration(TimeSpan.FromMilliseconds(600));
            aniTop.To             = notifyBox.Top + 15;
            aniTop.EasingFunction = new QuarticEase()
            {
                EasingMode = EasingMode.EaseOut
            };
            Storyboard.SetTargetProperty(aniTop, new PropertyPath(Window.TopProperty));
            Storyboard.SetTarget(aniTop, notifyBox);

            DoubleAnimation aniOpacity = new DoubleAnimation();

            aniOpacity.Duration       = new Duration(TimeSpan.FromMilliseconds(1000));
            aniOpacity.To             = 0;
            aniOpacity.EasingFunction = new QuarticEase()
            {
                EasingMode = EasingMode.EaseOut
            };
            aniOpacity.Completed += (s, e) =>
            {
                lock (_boxes)
                {
                    _boxes.Remove(notifyBox);
                }
                notifyBox.Close();
                ReLocateFirstBoxOutOfScreen(); // 刷新消息框位置
            };
            Storyboard.SetTargetProperty(aniOpacity, new PropertyPath(Window.OpacityProperty));
            Storyboard.SetTarget(aniOpacity, notifyBox);

            /*
             * DoubleAnimation aniScale = new DoubleAnimation();
             * aniScale.Duration = new Duration(TimeSpan.FromMilliseconds(600));
             * aniScale.From = 1;
             * aniScale.To = 1.2;
             * aniScale.EasingFunction = new QuarticEase() { EasingMode = EasingMode.EaseOut };
             * ((TransformGroup)notifyBox.RenderTransform).Children[0].BeginAnimation(ScaleTransform.ScaleXProperty, aniScale);
             */

            Storyboard sbOut = new Storyboard();

            sbOut.Children.Add(aniTop);
            sbOut.Children.Add(aniOpacity);
            sbOut.Begin();
        }
 /// <summary>
 /// 计算消息框底部位置
 /// </summary>
 /// <param name="screenIndex">屏幕序号</param>
 /// <returns></returns>
 static double CalcBoxBottom(int screenIndex)
 {
     lock (_boxes)
     {
         double      topFrom         = GetScrBottom(screenIndex) - 4;
         PopupNotify notifyBoxBottom = _boxes.FirstOrDefault(b => b._bottom == topFrom);
         while (notifyBoxBottom != null)
         {
             // 注意:notifyBoxBottom超出屏幕时,visibility设置为hidden,其ActualHeight为0
             topFrom         = topFrom - (notifyBoxBottom.ActualHeight > 0? notifyBoxBottom.ActualHeight:50);
             notifyBoxBottom = _boxes.FirstOrDefault(b => b._bottom == topFrom);
         }
         // 不限制是否超出屏幕
         return(topFrom);
     }
 }
 /// <summary>
 /// 计算消息框底部位置(在参照物右下角开始往上)
 /// </summary>
 /// <param name="relElement">参照物</param>
 /// <returns></returns>
 static double CalcBoxBottom(FrameworkElement relElement)
 {
     lock (_boxes)
     {
         Rect        rect            = Helper.GetElementBounds(relElement);
         double      topFrom         = rect.Bottom - 4;
         PopupNotify notifyBoxBottom = _boxes.FirstOrDefault(b => b._bottom == topFrom);
         while (notifyBoxBottom != null)
         {
             // 注意:notifyBoxBottom超出屏幕时,visibility设置为hidden,其ActualHeight为0
             topFrom         = topFrom - (notifyBoxBottom.ActualHeight > 0 ? notifyBoxBottom.ActualHeight : 50);
             notifyBoxBottom = _boxes.FirstOrDefault(b => b._bottom == topFrom);
         }
         // 不限制是否超出屏幕
         return(topFrom);
     }
 }