示例#1
0
        /// <summary>
        /// Handles window position changing event.
        /// </summary>
        protected override void HandleWindowPosChanging(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            var position = Marshal.PtrToStructure <WindowHelper.WINDOWPOS>(lParam);

            double width  = position.cx;
            double height = position.cy;

            if (position.flags.HasFlag(WindowHelper.SWP.SWP_SHOWWINDOW))
            {
                var dpi = VisualTreeHelperAddition.GetDpi(_window);
                width  = _window.ActualWidth * dpi.DpiScaleX;
                height = _window.ActualHeight * dpi.DpiScaleY;
            }

            if ((0 < width) && (0 < height) &&
                TryGetAdjacentLocation(width, height, out Point adjacentLocation) &&
                TryGetAdjustedPosition(width, height, adjacentLocation, out Rect adjustedPosition))
            {
                position.x      = (int)adjustedPosition.X;
                position.y      = (int)adjustedPosition.Y;
                position.flags &= ~WindowHelper.SWP.SWP_NOMOVE;

                if (((int)adjustedPosition.Width < (int)width) || ((int)adjustedPosition.Height < (int)height))
                {
                    position.cx     = (int)adjustedPosition.Width;
                    position.cy     = (int)adjustedPosition.Height;
                    position.flags &= ~WindowHelper.SWP.SWP_NOSIZE;
                }

                Marshal.StructureToPtr <WindowHelper.WINDOWPOS>(position, lParam, true);
            }
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Loaded -= OnLoaded;

            _viewer = VisualTreeHelperAddition.GetDescendants <ScrollViewer>(this.AssociatedObject).FirstOrDefault();
            if (_viewer is null)
            {
                return;
            }

            CheckItems();             // Initial check

            _subscription.Add(Observable.FromEventPattern <ScrollChangedEventHandler, ScrollChangedEventArgs>(
                                  handler => handler.Invoke,
                                  handler => _viewer.ScrollChanged += handler,
                                  handler => _viewer.ScrollChanged -= handler)
                              .Subscribe(x => CheckItems(x.EventArgs)));

            if (!(this.AssociatedObject.Items is INotifyCollectionChanged source))             // ItemsSource
            {
                return;
            }

            _subscription.Add(Observable.FromEventPattern <NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
                                  handler => handler.Invoke,
                                  handler => source.CollectionChanged += handler,
                                  handler => source.CollectionChanged -= handler)
                              .Do(x => ReflectItemsFormer(x.EventArgs))
                              .Delay(TimeSpan.FromMilliseconds(10))   // Waiting time for child items to perform Measure method
                              .ObserveOn(SynchronizationContext.Current)
                              .Subscribe(x => ReflectItemsLatter(x.EventArgs)));
        }
示例#3
0
        private void OnSourceInitialized(object sender, EventArgs e)
        {
            _source = PresentationSource.FromVisual(_window) as HwndSource;
            _source?.AddHook(WndProc);

            var dpi = VisualTreeHelperAddition.GetDpi(_window);

            if (!dpi.Equals(VisualTreeHelperAddition.SystemDpi))
            {
                AdjustWindow(dpi);
            }
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Loaded -= OnLoaded;

            _viewer = VisualTreeHelperAddition.GetDescendants <ScrollViewer>(this.AssociatedObject).FirstOrDefault();
            if (_viewer == null)
            {
                return;
            }

            CheckChild();             // Initial check

            _subscription.Add(Observable.FromEventPattern <ScrollChangedEventHandler, ScrollChangedEventArgs>(
                                  handler => handler.Invoke,
                                  handler => _viewer.ScrollChanged += handler,
                                  handler => _viewer.ScrollChanged -= handler)
                              //.Do(_ => Debug.WriteLine("ScrollChanged!"))
                              .Subscribe(_ => CheckChild()));

            var source = this.AssociatedObject.Items as INotifyCollectionChanged;             // ItemsSource

            if (source == null)
            {
                return;
            }

            var collectionChanged = Observable.FromEventPattern <NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
                handler => handler.Invoke,
                handler => source.CollectionChanged += handler,
                handler => source.CollectionChanged -= handler);

            _subscription.Add(collectionChanged
                              .Where(x => x.EventArgs.Action != NotifyCollectionChangedAction.Reset)
                              .Where(x => x.EventArgs.NewItems != null)
                                                                    //.Do(x => Debug.WriteLine($"CollectionChanged ({x.EventArgs.Action})!"))
                              .Delay(TimeSpan.FromMilliseconds(10)) // Waiting time for child to perform Measure method
                              .ObserveOn(SynchronizationContext.Current)
                              .Subscribe(x => CheckChild(x.EventArgs.NewItems.Cast <object>())));

            _subscription.Add(collectionChanged
                              .Where(x => x.EventArgs.Action == NotifyCollectionChangedAction.Reset)
                              //.Do(x => Debug.WriteLine($"CollectionChanged ({x.EventArgs.Action})!"))
                              .Throttle(TimeSpan.FromMilliseconds(10))
                              .ObserveOn(SynchronizationContext.Current)
                              .Subscribe(_ => CheckChild()));
        }
