private void PerformPlacement(double horizontalOffset, double verticalOffset) { double x = 0.0; double y = 0.0; PlacementMode placement = this.Placement; FrameworkElement element = this.PlacementTarget as FrameworkElement; bool isRTL = (element != null) ? (element.FlowDirection == Windows.UI.Xaml.FlowDirection.RightToLeft) : false; if ((element != null) && !element.IsHitTestVisible) { return; } switch (placement) { case PlacementMode.Bottom: case PlacementMode.Left: case PlacementMode.Right: case PlacementMode.Top: Point[] target = GetTransformedPoints(element, isRTL, element); Point[] menu = GetTransformedPoints((FrameworkElement)_hostPopup.Child, isRTL, element); if (menu[0].X > menu[1].X) { return; } Point p2 = PlacePopup(_windowBounds, target, menu, placement); x = p2.X; if (isRTL) { // TODO: Handle RTL - PerformPlacement //x = _windowBounds.Width - x; //this._hostPopup.VerticalOffset = y; //this._hostPopup.HorizontalOffset = x; //return; } y = p2.Y; break; case PlacementMode.Mouse: throw new NotImplementedException("Mouse PlacementMode is not implemented."); } if (x < 0.0) x = 0.0; if (y < 0.0) y = 0.0; var calcH = this.CalculateHorizontalCenterOffset(x, ((FrameworkElement)_hostPopup.Child).ActualWidth, element.ActualWidth); var calcY = this.CalculateVerticalCenterOffset(y, ((FrameworkElement)_hostPopup.Child).ActualHeight, element.ActualHeight); if (calcH < 0) { calcH = GUTTER_BUFFER; } else { // TODO: Correct right nudge positioning as it is incorrect if ((calcH > _windowBounds.Width) || (calcH + ((FrameworkElement)_hostPopup.Child).ActualWidth) > _windowBounds.Width) { calcH = _windowBounds.Width - ((FrameworkElement)_hostPopup.Child).ActualWidth - GUTTER_BUFFER; } } _hostPopup.HorizontalOffset = calcH; _hostPopup.VerticalOffset = calcY; _hostPopup.IsHitTestVisible = true; _hostPopup.Opacity = 1; // for entrance animation // UX guidelines show a PopIn animation Storyboard inAnimation = new Storyboard(); PopInThemeAnimation popin = new PopInThemeAnimation(); // TODO: Switch statement begs of refactoring switch (this.Placement) { case PlacementMode.Bottom: popin.FromVerticalOffset = -10; popin.FromHorizontalOffset = 0; break; case PlacementMode.Left: popin.FromVerticalOffset = 0; popin.FromHorizontalOffset = 10; break; case PlacementMode.Right: popin.FromVerticalOffset = 0; popin.FromHorizontalOffset = -10; break; case PlacementMode.Top: popin.FromVerticalOffset = 10; popin.FromHorizontalOffset = 0; break; } Storyboard.SetTarget(popin, _hostPopup); inAnimation.Children.Add(popin); inAnimation.Begin(); }
private void OnContextMenuOpened(object sender, object e) { if (this.m_contextMenuPopup.ActualHeight == 0 || this.m_contextMenuPopup.ActualWidth == 0) { SizeChangedEventHandler updatePosition = null; updatePosition = (s, sizeChangedEventArgs) => { if (sizeChangedEventArgs.NewSize.Width != 0 && sizeChangedEventArgs.NewSize.Height != 0) { OnContextMenuOpened(s, sizeChangedEventArgs); SizeChanged -= updatePosition; } }; SizeChanged += updatePosition; } this.m_contextMenuPopup.HorizontalOffset = this.HorizontalOffset; this.m_contextMenuPopup.VerticalOffset = this.VerticalOffset; this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); UIElement root = Window.Current.Content; if (root != null) { GeneralTransform transform = this.PlacementTarget.TransformToVisual(root); Point relativeSourceLocation = transform.TransformPoint(new Point(0, 0)); Rect bounds = Window.Current.Bounds; double horizondalOffset = 0; double verticalOffset = 0; horizondalOffset = Math.Min(relativeSourceLocation.X + (this.PlacementTarget.ActualWidth / 2) - (this.PlacementTarget.ActualWidth / 2), bounds.Width - this.m_contextMenuPopup.ActualWidth - 5); horizondalOffset = Math.Max(5, horizondalOffset - 2); verticalOffset = Math.Min(relativeSourceLocation.Y + (this.PlacementTarget.ActualHeight / 2) - (this.PlacementTarget.ActualHeight / 2), bounds.Height - this.PlacementTarget.ActualHeight - 5); verticalOffset = Math.Max(5, verticalOffset - 1); // for entrance animation // UX guidelines show a PopIn animation Storyboard inAnimation = new Storyboard(); PopInThemeAnimation popInThemeAnimation = new PopInThemeAnimation(); switch (this.Placement) { case Windows.UI.Popups.Placement.Left: popInThemeAnimation.FromVerticalOffset = 0; popInThemeAnimation.FromHorizontalOffset = 10; horizondalOffset = relativeSourceLocation.X - 2; break; case Windows.UI.Popups.Placement.Below: popInThemeAnimation.FromVerticalOffset = -10; popInThemeAnimation.FromHorizontalOffset = 0; verticalOffset = Math.Min(relativeSourceLocation.Y + this.PlacementTarget.ActualHeight - 1, bounds.Height - ((FrameworkElement)this.m_contextMenuPopup.Child).ActualHeight - 5); break; default: popInThemeAnimation.FromVerticalOffset = 10; popInThemeAnimation.FromHorizontalOffset = 0; verticalOffset = Math.Max(5, relativeSourceLocation.Y - ((FrameworkElement)this.m_contextMenuPopup.Child).ActualHeight - 1); break; } this.m_contextMenuPopup.HorizontalOffset = horizondalOffset; this.m_contextMenuPopup.VerticalOffset = verticalOffset; this.m_contextMenuPopup.Opacity = 1; Storyboard.SetTarget(popInThemeAnimation, this.m_contextMenuPopup); inAnimation.Children.Add(popInThemeAnimation); inAnimation.Begin(); } }