Silverlight Controls with Effects and Transitions

A big update for Silverlight.FX - now in sync with Silverlight 2 and with a bunch of new features. This post discusses one feature area: controls that intrinsically support effects and transitions.

Earlier this week, the much anticipated Silverlight 2 was finally released! Personally speaking, it's a day that's been coming for a while - ever since my days prototyping the Core CLR engine running in the browser some two+ years ago now... and already, we're busy building the next layer of frameworks beyond the foundation provided by the CLR and the graphics/media engine and basic controls. Wow!

I'm working on one such effort of building an application framework on top of Silverlight these days at work, which as usual for any v1 product takes time. Over the past few weeks, I've also been working on updating Silverlight.FX to work against the final SL2 build, as well as adding a bunch of new goodies into the framework.

The area I want to talk about in this post is using and writing Silverlight controls that are effects and transitions enabled. This picks up from my last Silverlight.FX post that demonstrated procedural animations and declarative effects and transitions. The first iteration of this framework allowed an app developer to add some richer user interaction by associating effects and transitions to basic events such as clicks, hovers, focus etc. This post takes that one step further - higher level controls that intrinsically support such effects and transitions.

I have three controls to share in the context of two sample applications (screenshots below - click to run). The first application is Flickr Tiles - a basic Flickr browser (yes, I gotta have a photos sample), and the second is a simple Task List sample (yes, I've used the Task List scenario in a number of contexts in the past - what can I say - it's a nice simple scenario).

Static screen shots don't do justice to animations - so I'd encourage running the samples to get an idea of the application experiences I am talking about enabling via controls before reading on. You'll need to make sure you've installed the final build of Silverlight 2 if you haven't already.

ContentView
This acts and behaves like the regular ContentControl, but adds a ContentTransition property. You can set it to a CrossFade, Slide, Flip, Blinds, or Explode transition, or to a custom transition you build. The control automatically plays the chosen transition to switch from one object to the next when its Content property is changed. In the Flickr Tiles app, each time a photo is selected, the old photo explodes out (ala Dashboard on the mac) and the new photo fades in.

Here is an snippet of XAML markup demonstrating ContentView.

<fxui:ContentView x:Name="photoView" Content="{Binding SelectedPhoto}">
  <fxui:ContentView.ContentTransition>
    <fxtransitions:Explode Easing="QuadraticInOut" Duration="0:0:0.5" />
  </fxui:ContentView.ContentTransition>
  <fxui:ContentView.ContentTemplate>
    <DataTemplate> ... </DataTemplate>
  </fxui:ContentView.ContentTemplate>
</fxui:ContentView>

This shows how the ContentView control shares the Content and ContentTemplate property model that ContentControl provides, and adds the ContentTransition property, which is this case has been set to an Explode transition that plays over 0.5 seconds and uses a quadratic easing in and out behavior for a more natural animation.

TilePanel
This is an example of an animated panel that uses the same procedural animations framework to arrange child elements from one location to the next location in a smooth manner. The Flickr Tiles application uses this to arrange thumbnails. The framework also contains StackPanels that support animation and the Task List sample uses a VStackPanel to arrange the list of tasks. Here again, the framework is extensible - you can create your own animated layouts and just derive from AnimatedPanel to automatically tap into the procedural animation framework without writing your own animation code.

<ItemsControl x:Name="photosList" ItemsSource="{Binding Photos}">
  <ItemsControl.ItemTemplate>
    <DataTemplate> ... </DataTemplate>
  </ItemsControl.ItemTemplate>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <fxui:TilePanel TileHeight="103" TileWidth="103"
        UseAnimatedLayout="True" Easing="QuadraticOut" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>

ListView
This is a basic data-bound control that can be bound to an arbitrary collection. It is similar to the basic ItemsControl, but adds a couple of properties - ItemAddedEffect and ItemRemovedEffect (as well as other things like filtering and sorting). The ListView control plays the added effect for any item added, and plays the removed effect on any item being removed from the underlying collection before the corresponding UI is removed from the visual tree itself. The Task List sample uses a ListView to represent the list of tasks, and each time a task is added, the app plays a Web 2.0'ish yellow fade in effect, and each time a task is deleted, it plays a fade out effect.

