Silverlight3D 墙效果
效果图:

C#(xaml)
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace Silverlight3D
{
public class Panel3D : Panel
{
private Point mouseStart, mouseNow;
private double destinationDistance = 800;
public enum AlignmentOptions { Left, Center, Right };
private const double MouseWheelScaleFactor = 2.5;
private const double Easing = 0.3;
private const double MaximumDistance = 3000;
private const double MinimumDistance = 200;
private const double MouseEasing = 0.03;
#region Dependency Properties
public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.RadiusChanged));
public static readonly DependencyProperty AngleItemProperty = DependencyProperty.Register("AngleItem", typeof(double), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.AngleItemChanged));
public static readonly DependencyProperty InitialAngleProperty = DependencyProperty.Register("InitialAngle", typeof(double), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.InitialAngleChanged));
public static readonly DependencyProperty AlignProperty = DependencyProperty.Register("Align", typeof(AlignmentOptions), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.AlignChanged));
public static readonly DependencyProperty IsDragOnProperty = DependencyProperty.Register("IsDragOn", typeof(bool), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.IsDragChanged));
public static readonly DependencyProperty OffsetYProperty = DependencyProperty.Register("OffsetY", typeof(double), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.OffsetYChanged));
public static readonly DependencyProperty DistanceProperty = DependencyProperty.Register("Distance", typeof(double), typeof(CircularPanel3D), new PropertyMetadata(CircularPanel3D.DistanceChanged));
private static void RadiusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CircularPanel3D)sender).Refresh(); }
private static void AngleItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CircularPanel3D)sender).Refresh(); }
private static void InitialAngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CircularPanel3D)sender).Refresh(); }
private static void AlignChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CircularPanel3D)sender).Refresh(); }
private static void IsDragChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CircularPanel3D)sender).OnIsDragChanged(e); }
private static void OffsetYChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CircularPanel3D)sender).Refresh(); }
private static void DistanceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
CircularPanel3D circularPanel3D = (CircularPanel3D)sender;
circularPanel3D.destinationDistance = (double)e.NewValue;
circularPanel3D.Refresh();
}
[Category("Circular Panel 3D")]
public double Radius
{
get { return (double)this.GetValue(CircularPanel3D.RadiusProperty); }
set { this.SetValue(CircularPanel3D.RadiusProperty, value); }
}
[Category("Circular Panel 3D")]
public double AngleItem
{
get { return (double)this.GetValue(CircularPanel3D.AngleItemProperty); }
set { this.SetValue(CircularPanel3D.AngleItemProperty, value); }
}
[Category("Circular Panel 3D")]
public double InitialAngle
{
get { return (double)this.GetValue(CircularPanel3D.InitialAngleProperty); }
set { this.SetValue(CircularPanel3D.InitialAngleProperty, value); }
}
[Category("Circular Panel 3D")]
public AlignmentOptions Align
{
get { return (AlignmentOptions)this.GetValue(CircularPanel3D.AlignProperty); }
set { this.SetValue(CircularPanel3D.AlignProperty, value); }
}
[Category("Circular Panel 3D")]
public bool IsDragOn
{
get { return (bool)this.GetValue(CircularPanel3D.IsDragOnProperty); }
set { this.SetValue(CircularPanel3D.IsDragOnProperty, value); }
}
[Category("Circular Panel 3D")]
public double OffsetY
{
get { return (double)this.GetValue(CircularPanel3D.OffsetYProperty); }
set { this.SetValue(CircularPanel3D.OffsetYProperty, value); }
}
[Category("Circular Panel 3D")]
public double Distance
{
get { return (double)this.GetValue(CircularPanel3D.DistanceProperty); }
set { this.SetValue(CircularPanel3D.DistanceProperty, value); }
}
#endregion
#region Dependency Property Events
private void OnIsDragChanged(DependencyPropertyChangedEventArgs e)
{
this.CaptureMouse();
this.MouseLeftButtonDown += new MouseButtonEventHandler(this.CircularPanel3D_MouseLeftButtonDown);
this.MouseLeftButtonUp += new MouseButtonEventHandler(this.CircularPanel3D_MouseLeftButtonUp);
}
#endregion
#region Mouse Interaction
private void CircularPanel3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.CaptureMouse();
this.mouseStart = e.GetPosition(this);
this.mouseNow = this.mouseStart;
CompositionTarget.Rendering += this.ApplyRotationFromMouseMove;
this.MouseMove += new MouseEventHandler(this.CircularPanel3D_MouseMove);
}
private void CircularPanel3D_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
this.ReleaseMouseCapture();
this.MouseMove -= new MouseEventHandler(this.CircularPanel3D_MouseMove);
}
// Updates mouse position when mouse moves
private void CircularPanel3D_MouseMove(object sender, MouseEventArgs e)
{
CompositionTarget.Rendering += this.ApplyRotationFromMouseMove;
this.mouseNow = e.GetPosition(this);
}
private void HandleMouseWheel(object sender, MouseWheelEventArgs e)
{
double newDistance = this.destinationDistance + CircularPanel3D.MouseWheelScaleFactor * -e.Delta;
if (newDistance <= CircularPanel3D.MaximumDistance &&
newDistance >= CircularPanel3D.MinimumDistance)
{
this.destinationDistance += CircularPanel3D.MouseWheelScaleFactor * -e.Delta;
}
}
private void ApplyZoomDistanceAnimation(object sender, EventArgs e)
{
if (Math.Abs(this.Distance - destinationDistance) < 1)
{
this.Distance = destinationDistance;
}
this.Distance += (destinationDistance - this.Distance) * CircularPanel3D.Easing;
if (this.Distance > CircularPanel3D.MaximumDistance)
{
this.destinationDistance = CircularPanel3D.MaximumDistance;
}
else if (this.Distance < CircularPanel3D.MinimumDistance)
{
this.destinationDistance = CircularPanel3D.MinimumDistance;
}
}
#endregion
#region Custom Panel Methods
protected override Size MeasureOverride(Size availableSize)
{
this.MouseWheel += this.HandleMouseWheel;
CompositionTarget.Rendering += this.ApplyZoomDistanceAnimation;
Size resultSize = new Size(0, 0);
foreach (UIElement child in this.Children)
{
child.Measure(availableSize);
resultSize.Width = Math.Max(resultSize.Width, child.DesiredSize.Width);
resultSize.Height = Math.Max(resultSize.Height, child.DesiredSize.Height);
}
resultSize.Width =
double.IsPositiveInfinity(availableSize.Width) ?
resultSize.Width : availableSize.Width;
resultSize.Height =
double.IsPositiveInfinity(availableSize.Height) ?
resultSize.Height : availableSize.Height;
return resultSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
this.Refresh();
return base.ArrangeOverride(finalSize);
}
#endregion
#region Programmatic Animation Methods
private void ApplyRotationFromMouseMove(object sender, EventArgs e)
{
// Rotates Circular Panel 3D using MouseMove (X)
if (Math.Abs(this.mouseNow.X - this.mouseStart.X) < 1)
{
this.mouseNow.X = this.mouseStart.X;
}
this.InitialAngle += ((this.mouseNow.X - this.mouseStart.X) * CircularPanel3D.MouseEasing) / 2.2;
this.mouseStart.X += ((this.mouseNow.X - this.mouseStart.X) * CircularPanel3D.MouseEasing);
if ((Math.Abs(this.mouseNow.X - this.mouseStart.X) < 1))
{
CompositionTarget.Rendering -= this.ApplyRotationFromMouseMove;
}
}
private void Refresh()
{
int count = 0;
int col = 0;
int row = 0;
int zLevel = 0;
foreach (FrameworkElement childElement in this.Children)
{
double angle = (this.AngleItem * count++) - this.InitialAngle;
double x = this.Radius * Math.Cos(Math.PI * angle / 180);
double z = this.Radius * Math.Sin(Math.PI * angle / 180);
PlaneProjection projection = new PlaneProjection();
if (projection != null)
{
projection.CenterOfRotationX = 0.5;
projection.CenterOfRotationY = 0.5;
projection.CenterOfRotationZ = 0.5;
projection.RotationY = angle + 90;
projection.GlobalOffsetX = x;
projection.GlobalOffsetZ = z - this.Distance;
projection.GlobalOffsetY = row * (-330) + this.OffsetY;
}
int depth = (int)(z * 100);
double pDist = (this.Distance - 1000) / 2000;
double pZ = ((z + 1000) / 2000) + 0.5;
double opacity = (pZ - pDist) + 0.4;
if (opacity >= 1)
{
childElement.Opacity = (2 - opacity);
}
else if (opacity < 0)
{
childElement.Opacity = 0;
}
else
{
childElement.Opacity = opacity;
}
// Variable zLevel changes value of ZIndex for each item in the ListBox.
// This way the reflex of elements at the top will be placed behind the item below it.
Canvas.SetZIndex(childElement, depth-(++zLevel*10));
double alignX = 0;
double alignY = 0;
switch (this.Align)
{
case AlignmentOptions.Left:
alignX = 0;
alignY = 0;
break;
case AlignmentOptions.Center:
alignX = childElement.DesiredSize.Width / 2;
alignY = childElement.DesiredSize.Height / 2;
break;
case AlignmentOptions.Right:
alignX = childElement.DesiredSize.Width;
alignY = childElement.DesiredSize.Height;
break;
}
childElement.Projection = projection;
childElement.Arrange(new Rect(this.Width / 2 - alignX , this.Height / 2 - alignY, childElement.DesiredSize.Width, childElement.DesiredSize.Height));
col++;
if (col > 14)
{
col = 0;
row++;
}
}
}
#endregion
}
}
浙公网安备 33010602011771号