代码之家  ›  专栏  ›  技术社区  ›  Gopichandar

具有支持所有方向的动画的扩展器

  •  3
  • Gopichandar  · 技术社区  · 10 年前

    我的目标: 是创建一个带有动画的自定义展开器,并应支持所有方向。

    我尝试了什么: 我在的帮助下实施了一个解决方案 this 。我修改了它,并根据我的需要使其工作。我的解决方案将与 Up 我甚至可以让它工作 Down 方向

    我现在有什么问题 我不能让它在所有方向上都工作。我试过了,但没能在布景时发挥作用 ExpanderDirection Left 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>
    

    乘法转换器。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"

    关于如何使其与所有方向或任何其他替代方案一起工作的任何建议?

    1 回复  |  直到 10 年前
        1
  •  0
  •   Gopichandar    10 年前

    经过8个小时的挣扎,我找到了解决问题的方法。让我回答我自己的问题,这样可以为其他人寻找解决方案节省一些时间。

    扩展器控制模板:

        <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>
    

    乘法转换器。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>
    

    代码是 未完全测试 并且可能存在bug。