The final snippet is the ListView control from the TaskList sample with a its effects properties initialized to a couple of out-of-the-box effects.

<fxui:ListView DataSource="{Binding Tasks}">
  <fxui:ListView.ItemTemplate>
    <DataTemplate> ... </DataTemplate>
  </fxui:ListView.ItemTemplate>
  <fxui:ListView.ItemAddedEffect>
    <fxeffects:Highlight HighlightColor="#FFE396" Duration="0:0:1" Easing="QuadraticInOut" />
  </fxui:ListView.ItemAddedEffect>
  <fxui:ListView.ItemRemovedEffect>
    <fxeffects:Fade FadeOpacity="0" Duration="0:0:0.75" Easing="QuadraticInOut" />
  </fxui:ListView.ItemRemovedEffect>
</fxui:ListView>

In each case above you can see that you don't have to define storyboards, or event handlers to begin and stop storyboards. Instead you can use some pre-canned effects and transitions, and let the controls figure out when and how to play them based on the semantics of the controls. Clearly this is just the tip of the iceberg, in terms of both the set of stock effects/transitions as well as the controls that could use them.

You can download the framework and associated samples (full source to both included) to see not only how the samples were built, but also look and poke around as deep as you'd like inside the framework... and obviously use it in your own apps.

For those writing controls, you're probably interested in seeing what is happening beyond the XAML markup. Lets look at how effects and transitions can be used programmatically.

The first snippet is from the code for ListView, and demonstrates how an effect can serve as a factory or template of sorts for procedural animations, so that the same effect has to be applied to multiple items in the control.

private void AddItem(object dataItem, int index) {
    Style itemContainerStyle = ItemContainerStyle;
    DataTemplate itemTemplate = ItemTemplate;

    ListViewItem item = CreateItem(dataItem, index, itemTemplate, itemContainerStyle);
    if (item != null) {
        _itemsPresenter.Children.Insert(index, item);

        Effect addedEffect = ItemAddedEffect;
        if (addedEffect != null) {
            addedEffect.Target = (FrameworkElement)item.Content;

            ProceduralAnimation addedAnimation = ((IAnimationFactory)addedEffect).CreateAnimation();
            addedAnimation.Play(item);
        }
    }
}

The second is a bit of code from ContentView where the assigned transition is used to animate old content to new content.

private void OnContentChanged(object oldContent, object newContent) {
    ...
    else {
        Transition contentTransition = ContentTransition;

        if (contentTransition == null) {
            Panel panel = (Panel)_contentGrid.Children[0];
            ContentPresenter contentPresenter = (ContentPresenter)panel.Children[0];

            contentPresenter.Content = newContent;
        }
        else {
            if (contentTransition.IsActive) {
                contentTransition.StopEffect();
            }

            AddContent(newContent);

            contentTransition.Target = _contentGrid;
            contentTransition.PlayEffect(EffectDirection.Forward);
        }
    }
}

Reasonably straightforward to incorporate into controls ... hopefully.

The latest update of Silverlight.FX also contains a number of other early features, some of which will quite likely come up in future samples. These new feature areas include a dialog framework, and other controls. There are a number of updates as well - the behaviors and effects model has been revamped; triggers and actions have also been revamped to be much more flexible; script expressions in actions to bind view events to view model operations no longer depend on the DLR. Some bugs (incl. the big one around custom controls in the theming system) have been fixed.

If you've been following Silverlight.FX for some while, I'll recommend checking out the samples which are always up-to-date, as well as ask any questions you have below.

Posted on Thursday, 10/16/2008 @ 12:54 AM | #Silverlight


Comments

23 comments have been posted.

rakesh ravuri

Posted on 10/16/2008 @ 5:05 AM
Awesome, waiting for this update since RC0 release :)

Tom

Posted on 10/16/2008 @ 6:38 AM
This is great, thanks for getting it together so quickly. We will definitely be using the framework.

Chris Ortman

Posted on 10/16/2008 @ 7:00 AM
Do you have any interest in community contribution to this code? I had a few patches from the last version that I tried to send but never heard anything back on.

