Tuesday, April 14, 2009

WPF Cover Flow Tutorial : Part 6 (bis)

I'll start with some Cover refactoring :
  • Class becomes internal
  • I add the ICover interface, mainly for unit testing with a fake class implementing ICover :
    public interface ICover
    {
    void Animate(int index, bool animate);
    bool Matches(MeshGeometry3D mesh);
    void Destroy();
    }
  • You may notice the new Destroy method. This is useful to be able to create or destroy objects at will. Relatively, covers now know about the containing ModelVisual3D.
  • I also add a static IThumbnailManager to put elsewhere all the code dealing with thumbnails (like managing an IsolatedStorageFile for example)
  • Animation is slightly modified : in some cases, no rotation is needed to allow faster browsing.
Here are the changes since Part 5 :
public interface IThumbnailManager
{
ImageSource GetThumbnail(string host, string path);
}
internal class Cover : ModelVisual3D, ICover
{
...
private static IThumbnailManager thumbCache;
private readonly ModelVisual3D visualModel;
...
private readonly string imageName;
...
private static ImageSource LoadImageSource(ImageInfo info)
{
if (thumbCache == null)
throw new InvalidOperationException("No thumbnail cache.");
return thumbCache.GetThumbnail(info.Host, info.Path);
}
...
public Cover(ImageInfo info, int coverPos, int currentPos, ModelVisual3D model)
{
pos = coverPos;
imageName = new FileInfo(info.Path).Name;
visualModel = model;

imageSource = LoadImageSource(info);
modelGroup = new Model3DGroup();
modelGroup.Children.Add(new GeometryModel3D(Tessellate(), LoadImage(imageSource)));
modelGroup.Children.Add(new GeometryModel3D(TessellateMirror(), LoadImageMirror(imageSource)));

rotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), RotationAngle(currentPos));
translation = new TranslateTransform3D(TranslationX(currentPos), 0, TranslationZ(currentPos));
var transformGroup = new Transform3DGroup();
transformGroup.Children.Add(new RotateTransform3D(rotation));
transformGroup.Children.Add(translation);
modelGroup.Transform = transformGroup;

Content = modelGroup;

visualModel.Children.Add(this);
}
public static IThumbnailManager Cache
{
set { thumbCache = value; }
}
public void Animate(int index, bool animate)
{
if (animate || rotation.HasAnimatedProperties)
{
var rotateAnimation = new DoubleAnimation(RotationAngle(index), AnimationDuration);
var xAnimation = new DoubleAnimation(TranslationX(index), AnimationDuration);
var zAnimation = new DoubleAnimation(TranslationZ(index), AnimationDuration);
rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, rotateAnimation);
translation.BeginAnimation(TranslateTransform3D.OffsetXProperty, xAnimation);
translation.BeginAnimation(TranslateTransform3D.OffsetZProperty, zAnimation);
}
else
{
rotation.Angle = RotationAngle(index);
translation.OffsetX = TranslationX(index);
translation.OffsetZ = TranslationZ(index);
}
}
public void Destroy()
{
visualModel.Children.Remove(this);
}
public override string ToString()
{
return string.Format("{0} {1}", pos, imageName);
}
}
I also add an ICoverFactory (mainly for testing purposes) :
public interface ICoverFactory
{
ICover NewCover(string host, string path, int coverPos, int currentPos);
}
internal class ImageInfo
{
public ImageInfo(string host, string path)
{
Host = host;
Path = path;
}
public string Host { get; private set; }
public string Path { get; private set; }
}
internal class CoverFactory : ICoverFactory
{
private readonly ModelVisual3D visualModel;
public CoverFactory(ModelVisual3D visualModel)
{
this.visualModel = visualModel;
}
#region ICoverFactory Members
public ICover NewCover(string host, string path, int coverPos, int currentPos)
{
return new Cover(new ImageInfo(host, path), coverPos, currentPos, visualModel);
}
#endregion
}
The FlowControl class is greatly refactored to implement virtualization.

2 comments:

Max Khan said...

Hi , first of all great article and very well written code. I could make almost perfect sense of everything.
One question I had was if I change the angle to a negative value ( that is make the images on the sides face outwards than inwards), why does the effect break. I played around with different variables like CoverStep and angle etc.but could not make it behave like the original . Any suggestions on what should I be looking at if I want the images to be facing outwards then inwards.

Unknown said...

hi,
great job ;)

My question:

is it possible to remove the aliasing on the edges of images ?