-
Notifications
You must be signed in to change notification settings - Fork 678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Popup placement properties API spec #4905
Merged
Merged
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
564a099
Updating CommandBarFlyout's CommandBar to take monitor information in…
llongley 0efa0e0
Adding spec information for the new API.
llongley b00bf0e
Fixing typo.
llongley 880334e
Changed the design to add additional APIs to Popup instead.
llongley 832a2b7
Updating some wording.
llongley 9eb5871
Updating wording.
llongley 0e1b81d
More wording updates.
llongley 7e31ace
Update Popup-AdditionalLayoutProperties-Spec.md
llongley a99f757
Update Popup-AdditionalLayoutProperties-Spec.md
llongley fe6003a
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 1ab598f
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 864cc2a
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 614c625
Updates
MikeHillberg 9513b70
Adding a spec for new Popup placement property APIs.
llongley a4a69b5
Merge remote-tracking branch 'origin/user/llongley/AddCommandBarFlyou…
llongley aa6eb16
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 6ab9640
Revert "Updating CommandBarFlyout's CommandBar to take monitor inform…
llongley a03baeb
Merge branch 'user/llongley/PopupPlacementAPISpec' of https://github.…
llongley 5994951
Super minor cleanup
MikeHillberg dde1b34
Update Popup-AdditionalLayoutProperties-Spec.md
llongley b4a7664
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 8ce00ee
Update specs/Popup-AdditionalLayoutProperties-Spec.md
llongley 66b27a7
Update Popup-AdditionalLayoutProperties-Spec.md
llongley eb51143
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 7cde2b1
Update Popup-AdditionalLayoutProperties-Spec.md
llongley 3a65a85
Update Popup-AdditionalLayoutProperties-Spec.md
llongley File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
Popup additional layout properties | ||
=== | ||
|
||
# Background | ||
|
||
[Popups](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.Primitives.Popup) | ||
and | ||
[flyouts](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.Primitives.FlyoutBase) | ||
in XAML are given two modes of display: | ||
* They can either appear as part of the rest of XAML, | ||
in which case they're confined to the bounds of the XAML root, | ||
* Or they can appear in their own HWND, which | ||
allows them to escape the bounds of the XAML root. This is common for elements such as context menus. | ||
|
||
[CommandBarFlyout](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.CommandBarFlyout) | ||
is one such element, but since it's defined in the WinUI 2 controls library | ||
rather than in the OS, it does not | ||
have access to the HWND used to allow it to escape the XAML root's bounds. As such, it has no way to | ||
determine which monitor it's being displayed in, which makes it unable to know whether it has enough visual space | ||
to open the popup for its secondary commands _below_ its primary commands or whether it should open them above instead. | ||
|
||
This new API adds three properties and an event to `Popup` which will allow apps to specify where it logically | ||
desires a popup | ||
to be displayed relative to another element, and then respond to where system XAML was able to actually place | ||
the popup. This will allow elements such as `CommandBarFlyout` to be able to rely on system XAML for the placement of their | ||
child popups in a way that will take monitor or app bounds into account without needing to do that accounting manually. | ||
|
||
## Visual Examples | ||
|
||
**Opening down** | ||
|
||
When CommandBarFlyout has enough space below its primary commands, we want it to open down. | ||
|
||
Secondary commands flyout closed: | ||
|
||
![Shows the CommandBarFlyout not yet open with sufficient monitor space below it](images/CommandBarFlyout-SufficientSpace.png) | ||
|
||
Secondary commands flyout open: | ||
|
||
![Shows the CommandBarFlyout opened down](images/CommandBarFlyout-SufficientSpace-Open.png) | ||
|
||
**Opening up** | ||
|
||
When CommandBarFlyout does *not* have enough space below its primary commands, we want it to be able to open up. | ||
|
||
Secondary commands flyout closed: | ||
|
||
![Shows the CommandBarFlyout not yet open with insufficient monitor space below it](images/CommandBarFlyout-InsufficientSpace.png) | ||
|
||
Secondary commands flyout open: | ||
|
||
![Shows the CommandBarFlyout opened up](images/CommandBarFlyout-InsufficientSpace-Open.png) | ||
|
||
# API Pages | ||
|
||
## Popup class | ||
|
||
```csharp | ||
class Popup | ||
{ | ||
// Existing APIs | ||
// ... | ||
|
||
// New APIs | ||
UIElement PlacementTarget { get; set; } | ||
PopupPlacementMode DesiredPlacement { get; set; } | ||
PopupPlacementMode ActualPlacement { get; } | ||
|
||
public event System.EventHandler<object> PlacementChanged; | ||
} | ||
``` | ||
|
||
The example below shows how the `Placement` APIs are used by the | ||
[CommandBarFlyout](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.CommandBarFlyout) | ||
to position its | ||
[CommandBarFlyoutCommandBar](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.Primitives.CommandBarFlyoutCommandBar)'s | ||
secondary commands Popup, and how to respond to the event raised when XAML places the Popup. | ||
|
||
```xml | ||
<!-- Part of the CommandBarFlyoutCommandBar's default template --> | ||
<Popup | ||
x:Name="OverflowPopup" | ||
PlacementTarget="{Binding ElementName=PrimaryItemsRoot}" | ||
DesiredPlacement="Bottom"> | ||
</Popup> | ||
``` | ||
|
||
```csharp | ||
void OnApplyTemplate() | ||
{ | ||
m_overflowPopup = GetTemplateChild("OverflowPopup"); | ||
m_overflowPopup.PlacementChanged += OnOverflowPopupPlacementChanged; | ||
} | ||
|
||
void OnOverflowPopupPlacementChanged(object sender, object args) | ||
{ | ||
UpdateVisualState(useTransitions: false); | ||
} | ||
|
||
void UpdateVisualState(bool useTransitions) | ||
{ | ||
if (m_overflowPopup.ActualPlacement == PopupPlacementMode.Top) | ||
{ | ||
VisualStateManager.GoToState(this, "ExpandedUp", useTransitions); | ||
} | ||
else | ||
{ | ||
VisualStateManager.GoToState(this, "ExpandedDown", useTransitions); | ||
} | ||
} | ||
``` | ||
|
||
## Popup.PlacementTarget property | ||
|
||
Use this property to describe which element the `Popup` should be positioned relative to. | ||
Defaults to `null`. | ||
|
||
If this is `null`, then `DesiredPlacement` is ignored, `ActualPlacement` is always `None`, and | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
`PlacementChanged` is never raised. If the `Popup` is in the visual tree, `PlacementTarget` will override what its | ||
position would otherwise be set to by layout. Setting `PlacementTarget` to an element under a different XAML root than | ||
`Popup.XamlRoot` is invalid and will throw an `ArgumentException`. | ||
|
||
Ignored if `DesiredPlacement` is `None`. | ||
|
||
_Spec note: this property is analogous to the | ||
[FlyoutBase.Target](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.Primitives.FlyoutBase.Target) | ||
property, but `Popup.Target` looked confusing, so we added the `Placement` prefix._ | ||
|
||
## Popup.DesiredPlacement property | ||
|
||
Use this property to describe how you would ideally like the `Popup` | ||
positioned relative to `PlacementTarget`. Defaults to `None`. | ||
|
||
If this is `None`, then `PlacementTarget` is ignored, | ||
`ActualPlacement` is always `None` and `PlacementChanged` is never raised. | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
If both `DesiredPlacement` and `PlacementTarget` are set and `HorizontalOffset` and/or `VerticalOffset` | ||
are also set, then the latter two properties will offset the `Popup` from where it would have been | ||
placed by `DesiredPlacement` and `PlacementTarget` alone. | ||
|
||
Ignored if `PlacementTarget` is null. | ||
|
||
## Popup.ActualPlacement property | ||
|
||
Use this read-only property to determine where the popup was positioned. | ||
Will always be `None` if either `PlacementTarget` and `DesiredPlacement` are not set. | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Popup.PlacementChanged event | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Raised whenever XAML changes the value of `ActualPlacement`, | ||
which allows apps to respond to where a `Popup` was placed. | ||
|
||
For example, use this to determine the visual state to go into, | ||
based on whether a `Popup` is appearing above or below `PlacementTarget`. | ||
|
||
This event is raised before the screen is refreshed, meaning that any visual changes made | ||
in response to this event can be made before anything is drawn to the screen at the new position. | ||
Will never be raised if either `PlacementTarget` and `DesiredPlacement` are not set. | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## PopupPlacementMode enum | ||
|
||
_Spec note: This is designed to align with the existing | ||
[FlyoutPlacementMode](https://docs.microsoft.com/uwp/api/Windows.UI.Xaml.Controls.Primitives.FlyoutPlacementMode) | ||
enum, with the exception of the absence of "Full". "Full" is absent since developers should use a Flyout | ||
if they want something full-screen._ | ||
|
||
```csharp | ||
enum PopupPlacementMode | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
None, | ||
Top, | ||
llongley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Bottom, | ||
Left, | ||
Right, | ||
TopEdgeAlignedLeft, | ||
TopEdgeAlignedRight, | ||
BottomEdgeAlignedLeft, | ||
BottomEdgeAlignedRight, | ||
LeftEdgeAlignedTop, | ||
LeftEdgeAlignedBottom, | ||
RightEdgeAlignedTop, | ||
RightEdgeAlignedBottom | ||
} | ||
``` | ||
|
||
_Spec note: The meaning of "Left" and "Right" are swapped if | ||
[FlowDirection](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.frameworkelement.flowdirection) | ||
is `RightToLeft`._ | ||
|
||
# API Details | ||
|
||
```csharp | ||
namespace Windows.UI.Xaml.Controls.Primitives | ||
{ | ||
[webhosthidden] | ||
enum PopupPlacementMode | ||
{ | ||
None, | ||
Top, | ||
Bottom, | ||
Left, | ||
Right, | ||
TopEdgeAlignedLeft, | ||
TopEdgeAlignedRight, | ||
BottomEdgeAlignedLeft, | ||
BottomEdgeAlignedRight, | ||
LeftEdgeAlignedTop, | ||
LeftEdgeAlignedBottom, | ||
RightEdgeAlignedTop, | ||
RightEdgeAlignedBottom | ||
}; | ||
|
||
[webhosthidden] | ||
interface IPopup2 | ||
{ | ||
Windows.UI.Xaml.UIElement PlacementTarget; | ||
Windows.UI.Xaml.Controls.Primitives.PopupPlacementMode DesiredPlacement; | ||
Windows.UI.Xaml.Controls.Primitives.PopupPlacementMode ActualPlacement { get; }; | ||
|
||
event Windows.Foundation.EventHandler<Object> PlacementChanged; | ||
|
||
static Windows.UI.Xaml.DependencyProperty PlacementTargetProperty{ get; }; | ||
static Windows.UI.Xaml.DependencyProperty DesiredPlacementProperty{ get; }; | ||
static Windows.UI.Xaml.DependencyProperty ActualPlacementProperty{ get; }; | ||
}; | ||
} | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the addition of this property will require some reworking of the existing Popup documentation that talks about placement.
In fact, we forgot to update the Popup documentation when we added
ShouldConstrainToRootBounds
. The Popup documentation still says right there in the first sentence, "Displays content on top of existing content, within the bounds of the application window" which is no longer true ifShouldConstrainToRootBounds
is false.