Skip to content
23 changes: 20 additions & 3 deletions src/Wpf.Ui.Gallery/Views/Pages/Layout/ExpanderPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,36 @@

<StackPanel Margin="0,0,0,24">
<controls:ControlExample
x:Name="ControlExample1"
Margin="0"
HeaderText="An Expander with text in the header and content areas"
XamlCode="&lt;Expander Header=&quot;This text is in the header&quot; Content=&quot;This is in the content&quot; /&gt;">
HeaderText="An Expander with text in the header and content areas">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Expander
x:Name="Expander1"
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
d:IsExpanded="True"
Content="This is in the content"
ExpandDirection="Down"
Header="This text is in the header" />
<!-- TODO: ExpandDirection -->
<StackPanel Grid.Column="2" Margin="16">
<TextBlock Margin="0,0,0,8" Text="ExpandDirection" />
<ComboBox
VerticalAlignment="Center"
SelectedIndex="0"
SelectionChanged="ComboBox_SelectionChanged">
<ComboBoxItem Content="Down" />
<ComboBoxItem Content="Up" />
<ComboBoxItem Content="Left" />
<ComboBoxItem Content="Right" />
</ComboBox>
</StackPanel>
</Grid>
</controls:ControlExample>

Expand Down
55 changes: 54 additions & 1 deletion src/Wpf.Ui.Gallery/Views/Pages/Layout/ExpanderPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// This Source Code Form is subject to the terms of the MIT License.
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

using System.Windows.Controls;
using Wpf.Ui.Controls;
using Wpf.Ui.Gallery.Controls;
using Wpf.Ui.Gallery.ControlsLookup;
using Wpf.Ui.Gallery.ViewModels.Pages.Layout;

Expand All @@ -19,4 +21,55 @@ public ExpanderPage(ExpanderViewModel viewModel)
}

public ExpanderViewModel ViewModel { get; }

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var comboBox = (ComboBox)sender;
string selectedText = (string)((ComboBoxItem)comboBox.SelectedValue).Content;
ExpandDirection direction = Enum.Parse<ExpandDirection>(selectedText);

Expander1.SetCurrentValue(Expander.ExpandDirectionProperty, direction);

switch (direction)
{
case ExpandDirection.Down:
Expander1.SetCurrentValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
Expander1.SetCurrentValue(VerticalAlignmentProperty, VerticalAlignment.Top);

ControlExample1.SetCurrentValue(ControlExample.XamlCodeProperty, """
<Expander HorizontalAlignment="Left" VerticalAlignment="Top" Content="This is in the content" ExpandDirection="Down" Header="This text is in the header" />
""");

break;
case ExpandDirection.Up:
Expander1.SetCurrentValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
Expander1.SetCurrentValue(VerticalAlignmentProperty, VerticalAlignment.Bottom);

ControlExample1.SetCurrentValue(ControlExample.XamlCodeProperty, """
<Expander HorizontalAlignment="Left" VerticalAlignment="Bottom" Content="This is in the content" ExpandDirection="Up" Header="This text is in the header" />
""");

break;
case ExpandDirection.Left:
Expander1.SetCurrentValue(HorizontalAlignmentProperty, HorizontalAlignment.Right);
Expander1.SetCurrentValue(VerticalAlignmentProperty, VerticalAlignment.Top);

ControlExample1.SetCurrentValue(ControlExample.XamlCodeProperty, """
<Expander HorizontalAlignment="Right" VerticalAlignment="Top" Content="This is in the content" ExpandDirection="Left" Header="This text is in the header" />
""");

break;
case ExpandDirection.Right:
Expander1.SetCurrentValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
Expander1.SetCurrentValue(VerticalAlignmentProperty, VerticalAlignment.Top);

ControlExample1.SetCurrentValue(ControlExample.XamlCodeProperty, """
<Expander HorizontalAlignment="Left" VerticalAlignment="Top" Content="This is in the content" ExpandDirection="Right" Header="This text is in the header" />
""");

break;
default:
break;
}
}
}
157 changes: 129 additions & 28 deletions src/Wpf.Ui/Controls/Expander/Expander.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,71 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:animations="clr-namespace:Wpf.Ui.Animations"
xmlns:controls="clr-namespace:Wpf.Ui.Controls"
xmlns:converters="clr-namespace:Wpf.Ui.Converters"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:animations="clr-namespace:Wpf.Ui.Animations">
xmlns:system="clr-namespace:System;assembly=System.Runtime">

