<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Silverlight &#124; WPF &#124; Microsoft.Net &#187; 3D Flip</title>
	<atom:link href="http://joel.neubeck.net/tag/3d-flip/feed/" rel="self" type="application/rss+xml" />
	<link>http://joel.neubeck.net</link>
	<description>Simplifing structure without changing results</description>
	<lastBuildDate>Fri, 01 Apr 2011 21:34:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Silverlight 3 Flip TargetedTriggerAction</title>
		<link>http://joel.neubeck.net/2009/08/silverlight-3-flip-targetedtriggeraction/</link>
		<comments>http://joel.neubeck.net/2009/08/silverlight-3-flip-targetedtriggeraction/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 22:36:41 +0000</pubDate>
		<dc:creator>joel</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[3D Flip]]></category>
		<category><![CDATA[Silverlight 3]]></category>
		<category><![CDATA[TargetedTriggerAction]]></category>

		<guid isPermaLink="false">http://joel.neubeck.net/?p=421</guid>
		<description><![CDATA[Last week I created a Trigger Action which flipped a panel. It was intended to be invoked from clicking on the panel directly. Earlier today I was asked if you could invoke this trigger from multiple places. The answer is no, but it is very easily to rewrite this trigger to achieve this behavior. In [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I created a Trigger Action which flipped a panel.  It was intended to be invoked from clicking on the panel directly.  Earlier today I was asked if you could invoke this trigger from multiple places.  The answer is no, but it is very easily to rewrite this trigger to achieve this behavior.  In this blog post I am going to create a TargetedTriggerAction which allows me to add the trigger to a button or multiple UIElement and &#8220;Target&#8221; a panel to be flipped.  What is really cool about this approach is that each button can contain the logic used to flip the panel (Storyboard direction, duration, etc).</p>
<p> The following is the code I used to create my Flip TargetedTriggerAction.</p>

<div class="wp_syntax"><div class="code"><pre class="c-sharp" style="font-family:monospace;">using System.ComponentModel;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
&nbsp;
namespace FlipTargetedTrigger
{
    public enum RotationDirection
    {
        LeftToRight,
        RightToLeft,
        TopToBottom,
        BottomToTop
    }
&nbsp;
    public class Flip : TargetedTriggerAction&lt;FrameworkElement&gt;
    {
        public static readonly DependencyProperty FrontElementNameProperty =
            DependencyProperty.Register(&quot;FrontElementName&quot;, typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
&nbsp;
        [Category(&quot;Flip Properties&quot;)]
        public string FrontElementName
        {
            get
            {
                return (string)GetValue(FrontElementNameProperty);
            }
            set
            {
                SetValue(FrontElementNameProperty, value);
            }
        }
&nbsp;
        public static readonly DependencyProperty BackElementNameProperty =
            DependencyProperty.Register(&quot;BackElementName&quot;, typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
&nbsp;
        [Category(&quot;Flip Properties&quot;)]
        public string BackElementName
        {
            get
            {
                return (string)GetValue(BackElementNameProperty);
            }
            set
            {
                SetValue(BackElementNameProperty, value);
            }
        }
&nbsp;
        public static readonly DependencyProperty DurationProperty =
            DependencyProperty.Register(&quot;Duration&quot;, typeof(Duration),
                                        typeof(Flip), new PropertyMetadata(null));
&nbsp;
        [Category(&quot;Animation Properties&quot;)]
        public Duration Duration
        {
            get
            {
                return (Duration)GetValue(DurationProperty);
            }
            set
            {
                SetValue(DurationProperty, value);
            }
        }
&nbsp;
        public static readonly DependencyProperty RotationProperty =
            DependencyProperty.Register(&quot;Rotation&quot;, typeof(RotationDirection),
                                        typeof(Flip), new PropertyMetadata(RotationDirection.LeftToRight));
&nbsp;
        [Category(&quot;Animation Properties&quot;)]
        public RotationDirection Rotation
        {
            get
            {
                return (RotationDirection)GetValue(RotationProperty);
            }
            set
            {
                SetValue(RotationProperty, value);
            }
        }
&nbsp;
        public static readonly DependencyProperty FrontStoryboardProperty =
            DependencyProperty.Register(&quot;FrontStoryboard&quot;, typeof(Storyboard), typeof(Flip), null);
&nbsp;
        public Storyboard FrontStoryBoard
        {
            get
            {
                return (Storyboard)GetValue(FrontStoryboardProperty);
            }
        }
        public static readonly DependencyProperty BackStoryboardProperty =
            DependencyProperty.Register(&quot;BackStoryboard&quot;, typeof(Storyboard), typeof(Flip), null);
&nbsp;
        public Storyboard BackStoryboard
        {
            get
            {
                return (Storyboard)GetValue(BackStoryboardProperty);
            }
        }
&nbsp;
        private bool _forward = true;
&nbsp;
        protected override void OnAttached()
        {
            base.OnAttached();
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            if (element != null) element.Loaded += TargetLoaded;
        }
&nbsp;
        void TargetLoaded(object sender, RoutedEventArgs e)
        {
            PlaneProjection pp = Target.Projection as PlaneProjection;
            if (Target.Projection == null)
            {
                pp = new PlaneProjection { CenterOfRotationY = .51 };
&nbsp;
                Target.RenderTransformOrigin = new Point(.5, .5);
                Target.Projection = pp;
            }
&nbsp;
            Storyboard sbF = new Storyboard();
            Storyboard sbB = new Storyboard();
&nbsp;
            UIElement f = null;
            UIElement b = null;
&nbsp;
            f = Target.FindName(FrontElementName) as UIElement;
            if (f != null)
            {
                PlaneProjection ppFront = new PlaneProjection { CenterOfRotationY = .51 };
                f.Projection = ppFront;
                f.RenderTransformOrigin = new Point(.5, .5);
            }
            b = Target.FindName(BackElementName) as UIElement;
            if (b != null)
            {
                PlaneProjection ppBack = new PlaneProjection { CenterOfRotationY = .51, RotationY = 180.0 };
                b.Projection = ppBack;
                b.RenderTransformOrigin = new Point(.5, .5);
                b.Opacity = 0.0;
            }
&nbsp;
&nbsp;
            double to = 0.0;
            double from = 180.0;
            string property = &quot;RotationY&quot;;
&nbsp;
            switch (Rotation)
            {
                case RotationDirection.RightToLeft:
                    to = 180.0;
                    from = 0.0;
                    break;
                case RotationDirection.TopToBottom:
                    property = &quot;RotationX&quot;;
                    break;
                case RotationDirection.BottomToTop:
                    to = 0.0;
                    from = 180.0;
                    property = &quot;RotationX&quot;;
                    break;
            }
&nbsp;
            sbF.Duration = Duration;
            sbB.Duration = Duration;
&nbsp;
            sbF.Children.Add(CreateDoubleAnimation(pp, property, from, to, true));
            sbB.Children.Add(CreateDoubleAnimation(pp, property, to, from, true));
&nbsp;
            sbF.Children.Add(CreateDoubleAnimation(f, &quot;Opacity&quot;, 1.0, 0.0, false));
            sbB.Children.Add(CreateDoubleAnimation(f, &quot;Opacity&quot;, 0.0, 1.0, false));
&nbsp;
            sbF.Children.Add(CreateDoubleAnimation(b, &quot;Opacity&quot;, 0.0, 1.0, false));
            sbB.Children.Add(CreateDoubleAnimation(b, &quot;Opacity&quot;, 1.0, 0.0, false));
&nbsp;
            SetValue(FrontStoryboardProperty, sbF);
            SetValue(BackStoryboardProperty, sbB);
&nbsp;
&nbsp;
        }
&nbsp;
        protected override void Invoke(object parameter)
        {
            Storyboard sbF = GetValue(FrontStoryboardProperty) as Storyboard;
            Storyboard sbB = GetValue(BackStoryboardProperty) as Storyboard;
&nbsp;
            if (_forward)
            {
                sbF.Begin();
                _forward = false;
            }
            else
            {
                sbB.Begin();
                _forward = true;
            }
        }
&nbsp;
        private static DoubleAnimation CreateDoubleAnimation(DependencyObject element, string property, double from,
                                                             double to, bool addEasing)
        {
            DoubleAnimation da = new DoubleAnimation();
            da.To = to;
            da.From = from;
            if (addEasing)
                da.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 };
&nbsp;
            Storyboard.SetTargetProperty(da, new PropertyPath(property));
            Storyboard.SetTarget(da, element);
            return da;
        }
    }
}</pre></div></div>

<p>For the most part the code is very simmiler to the other trigger.  When you inherate from TargetTriggerAction you gain access to a new property called &#8220;Target&#8221; this will contain a reference to the UIELement I plan on flipping.  Instead of adding my PlainProjection to the AssociatedObject I instead add it to the target.  I made a few other changes like storing my Storyboards as dependency properties which allow me to reuse the same animiation each time I lick the button.  These DependencyProperites get stored in the AssociatedObject and not the Target.  This allows each item being clicked to have a unique animation.  Below is how I implement the TargetTriggerAction.</p>

<div class="wp_syntax"><div class="code"><pre class="c-sharp" style="font-family:monospace;">&lt;StackPanel Orientation=&quot;Vertical&quot;&gt;
    &lt;Grid Margin=&quot;10&quot; x:Name=&quot;flipMe&quot;&gt;
        &lt;StackPanel x:Name=&quot;back1&quot; Height=&quot;200&quot; Width=&quot;200&quot; HorizontalAlignment=&quot;Center&quot; 
                    VerticalAlignment=&quot;Center&quot;&gt;
            &lt;Rectangle Fill=&quot;Green&quot; Height=&quot;200&quot; Width=&quot;200&quot; StrokeThickness=&quot;1&quot; Stroke=&quot;Black&quot; /&gt;
        &lt;/StackPanel&gt;
        &lt;Rectangle x:Name=&quot;front1&quot; Fill=&quot;Gold&quot; Height=&quot;200&quot; Width=&quot;200&quot; 
                   HorizontalAlignment=&quot;Center&quot; VerticalAlignment=&quot;Center&quot;/&gt;
    &lt;/Grid&gt;
    &lt;Button Content=&quot;Flip RightToLeft&quot; Width=&quot;100&quot;&gt;
        &lt;i:Interaction.Triggers&gt;
            &lt;i:EventTrigger EventName=&quot;Click&quot;&gt;
                &lt;targeted:Flip FrontElementName=&quot;front1&quot; BackElementName=&quot;back1&quot; 
                               TargetName=&quot;flipMe&quot; Duration=&quot;00:00:1&quot; Rotation=&quot;RightToLeft&quot;/&gt;
            &lt;/i:EventTrigger&gt;
        &lt;/i:Interaction.Triggers&gt;
    &lt;/Button&gt;
    &lt;Button Content=&quot;Flip TopToBtoom&quot; Width=&quot;100&quot;&gt;
        &lt;i:Interaction.Triggers&gt;
            &lt;i:EventTrigger EventName=&quot;Click&quot;&gt;
                &lt;targeted:Flip FrontElementName=&quot;front1&quot; BackElementName=&quot;back1&quot; 
                               TargetName=&quot;flipMe&quot; Duration=&quot;00:00:1&quot; Rotation=&quot;TopToBottom&quot;/&gt;
            &lt;/i:EventTrigger&gt;
        &lt;/i:Interaction.Triggers&gt;
    &lt;/Button&gt;
&lt;/StackPanel&gt;</pre></div></div>

<p><br style="clear:both"/><br />
<iframe src="/wp-content/uploads/2009/08/FlipTargetedTrigger/" width="500" height="300"></iframe><br />
Code: <a onclick="javascript: pageTracker._trackPageview('/code/FlipTargetedTrigger.zip'); " href="/wp-content/uploads/2009/08/FlipTargetedTrigger/FlipTargetedTrigger.zip">FlipTargetedTrigger.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://joel.neubeck.net/2009/08/silverlight-3-flip-targetedtriggeraction/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Silverlight 3 Flip TriggerAction</title>
		<link>http://joel.neubeck.net/2009/07/silverlight-3-flip-triggeraction/</link>
		<comments>http://joel.neubeck.net/2009/07/silverlight-3-flip-triggeraction/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 18:26:23 +0000</pubDate>
		<dc:creator>joel</dc:creator>
				<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[3D Flip]]></category>
		<category><![CDATA[Silverlight 3]]></category>
		<category><![CDATA[System.Windows.Interactivity]]></category>
		<category><![CDATA[TiggerAction]]></category>

		<guid isPermaLink="false">http://joel.neubeck.net/?p=417</guid>
		<description><![CDATA[In this blog post I am going to create a TriggerAction which makes it incredibly simple to take two UIElements and compose them into a panel which can be flipped. I have demonstrated the technique many times, but here it is all packaged up in a nice reusable class. The following is the code I [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://joel.neubeck.net/wp-content/uploads/2009/07/flip1.PNG"><img src="http://joel.neubeck.net/wp-content/uploads/2009/07/flip1-300x154.PNG" alt="flip1" title="flip1" width="300" height="154" class="alignleft size-medium wp-image-418" /></a>In this blog post I am going to create a TriggerAction which makes it incredibly simple to take two UIElements and compose them into a panel which can be flipped.  I have demonstrated the technique many times, but here it is all packaged up in a nice reusable class.</p>
<p> The following is the code I used to create by Flip TriggerAction.</p>

<div class="wp_syntax"><div class="code"><pre class="c-sharp" style="font-family:monospace;">using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Interactivity;
using System.ComponentModel;
&nbsp;
namespace FlipTriggerAction
{
    public enum RotationDirection
    {
        LeftToRight,
        RightToLeft,
        TopToBottom,
        BottomToTop
    }
&nbsp;
    public class Flip : TriggerAction&lt;FrameworkElement&gt;
    {
        public static readonly DependencyProperty FrontElementNameProperty =
            DependencyProperty.Register(&quot;FrontElementName&quot;, typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
&nbsp;
        [Category(&quot;Flip Properties&quot;)]
        public string FrontElementName { get; set; }
&nbsp;
        public static readonly DependencyProperty BackElementNameProperty =
            DependencyProperty.Register(&quot;BackElementName&quot;, typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
&nbsp;
        [Category(&quot;Flip Properties&quot;)]
        public string BackElementName { get; set; }
&nbsp;
        public static readonly DependencyProperty DurationProperty =
            DependencyProperty.Register(&quot;Duration&quot;, typeof(Duration),
                                        typeof(Flip), new PropertyMetadata(null));
&nbsp;
        [Category(&quot;Animation Properties&quot;)]
        public Duration Duration { get; set; }
&nbsp;
        public static readonly DependencyProperty RotationProperty =
            DependencyProperty.Register(&quot;Rotation&quot;, typeof(RotationDirection),
                                        typeof(Flip), new PropertyMetadata(RotationDirection.LeftToRight));
&nbsp;
        [Category(&quot;Animation Properties&quot;)]
        public RotationDirection Rotation { get; set; }
&nbsp;
        private readonly Storyboard _sbF = new Storyboard();
        private readonly Storyboard _sbB = new Storyboard();
        private bool _forward = true;
&nbsp;
        protected override void Invoke(object parameter)
        {
            if (AssociatedObject.Projection == null)
            {
                FrameworkElement parent = AssociatedObject as FrameworkElement;
                UIElement f = null;
                UIElement b = null;
&nbsp;
                if (parent != null)
                {
                    f = parent.FindName(FrontElementName) as UIElement;
                    if (f != null)
                    {
                        PlaneProjection ppFront = new PlaneProjection { CenterOfRotationY = .51 };
                        f.Projection = ppFront;
                        f.RenderTransformOrigin = new Point(.5, .5);
                    }
                    b = parent.FindName(BackElementName) as UIElement;
                    if (b != null)
                    {
                        PlaneProjection ppBack = new PlaneProjection { CenterOfRotationY = .51, RotationY = 180.0 };
                        b.Projection = ppBack;
                        b.RenderTransformOrigin = new Point(.5, .5);
                        b.Opacity = 0.0;
                    }
                }
&nbsp;
                PlaneProjection pp = new PlaneProjection { CenterOfRotationY = .51 };
&nbsp;
                AssociatedObject.RenderTransformOrigin = new Point(.5, .5);
                AssociatedObject.Projection = pp;
&nbsp;
                double to = 180.0;
                double from = 0.0;
                string property = &quot;RotationY&quot;;
&nbsp;
                switch (Rotation)
                {
                    case RotationDirection.RightToLeft:
                        to = 0.0;
                        from = 180.0;
                        break;
                    case RotationDirection.TopToBottom:
                        property = &quot;RotationX&quot;;
                        break;
                    case RotationDirection.BottomToTop:
                        to = 0.0;
                        from = 180.0;
                        property = &quot;RotationX&quot;;
                        break;
                }
&nbsp;
                _sbF.Duration = Duration;
                _sbB.Duration = Duration;
&nbsp;
                _sbF.Children.Add(CreateDoubleAnimation(pp, property, from, to, true));
                _sbB.Children.Add(CreateDoubleAnimation(pp, property, to, from, true));
&nbsp;
                _sbF.Children.Add(CreateDoubleAnimation(f, &quot;Opacity&quot;, 1.0, 0.0, false));
                _sbB.Children.Add(CreateDoubleAnimation(f, &quot;Opacity&quot;, 0.0, 1.0, false));
&nbsp;
                _sbF.Children.Add(CreateDoubleAnimation(b, &quot;Opacity&quot;, 0.0, 1.0, false));
                _sbB.Children.Add(CreateDoubleAnimation(b, &quot;Opacity&quot;, 1.0, 0.0, false));
            }
            if (_forward)
            {
                _sbF.Begin();
                _forward = false;
            }
            else
            {
                _sbB.Begin();
                _forward = true;
            }
        }
&nbsp;
        private static DoubleAnimation CreateDoubleAnimation(DependencyObject element, string property, double from,
                                                             double to, bool addEasing)
        {
            DoubleAnimation da = new DoubleAnimation();
            da.To = to;
            da.From = from;
            if (addEasing)
                da.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 };
&nbsp;
&nbsp;
            Storyboard.SetTargetProperty(da, new PropertyPath(property));
            Storyboard.SetTarget(da, element);
            return da;
        }
    }
}</pre></div></div>

<p>Once you have the class constructed you can add the trigger to your UIElement in Blend.  Clicking on the trigger in the Object &#038; Timeline tab will allow you to configure each of the the properties you have defined in your class.<br />
<a href="http://joel.neubeck.net/wp-content/uploads/2009/07/flip2.PNG"><img src="http://joel.neubeck.net/wp-content/uploads/2009/07/flip2-300x205.PNG" alt="flip2" title="flip2" width="300" height="205" class="aligncenter size-medium wp-image-419" /></a><br style="clear:both"/><br />
<iframe src="/wp-content/uploads/2009/07/FlipTriggerAction/" width="500" height="300"></iframe><br />
Code: <a onclick="javascript: pageTracker._trackPageview('/code/FlipTriggerAction.zip'); " href="/wp-content/uploads/2009/07/FlipTriggerAction/FlipTriggerAction.zip">FlipTriggerAction.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://joel.neubeck.net/2009/07/silverlight-3-flip-triggeraction/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Silverlight Flipping Tiles Animation</title>
		<link>http://joel.neubeck.net/2008/05/silverlight-flipping-tiles-animation/</link>
		<comments>http://joel.neubeck.net/2008/05/silverlight-flipping-tiles-animation/#comments</comments>
		<pubDate>Fri, 16 May 2008 06:36:30 +0000</pubDate>
		<dc:creator>joel</dc:creator>
				<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[3D Flip]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[Blend]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[DispatcherTimer]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[Tiles]]></category>

		<guid isPermaLink="false">http://joel.neubeck.net/2008/05/silverlight-flipping-tiles-animation/</guid>
		<description><![CDATA[Back a few weeks ago I posted an example of how to create a 3D flip animation similar to the effect seen on an iPhone. Today I will build upon that procedural animation and simulate the flipping tile affect seen in the iTunes album art screen saver, available on a Mac. In my example I [...]]]></description>
			<content:encoded><![CDATA[<p>Back a few weeks ago I posted an example of how to create a <a href="http://joel.neubeck.net/2008/04/silverlight-3d-flip-animation/">3D flip animation</a> similar to the effect seen on an iPhone. Today I will build upon that procedural animation and simulate the flipping tile affect seen in the iTunes album art screen saver, available on a Mac.
<p><iframe src="/wp-content/uploads/2008/05/LeopardSreenSaver/default.html" width="400" height="400"></iframe></p>
<p>In my example I have a total of 16 random tiles displayed from a collection of 42 different images. Any image not currently displayed is available to be randomly selected to replace an existing tile.&nbsp; Here is how I achieve the effect.&nbsp; </p>
<p>The project is comprised of a &#8220;Tile&#8221; UserControl , a class called &#8220;Media&#8221; and two generic lists (one to store references to the 16 tiles and one to store all 42 URI to the images).&nbsp; The first step is to fill my page.xaml grid with 16 tiles.&nbsp;&nbsp; Here is a snip of the code used to fill the grid.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="code"><pre class="c-sharp" style="font-family:monospace;">private void BuildCollection()
{
    int row = -1;
    int col = 0;
    for (int i = 0; i &amp;lt; 42; i++)
    {
        Uri imageUri = new Uri(string.Format(&quot;Images/{0}.png&quot;, 
		(i+1).ToString()), UriKind.Relative);
        if (i &amp;lt;= 16)
        {
            Tile tile = new Tile();
            Media media =  new Media(imageUri, true);
            tile.Media = media;
&nbsp;
            if (col % 4 == 0)
            {
                row++;
                col = 0;
            }
            tile.SetValue(Grid.ColumnProperty, col.ToString());
            tile.SetValue(Grid.RowProperty, row.ToString());
            this.LayoutRoot.Children.Add(tile);
&nbsp;
            col++;
            _tiles.Add(tile);
            _images.Add(media);
&nbsp;
        }
        else
            _images.Add(new Media(imageUri, false));
    }
}</pre></td></tr></table></div>

<p>For those of you just getting familiar with the &#8220;Grid&#8221; control you might not be aware that it supports implicitly specifying columns and rows. In this example I leverage this to ensure my tiles form a nice 4&#215;4 grid.&nbsp;&nbsp; </p>
<p>As you can see from the code, I have chosen to store only the URI to the image and not store the image itself. I had some difficulty storing a &#8220;BitmapImage&#8221; object in my collection and retrieving it consistently when I was ready to flip a tile. The URI seems less efficient, was reliable. </p>
<p>Now that I have built up my grid and two collections, I can use a DispacherTimer to randomly select a tile and randomly select an image to be used as the backside of the flip. He is how that code looks. </p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="c-sharp" style="font-family:monospace;">void _timer_Tick(object sender, EventArgs e)
{
    System.Random RandNum = new System.Random();
    int randomTile = RandNum.Next(16);
&nbsp;
    bool match = false;
    while(!match)
    {
        int randomImage = RandNum.Next(42);
        if(!_images[randomImage].Displayed)
        {
            _images[randomImage].Displayed = true;
            _tiles[randomTile].Media.Displayed = false;
            _tiles[randomTile].Flip(_images[randomImage]);
            match=true;
            break;
        }
    }
}</pre></td></tr></table></div>

<p>As you can see I am using a boolean property in the &#8220;Media&#8221; object to determine if an image is already displayed. The second level of randomization is there to help ensures that I am giving each image equal chance of getting displayed. </p>
<p>If one were to examine the &#8220;Tile&#8221; UserControl, it looks almost exactly like the code I created for the 3D flip animation example. In&nbsp; this situation instead of firing the flip based on a button click, I use the followings public method called from my main page.xaml DispatcherTimer tick. </p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="c-sharp" style="font-family:monospace;">public void Flip(Media media)
{
    this.Media = media;
&nbsp;
    if (_Front)
    {
        this.ImageBack.Source = new BitmapImage(_Media.ImageUri);
        _sb.Pause();
        _sb.AutoReverse = false;
        _sb.Begin();
        _Front = false;
    }
    else
    {
        this.ImageFront.Source = new BitmapImage(_Media.ImageUri);
        _sb.Pause();
        _sb.AutoReverse = true;
        _sb.Seek(_tsLastFrame);
        _sb.Resume();
&nbsp;
        _Front = true;
    }
}</pre></td></tr></table></div>

<p>Code: <a onclick="javascript: pageTracker._trackPageview('/code/LeopardSreenSaver.zip');" href="/wp-content/uploads/2008/05/LeopardSreenSaver/LeopardSreenSaver.zip">LeopardSreenSaver.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://joel.neubeck.net/2008/05/silverlight-flipping-tiles-animation/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Silverlight 3D flip animation</title>
		<link>http://joel.neubeck.net/2008/04/silverlight-3d-flip-animation/</link>
		<comments>http://joel.neubeck.net/2008/04/silverlight-3d-flip-animation/#comments</comments>
		<pubDate>Fri, 25 Apr 2008 07:20:16 +0000</pubDate>
		<dc:creator>joel</dc:creator>
				<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[3D Flip]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[Blend]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[DiscreteDoubleKeyFrame]]></category>
		<category><![CDATA[DoubleAnimationUsingKeyFrames]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[SplineDoubleKeyFrame]]></category>

		<guid isPermaLink="false">http://joel.neubeck.net/2008/04/silverlight-3d-flip-animation/</guid>
		<description><![CDATA[Up until now I have not had an opportunity to create any Silverlight procedural animations that were more complicated then positioning an object with some simple easing. I thought it would be fun to attempt to duplicate one of the transitions used on the iPhone. While making a phone call, if you choose to display [...]]]></description>
			<content:encoded><![CDATA[<p>Up until now I have not had an opportunity to create any Silverlight procedural animations that were more complicated then positioning an object with some simple easing.  I thought it would be fun to attempt to duplicate one of the transitions used on the iPhone. While making a phone call, if you choose to display the keypad there is a cool 3D flip that occurs. Here is a quick video of the transition.   [[VIDEO]] In hopes not to reinvent the wheel, I embarked on an endless search of the Internet for anything resembling a flip.  After some quality time on Google, I stumbled upon a great Flash site called <a href="http://tinyurl.com/63c89a" target="_blank">reflektions</a> by Paul Ortchanian. This site has a ton of Flash examples that highlight 2D and 3D effects done in flash.  Those of us new to interactive development can learn a ton from the techniques Flash and Flex developers have used for years.  To get started I created a simple page that contained two Grid controls, one for the front of the flip and one for the back.  Both were placed inside of a single canvas named &#8220;screens&#8221;.
<p><iframe src="/wp-content/uploads/2008/04/ScreenFlip/default.html" width="300" height="250"></iframe></p>
<p>  The guts of this effect has been encapsulated in a method called &#8220;AnimateFlip&#8221;.  The result of this method is a DobuleAnimation with approximately 48 descreate keys frames.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
</pre></td><td class="code"><pre class="c-sharp" style="font-family:monospace;">private TimeSpan AnimateFlip(Storyboard sb, ScaleTransform scale, 
out TimeSpan tsLastFrame)
{
    double speed = 4;
    double flipRotation = 0;
    double flipped = 2;
    tsLastFrame = new TimeSpan();
    TimeSpan tsSideFlipped = new TimeSpan();
&nbsp;
    int frames = 1;
    DoubleAnimationUsingKeyFrames daX = 
	new DoubleAnimationUsingKeyFrames();
    tsLastFrame = new TimeSpan();
    while (flipRotation != flipped * 180)
    {
        flipRotation += speed;
        double flipRadian = flipRotation * (Math.PI / 180);
        double size = Math.Cos(flipRadian);
        double scalar = (1 / (1 / size));
&nbsp;
        DiscreteDoubleKeyFrame ddkfX = new DiscreteDoubleKeyFrame();
        ddkfX.Value = (size * scalar) ;
&nbsp;
        tsLastFrame = TimeSpan.FromMilliseconds(frames * 7);
&nbsp;
        //the first time we flip to negative capture the 
	//tsLastFrame so we know when we will need to
        //visualize the flip side
        flipped = (size &lt; 0) ? +1 : +0;
        if (flipped == 1 &amp;&amp; tsSideFlipped.Ticks == 0)
        {
            tsSideFlipped = tsLastFrame;
        }
&nbsp;
        ddkfX.KeyTime = KeyTime.FromTimeSpan(tsLastFrame);
&nbsp;
        //add the DiscreteDoubleKeyFrame to the 
	//DoubleAnimationUsingKeyFrames
        daX.KeyFrames.Add(ddkfX);
&nbsp;
        flipRotation %= 360;
        frames++;
    }
&nbsp;
    Storyboard.SetTarget(daX, scale);
    Storyboard.SetTargetProperty(daX, &quot;ScaleX&quot;);
    sb.Children.Add(daX);
&nbsp;
    VisualizeSide(sb, tsSideFlipped, 0, TimeSpan.FromMilliseconds
		((tsSideFlipped.Milliseconds + 100)), 
		back.Opacity, this.back);
    VisualizeSide(sb, TimeSpan.FromMilliseconds((
		tsSideFlipped.Milliseconds - 100)), front.Opacity, 
		tsSideFlipped, 0, this.front);
    back.Opacity = 0;
    return tsLastFrame;
}</pre></td></tr></table></div>

<p>At the very bottom of the above method their is two calls to &#8220;VisualizeSide&#8221;.  This method is responsible for visualizing the second side when the screen has rotated 180 degrees (Flipped). </p>
<p>My animation is by no means exact, but a pretty good first attempt.  If you watch the video very slowly you might notice that on the iPhones rotation it looks like it rotates in perspective.  I would love to add this, but am at a lost </p>
<p>Code: <a onclick="javascript: pageTracker._trackPageview(&#39;/code/ScreenFlip.zip&#39;);" href="/wp-content/uploads/2008/04/ScreenFlip/ScreenFlip.zip">ScreenFlip.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://joel.neubeck.net/2008/04/silverlight-3d-flip-animation/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

