Showing posts with label Zune. Show all posts
Showing posts with label Zune. Show all posts

03 September, 2010

Now Playing with MVVM – Animating cover transitions

This is part 6 of a series of posts in which I attempt to reproduce the Zune Now Playing interface using the MVVM pattern within WPF. An introduction to the series and table of contents can be found in the first post of this series.

The Zune Now Playing interface uses a subtle animation when transitioning from one album cover to another. To help me reproduce this effect I used Blend, which provides an intuitive interface for creating keyframe-based animations using storyboard or visual states. I’ve chosen to use storyboards, which I think will make my MVVM approach easier to implement because if won’t encourage me to rely on the VisualStateManager class, which is closely associated to the world of the view.

There are a number of documented approaches on the Internet for how to handle animations when using the MVVM pattern. Some initially felt like complex implementations which put the purity of separation first, while others conceded to a small splash of code behind in the view. While the code-behind approach certainly appeals to me because it appears to offer an easier solution, I don’t want to go that way, because I’d rather focus on adhering to the guiding principles of the MVVM pattern.

Most of the suggestions only deal with kicking a single animation off, but what I’m after is more complex than that. When an Album is updated, I’ll start a fade out animation. Once the fade out completes, I’ll update the Album in the model and fire the view’s databinding updates via INotifyPropertyChanged. Finally, I’ll start a different animation to fade the album back in. With such interdependency between animations that occur in the view and state that is transitioning in the viewmodel, this quickly becomes a chicken-or-the-egg problem. I don’t want animation constructs in my viewmodel because the goal is to keep the project blendable, and to allow designers to tweak the animation in Blend.

My approach is similar to those that appear in some of the articles I’ve linked to above. I’ve ended up using a combination of an enum for the various states of the image transition process, a couple of data triggers, and a storyboard completed trigger. Here’s what the flow looks like:

MVVMAnimationFlow

Here’s how I’ve modified the CoverViewModel to accommodate the change. An external entity would call UpdateAlbum to start the process.


namespace NowPlayingMVVM.ViewModel {
public enum ImageState {
New,
BeforeChange,
Changing,
AfterChange
}

public class CoverViewModel : ViewModelBase, IAlbumConsumer {
private Album theAlbum;
private ImageState theImageState = ImageState.New;
...
public ImageState ImageState {
get { return theImageState; }
set {
theImageState = value;
NotifyPropertyChanged("ImageState");
if(value == ImageState.Changing) {
NotifyPropertyChanged("ArtworkUrl");
NotifyPropertyChanged("Name");
}
}
}

public void UpdateAlbum(Album anAlbum) {
if(theAlbum == anAlbum) return;
if (theAlbum == null) {
theAlbum = anAlbum;
ImageState = ImageState.Changing;
} else {
ImageState = ImageState.BeforeChange;
theAlbum = anAlbum;
}
}
}
}

And on the View side


<Image x:Name="image" Source="{Binding ArtworkUrl}" Stretch="Fill" Width="280" Height="280" RenderTransformOrigin="0.5,0.5">
<Interactivity:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding ImageState}" Value="BeforeChange">
<!-- When ImageState becomes BeforeChange, fire FadeOut animation -->
<ei:ControlStoryboardAction Storyboard="{StaticResource FadeOut}" />
</ei:DataTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{StaticResource FadeOut}">
<!-- When FadeOut completes, update ImageState to Changing -->
<ei:ChangePropertyAction PropertyName="ImageState" TargetObject="{Binding}" Value="Changing" />
</ei:StoryboardCompletedTrigger>
<ei:DataTrigger Binding="{Binding ImageState}" Value="Changing">
<!-- When ImageState becomes Changing, fire FadeIn animation -->
<ei:ControlStoryboardAction Storyboard="{StaticResource FadeIn}" />
</ei:DataTrigger>
<ei:StoryboardCompletedTrigger Storyboard="{StaticResource FadeIn}">
<!-- When FadeIn completes, update ImageState to AfterChange -->
<ei:ChangePropertyAction PropertyName="ImageState" TargetObject="{Binding}" Value="AfterChange" />
</ei:StoryboardCompletedTrigger>
</Interactivity:Interaction.Triggers>
</Image>

