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
	}
}



 

posted on 2010-08-19 15:00  cnblogs2010  阅读(2097)  评论(8编辑  收藏  举报

71