示例#5
0
        /// <summary>
        /// Handles DPI changed event.
        /// </summary>
        protected virtual void HandleDpiChanged(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (OsVersion.Is10Build14393OrGreater)
            {
                return;
            }

            if (_window.SizeToContent != SizeToContent.WidthAndHeight)
            {
                var windowRect = VisualTreeHelperAddition.ConvertToRect(lParam);
                WindowHelper.SetWindowPosition(_window, windowRect);
            }

            var dpi = VisualTreeHelperAddition.ConvertToDpiScale(wParam);

            VisualTreeHelper.SetRootDpi(_window, dpi);
            handled = true;
        }
示例#6
0
 /// <summary>
 /// Gets Per-Monitor DPI of the monitor.
 /// </summary>
 /// <returns>DPI information</returns>
 protected virtual DpiScale GetDpi() => VisualTreeHelperAddition.GetDpi(_window);
示例#7
0
        /// <summary>
        /// Attempts to get the adjacent location to NotifyIcon using specified window width and height.
        /// </summary>
        /// <param name="windowWidth">Window width</param>
        /// <param name="windowHeight">Window height</param>
        /// <param name="location">Location of window</param>
        /// <returns>True if successfully gets</returns>
        protected bool TryGetAdjacentLocationToTaskbar(double windowWidth, double windowHeight, out Rect location)
        {
            if (!WindowHelper.TryGetTaskbar(out Rect taskbarRect, out TaskbarAlignment taskbarAlignment, out bool isShown))
            {
                location = default;
                return(false);
            }

            var iconPlacement    = IconPlacement.Unknown;
            var overflowAreaRect = default(Rect);

            if (NotifyIconHelper.TryGetNotifyIconRect(_notifyIcon, out Rect iconRect))
            {
                if (taskbarRect.Contains(
                        iconRect.X + iconRect.Width / 2D,
                        iconRect.Y + iconRect.Height / 2D))
                {
                    iconPlacement = IconPlacement.InTaskbar;
                }
                else if (WindowHelper.TryGetOverflowAreaRect(out overflowAreaRect) &&
                         overflowAreaRect.Contains(iconRect))
                {
                    iconPlacement = IconPlacement.InOverflowArea;
                }
            }

            if (!WindowHelper.TryGetDwmWindowMargin(_window, out Thickness windowMargin))
            {
                windowMargin = new Thickness(0);                 // Fallback
            }
            var isLeftToRight = !CultureInfoAddition.UserDefaultUICulture.TextInfo.IsRightToLeft;

            var distance = KeepsDistance
                                ? new Vector(Distance, Distance) * VisualTreeHelperAddition.GetDpi(_window).ToMatrix()
                                : new Vector(0, 0);

            double x = 0, y = 0;

            // To avoid a gap between window and taskbar when taskbar alignment is right or bottom
            // and monitor DPI is 125%, 150%, 175%, the window width and height (in DIP) must be
            // a multiple of 4. Otherwise, the window width and height multiplied with those DPI
            // will have a fraction and it will cause a blurry edge looking as if there is a gap.
            switch (taskbarAlignment)
            {
            case TaskbarAlignment.Top:
            case TaskbarAlignment.Bottom:
                x = iconPlacement switch
                {
                    IconPlacement.InTaskbar => isLeftToRight ? iconRect.Right : iconRect.Left,
                    IconPlacement.InOverflowArea => isLeftToRight ? (overflowAreaRect.Left - distance.X) : (overflowAreaRect.Right + distance.X),
                    _ => isLeftToRight ? (taskbarRect.Right - distance.X) : (taskbarRect.Left + distance.X),                             // Fallback
                };
                x -= isLeftToRight ? (windowWidth - windowMargin.Right) : windowMargin.Left;

                switch (taskbarAlignment)
                {
                case TaskbarAlignment.Top:
                    y = (isShown ? taskbarRect.Bottom : taskbarRect.Top) - windowMargin.Top + distance.Y;
                    PivotAlignment = isLeftToRight ? PivotAlignment.TopRight : PivotAlignment.TopLeft;
                    break;

                case TaskbarAlignment.Bottom:
                    y = (isShown ? taskbarRect.Top : taskbarRect.Bottom) - (windowHeight - windowMargin.Bottom) - distance.Y;
                    PivotAlignment = isLeftToRight ? PivotAlignment.BottomRight : PivotAlignment.BottomLeft;
                    break;
                }
                break;

            case TaskbarAlignment.Left:
            case TaskbarAlignment.Right:
                switch (taskbarAlignment)
                {
                case TaskbarAlignment.Left:
                    x = (isShown ? taskbarRect.Right : taskbarRect.Left) - windowMargin.Left + distance.X;
                    PivotAlignment = PivotAlignment.BottomLeft;
                    break;

                case TaskbarAlignment.Right:
                    x = (isShown ? taskbarRect.Left : taskbarRect.Right) - (windowWidth - windowMargin.Right) - distance.X;
                    PivotAlignment = PivotAlignment.BottomRight;
                    break;
                }

                y = iconPlacement switch
                {
                    IconPlacement.InTaskbar => iconRect.Bottom,
                    IconPlacement.InOverflowArea => overflowAreaRect.Top - distance.Y,
                    _ => taskbarRect.Bottom - distance.Y,                             // Fallback
                };
                y -= (windowHeight - windowMargin.Bottom);
                break;
            }
            location = new Rect(x, y, windowWidth, windowHeight);
            return(true);
        }
示例#8
0
 /// <summary>
 /// Gets Per-Monitor DPI of the monitor.
 /// </summary>
 /// <returns>DPI information</returns>
 protected override DpiScale GetDpi() => VisualTreeHelperAddition.GetDpi(_pivot);