I wanted to do this animation at runtime. I’ve noticed that XAML is great when you know exactly which pre-created object you want to animate in a pre-determined way. If you however haven’t created the object yet or want to use some custom parameters, using C# code can sometimes be a better way to achieve your goals.
Archive for April 26th, 2010
Learning Silverlight – Advanced Color Animations
Floating Visual Elements
This is part 2 of the series “Silverlight in Action”:
- Visuals staring at the mouse cursor.
- Floating Visual Elements.
Here we’re sharing our experience from the amazing CompletIT web site.
As you may already know, every Silverlight application “must” have some objects floating around in a quite 3D manner. For example, let’s make a panel with happy faces floating around the screen in a controlled way, like this one.
See how it looks
Floating in Action
Idea
The idea is to create an attached behavior for a panel, so that when enabled, through attached property it’ll make all panel’s children float around. To make this effect we will use PlaneProjection and TranslateTransform. We’ll create Storyboard that will animate these properties, to random values (but in controlled manner with a threshold) and when it completes – the animation will begin again with changed “To” by random. This way we’ll create random continuous floating of the visual objects.
Implementation
We need a class that holds the attached property. Let’s name it FloatingService. It has one attached property, for instance IsChildrenFloating of type boolean to trigger the behavior and two more properties to handle the Maximum allowed values for the PlaneProjection and TranslateTransform. So when IsChildrenFloating is attached to the panel with value of true, all its children will start floating.
This is how we control the animation in the FloatingService class.
1: var panel = sender as Panel;
2: if (panel != null)
3: {
4: var projectionMax = GetProjectionMax(panel);
5: var translateMax = GetTranslateMax(panel);
6:
7: foreach (UIElement child in panel.Children)
8: {
9: var storyboard = new Storyboard();
10:
11: PlaneProjection planeProjection;
12: child.EnsureProjection(out planeProjection);
13:
14: DoubleAnimation projectionX = AnimationFactory.CreateProjectionXAnimation(planeProjection, random.Next(projectionMax), seconds);
15: DoubleAnimation projectionY = AnimationFactory.CreateProjectionYAnimation(planeProjection, random.Next(projectionMax), seconds);
16: DoubleAnimation projectionZ = AnimationFactory.CreateProjectionZAnimation(planeProjection, random.Next(projectionMax), seconds);
17:
18: storyboard.Children.Add(projectionX);
19: storyboard.Children.Add(projectionY);
20: storyboard.Children.Add(projectionZ);
21:
22: ScaleTransform scale;
23: TranslateTransform translate;
24: RotateTransform rotate;
25: SkewTransform skew;
26: child.EnsureTransforms(out scale, out rotate, out skew, out translate);
27:
28: DoubleAnimation translateX = AnimationFactory.CreateTranslateXAnimation(translate, random.Next(translateMax), seconds);
29: DoubleAnimation translateY = AnimationFactory.CreateTranslateYAnimation(translate, random.Next(translateMax), seconds);
30:
31: storyboard.Children.Add(translateX);
32: storyboard.Children.Add(translateY);
33:
34: storyboard.Completed += (s, e1) =>
35: {
36: projectionX.To = random.Next(projectionMax);
37: projectionY.To = random.Next(projectionMax);
38: projectionZ.To = random.Next(projectionMax);
39: translateX.To = random.Next(translateMax);
40: translateY.To = random.Next(translateMax);
41: storyboard.Begin();
42: };
43: storyboard.Begin();
44: }
45: }
So we create Storyboard from code, to hold the 5 animations – for rotating X,Y,Z and translating X,Y. And when the Storyboard finishes we choose new random values for end of the animations and start it again.
And now we only need to use the attached behavior to begin the floating of visuals.
How to use the behavior
1: <StackPanel FloatingObjects:FloatingService.IsChildrenFloating="True"
2: Orientation="Horizontal"
3: VerticalAlignment="Center">
4: <StackPanel.Resources>
5: <Style TargetType="ContentControl"
6: x:Key="faceControl">
7: <Setter Property="Height"
8: Value="75" />
9: <Setter Property="Width"
10: Value="75" />
11: <Setter Property="Margin"
12: Value="10" />
13: <Setter Property="Effect">
14: <Setter.Value>
15: <DropShadowEffect BlurRadius="5"
16: Color="Black"
17: Opacity=".7" />
18: </Setter.Value>
19: </Setter>
20: <Setter Property="Template">
21: <Setter.Value>
22: <ControlTemplate>
23: <Grid>
24: <Rectangle Fill="{TemplateBinding Background}" />
25: <Ellipse Height="10"
26: Width="10"
27: Fill="Blue"
28: Margin="20 20 0 0"
29: HorizontalAlignment="Left"
30: VerticalAlignment="Top" />
31: <Ellipse Height="10"
32: Fill="Blue"
33: Width="10"
34: Margin="0 20 20 0"
35: HorizontalAlignment="Right"
36: VerticalAlignment="Top" />
37: <Path Data="M0,0 A 10, 10 0 0 0 25, 0"
38: Stroke="#FFFA0D0D"
39: HorizontalAlignment="Center"
40: VerticalAlignment="Bottom"
41: Margin="0 0 0 10"
42: StrokeThickness="2" />
43: </Grid>
44: </ControlTemplate>
45: </Setter.Value>
46: </Setter>
47: </Style>
48: </StackPanel.Resources>
49:
50: <ContentControl Style="{StaticResource faceControl}"
51: Background="Yellow" />
52: <ContentControl Style="{StaticResource faceControl}"
53: Background="Silver" />
54: <ContentControl Style="{StaticResource faceControl}"
55: Background="Cyan" />
56: <ContentControl Style="{StaticResource faceControl}"
57: Background="Green" />
58: <ContentControl Style="{StaticResource faceControl}"
59: Background="Brown" />
60: </StackPanel>
Download the code
Working with multiple interfaces on a single mock.
Today , I will cover a very simple topic, which can be useful in cases we want to mock different interfaces on our expected mock object. Our target interface is simple and it looks like:
- public interface IFoo : IDisposable
- {
- void Do();
- }
Our target interface has an IDisposable implemented. Now, generally if we implement it in a class , we have to implement the whole of it [which is quite logical] and that should not wait for any extra calls or constructs. Considering that, when we are creating our target mock it should also implement all the dependent interfaces for us as well.
Therefore, as we are creating our mock using Mock.Create<IFoo> like that follows, it also implements the dependencies for us :
- var foo = Mock.Create<IFoo>();
Then, as we are interested only in IDisposable calls, we just need to do the following:
- var iDisposable = foo as IDisposable;
Finally, we proceed with our existing mock code. Considering the current context, I will check if the dispose method has invoked our mock code successfully.
- bool called = false;
- Mock.Arrange(() => iDisposable.Dispose()).DoInstead(() => called = true);
- iDisposable.Dispose();
- Assert.True(called);
Further, we assert our expectation as follows:
- Mock.Assert(() => iDisposable.Dispose(), Occurs.Once());
Hopefully that will help a bit and stay tuned.
Enjoy!!
