예제 #1
0
        /// <summary>
        /// Displays the <see cref="TrayPopup"/> control if
        /// it was set.
        /// </summary>
        private void ShowTrayPopup(Point cursorPosition)
        {
            if (IsDisposed)
            {
                return;
            }

            //raise preview event no matter whether popup is currently set
            //or not (enables client to set it on demand)
            var args = RaisePreviewTrayPopupOpenEvent();

            if (args.Handled)
            {
                return;
            }

            if (TrayPopup != null)
            {
                //use absolute position, but place the popup centered above the icon
                TrayPopupResolved.Placement = PlacementMode.AbsolutePoint;
                Point position = TrayInfo.GetTrayLocation();
                TrayPopupResolved.HorizontalOffset = position.X - 20;
                TrayPopupResolved.VerticalOffset   = position.Y - 1;

                //open popup
                TrayPopupResolved.IsOpen = true;

                IntPtr handle = IntPtr.Zero;
                if (TrayPopupResolved.Child != null)
                {
                    //try to get a handle on the popup itself (via its child)
                    HwndSource source = (HwndSource)PresentationSource.FromVisual(TrayPopupResolved.Child);
                    if (source != null)
                    {
                        handle = source.Handle;
                    }
                }

                //if we don't have a handle for the popup, fall back to the message sink
                if (handle == IntPtr.Zero)
                {
                    handle = messageSink.MessageWindowHandle;
                }

                //activate either popup or message sink to track deactivation.
                //otherwise, the popup does not close if the user clicks somewhere else
                WinApi.SetForegroundWindow(handle);

                //raise attached event - item should never be null unless developers
                //changed the CustomPopup directly...
                if (TrayPopup != null)
                {
                    RaisePopupOpenedEvent(TrayPopup);
                }

                //bubble routed event
                RaiseTrayPopupOpenEvent();
            }
        }
예제 #2
0
        public ChimeHelperTray(TaskbarIcon trayIcon)
        {
            _tray             = trayIcon;
            _tray.DataContext = MEETINGS_LOADING;

            // workaround for an apparent bug in TrayIcon where the first menu appearance
            // often happens in one of the corners of the screen. Calling GetTrayLocation
            // seems to wake Windows up to the real location which is then used subsequently.
            TrayInfo.GetTrayLocation();
        }
예제 #3
0
        /// <summary>
        /// Shows a custom control as a tooltip in the tray location.
        /// </summary>
        /// <param name="balloon"></param>
        /// <param name="animation">An optional animation for the popup.</param>
        /// <param name="timeout">The time after which the popup is being closed.
        /// Submit null in order to keep the balloon open inde
        /// </param>
        /// <exception cref="ArgumentNullException">If <paramref name="balloon"/>
        /// is a null reference.</exception>
        public void ShowCustomBalloon(UIElement balloon, PopupAnimation animation, int?timeout)
        {
            Dispatcher dispatcher = this.GetDispatcher();

            if (!dispatcher.CheckAccess())
            {
                dispatcher.InvokeAsync(
                    (() => ShowCustomBalloon(balloon, animation, timeout)),
                    DispatcherPriority.Normal
                    );
                return;
            }

            if (balloon == null)
            {
                throw new ArgumentNullException("balloon");
            }

            if (timeout.HasValue && timeout < 500)
            {
                throw new ArgumentOutOfRangeException("timeout", string.Format("Invalid timeout of {0} milliseconds. Timeout must be at least 500 ms", timeout));
            }

            if (this.IsDisposed)
            {
                throw new ObjectDisposedException(this.Name ?? this.GetType().Name);
            }

            //make sure we don't have an open balloon
            lock (this.SyncLock)
            {
                CloseBalloon();
            }

            // create an invisible popup that hosts the UIElement
            Popup popup = new Popup
            {
                AllowsTransparency = true
            };

            //provide the popup with the taskbar icon's data context
            UpdateDataContext(popup, null, DataContext);

            //don't animate by default - devs can use attached events or override
            popup.PopupAnimation = animation;

            //in case the balloon is cleaned up through routed events, the
            //control didn't remove the balloon from its parent popup when
            //if was closed the last time - just make sure it doesn't have
            //a parent that is a popup
            var parent = LogicalTreeHelper.GetParent(balloon) as Popup;

            if (parent != null)
            {
                parent.Child = null;
            }

            if (parent != null)
            {
                string msg =
                    "Cannot display control [{0}] in a new balloon popup - that control already has a parent. You may consider creating new balloons every time you want to show one.";
                msg = String.Format(msg, balloon);
                throw new InvalidOperationException(msg);
            }

            popup.Child = balloon;

            //don't set the PlacementTarget as it causes the popup to become hidden if the
            //TaskbarIcon's parent is hidden, too...
            //popup.PlacementTarget = this;

            popup.Placement = PlacementMode.AbsolutePoint;
            popup.StaysOpen = true;

            Point position = TrayInfo.GetTrayLocation();

            position = GetDeviceCoordinates(position);
            popup.HorizontalOffset = position.X - 1;
            popup.VerticalOffset   = position.Y - 1;

            //store reference
            lock (this.SyncLock)
            {
                SetCustomBalloon(popup);
            }

            //assign this instance as an attached property
            SetParentTaskbarIcon(balloon, this);

            //fire attached event
            RaiseBalloonShowingEvent(balloon, this);

            //display item
            popup.IsOpen = true;

            if (timeout.HasValue)
            {
                //register timer to close the popup
                balloonCloseTimer.Change(timeout.Value, Timeout.Infinite);
            }
        }
