We define a new assembly called FlowComponent where we will move most of the code. First, the c# code will be part of a new class called FlowControl. This class herits from UserControl :
- using[...]
- namespace Ded.Tutorial.Wpf.CoverFlow.Part5.FlowComponent
- {
- public partial class FlowControl : UserControl
- {
- #region Fields
- private int index;
- private readonly List<Cover> coverList = new List<Cover>();
- #endregion
- #region Private stuff
- private void RotateCover(int pos)[...]
- private void UpdateIndex(int newIndex)[...]
- private void viewPort_MouseDown(object sender, MouseButtonEventArgs e)[...]
- #endregion
- public FlowControl()
- {
- InitializeComponent();
- }
- public void Load(string imagePath)
- {
- coverList.Clear();
- var imageDir = new DirectoryInfo(imagePath);
- int doneImages = 0;
- foreach (FileInfo image in imageDir.GetFiles("*.jpg"))
- {
- var cover = new Cover(image.FullName, doneImages++);
- coverList.Add(cover);
- visualModel.Children.Add(cover);
- }
- }
- public void GoToNext()
- {
- if (index < coverList.Count - 1)
- UpdateIndex(index + 1);
- }
- public void GoToPrevious()
- {
- if (index > 0)
- UpdateIndex(index - 1);
- }
- }
- }
This is the same in the xaml code : we migrate the Grid (its background) and the Viewport3D to our custom UserControl :
- <UserControl x:Class="Ded.Tutorial.Wpf.CoverFlow.Part5.FlowComponent.FlowControl"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Height="282" Width="490">
- <Grid ClipToBounds="True">
- <Grid.Background[...]>
- <Viewport3D x:Name="viewPort" Grid.Column="0" Grid.Row="0" ClipToBounds="False" MouseDown="viewPort_MouseDown">
- <Viewport3D.Camera[...]>
- <Viewport3D.Children[...]>
- </Viewport3D>
- </Grid>
- </UserControl>
The Cover class is also moved to the FlowComponent assembly.
As we are creating a CoverFlow component, it is a good idea to deal with rectangle images. We update the Point3D coordinates with the ImageSource size. The ImageSource will be stored as a class attribute.
- private readonly ImageSource imageSource;
- private double RectangleDx()
- {
- if (imageSource.Width > imageSource.Height)
- return 0;
- else
- return 1 - imageSource.Width / imageSource.Height;
- }
- private double RectangleDy()
- {
- if (imageSource.Width > imageSource.Height)
- return 1 - imageSource.Height / imageSource.Width;
- else
- return 0;
- }
- private Geometry3D Tessellate()
- {
- double dx = RectangleDx();
- double dy = RectangleDy();
- var p0 = new Point3D(-1 + dx, -1 + dy, 0);
- var p1 = new Point3D(1 - dx, -1 + dy, 0);
- var p2 = new Point3D(1 - dx, 1 - dy, 0);
- var p3 = new Point3D(-1 + dx, 1 - dy, 0);
- ...
- }
- private Geometry3D TessellateMirror()
- {
- double dx = RectangleDx();
- double dy = RectangleDy();
- var p0 = new Point3D(-1 + dx, -3 + 3 * dy, 0);
- var p1 = new Point3D(1 - dx, -3 + 3 * dy, 0);
- var p2 = new Point3D(1 - dx, -1 + dy, 0);
- var p3 = new Point3D(-1 + dx, -1 + dy, 0);
- ...
- }
- public Cover(string imagePath, int pos)
- {
- ...
- imageSource = LoadImageSource(imagePath);
- ...
- }

There is nothing much left in the TestWindow class. In the xaml code, after we've referenced our component assembly, we just use our FlowControl as main Content :
- <Window x:Class="Ded.Tutorial.Wpf.CoverFlow.Part5.TestWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="WPF Coverflow" Width="512" Height="320" KeyDown="Window_KeyDown"
- xmlns:flow="clr-namespace:Ded.Tutorial.Wpf.CoverFlow.Part5.FlowComponent;assembly=Ded.Tutorial.Wpf.CoverFlow.Part5.FlowComponent">
- <flow:FlowControl x:Name="flow" Margin="0"></flow:FlowControl>
- </Window>
- using System.Windows;
- using System.Windows.Input;
- namespace Ded.Tutorial.Wpf.CoverFlow.Part5
- {
- public partial class TestWindow : Window
- {
- #region Private stuff
- private void Window_KeyDown(object sender, KeyEventArgs e)
- {
- switch (e.Key)
- {
- case Key.Right:
- flow.GoToNext();
- break;
- case Key.Left:
- flow.GoToPrevious();
- break;
- }
- }
- #endregion
- public TestWindow()
- {
- InitializeComponent();
- flow.Load(@"c:\_covers");
- }
- }
- }
Continue with Part 6.
Edit 2014-02-23 : Code has moved to github.
5 comments:
Good afternoon,
I wanted to tell you how great your blog is! I am currently learning WPF and I found your posts very useful! So thanks :)
I am now on the WPF Cover Flow Tutorial - Part 5, and I try to download the source code: http://vianney.philippe.googlepages.com/WPFCoverFlowTutorialPart5.zip
Unfortunately, the link is broken. Would you please be able to send me a new link or send me the files by email please? (inasonarmour@gmail.com)
Keep up the great job!
Thanks,
Romain
Links fixed (googlepages migration).
Hi ded, I don't understand the part where you said "We define a new assembly called FlowComponent where we will move most of the code", What kind of component I must add? Could you explain me please I can't pass to the part 5.
@Miguel The base component class is UserControl, you can download the source code at the bottom.
Post a Comment