Home » Source Code » WPF 3D Tab Carousel

WPF 3D Tab Carousel

2015-02-10 04:47:03
The author
Download(s): 0
Point (s): 1 
Category Category:
WindowsWindows OthersOthers


1) tabToIndex = tabs.Count - 1; } // Unhook from visual tree if required because // a Visual cannot have to parents foreach (Tab owner in (from tab in tabs where tab.Element == elements[instruction.To] || tab.Element == elements[instruction.From] select tab)) owner.Element = null; // Make sure the current tab contains the From element tabs[currentTabIndex].Element = elements[instruction.From]; tabs[currentTabIndex].UpdateTransform(currentTabIndex, angle, CalculateRadius()); // Make sure the target tab contains the To element, // this is what allows less tab panels than elements tabs[tabToIndex].Element = elements[instruction.To]; tabs[tabToIndex].UpdateTransform(tabToIndex, angle, CalculateRadius()); isAnimating = true; // The angles of the carousel for the from and to tabs double fromAngle = currentTabIndex * angle; double toAngle = tabToIndex * angle; // If this is a wrapping spin add/remove // a full lap otherwise the animation // would run backwards for these cases if (wrapIt) { if (instruction.To == 0) toAngle += 360; if (instruction.To == elements.Count - 1) toAngle -= 360; } // If this is spinning to a later element, // but the tab index is less than the current tab index, add a lap if (instruction.To - instruction.From > 0 && tabToIndex < currentTabIndex) toAngle += 360; // If this is spinning to a earlier element, // but the tab index is greater than the // current tab index, subtract a lap if (instruction.To - instruction.From < 0 && tabToIndex > currentTabIndex) toAngle -= 360; CreateSpinAnimation(instruction, tabToIndex, fromAngle, toAngle); }
TheCreateSpinAnimationis responsible for creating the actual animations and callingAnimateagain when the spin animation has completed.

Mid-rotation with the FlipIt flag set to true.
Calculating camera distance

In the code above, the camera distance is calculated on a tab-per-tab basis. This is because although the tabs themselves will scale to the correct aspect ratio, there's also the issue with size on screen. If, for example, a user control was designed to be displayed in 300x400, it's not enough to create a 3D box 300 wide and 400 tall, because one set of units (the first) are in pixels and the second is unit less. It's just distance in 3D, not pixels. Therefore, theCarouselhas to calculate the distance from the panel that the camera has to be at in order for the UI element to be rendered correctly. This also depends on the size of theViewport3Dcontaining all the elements.
Basically, it looks something like this:

And, in math terms: solve the distance y, where y is one leg of a square triangle made up of y itself, 0.5 (half the 3D panel width), and the hypotenuse is formed by extending the camera's field of view (or half field of view). Since we don't know the length of the hypotenuse but can figure out the angle (as it's half the field of view), we can use tan(field of view / 2.0), or in code terms:
private double CalculateCameraDistance(int index, int tabIndex)
    Tab tab = tabs[tabIndex]; double y = 0.5 / Math.Tan(DegreesToRadians(MainCamera.FieldOfView / 2.0)); double panelWidth = tab.Element != null ? tab.Element.Width : 1.0; double ratio = Grid3D.ActualWidth / panelWidth; return CalculateRadius() + Math.Max(ratio, 1.0) * y;

When y is found, multiply it with the ratio between the designed UI element width and theViewport3Dcurrent width to compensate for the size of theViewport3D. And lastly, offset it by the distance of the radius of the carousel. By taking the max of 1.0 and the calculated ratio,Math.Max(ratio, 1.0), the distance will make sure the entire width of the panel is always visible, even if theViewport3Dis smaller than the designed size of the panel.
Since most WPF user controls are designed to be used inside a window or another control, their width and height cannot always be determined (hence the need for bothWidthandActualWidthproperties found on some WPF UI elements). In order for a user control to play nice with this tab control, it's therefore important to set theMinWidth,MaxWidth, andWidthat design time.
The user control

The WPF user control that implements the carousel is calledCarousel, intuitive, eh? And, as this control is mostly about rotation and camera position calculations, the XAML for it is quite simple:
<UserControl x:Class="Bornander.UI.TabCarousel.Carousel" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" SizeChanged="HandleSizeChanged"> <Grid x:Name="Grid3D" Width="Auto" Height="Auto"> <Viewport3D> <Viewport3D.Camera> <PerspectiveCamera x:Name="MainCamera" FieldOfView="90" Position="0,0,0" LookDirection="0,0,-1"/> </Viewport3D.Camera> <ModelVisual3D> <ModelVisual3D.Content> <AmbientLight x:Name="Ambient" Color="#808080"/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight x:Name="Directional" Color="#FFFFFFFF" Direction="0,-1,-1"/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D x:Name="CarouselContainer"/> </Viewport3D> </Grid> </UserControl>

The user control sets up a few things:
The camera; it's important that the position for the camera is at(0, 0, 0)in order to get the distance calculations right; also, the look direction has to be along the Z-axis.
Ambient light, so that not only surfaces hit by the directional light are visible.
Directional light; this is important as the scene looks "flat" without it.
CarouselContainer: this is just theModelVisual3Dused to hold all items in the carousel; this is what is actually being rotated when the carousel spins.
Points of interest

I could have had the definitions for the meshes in XAML as well, but I find it easier and more flexible to use code for this. The most complicated part was getting the wrapping rotation right, especially when there's less tab than there are elements in the carousel. This is because the way the rotation animation works, animating from 270 degrees to 360 is different than going from 270 to 0, which kind of makes sense, but still caused me some head aches as 360 and 0 are really the same.
As always, any comments on the code or the article are most welcome.

Sponsored links

File list

Tips: You can preview the content of files by clicking file names^_^
Name Size Date
Bornander.UI.TabCarousel.sln1.97 kB2009-12-26|13:54
01.96 kB
App.xaml313.00 B2009-12-26|13:42
App.xaml.cs331.00 B2009-12-26|13:38
Bornander.UI.TabCarousel.Test.csproj4.69 kB2010-01-01|20:45
Bornander.UI.TabCarousel.Test.csproj.user74.00 B2009-12-26|13:45
01.96 kB
LoginPanel.xaml1.98 kB2010-01-01|20:45
LoginPanel.xaml.cs200.00 B2010-01-01|20:45
MainWindow.xaml3.03 kB2010-01-01|21:24
MainWindow.xaml.cs2.98 kB2010-01-01|21:25
01.96 kB
AssemblyInfo.cs2.27 kB2009-12-26|13:38
Resources.Designer.cs2.82 kB2009-12-26|13:38
Resources.resx5.48 kB2009-12-26|13:38
Settings.Designer.cs1.09 kB2009-12-26|13:38
Settings.settings201.00 B2009-12-26|13:38
01.96 kB
Bornander.UI.TabCarousel.csproj3.46 kB2009-12-26|15:04
Carousel.xaml1.03 kB2009-12-28|19:39
Carousel.xaml.cs11.61 kB2009-12-28|20:57
01.96 kB
AssemblyInfo.cs1.43 kB2009-12-26|13:45
Tab.cs2.77 kB2009-12-28|20:34
01.96 kB
Bornander.Wpf.Meshes.csproj2.85 kB2009-12-26|14:15
Box.cs3.81 kB2009-12-26|14:47
Plane.cs1.65 kB2009-12-26|14:49
01.96 kB
AssemblyInfo.cs1.42 kB2009-12-26|13:51
Sponsored links


(Add your comment, get 0.1 Point)
Minimum:15 words, Maximum:160 words
  • 1
  • Page 1
  • Total 1

WPF 3D Tab Carousel (22.50 kB)

Need 1 Point(s)
Your Point (s)

Your Point isn't enough.

Get 22 Point immediately by PayPal

Point will be added to your account automatically after the transaction.

More(Debit card / Credit card / PayPal Credit / Online Banking)

Submit your source codes. Get more Points


Don't have an account? Register now
Need any help?
Mail to: support@codeforge.com


CodeForge Chinese Version
CodeForge English Version

Where are you going?

^_^"Oops ...

Sorry!This guy is mysterious, its blog hasn't been opened, try another, please!

Warm tip!

CodeForge to FavoriteFavorite by Ctrl+D