예제 #4
0
        /// <summary>
        /// Shows a custom control as a tooltip in the tray location.
        /// </summary>
        /// <param name="balloon"></param>
        /// <param name="animation">An optional animation for the popup.</param>
        /// <param name="timeout">The time after which the popup is being closed.
        /// Submit null in order to keep the balloon open inde
        /// </param>
        /// <exception cref="ArgumentNullException">If <paramref name="balloon"/>
        /// is a null reference.</exception>
        public void ShowCustomBalloon(UIElement balloon, PopupAnimation animation, int?timeout)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                var action = new Action(() => ShowCustomBalloon(balloon, animation, timeout));
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, action);
                return;
            }

            if (balloon == null)
            {
                throw new ArgumentNullException("balloon");
            }
            if (timeout.HasValue && timeout < 500)
            {
                string msg = "Invalid timeout of {0} milliseconds. Timeout must be at least 500 ms";
                msg = String.Format(msg, timeout);
                throw new ArgumentOutOfRangeException("timeout", msg);
            }

            EnsureNotDisposed();

            //make sure we don't have an open balloon
            lock (this)
            {
                CloseBalloon();
            }

            //create an invisible popup that hosts the UIElement
            Popup popup = new Popup();

            popup.AllowsTransparency = true;

            //provide the popup with the taskbar icon's data context
            UpdateDataContext(popup, null, DataContext);

            //don't animate by default - devs can use attached
            //events or override
            popup.PopupAnimation = animation;

            popup.Child = balloon;

            //don't set the PlacementTarget as it causes the popup to become hidden if the
            //TaskbarIcon's parent is hidden, too...
            //popup.PlacementTarget = this;

            popup.Placement = PlacementMode.AbsolutePoint;
            popup.StaysOpen = true;

            Point position = TrayInfo.GetTrayLocation();

            popup.HorizontalOffset = position.X - 1;
            popup.VerticalOffset   = position.Y - 1;

            //store reference
            lock (this)
            {
                SetCustomBalloon(popup);
            }

            //assign this instance as an attached property
            SetParentTaskbarIcon(balloon, this);

            //fire attached event
            RaiseBalloonShowingEvent(balloon, this);

            //display item
            popup.IsOpen = true;

            if (timeout.HasValue)
            {
                //register timer to close the popup
                balloonCloseTimer.Change(timeout.Value, Timeout.Infinite);
            }

            return;
        }
예제 #5
0
 public Point GetPopupTrayPosition()
 {
     return(TrayInfo.GetTrayLocation());
 }