Thanks

fiatkongen

Posted on 10/16/2008 @ 11:45 AM
Thanks for the great update. Loks great

I would be very happy if you could you post how to programmatically add fx a fade-transition using the new framework.

Thanks

Nikhil Kothari

Posted on 10/16/2008 @ 1:26 PM
@Chris - if there are simple bug fixes/patches, I'd love to hear about the issue - please use my contact form. I haven't been able to check on that mail in the last couple of weeks... but will do so. I am going to work out what model I want to use for this project in terms of community contribution. While I'd love to go down that route, I need to rationalize how that affects what I do at work, since it is in very similar space... as you can anticipate, this brings up some interesting questions.

@fiatkongen - I'd love to do a followup blog post on more deeper details. Just so I know specifically what you're after... is it:
a) Attaching effects programmatically - such as a Fade on Hover effect - rather than declaratively in XAML
b) More details on writing a control such as ContentView
c) Creating a custom effect

fiatkongen

Posted on 10/16/2008 @ 2:03 PM
Hi

Actually all 3 mentioned items would be great to hear about. But right now I am very much interested in how to attach effects programmatically. For example, how to create and attach a Crossfade transition dynamically, and then play the effect

Thanks again

David Roh

Posted on 10/17/2008 @ 4:25 AM
Very nice!

Thank you for sharing.

Fallon Massey

Posted on 10/18/2008 @ 12:15 AM
Nikhil, I would also like to see Attaching effects programmatically, but also, the library is starting to get quite large.

It would be nice to break it down into component parts(assemblies) so that we can include only what we need, and use delayed loading for the rest(if needed).

BTW, I LOVE the Flickr app, it's really sweet!

Nikhil Kothari

Posted on 10/18/2008 @ 1:44 AM
@fiatkongen, @Fallon - I will hopefully post a followup on more advanced/programmatic use of the effects library.

@Fallon - Its a bit hard to split the library into pieces - there is certainly the stuff under $Platform that could be split out. The real problem with splitting out is finding a factoring that works for every app.

For example, I could split out an assembly per control, per effect etc. That creates a real problem for requiring one to add many assembly references. Keeping all effects together but in a separate assembly also doesn't solve all the problems - the moment you want one, you have all. It does solve the problem where if you don't want any effects, but want some other control, then you can ignore a whole assembly.

My thought is that the real solution is keeping all the stuff together in a single assembly, and then running a static linker that for a given app prunes out all types that aren't needed. This would be run over the xap and would prune out not just Silverlight.FX but every other SDK assembly. I've got a prototype of just such a static linker, and initial results seem promising, but is still very early...

The current compressed size of Silverlight.FX is ~75KB. My internal mental quota was 100KB. Between that number and the possible static linking approach, I didn't want to spoil the dev simplicity of a single reference... I'll certainly look and see if there is a bit more of a split between core platform extensions and then features on top. That way someone can reference the core platform extensions assembly, and then pick up different features in source form if they don't want an entire assembly.

Fallon Massey

Posted on 10/18/2008 @ 7:45 PM
Nikhil, actually, it's my mistake. I was looking at the uncompressed files, not te compressed XAP. Even 100K wouldn't be a problem for what I envision using this code for.

Having said that, your concept of pruning out types is quite interesting in general. Keep us informed when/if you get time to play with that, and ignore my request for breaking up the library.

Mohammed Mudassir Azeemi

Posted on 11/4/2008 @ 11:30 AM
Hey Nikhil,

That Silverlight.FX is not compiling accordingly. It keep throwing this strange error:

Error 2 The "AddZhSatellites" task was not found. Check the following: 1.) The name of the task in the project file is the same as the name of the task class. 2.) The task class is "public" and implements the Microsoft.Build.Framework.ITask interface. 3.) The task is correctly declared with <UsingTask> in the project file, or in the *.tasks files located in the "C:\WINDOWS\Microsoft.NET\Framework\v3.5" directory. EffectsSample


Any idea what's that mean is?

Thanks,

Mudassir Azeemi

Mohammed Mudassir Azeemi

