Skip to content
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

Expander Control #100

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions active/Expander/Expander.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@

# Background

> This spec corresponds to [this issue](https://github.com/microsoft/microsoft-ui-xaml/issues/3279) on the WinUI repo.

Throughout Windows, different expander controls are used by various apps and surfaces.
There’s currently no consistent way to address this common UX pattern.
This control is needed for situations where expanding (instead of overlaying) content is needed.
An Expander control is motivated by its use in many app scenarios and supporting developers in migrating from
[WPF](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/controls/expander-overview?view=netframeworkdesktop-4.8)
and [Windows Community Toolkit](https://docs.microsoft.com/en-us/windows/communitytoolkit/controls/expander).

# API Pages

## Expander class

Represents the control that displays a header and a collapsible content area.

> Spec note: the Expander class and ExpandDirection enum names match WPF.

An Expander control is a UI component that provides a standard interaction for
showing more content in a container that pushes adjacent content while expanding and collapsing.
An Expander cannot be light dismissed and is independent of the contents inside it, including controls.
Expander should be used when some content is only relevant some of the time (for example to
read more information or access additional options for an item).

![A collapsed Expander that is expanded (pushing downwards) and then collapsed. The Header has the text "This is in the header" and the Content has the text "This is in the content". There is a TextBlock saying "This TextBlock is Below the Expander" that is pushed away](images/Expander_with_textblock.gif)

### Examples

#### Create an Expander

![A collapsed Expander that is expanded and then collapsed. The Header has the text "This is in the header" and the Content has the text "This is in the content".](images/Expander.gif)

XAML
~~~~
<muxc:Expander x:Name="DefaultExpander"
Header="This text is in the header"
Content="This is in the content"/>
~~~~

#### Put controls inside an Expander

![A collapsed Expander. The Header has the text "This is in the header" and the Content has a button with the text "This ToggleButton is in the Content". The Expander is expanded, the button is toggled on and off, and the Expander is collapsed. ](images/Expander_togglebutton.gif)

XAML
~~~~
<muxc:Expander x:Name="Expander2" Header="This is in the header">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably, I could also put content in the Header?

<muxc:Expander x:Name="Expander2">
    <muxc:Expander.Header>
        <Button>Button in the header</Button>
    </muxc:Expander.Header>
    <Button>Button in the content</Button>
</muxc:Expander>

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify this, I'll be updating the examples so the second one has a ToggleButton in the header as well!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean to have a toggle button in the header, the header is already a toggle button?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By this I mean putting a ToggleButton inside the Header as part of an example showing controls in the Header and Content.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other interactive control would help. A toggle within a toggle creates some confusion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend: Just some interactive content other than a ToggleButton.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a TextBox or RichEditBox (a scenario might be "Enter your password" with the dropdown showing a "Forgot password button" or something like that)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea @oldnewthing, that's a very good example; @kat-y I think we should use that.

<ToggleButton>This ToggleButton is in the Content</ToggleButton>
</muxc:Expander>
~~~~

Updated pictures with final visuals to come.

### Theme Resources

You can modify the look of an Expander by specifying Xaml resources in your app.
For more info, see the
[lightweight styling guide](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/xaml-styles#lightweight-styling).

| Name| Description |
| :---------- | :------- |
| ExpanderChevronMargin | Chevron margin thickness|
| ExpanderChevronGlyph | Chevron glyph|
| ExpanderChevronSize | Chevron size|
| ExpanderPopinVerticalOffset | vertical offset for animation|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I style the background for the header and content separately? Which one does the Background property apply to? Similarly for font properties and Foreground.

Is this where HeaderTemplate enters the picture?

Or is this a case where you have to edit the template, and we expect most people to accept the default background and font?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the HeaderTemplate can be used to style the header, but @alexhinz knows more about this than me.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header, HeaderTemplate, and HeaderTemplateSelector are functionally analogous to Content, ContentTemplate, and ContentTemplateSelector, and they apply to the area of Expander that's to the left of the chevron. So because they don't span the entire border-to-border (inclusive) area of the header, they're likely not a good fit for that kind of styling. They also would not be aware of any Expander states, like if it's expanded, if a dev would like to change colors based on them.

So devs could retemplate to style the header and background areas separately. Adding in additional lightweight styling properties would help avoid the need to retemplate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does Expander.Background apply to? Both the header and the content?

Other controls have a Background resource, should there be one for Expander too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think lightweight styling properties would be popular.

  • To convey state. E.g. "Tuesday has slots available, Wednesday is full, and Thursday is oversubscribed."
  • To color-code the Expanders. E.g., Errors in red, Warnings in yellow.
  • Everybody wants their colors to match their brand.

Copy link
Contributor Author

@kat-y kat-y Feb 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re @MikeHillberg question: Following the latest Expander PR merge the Background property now does propagates to the Header (while the Foreground, Fontsize, and FontFamily propagate to the Content).

As an example, the following code results in an Expander where the entire header area (including 'under' the chevron) is Cyan, with default text styling, but the content area has default background color with text that is pink and size 25 Times New Roman font. (If there's a way to add pictures to a PR thread let me know!). I'll update this section to reflect the current behavior for now.

<controls:Expander x:Name="Expander1" Header="This is in the header" Content="This is in the content" FontSize ="25" FontFamily="Times New Roman" Foreground="Magenta" Background="Cyan"/>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussion: You could set the background of the Header using the Background property, and the background of the Content within the content itself.

Recommend: Maybe show an example?


Some theme resources TBD.
kat-y marked this conversation as resolved.
Show resolved Hide resolved



## Expander members

### Properties

| Name | Description | Default |
| :---------- | :------- | :------- |
| ExpandDirection | Sets the direction of expansion | Down = 0 |
| IsExpanded | Whether or not control is expanded | False |
kat-y marked this conversation as resolved.
Show resolved Hide resolved

### Events
| Name | Description |
| :---------- | :------- |
| Expanding | Occurs when expanded |
kat-y marked this conversation as resolved.
Show resolved Hide resolved
| Collapsed| Occurs when collapsed |



# API Details

~~~~
enum ExpandDirection
kat-y marked this conversation as resolved.
Show resolved Hide resolved
{
Down = 0,
Up = 1
};

runtimeclass ExpanderExpandingEventArgs
{
}

runtimeclass ExpanderCollapsedEventArgs
{
}

unsealed runtimeclass Expander : Windows.UI.Xaml.Controls.ContentControl
{
Expander();

Object Header{ get; set; };
Windows.UI.Xaml.DataTemplate HeaderTemplate{ get; set; };
Windows.UI.Xaml.Controls.DataTemplateSelector HeaderTemplateSelector{ get; set; };

[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
Boolean IsExpanded{ get; set; };

[MUX_DEFAULT_VALUE("winrt::ExpandDirection::Down")]
[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
ExpandDirection ExpandDirection{ get; set; };

event Windows.Foundation.TypedEventHandler<Expander, ExpanderExpandingEventArgs> Expanding;
event Windows.Foundation.TypedEventHandler<Expander, ExpanderCollapsedEventArgs> Collapsed;

static Windows.UI.Xaml.DependencyProperty HeaderProperty{ get; };
static Windows.UI.Xaml.DependencyProperty HeaderTemplateProperty{ get; };
static Windows.UI.Xaml.DependencyProperty HeaderTemplateSelectorProperty{ get; };

static Windows.UI.Xaml.DependencyProperty IsExpandedProperty{ get; };
static Windows.UI.Xaml.DependencyProperty ExpandDirectionProperty{ get; };
}
~~~~

# Inputs and Accessibility
kat-y marked this conversation as resolved.
Show resolved Hide resolved

## UI Automation Patterns
Expander will use a ExpandCollapsePattern. Expanding/Collapsing the expander will raise [RaisePropertyChanged](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.automation.peers.automationpeer.raisepropertychangedevent?view=winrt-19041) with the property changed being the [ExpandCollapseProperty](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.automation.expandcollapsepatternidentifiers.expandcollapsestateproperty?view=winrt-19041) property.
kat-y marked this conversation as resolved.
Show resolved Hide resolved

## Keyboard
* Tabbing brings focus to the Header, neither the entire Expander nor the chevron is a tab-stop
* When focus is on the Header, space key expands and collapse and focus does not move
* Keyboard navigation inside the Expander's Header/Content is based on the content inside them
kat-y marked this conversation as resolved.
Show resolved Hide resolved

## GamePad
The Expander can be expanded and collapsed with A. Spatial navigation will navigate between the content of the Expander.
kat-y marked this conversation as resolved.
Show resolved Hide resolved

## Screen reader
When focus is on the Header of an Expander, the screen reader will announce "Expander collapsed" or "Expander expanded". With focus staying on the header, the screen reader will then anounce "expanded" or "collapsed" accordingly. Expander should not have [focus engagement](https://docs.microsoft.com/en-us/windows/uwp/design/input/gamepad-and-remote-interactions#focus-engagement) enabled.
kat-y marked this conversation as resolved.
Show resolved Hide resolved

<!-- # Appendix
<!-- Anything else that you want to write down for posterity, but
that isn't necessary to understand the purpose and usage of the API.
For example, implementation details. -->

# Open Questions
* How should properties from ContentControl (ex: Background, Foreground, FontSize) propagate?
Binary file added active/Expander/images/Expander.gif
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.