I don’t really love this approach because although it technically doesn’t require the View and ViewModel to know about each other, the two are still tightly bound by the use of the enum and the order of events. When looking at the ViewModel, the trigger logic can only really be understood with a good grasp of what is happening in the View. In addition, while the View still renders in Blend, the animations don’t fire, so I’m unable to test and refine them. Because I’m trying to create a common animation for each of my cover views, I’ve had to resort to creating a TestAnimation user control where I can use the tools to develop the animation I want, before copying the resource to my shared ResourceDictionary. Each of the cover views is a different size, so I can’t take advantage of FrameworkElement.Width, and I have to use RenderTransforms instead.


I wonder if my objections to this approach are petty and over-thought. This solution doesn’t feel right, but it will work for the time being. As I learn more about WPF, I’ll refine my understanding of what the pluses and minuses of this approach are.


Download Project

19 August, 2010

Now Playing with MVVM – Replicating the Zune Now Playing layout

This is part 4 of a series of posts in which I attempt to reproduce the Zune Now Playing interface using the MVVM pattern within WPF. An introduction to the series and table of contents can be found in the first post of this series.

In the previous postings I’ve assembled the infrastructure (however simplistic) that will help me reconstruct the Zune Now Playing interface. The plumbing I have in place so far has a lot of shortcomings, but I’m ready to put them behind me for now and focus on the layout for a bit. So the first order of business is to analyze the Zune software to see how they organize the covers. There is a pattern to the layout, which I’ve outlined below.

ZuneNowPlayingTemplateTrace

As you can see, the interface is made up of a collection of templates that overlap, giving it a random feel. With this information, I can lay out the interface by creating a new view that hosts 49 individual cover views of varying sizes.

ZuneTemplateSkeleton

These cover views are arranged in a parent grid by setting the margins for each one individually.

<Grid x:Name="LayoutRoot">
<Views:LargeCover Margin="0,0,0,0" />
<Views:SmallCover Margin="0,280,0,0" />
<Views:SmallCover Margin="70,280,0,0" />
<Views:SmallCover Margin="140,280,0,0" />
<Views:SmallCover Margin="210,280,0,0" />
<Views:SmallCover Margin="0,350,0,0" />
<Views:SmallCover Margin="70,350,0,0" />
...



The interface is still Blendable, which gives me the opportunity to see how the albums line up.


BlendableCoverTemplate



To get a better feel for how the templates are going to come together, I can replace the covers on the MainWindow from previous postings with a couple of these new CoverTemplateViews.


MainWindowTemplated



Sweet. The UI is beginning to take shape, but it also creates a few //TODO items for me.



  • Now that I’m working with larger surface areas, I’ll need some more sample data. I need to be sure that the covers are evenly distributed and changed randomly. I’d also like to introduce song data into the model for future use.
  • The Zune software is resizable, and allows the user to maximize to a single monitor. Since I won’t know the end user’s screen resolution ahead of time, I’ll need to dynamically assemble these CoverTemplateViews inside a host container at runtime.
  • The cover transitions in the Zune software are smooth and buttery. I need to work on the transition animations for my implementation.
  • The Zune software has a nice looking overlay that tints the covers. The overlay is radial, and moves around a bit.

Download Project

03 August, 2010

Taking WPF for a ride – Now Playing with MVVM

This is the first in what I plan to be a multi-part series on my experiences with getting started in WPF development using the MVVM platform. In this series of posts I will aim to reproduce the Now Playing screen of the Zune software, pictured below.
Zune - Now Playing
I think the Zune software’s Now Playing screen lends itself well to this type of experiment. It offers a chance to play with:
  • Complex Layout – figuring out how to organize the album covers should prove to be an interesting challenge.
  • MVVM and Data binding – what will the best approach be for binding a collection of albums to my interface?
  • Animations – album cover transitions and the colored overlay
  • Efficiency concerns – how can I manage all those image assets without consuming an inordinate amount of memory?

I plan to blog while I develop the application, so I expect my implementation to go through a number of changes. Because of this approach, some of the code I produce along the way will not be best-in-class, and some of the technical approaches will probably change. The idea is to document the journey, not to take a position on what the best approach may be. I’m learning as I go…

Ok, enough lead in, let’s get to it.

 

Table of contents