/// <summary> /// Implements custom placement for ribbon popup /// </summary> /// <param name="popupsize"></param> /// <param name="targetsize"></param> /// <param name="offset"></param> /// <returns></returns> CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupsize, Size targetsize, Point offset) { if ((popup != null) && (SelectedTabItem != null)) { // Get current workarea Point tabItemPos = SelectedTabItem.PointToScreen(new Point(0, 0)); NativeMethods.Rect tabItemRect = new NativeMethods.Rect(); tabItemRect.Left = (int)tabItemPos.X; tabItemRect.Top = (int)tabItemPos.Y; tabItemRect.Right = (int)tabItemPos.X + (int)SelectedTabItem.ActualWidth; tabItemRect.Bottom = (int)tabItemPos.Y + (int)SelectedTabItem.ActualHeight; uint MONITOR_DEFAULTTONEAREST = 0x00000002; System.IntPtr monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); if (monitor != System.IntPtr.Zero) { NativeMethods.MonitorInfo monitorInfo = new NativeMethods.MonitorInfo(); monitorInfo.Size = Marshal.SizeOf(monitorInfo); NativeMethods.GetMonitorInfo(monitor, monitorInfo); Point startPoint = PointToScreen(new Point(0, 0)); if (FlowDirection == FlowDirection.RightToLeft) startPoint.X -= ActualWidth; double inWindowRibbonWidth = monitorInfo.Work.Right - Math.Max(monitorInfo.Work.Left, startPoint.X); double actualWidth = ActualWidth; if (startPoint.X < monitorInfo.Work.Left) { actualWidth -= monitorInfo.Work.Left - startPoint.X; startPoint.X = monitorInfo.Work.Left; } // Set width popup.Width = Math.Min(actualWidth, inWindowRibbonWidth); return new CustomPopupPlacement[] { new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, SelectedTabItem.ActualHeight-(popup.Child as FrameworkElement).Margin.Top), PopupPrimaryAxis.None), new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, -(SelectedContent as ScrollViewer).ActualHeight-(popup.Child as FrameworkElement).Margin.Bottom), PopupPrimaryAxis.None), }; } } return null; }
/// <summary> /// Returns screen workarea in witch control is placed /// </summary> /// <param name="control">Control</param> /// <returns>Workarea in witch control is placed</returns> public static Rect GetControlWorkArea(FrameworkElement control) { Point tabItemPos = control.PointToScreen(new Point(0, 0)); NativeMethods.Rect tabItemRect = new NativeMethods.Rect(); tabItemRect.Left = (int)tabItemPos.X; tabItemRect.Top = (int)tabItemPos.Y; tabItemRect.Right = (int)tabItemPos.X + (int)control.ActualWidth; tabItemRect.Bottom = (int)tabItemPos.Y + (int)control.ActualHeight; uint MONITOR_DEFAULTTONEAREST = 0x00000002; System.IntPtr monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); if (monitor != System.IntPtr.Zero) { NativeMethods.MonitorInfo monitorInfo = new NativeMethods.MonitorInfo(); monitorInfo.Size = Marshal.SizeOf(monitorInfo); NativeMethods.GetMonitorInfo(monitor, monitorInfo); return new Rect(monitorInfo.Work.Left, monitorInfo.Work.Top, monitorInfo.Work.Right - monitorInfo.Work.Left, monitorInfo.Work.Bottom - monitorInfo.Work.Top); } return new Rect(); }
private void SetRoundingRegion(NativeMethods.WINDOWPOS? wp) { const int MONITOR_DEFAULTTONEAREST = 0x00000002; // We're early - WPF hasn't necessarily updated the state of the window. // Need to query it ourselves. NativeMethods.WINDOWPLACEMENT wpl = new NativeMethods.WINDOWPLACEMENT(); NativeMethods.GetWindowPlacement(handle, wpl); if (wpl.showCmd == NativeMethods.SW_SHOWMAXIMIZED && IsDwmEnabled == true) { int left; int top; if (wp.HasValue) { left = wp.Value.x; top = wp.Value.y; } else { NativeMethods.Rect r = new NativeMethods.Rect(); NativeMethods.GetWindowRect(handle, ref r); left = r.Left; top = r.Top; } IntPtr hMon = NativeMethods.MonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST); NativeMethods.MonitorInfo mi = new NativeMethods.MonitorInfo(); NativeMethods.GetMonitorInfo(hMon, mi); NativeMethods.Rect rcMax = mi.Work; // The location of maximized window takes into account the border that Windows was // going to remove, so we also need to consider it. rcMax.Left -= left; rcMax.Right -= left; rcMax.Top -= top; rcMax.Bottom -= top; IntPtr hrgn = IntPtr.Zero; try { hrgn = NativeMethods.CreateRectRgnIndirect(ref rcMax); NativeMethods.SetWindowRgn(handle, hrgn, NativeMethods.IsWindowVisible(handle)); hrgn = IntPtr.Zero; } finally { NativeMethods.DeleteObject(hrgn); } } else { Size windowSize; // Use the size if it's specified. if (null != wp && !IsFlagSet(wp.Value.flags, NativeMethods.SWP_NOSIZE)) { windowSize = new Size((double)wp.Value.cx, (double)wp.Value.cy); } else if (null != wp && (lastRoundingState == WindowState)) { return; } else { NativeMethods.Rect r = new NativeMethods.Rect(); NativeMethods.GetWindowRect(handle, ref r); Rect rect = new Rect(r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top); windowSize = rect.Size; } lastRoundingState = WindowState; IntPtr hrgn = IntPtr.Zero; try { double shortestDimension = Math.Min(windowSize.Width, windowSize.Height); double topLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(CornerRadius.TopLeft, 0)).X; topLeftRadius = Math.Min(topLeftRadius, shortestDimension / 2); if (IsUniform(CornerRadius)) { // RoundedRect HRGNs require an additional pixel of padding. hrgn = CreateRoundRectRgn(new Rect(windowSize), topLeftRadius); } else { // We need to combine HRGNs for each of the corners. // Create one for each quadrant, but let it overlap into the two adjacent ones // by the radius amount to ensure that there aren't corners etched into the middle // of the window. hrgn = CreateRoundRectRgn(new Rect(0, 0, windowSize.Width / 2 + topLeftRadius, windowSize.Height / 2 + topLeftRadius), topLeftRadius); double topRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(CornerRadius.TopRight, 0)).X; topRightRadius = Math.Min(topRightRadius, shortestDimension / 2); Rect topRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + topRightRadius, windowSize.Height / 2 + topRightRadius); topRightRegionRect.Offset(windowSize.Width / 2 - topRightRadius, 0); CreateAndCombineRoundRectRgn(hrgn, topRightRegionRect, topRightRadius); double bottomLeftRadius = /*DpiHelper.LogicalPixelsToDevice*/(new Point(CornerRadius.BottomLeft, 0)).X; bottomLeftRadius = Math.Min(bottomLeftRadius, shortestDimension / 2); Rect bottomLeftRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomLeftRadius, windowSize.Height / 2 + bottomLeftRadius); bottomLeftRegionRect.Offset(0, windowSize.Height / 2 - bottomLeftRadius); CreateAndCombineRoundRectRgn(hrgn, bottomLeftRegionRect, bottomLeftRadius); double bottomRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(CornerRadius.BottomRight, 0)).X; bottomRightRadius = Math.Min(bottomRightRadius, shortestDimension / 2); Rect bottomRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomRightRadius, windowSize.Height / 2 + bottomRightRadius); bottomRightRegionRect.Offset(windowSize.Width / 2 - bottomRightRadius, windowSize.Height / 2 - bottomRightRadius); CreateAndCombineRoundRectRgn(hrgn, bottomRightRegionRect, bottomRightRadius); } NativeMethods.SetWindowRgn(handle, hrgn, NativeMethods.IsWindowVisible(handle)); hrgn = IntPtr.Zero; } finally { // Free the memory associated with the HRGN if it wasn't assigned to the HWND. NativeMethods.DeleteObject(hrgn); } } }
/// <summary> /// Implements custom placement for ribbon popup /// </summary> /// <param name="popupsize"></param> /// <param name="targetsize"></param> /// <param name="offset"></param> /// <returns></returns> private CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupsize, Size targetsize, Point offset) { if (this.DropDownPopup != null && this.SelectedTabItem != null) { // Get current workarea var tabItemPos = this.SelectedTabItem.PointToScreen(new Point(0, 0)); var tabItemRect = new NativeMethods.Rect { Left = (int)tabItemPos.X, Top = (int)tabItemPos.Y, Right = (int)tabItemPos.X + (int)this.SelectedTabItem.ActualWidth, Bottom = (int)tabItemPos.Y + (int)this.SelectedTabItem.ActualHeight }; const uint MONITOR_DEFAULTTONEAREST = 0x00000002; var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); if (monitor != IntPtr.Zero) { var monitorInfo = new NativeMethods.MonitorInfo(); monitorInfo.Size = Marshal.SizeOf(monitorInfo); NativeMethods.GetMonitorInfo(monitor, monitorInfo); var startPoint = this.PointToScreen(new Point(0, 0)); if (this.FlowDirection == FlowDirection.RightToLeft) { startPoint.X -= this.ActualWidth; } var inWindowRibbonWidth = monitorInfo.Work.Right - Math.Max(monitorInfo.Work.Left, startPoint.X); var actualWidth = this.ActualWidth; if (startPoint.X < monitorInfo.Work.Left) { actualWidth -= monitorInfo.Work.Left - startPoint.X; startPoint.X = monitorInfo.Work.Left; } // Set width this.DropDownPopup.Width = Math.Min(actualWidth, inWindowRibbonWidth); return new[] { new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, this.SelectedTabItem.ActualHeight - ((FrameworkElement)this.DropDownPopup.Child).Margin.Top), PopupPrimaryAxis.None), new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, -((ScrollViewer)this.SelectedContent).ActualHeight - ((FrameworkElement)this.DropDownPopup.Child).Margin.Bottom), PopupPrimaryAxis.None) }; } } return null; }