예제 #6
0
파일: Notify.cs 프로젝트: metaseed/Metakey
        public static MessageToken <TipItem> ShowMessage(System.Windows.FrameworkElement balloon,
                                                         ObservableCollection <TipItem> data, int?timeout,
                                                         NotifyPosition position = NotifyPosition.ActiveScreen, PopupAnimation animation = PopupAnimation.None)
        {
            var dispatcher = balloon.Dispatcher;

            if (!dispatcher.CheckAccess())
            {
                return(dispatcher.Invoke(DispatcherPriority.Normal,
                                         (Func <MessageToken <TipItem> >)(() =>
                                                                          ShowMessage(balloon, data, timeout, position, animation))) as
                       MessageToken <TipItem>);
            }

            if (balloon == null)
            {
                throw new ArgumentNullException("balloon");
            }
            if (timeout.HasValue && timeout < 500)
            {
                var msg = "Invalid timeout of {0} milliseconds. Timeout must be at least 500 ms";
                msg = String.Format(msg, timeout);
                throw new ArgumentOutOfRangeException("timeout", msg);
            }

            if (LogicalTreeHelper.GetParent(balloon) is Popup parent)
            {
                parent.Child = null;
                var msg =
                    "Cannot display control [{0}] in a new balloon popup - that control already has a parent. You may consider creating new balloons every time you want to show one.";
                msg = String.Format(msg, balloon);
                throw new InvalidOperationException(msg);
            }

            var popup = new Popup();

            popup.AllowsTransparency = true;
            popup.PopupAnimation     = animation;
            popup.Placement          = PlacementMode.AbsolutePoint;
            popup.StaysOpen          = true;
            popup.DataContext        = data;

            Point point;

            switch (position)
            {
            case NotifyPosition.Caret:
            {
                var rect = Utils.Window.GetCurrentWindowCaretPosition();
                var X    = (rect.Left + rect.Width / 2 - balloon.ActualWidth / 2);
                var Y    = (rect.Bottom + rect.Height / 2 - balloon.ActualHeight / 2);
                if (X == 0 && Y == 0)
                {
                    goto case NotifyPosition.ActiveWindowCenter;
                }

                point = new Point(X, Y);
                break;
            }

            case NotifyPosition.ActiveWindowCenter:
            {
                var rect = Utils.Window.GetCurrentWindowRect();
                var X    = (rect.X + rect.Width / 2 - balloon.ActualWidth / 2);
                var Y    = (rect.Y + rect.Height / 2 - balloon.ActualHeight / 2);
                point = new Point(X, Y);
                break;
            }

            case NotifyPosition.ActiveScreen:
            {
                var screen = Screen.FromHandle(Utils.Window.CurrentWindowHandle);
                if (screen.Equals(Screen.PrimaryScreen))
                {
                    var p = TrayInfo.GetTrayLocation();
                    point = new Point(p.X, p.Y);
                    break;
                }

                var bounds = screen.Bounds;
                var X      = bounds.X + bounds.Width;
                var Y      = bounds.Y + bounds.Height;
                point = new Point(X, Y);
                break;
            }

            case NotifyPosition.Default:
            {
                var p = TrayInfo.GetTrayLocation();
                point = new Point(p.X, p.Y);
                break;
            }


            default:
                throw new ArgumentOutOfRangeException(nameof(position) + " not supported", position, null);
            }


            popup.Child            = balloon;
            popup.HorizontalOffset = point.X + 1;
            popup.VerticalOffset   = point.Y - 2;
            balloon.Focusable      = true;

            IInputElement element = null;

            popup.Opened += (s, a) =>
            {
                element = Keyboard.FocusedElement;
                var source = (HwndSource)PresentationSource.FromVisual(balloon);
                var handle = source.Handle;
                PInvokes.SetForegroundWindow(handle);
                Keyboard.Focus(balloon);
            };

            popup.IsOpen = true;
            popup.Focus();

            var r = new MessageToken <TipItem>(popup);

            popup.Closed += (s, a) =>
            {
                Keyboard.Focus(element);
                r.Close();
            };

            void TimerTick(object sender, EventArgs e)
            {
                r.Timer.Tick -= TimerTick;
                r.Close();
            }

            if (timeout.HasValue)
            {
                r.Timer = new DispatcherTimer {
                    Interval = TimeSpan.FromMilliseconds(timeout.Value)
                };
                r.Timer.Tick += TimerTick;
                r.Timer.Start();
            }

            return(r);
        }