/// <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))); }
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())); }
/// <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; }
/// <summary> /// Gets Per-Monitor DPI of the monitor. /// </summary> /// <returns>DPI information</returns> protected virtual DpiScale GetDpi() => VisualTreeHelperAddition.GetDpi(_window);
/// <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); }
/// <summary> /// Gets Per-Monitor DPI of the monitor. /// </summary> /// <returns>DPI information</returns> protected override DpiScale GetDpi() => VisualTreeHelperAddition.GetDpi(_pivot);