具有支持全方位动画的扩展器 [英] Expander with animation that support all direction
问题描述
我的目标:要在展开时使用动画创建自定义展开器,并且应该支持所有方向.
My Objective: is to create a Custom Expander with Animation on expanding and should support for all the directions.
我尝试过的事情:我已经在此.我对其进行了修改,并根据需要使其工作.我的解决方案可以与Up
一起使用,即使在Down
Direction上也可以使它工作.
What I tried: I have Implemented a solution with the help of this. I modified it and made it work based on my need. My solution will work with Up
and I can able to make it work even with Down
Direction.
我现在的问题是什么:我无法使其适用于所有方向.我尝试并无法使其在将ExpanderDirection
设置为Left
和Right
时起作用.
Whats my problem now: I couldn't make it work with all Directions. I tried and failed to make it work on setting ExpanderDirection
to Left
and Right
.
扩展器模板:
<ControlTemplate x:Key="AnimatedExpanderButtonTemp" TargetType="{x:Type ToggleButton}">
<Border x:Name="ExpanderButtonBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle Fill="Transparent"
Grid.ColumnSpan="2"/>
<Ellipse Name="Circle"
Grid.Column="0"
Stroke="DarkGray"
Width="20"
Height="20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
/>
<Path x:Name="Arrow"
Grid.Column="0"
Data="M 1,1.5 L 4.5,5 8,1.5"
Stroke="#FF666666"
StrokeThickness="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RenderTransformOrigin="0.5,0.5"
>
<Path.RenderTransform>
<RotateTransform Angle="0"/>
</Path.RenderTransform>
</Path>
<ContentPresenter x:Name="HeaderContent"
Grid.Column="1"
Margin="4,0,0,0"
ContentSource="Content"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!-- Animate arrow when toggled-->
<Trigger Property="IsChecked"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Arrow"
Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)"
To="180"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Arrow"
Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)"
To="0"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<!-- MouseOver, Pressed behaviours-->
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Stroke"
Value="#FF3C7FB1"
TargetName="Circle"/>
<Setter Property="Stroke"
Value="#222"
TargetName="Arrow"/>
</Trigger>
<Trigger Property="IsPressed"
Value="true">
<Setter Property="Stroke"
Value="#FF526C7B"
TargetName="Circle"/>
<Setter Property="StrokeThickness"
Value="1.5"
TargetName="Circle"/>
<Setter Property="Stroke"
Value="#FF003366"
TargetName="Arrow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Slide Out Content Expander's Template,
Uses: AnimatedExpanderButtonTemp from above,
MultiplyConverter in codebehind-->
<local:MultiplyConverter x:Key="multiplyConverter" />
<ControlTemplate x:Key="RevealExpanderTemp" TargetType="{x:Type Expander}">
<DockPanel>
<Border Background="{Binding Path=Background, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Stretch" DockPanel.Dock="Bottom" Padding="5,3">
<ToggleButton x:Name="ExpanderButton" HorizontalAlignment="Center" HorizontalContentAlignment="Center"
Template="{StaticResource AnimatedExpanderButtonTemp}"
Content="{TemplateBinding Header}"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True"
Padding="1.5,0">
</ToggleButton>
</Border>
<ScrollViewer x:Name="ExpanderContentScrollView" DockPanel.Dock="Top"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Bottom"
>
<ScrollViewer.Tag>
<sys:Double>0.0</sys:Double>
</ScrollViewer.Tag>
<ScrollViewer.Height>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</ScrollViewer.Height>
<ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
</ScrollViewer>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="1"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="0"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
MultiplyConverter.cs(模板所需)
public class MultiplyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double result = 1.0;
for (int i = 0; i < values.Length; i++)
{
if (values[i] is double)
result *= (double)values[i];
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new Exception("Not implemented");
}
}
像这样使用它:
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Orange">
<Expander Template="{StaticResource RevealExpanderTemp}"
OverridesDefaultStyle="True"
HorizontalAlignment="Left"
VerticalAlignment="Top" Background="LightGray">
<StackPanel>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
</StackPanel>
</Expander>
</Grid>
<Grid Grid.Row="2" Background="Chocolate" />
</Grid>
上述解决方案不适用于ExpandDirection="Left" or "Right"
Above solution will not work with ExpandDirection="Left" or "Right"
关于如何使它与所有方向或其他替代方法配合使用的任何建议?
Any suggestions on how could I make it work with all Directions or any other alternatives for this?
推荐答案
经过8个小时的努力,我找到了解决问题的方法.让我回答我自己的问题,以便为其他人寻找解决方案节省时间.
After 8 hours of struggle, I found the workaround for my question. Let me answer my own question so that It may save some time for other peoples looking for solution.
扩展器的控制模板:
<ControlTemplate x:Key="AnimatedExpanderButtonTemp" TargetType="{x:Type ToggleButton}">
<Border x:Name="ExpanderArrow" CornerRadius="5"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle Fill="Transparent"
Grid.ColumnSpan="2"/>
<Ellipse Name="Circle"
Grid.Column="0"
Stroke="DarkGray"
Width="20"
Height="20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
/>
<Path x:Name="Arrow"
Grid.Column="0"
Data="M 0 0 L 3,6 L 6,0"
Stroke="#FF666666"
StrokeThickness="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RenderTransformOrigin="0.5,0.5"
>
<Path.RenderTransform>
<RotateTransform Angle="0"/>
</Path.RenderTransform>
</Path>
<ContentPresenter x:Name="HeaderContent"
Margin="4,0,0,0"
ContentSource="Content"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="DockPanel.Dock"
Value="Right">
<Setter Property="Data" TargetName="Arrow" Value="M 0 0 L 3 3 L 0 6 "/>
</Trigger>
<Trigger Property="DockPanel.Dock"
Value="Left">
<Setter Property="Data" TargetName="Arrow" Value="M 0 0 L 3 3 L 0 6"/>
</Trigger>
<Trigger Property="DockPanel.Dock"
Value="Top">
<Setter Property="Data" TargetName="Arrow" Value="M 0 0 L 3,6 L 6,0"/>
</Trigger>
<!-- Animate arrow when toggled-->
<Trigger Property="IsChecked"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Arrow"
Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)"
To="180"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Arrow"
Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)"
To="0"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<!-- MouseOver, Pressed behaviours-->
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Stroke"
Value="#FF3C7FB1"
TargetName="Circle"/>
<Setter Property="Stroke"
Value="#222"
TargetName="Arrow"/>
</Trigger>
<Trigger Property="IsPressed"
Value="true">
<Setter Property="Stroke"
Value="#FF526C7B"
TargetName="Circle"/>
<Setter Property="StrokeThickness"
Value="1.5"
TargetName="Circle"/>
<Setter Property="Stroke"
Value="#FF003366"
TargetName="Arrow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Slide Out Content Expander's Template,
Uses: AnimatedExpanderButtonTemp from above,
MultiplyConverter in codebehind-->
<local:MultiplyConverter x:Key="multiplyConverter" />
<ControlTemplate x:Key="RevealExpanderTemp" TargetType="{x:Type Expander}">
<DockPanel>
<!--<Border x:Name="ExpanderButtonBorder" Background="{Binding Path=Background, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Stretch" DockPanel.Dock="Bottom" Padding="5,3">-->
<ToggleButton x:Name="ExpanderButton" HorizontalAlignment="Stretch" DockPanel.Dock="Bottom"
Template="{StaticResource AnimatedExpanderButtonTemp}"
Content="{TemplateBinding Header}"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
Background="{Binding Path=Background, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True"
Padding="0">
</ToggleButton>
<!--</Border>-->
<ScrollViewer x:Name="ExpanderContentScrollView" DockPanel.Dock="Top"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Bottom"
>
<ScrollViewer.Tag>
<sys:Double>0.0</sys:Double>
</ScrollViewer.Tag>
<ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
</ScrollViewer>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="ExpandDirection" Value="Right">
<Setter Property="DockPanel.Dock" TargetName="ExpanderButton" Value="Right"/>
<Setter Property="DockPanel.Dock" TargetName="ExpanderContentScrollView" Value="Left"/>
<Setter Property="Width" TargetName="ExpanderContentScrollView">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualWidth" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Up">
<Setter Property="DockPanel.Dock" TargetName="ExpanderButton" Value="Top"/>
<Setter Property="DockPanel.Dock" TargetName="ExpanderContentScrollView" Value="Bottom"/>
<Setter Property="Height" TargetName="ExpanderContentScrollView">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Left">
<Setter Property="DockPanel.Dock" TargetName="ExpanderButton" Value="Left"/>
<Setter Property="DockPanel.Dock" TargetName="ExpanderContentScrollView" Value="Right"/>
<Setter Property="Width" TargetName="ExpanderContentScrollView">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualWidth" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Down">
<Setter Property="Height" TargetName="ExpanderContentScrollView">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="1"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="0"
Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
MultiplyConverter.cs(模板所需)
public class MultiplyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double result = 1.0;
for (int i = 0; i < values.Length; i++)
{
if (values[i] is double)
result *= (double)values[i];
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new Exception("Not implemented");
}
}
演示:
<!-- Small demo of Expander Template above-->
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Orange">
<Expander Template="{StaticResource RevealExpanderTemp}" ExpandDirection="Right"
OverridesDefaultStyle="True"
HorizontalAlignment="Left"
VerticalAlignment="Top" Background="LightGray">
<StackPanel>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
<TextBlock Text="This is Sample Text for Expander" Margin="5"/>
</StackPanel>
</Expander>
</Grid>
<Grid Grid.Row="2" Background="Chocolate" />
</Grid>
该代码未经过完整测试,并且可能存在错误.
The code was not tested fully and there may be bugs.
这篇关于具有支持全方位动画的扩展器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!