Posted on 11/4/2008 @ 12:08 PM
Hello Nikhil,

I think I solved that AddZhSatellites issue, actually I uninstall Silverlight 2 SDK Beta 2 and then install the Silverlight 2 SDK final version.

Now the problem is, whenever I run the sample app, the Silverlight Sample page keeping looping in the wait circle ('C:\Documents and Settings\mmudassir\Desktop\SilverlightFX\SilverlightFX\samples\SampleApp\Bin\Debug\TestPage.html")

Hmm, something needs to be done on some side?

Thanks,

Mudassir Azeemi
San Francisco, CA

Nikhil Kothari

Posted on 11/4/2008 @ 12:36 PM
Yes, this is now sync'd to the final version of Silverlight 2.

You need to set up the Web project as the startup project and browse to the aspx by loading it over http as opposed to browsing to the test html page via the file system.

Mohammed Mudassir Azeemi

Posted on 11/4/2008 @ 5:08 PM
Hey Nikhil,

What is the best book I can read for Silverlight 2.0 ?

Any course by MS or anyone you know that offer the superb stuff?

Thanks,

Mudassir Azeemi

Mohammed Mudassir Azeemi

Posted on 11/5/2008 @ 3:49 PM
Hey Nikhil,

The comments I posted are deleted some how?

Why's that?

Thanks,

Mudassir Azeemi

Jaime Bula

Posted on 12/3/2008 @ 1:30 PM
Hi! Can someone provide an example of an animation executed from code behind?

I tried

Silverlight.FX.UserInterface.Transitions.Flip flip = new Silverlight.FX.UserInterface.Transitions.Flip();
flip.TargetName = "infoPanel";
flip.Target = infoPanel;
flip.PlayEffect(System.Windows.Media.Glitz.EffectDirection.Forward);

But I get a Null Reference Exception.

Jaime Bula

Posted on 12/4/2008 @ 4:58 AM
Ik I answered myself this morning.

XAML:

<fxtransitions:Flip x:Name="DoFlip" TargetName="infoPanel" />
<Grid x:Name="infoPanel">
<Grid>
...

Code Behind:

Effect addedEffect = DoFlip;

if (addedEffect != null)
{
addedEffect.Target = infoPanel;
ProceduralAnimation addedAnimation = ((IAnimationFactory)addedEffect).CreateAnimation();
addedAnimation.Play(infoPanel);
}

I was missing the XAML Definition of the animation.

John Wilcox

Posted on 2/5/2009 @ 9:10 AM
Just started to look at the TilePanel, looks great but is there any way to make it support vertical scrolling? I would like to use this panel to display an unknown but potentially large number of items...and don't want to lose them off the bottom of the panel.

Thanks -- the FX framework looks awesome!

Sai

Posted on 3/29/2009 @ 8:45 AM
Hi excellent source of page transition.

I have a question about using your framework. I have a dynamically generated pagination Page 1 2 3 4 5 6 7 ...etc.
How can I apply your framework for page transition on my pagination?

I am new to silverlight about 1 month into learning it.

Thank you.

jon

Posted on 5/2/2009 @ 2:34 PM
Great stuff!

How do you get the Focus effects to work... I just added the following to your sample.. but nothing happens... thanks again

<fxui:FocusEffect>
<fxeffects:Spin TargetName="spinImage" SpinAngle="360" Duration="00:00:01" />
</fxui:FocusEffect>

Tobby

Posted on 7/29/2009 @ 2:48 AM
Hi ! Excellent work man.
Just want to ask how possible is it to integrate the model of your "Window" into a normal silverlight child window. Thereby getting the capability of something like this $model.Remove($dataContext).
Thanks.

Jon

Posted on 8/7/2009 @ 9:13 AM
Great Stuff!!!!!
Any plans or ideas about a 'flashlight / shine' effect.
When a control loads - a light/glare is shown moving across the object.
thanks!!!!!!!!

Abhilash

Posted on 12/20/2009 @ 10:42 PM
Hi Nikhil,
Great work. I am much interested in SL static linker. Could you please update the status of that?
Thanks much
Post your comment and continue the discussion.