<Thickness x:Key="ExpanderPadding">11,11,11,11</Thickness>
<Thickness x:Key="ExpanderBorderThemeThickness">1</Thickness>
<system:Double x:Key="ExpanderChevronSize">16.0</system:Double>

<converters:AnimationFactorToValueConverter x:Key="AnimationFactorToValueConverter" />

<TranslateTransform x:Key="RollDownTransform">
<TranslateTransform.Y>
<MultiBinding Converter="{StaticResource AnimationFactorToValueConverter}" ConverterParameter="negative">
<Binding ElementName="ContentPresenterBorder" Path="ActualHeight" />
<Binding ElementName="ContentPresenterBorder" Path="(animations:AnimationProperties.AnimationTagValue)" />
</MultiBinding>
</TranslateTransform.Y>
</TranslateTransform>

<TranslateTransform x:Key="RollUpTransform">
<TranslateTransform.Y>
<MultiBinding Converter="{StaticResource AnimationFactorToValueConverter}" ConverterParameter="positive">
<Binding ElementName="ContentPresenterBorder" Path="ActualHeight" />
<Binding ElementName="ContentPresenterBorder" Path="(animations:AnimationProperties.AnimationTagValue)" />
</MultiBinding>
</TranslateTransform.Y>
</TranslateTransform>

<TranslateTransform x:Key="RollLeftTransform">
<TranslateTransform.X>
<MultiBinding Converter="{StaticResource AnimationFactorToValueConverter}" ConverterParameter="positive">
<Binding ElementName="ContentPresenterBorder" Path="ActualWidth" />
<Binding ElementName="ContentPresenterBorder" Path="(animations:AnimationProperties.AnimationTagValue)" />
</MultiBinding>
</TranslateTransform.X>
</TranslateTransform>

<TranslateTransform x:Key="RollRightTransform">
<TranslateTransform.X>
<MultiBinding Converter="{StaticResource AnimationFactorToValueConverter}" ConverterParameter="negative">
<Binding ElementName="ContentPresenterBorder" Path="ActualWidth" />
<Binding ElementName="ContentPresenterBorder" Path="(animations:AnimationProperties.AnimationTagValue)" />
</MultiBinding>
</TranslateTransform.X>
</TranslateTransform>

<ControlTemplate x:Key="DefaultExpanderToggleButtonStyle" TargetType="{x:Type ToggleButton}">
<Grid Margin="{TemplateBinding Padding}" Background="Transparent">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter
x:Name="ContentPresenter"
Grid.Column="0"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
TextElement.FontSize="{TemplateBinding FontSize}" />
<Grid
x:Name="ChevronGrid"
Grid.Column="1"
Margin="0"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center"
Background="Transparent"
RenderTransformOrigin="0.5, 0.5">
Expand All @@ -47,10 +86,36 @@
x:Name="ControlChevronIcon"
FontSize="{StaticResource ExpanderChevronSize}"
Foreground="{TemplateBinding Foreground}"
Symbol="ChevronDown24" />
RenderTransformOrigin="0.5, 0.5"
Symbol="ChevronDown24">
<controls:SymbolIcon.RenderTransform>
<RotateTransform Angle="0" />
</controls:SymbolIcon.RenderTransform>
</controls:SymbolIcon>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Expander}, Path=ExpandDirection}" Value="Left">
<Setter TargetName="ControlChevronIcon" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="90" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Expander}, Path=ExpandDirection}" Value="Up">
<Setter TargetName="ControlChevronIcon" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Expander}, Path=ExpandDirection}" Value="Right">
<Setter TargetName="ControlChevronIcon" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="270" />
</Setter.Value>
</Setter>
</DataTrigger>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
Expand Down Expand Up @@ -100,20 +165,11 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<ControlTemplate.Resources>
<converters:AnimationFactorToValueConverter x:Key="AnimationFactorToValueConverter" />
</ControlTemplate.Resources>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel x:Name="DockPanel">

