C# XAML Button Animation

-Rayz-

Lieutenant
Registriert
Okt. 2010
Beiträge
901
Hallo,

ich versuche gerade meine Buttons zu animieren und zwar nicht so ruckartig sondern mit einem Fade Effekt und zwar im Scaling.
Über die ControlTemplate.Trigger und dem entsprechenden Event klappt das schon wenn ich meine Defaultwerte einfach in Höhe und Breite ändere aber das ist nicht ganz was ich möchte. Da fehlt ja komplett der Fade Effekt.

Nun habe ich mir um den Button ein Canvas gemacht und im Code sieht es nun so aus:

C#:
 private void On_Hover(object sender, MouseEventArgs e)
        {
            Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(ScaleTransform.ScaleXProperty));
            Storyboard.SetTarget(widthAnimation, (sender as Canvas));

            Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(ScaleTransform.ScaleYProperty));
            Storyboard.SetTarget(heightAnimation, (sender as Canvas));

            Storyboard s = new Storyboard();
            s.Children.Add(widthAnimation);
            s.Children.Add(heightAnimation);
            s.Begin();
        
 }


        DoubleAnimation widthAnimation = new DoubleAnimation
        {
            From = 1,
            To = 1.2,
            Duration = TimeSpan.FromSeconds(1)
        };

        DoubleAnimation heightAnimation = new DoubleAnimation
        {
            From = 1,
            To = 1.2,
            Duration = TimeSpan.FromSeconds(1)
        };

XML:
 <StackPanel Grid.Column="1" Grid.Row="2" Height="100">
            <Canvas MouseEnter="On_Hover" MouseLeave="On_Leave" Name="Test" Width="60" Height="60" Background="Aqua">
                <Button x:Name="First" Template="{DynamicResource FirstBtn}"/>
            </Canvas>
        </StackPanel>

Ich bekomme hier aber keine Änderungen hin... für Opacity würde das funktionieren aber für die Höhe/Breite.. komm ich leider nicht weiter. Auch weiß ich gar nicht, wenn ich ein Scale aufs Canvas mache, ich den Button damit überhaupt vergrößern kann.
 
Wenn ich das richtig verstehe wird deine Animation gerade nicht abgespielt oder?
(Bin leider kein Experte in C# und XAML, aber versuche mit meinen Erfahrungen soweit es geht zu helfen)
Also wenn das Canvas um den Button nur für den Animationseffekt ist, solltest du den weglassen können.
Das was deinem Button fehlt bzw. in der Animation als falsches Target gesetzt sein sollte, sind die Scale Properties.
Probier mal dem Button ein RenderTransform hinzuzufügen (ich lasse das Canvas einfach mal mit drinnen, sollte nichts negativ beeinflussen):
XML:
 <StackPanel Grid.Column="1" Grid.Row="2" Height="100">
     <Canvas MouseEnter="On_Hover" MouseLeave="On_Leave" Name="Test" Width="60" Height="60" Background="Aqua">
         <Button x:Name="First" Template="{DynamicResource FirstBtn}">
             <Button.RenderTransform>
                 <TransformGroup>
                     <ScaleTransform x:Name="ButtonScaleTransform"/>
                 </TransformGroup>
             </Button.RenderTransform>
         </Button>
     </Canvas>
</StackPanel>
Und ziele dann im Hover Code stattdessen auf dieses Transform, statt auf das Canvas.
Theoretisch kannst du natürlich auch das ganze Canvas vergrößern statt den Button.
C#:
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(ScaleTransform.ScaleXProperty));
Storyboard.SetTarget(widthAnimation, ButtonScaleTransform);
Ich kann das gerade nicht selbst austesten, aber in diese Richtung sollte es eigentlich funktionieren.
 
Also irgendwie bekomm ich das im Code Behind nicht hin.... leider

So funktioniert es aber nun:

XML:
<UserControl.Resources>
        <ImageBrush x:Key="firstBtn" ImageSource="/Resources/first_arrow.png" Stretch="Fill" />
        <ImageBrush x:Key="lastBtn" ImageSource="/Resources/last_arrow.png" Stretch="Fill" />
        <ControlTemplate x:Key="HoverButton" TargetType="Button">
            <Border x:Name="render">
                <Border.RenderTransform>
                    <ScaleTransform ScaleX="1.0" ScaleY="1.0"></ScaleTransform>
                </Border.RenderTransform>
                <ContentPresenter Height="80" Width="80" />
            </Border>
            <ControlTemplate.Triggers>
                <EventTrigger RoutedEvent="Mouse.MouseEnter">
                    <BeginStoryboard>
                        <Storyboard TargetProperty="RenderTransform.ScaleX">
                            <DoubleAnimation From="1" To="1.2" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                    <BeginStoryboard>
                        <Storyboard TargetProperty="RenderTransform.ScaleY">
                            <DoubleAnimation From="1" To="1.2" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
                <EventTrigger RoutedEvent="Mouse.MouseLeave">
                    <BeginStoryboard>
                        <Storyboard TargetProperty="RenderTransform.ScaleX">
                            <DoubleAnimation From="1.2" To="1" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                    <BeginStoryboard>
                        <Storyboard TargetProperty="RenderTransform.ScaleY">
                            <DoubleAnimation From="1.2" To="1" Duration="0:0:0.2" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </UserControl.Resources>

