11
\$\begingroup\$

After spending a few ages writing out every combination of triggers, bindings and storyboards, I finally managed to get my program working. First time working with WPF, so I made a big mess. Now it's time to put on my refactoring hat and make the code neat and proper again!

That is, if I knew how. Could anyone experienced with WPF or XAML files help me out here and explain how to unmess this code? Suggesting a change of design is fine too, though like I said, this is the only way that I managed to actually get it working.

What the code is supposed to do, is dynamically be able to change sprite animations (by binding a .gif source to an Image), and dynamically "move around" the sprite on a preset animation, different animations depending on what happens in the rest of the code. Like, up and down, or in a circle, or to the corner of the screen and back. Etcetera.

I only copied three storyboards with small changes each per sprite in here for brevity, I suppose you can see what happens when I extend them even further..

<Window x:Class="Simplively.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:gif="clr-namespace:WpfAnimatedGif"
    gif:ImageBehavior.AnimateInDesignMode="True"
    Title="MainWindow"
    Background="Cyan" Margin="0" SizeToContent="WidthAndHeight">
<Grid Width="1280" Height="720">
    <Image Source="Overlay.png" Stretch="Fill" Width="1280" Height="720"/>
    <Image Name="p1Sprite" gif:ImageBehavior.AnimatedSource="{Binding PlayerOneSprite}" gif:ImageBehavior.RepeatBehavior="Forever" HorizontalAlignment="Left" Height="47" Margin="239,191,0,0" VerticalAlignment="Top" Width="47" Source="Sprites/Bard.gif" RenderTransformOrigin="1,1">
        <Image.RenderTransform>
            <TransformGroup>
                <ScaleTransform x:Name="p1Scale" ScaleY="1" ScaleX="1"/>
                <SkewTransform x:Name="p1Skew" AngleY="0" AngleX="0"/>
                <RotateTransform x:Name="p1Rotate" Angle="0"/>
                <TranslateTransform x:Name="p1Translate" X="0" Y="0"/>
            </TransformGroup>
        </Image.RenderTransform>
        <Image.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p1leftright">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p1updown">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p1ToCorner">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Image.Style>
    </Image>
    <Image Name="p2Sprite" gif:ImageBehavior.AnimatedSource="{Binding PlayerTwoSprite}" gif:ImageBehavior.RepeatBehavior="Forever" HorizontalAlignment="Left" Height="47" Margin="239,344,0,0" VerticalAlignment="Top" Width="47" Source="Sprites/Bard.gif">
        <Image.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p2leftright">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p2updown">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-64"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p2ToCorner">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-64"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Image.Style>
    </Image>
    <Image Name="p3Sprite" gif:ImageBehavior.AnimatedSource="{Binding PlayerThreeSprite}" gif:ImageBehavior.RepeatBehavior="Forever" HorizontalAlignment="Left" Height="47" Margin="239,396,0,0" VerticalAlignment="Top" Width="47" Source="Sprites/Bard.gif">
            <Image.Style>
                <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p3leftright">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p3updown">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-96"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p3ToCorner">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-96"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
            </Image.Style>
        </Image>
        <Image Name="p4Sprite" gif:ImageBehavior.AnimatedSource="{Binding PlayerFourSprite}" gif:ImageBehavior.RepeatBehavior="Forever" HorizontalAlignment="Left" Height="47" Margin="239,448,0,0" VerticalAlignment="Top" Width="47" Source="Sprites/Bard.gif">
                <Image.Style>
                    <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p4leftright">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p4updown">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-128"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding StartAnimation}" Value="p4ToCorner">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                        From="0"
                                        To="-32"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                    <DoubleAnimation
                                        Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
                                        From="0"
                                        To="-128"
                                        Duration="0:0:0.2"
                                        RepeatBehavior="1x"
                                        AutoReverse="True"
                                        />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
                </Image.Style>
            </Image>
            <Image HorizontalAlignment="Left" Height="152" Margin="10,10,0,0" VerticalAlignment="Top" Width="152" Source="Ffiigreendragon_psp.png"/>
    <TextBlock HorizontalAlignment="Left" Height="47" Margin="26,191,0,0" TextWrapping="Wrap" Text="{Binding PlayerOneName}" VerticalAlignment="Top" Width="175"/>
</Grid>

\$\endgroup\$

1 Answer 1

6
\$\begingroup\$

Your markup is inlining the styles, which has the effect of producing extremely redundant markup - as you've noticed.

You can define the resources of a window in its Resources property - step one would be to extract your inline styles into the Window tag:

<Window.Resources>
    <Style x:Key="MyStyle1" TargetType="{x:Type Image}">
      ...
    </Style>
    <Style x:Key="MyStyle2" TargetType="{x:Type Image}">
      ...
    </Style>
</Window.Resources>

Then, you can refer to these styles with a StaticResource markup extension:

<Image Style="{StaticResource MyStyle1}">
    ...
</Image>

Depending on exactly what the "small value changes" are, you'll want to create a new Style, or put a BasedOn attribute to specify a Style to "derive" from another. An individual element can always override any value determined by its Style.

Once you've extracted the styles into the window's resources, you might want to move them to a ResourceDictionary so you can reuse the same styles in other windows, without having to redefine them over again.

\$\endgroup\$
3
  • \$\begingroup\$ Hmn, I think the biggest issue is that decide which of the four sprite's animation to activate, I need all kinds of variables like 'p1transform', 'p2transform', 'p3transform' etc.etc. for all the different things there are to animate. Is there a way to group the styles and still call on them with different names? Like.. only define "transform" once, and then do something like "p1.transform", "p2.transform", etc? \$\endgroup\$
    – Taelia
    Mar 9, 2014 at 0:27
  • 1
    \$\begingroup\$ that could have been clearer if you had included the entire markup. \$\endgroup\$ Mar 9, 2014 at 0:30
  • \$\begingroup\$ Ah, I apologize. Edited with the full thing in. \$\endgroup\$
    – Taelia
    Mar 9, 2014 at 0:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.