timheuer / callisto

A control toolkit for Windows 8 XAML applications. Contains some UI controls to make it easier to create Windows UI style apps for the Windows Store in accordance with Windows UI guidelines.
http://timheuer.com/blog/archive/2012/05/31/introducing-callisto-a-xaml-toolkit-for-metro-apps.aspx
Other
338 stars 108 forks source link

Flyout Position moves to 'random' position when default location won't fit in screen. #237

Open deruss opened 10 years ago

deruss commented 10 years ago

Hi, I've seen problems whenever Flyout is opened and its default position won't fit entirely within the screen. The 'adjustment' to the position can result in strange placement, sometimes partially off-screen.

I've tracked the issue down to the way CalculateVerticalCenterOffset()/CalculateHorizontalCenterOffset() are applied.

These methods are used to 'center align' a flyout with it's target element. For example, if PlacementMode is Right, then the flyout will attempt to position such that is vertical center is aligned with the target element's vertical center. It 'shifts' the flyout upwards by half the flyout's Height.

The trouble is that these methods are applied AFTER the window bounding-box code (the second half of PlacePopup() ). If the bounding-box code has shifted the Flyout (to keep it flush with edge of screen - eg. X or Y may become 0 to be flush left or top), then the application of Calculate*CenterOffset() methods will shift it even more. The offsets may accumulate to a position well away from the target element. (But only in the direction of the center alignment - the other direction is unaffected).

I think the proper solution would be to change the pointArray initial values in PlacePopup() to account for the center alignment, rather than just the corners of the target. This would ensure the bounding-box code applies to the actual desired position(s).

But a quick solution for me is to remove the center alignment altogether, by making a simple code change. Change this:

  var calcH = this.CalculateHorizontalCenterOffset(x, ((FrameworkElement)_hostPopup.Child).ActualWidth, element.ActualWidth);
  var calcY = this.CalculateVerticalCenterOffset(y, ((FrameworkElement)_hostPopup.Child).ActualHeight, element.ActualHeight);

To this:

  var calcH = this.HorizontalOffset + x;
  var calcY = this.HorizontalOffset + y;

This is similar to issue #26 , particularly the case reported by daniel-chambers, and also an earlier issue I raised #224

David.