<Button Template="{StaticResource HoverButton}" x:Name="Last" Margin="20 0 0 0">
     <Image Source="/Resources/last_arrow.png"></Image>
     <Button.RenderTransform>
         <ScaleTransform ScaleX="1.0" ScaleY="1.0"></ScaleTransform>
     </Button.RenderTransform>
</Button>

Hätte es aber dennoch lieber in der .cs Datei aber da will es einfach nicht triggern.
 
Wenn du deinem Button wieder die Events MouseEnter und MouseLeave hinzufügst, hast du mit Code Behind 2 Möglichkeiten:
Zuerst die kompakte:
C#:
private void Last_MouseEnter(object sender, MouseEventArgs e)
{
    var animation = new DoubleAnimation() { To = 1.2, Duration = new Duration(TimeSpan.FromSeconds(1)) };
    Last.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
    Last.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
}

private void Last_MouseLeave(object sender, MouseEventArgs e)
{
    var animation = new DoubleAnimation() { To = 1, Duration = new Duration(TimeSpan.FromSeconds(1)) };
    Last.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
    Last.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
}
Oder wieder mit einem Storyboard (hier nur für Enter, ist sonst unnötig viel):
C#:
private void Last_MouseEnter(object sender, MouseEventArgs e)
{
    Storyboard storyboard = new Storyboard();
    DoubleAnimation widthAnimation = new DoubleAnimation() { To = 1.2, Duration = new Duration(TimeSpan.FromSeconds(1)) };
    DoubleAnimation heightAnimation = new DoubleAnimation() { To = 1.2, Duration = new Duration(TimeSpan.FromSeconds(1)) };
    Storyboard.SetTargetProperty(widthAnimation, new PropertyPath("RenderTransform.ScaleX"));
    Storyboard.SetTarget(widthAnimation, Last);
    storyboard.Children.Add(widthAnimation);
    Storyboard.SetTargetProperty(heightAnimation, new PropertyPath("RenderTransform.ScaleY"));
    Storyboard.SetTarget(heightAnimation, Last);
    storyboard.Children.Add(heightAnimation);
    storyboard.Begin();
}
Unabhängig davon würde ich empfehlen, den "From" Wert nicht zu setzen, da dann einfach der aktuelle Wert benutzt wird. Das heißt die Animation wird bei Enter/Leave nicht komisch rumzucken, sondern sollten immer smooth sein (hier bin ich mir aber nicht ganz sicher ob das für alle Fälle gilt).
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: -Rayz-
Die erste Variante gefällt mir da doch deutlich besser und funktioniert auch :-)
Hab nur ein paar Änderungen gemacht damit jeder Button das Event Aufrufen kann.
C#:
private void OnMouseEnter(object sender, MouseEventArgs e)
{
    var btn = (sender as Button);
    var animation = new DoubleAnimation() { To = 1.2, Duration = new Duration(TimeSpan.FromSeconds(1)) };
    btn.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
    btn.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
}

private void OnMouseLeave(object sender, MouseEventArgs e)
{
    var btn = (sender as Button);
    var animation = new DoubleAnimation() { To = 1, Duration = new Duration(TimeSpan.FromSeconds(1)) };
    btn.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
    btn.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
}

Beim Hover ist ja auch noch die Default Color vom Button hinterlegt. Das musste ich noch ändern:

XML:
<Button x:Name="Last" Margin="20 0 0 0" Background="{StaticResource lastBtn}"
          Style="{StaticResource HoverStyle}"
          Width="80" Height="80" MouseEnter="OnMouseEnter" MouseLeave="OnMouseLeave">
      <Button.RenderTransform>
          <ScaleTransform ScaleX="1.0" ScaleY="1.0"></ScaleTransform>
      </Button.RenderTransform>
</Button>

<Style x:Key="HoverStyle" TargetType="Button">
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid Background="{TemplateBinding Background}">
                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Schön das Code Behind nun auch klappt. :daumen: Danke dir
 
Zurück
Oben