<!-- Top level controls always visible -->
<Border
x:Name="ToggleButtonBorder"
Grid.Row="0"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
Expand All @@ -136,7 +192,7 @@
</Border>

<!-- Collapsed content to expand -->
<Grid Grid.Row="1" ClipToBounds="True">
<Grid x:Name="ContentGrid" ClipToBounds="True">
<Border
x:Name="ContentPresenterBorder"
Background="{DynamicResource ExpanderContentBackground}"
Expand All @@ -150,23 +206,68 @@
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}" />
<Border.RenderTransform>
<TranslateTransform>
<TranslateTransform.Y>
<MultiBinding Converter="{StaticResource AnimationFactorToValueConverter}" ConverterParameter="negative">
<Binding ElementName="ContentPresenterBorder" Path="ActualHeight" />
<Binding ElementName="ContentPresenterBorder" Path="(animations:AnimationProperties.AnimationTagValue)" />
</MultiBinding>
</TranslateTransform.Y>
</TranslateTransform>
</Border.RenderTransform>
</Border>
</Grid>
</Grid>
</DockPanel>

<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Trigger Property="ExpandDirection" Value="Down">
<Setter TargetName="ContentGrid" Property="DockPanel.Dock" Value="Bottom" />
<Setter TargetName="ToggleButtonBorder" Property="DockPanel.Dock" Value="Top" />
<Setter TargetName="ContentPresenterBorder" Property="RenderTransform" Value="{StaticResource RollDownTransform}" />
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
<Setter TargetName="ContentGrid" Property="DockPanel.Dock" Value="Right" />
<Setter TargetName="ToggleButtonBorder" Property="DockPanel.Dock" Value="Left" />
<Setter TargetName="ContentPresenterBorder" Property="RenderTransform" Value="{StaticResource RollRightTransform}" />
</Trigger>
<Trigger Property="ExpandDirection" Value="Up">
<Setter TargetName="ContentGrid" Property="DockPanel.Dock" Value="Top" />
<Setter TargetName="ToggleButtonBorder" Property="DockPanel.Dock" Value="Bottom" />
<Setter TargetName="ContentPresenterBorder" Property="RenderTransform" Value="{StaticResource RollUpTransform}" />
</Trigger>
<Trigger Property="ExpandDirection" Value="Left">
<Setter TargetName="ContentGrid" Property="DockPanel.Dock" Value="Left" />
<Setter TargetName="ToggleButtonBorder" Property="DockPanel.Dock" Value="Right" />
<Setter TargetName="ContentPresenterBorder" Property="RenderTransform" Value="{StaticResource RollLeftTransform}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsExpanded" Value="True" />
<Condition Property="ExpandDirection" Value="Down" />
</MultiTrigger.Conditions>
<Setter TargetName="ToggleButtonBorder" Property="CornerRadius" Value="4,4,0,0" />
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="1,0,1,1" />
<Setter TargetName="ContentPresenterBorder" Property="CornerRadius" Value="0,0,4,4" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsExpanded" Value="True" />
<Condition Property="ExpandDirection" Value="Left" />
</MultiTrigger.Conditions>
<Setter TargetName="ToggleButtonBorder" Property="CornerRadius" Value="0,4,4,0" />
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="1,1,0,1" />
<Setter TargetName="ContentPresenterBorder" Property="CornerRadius" Value="4,0,0,4" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsExpanded" Value="True" />
<Condition Property="ExpandDirection" Value="Up" />
</MultiTrigger.Conditions>
<Setter TargetName="ToggleButtonBorder" Property="CornerRadius" Value="0,0,4,4" />
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="1,1,1,0" />
<Setter TargetName="ContentPresenterBorder" Property="CornerRadius" Value="4,4,0,0" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsExpanded" Value="True" />
<Condition Property="ExpandDirection" Value="Right" />
</MultiTrigger.Conditions>
<Setter TargetName="ToggleButtonBorder" Property="CornerRadius" Value="4,0,0,4" />
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="0,1,1,1" />
<Setter TargetName="ContentPresenterBorder" Property="CornerRadius" Value="0,4,4,0" />
</MultiTrigger>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
Expand Down
Loading