【问题标题】:Expander with animation that support all direction具有支持所有方向的动画的扩展器
【发布时间】:2016-03-16 09:17:20
【问题描述】:

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

我尝试了什么:我在this 的帮助下实施了一个解决方案。我对其进行了修改并根据我的需要使其工作。我的解决方案适用于Up,即使使用Down Direction,我也能使其工作。

我现在有什么问题:我无法让它适用于所有方向。我尝试将ExpanderDirection设置为LeftRight,但未能成功。

这是我的解决方案:

扩展器模板:

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

关于如何使它适用于所有方向或任何其他替代方案的任何建议?

【问题讨论】:

    标签: c# wpf xaml controltemplate expander


    【解决方案1】:

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

    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>
    

    代码未经过全面测试,可能存在错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      • 2014-11-27
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2019-07-18
      相关资源
      最近更新 更多