最近在做一个SilverLight项目,两个屏幕面板切换(比如从一个Grid切换到另一个Grid)时需要用到3D旋转的方式,部分文字、按钮切换时也要用到3D旋转的方式,刚开始看到这样需求的时候,自然而然的想到了用storyboard来做动画,于是开始动起手来画,研究了一阵3D旋转的方式,画出了第一个面板的3D左切换方式,但随之而来的问题让人头疼,不光有右、上、下的不同甚至随机的切换方式,还有不同控件、动画速度等需要控制,用动画的方式做出来似乎程序的伸缩很小,也不是太方便,于是有了写一个实现这样功能的类来用的想法,日后如果碰到需要这类功能的需要还可以重复使用。

  用了一天来写代码并测试,感觉还算可以,写代码时用了几种Timer来尝试控制动画,包括使用Thread,发现还是用storyboard来做Timer比较合适,没有过多的限制和线程外控件等问题,所以类中的动画主要用了两个storyboard来做Timer,分别控控制一进一出,实现动画则用PlaneProjection类来控制。3D旋转的主要实现方法是对PlaneProjection类的LocalOffsetZ和GlobalOffsetZ属性值进行正确的设置,左右旋转时LocalOffsetZ设置为控件的Widh/2,上下旋转则为Height/2,GlobalOffsetZ设置为相应的负值,也就是GlobalOffsetZ=-LocalOffsetZ,如果不写这句,控件会被拉伸大一截,要加上这一句花了我好长时间在HELP看了老半天,其次就是RotationX和RotationY的角度设置问题,弄清楚后就基本可以写完成了。

      找到了个可以上传XAP在线演示的地方,大家可以先看看在线演示,地址: http://www.bbniu.com/matrix/ShowApplication.aspx?id=122

  下面是类代码,大家可以把类引用到工程里或者是编译成DLL引用,后面还写了一个基本的应用例子:

应用图例:

         

-----------------类代码(c3dplane.cs)------------------------------------------------

 

 

c3dplane.cs代码
/*
* 大家共同交流,共同进步
* QQ:16277488
* MAIL:fanxiaokaitp@163.com
*
*
*/

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace c3dplane
{
public enum enumDirection
{
Up, Down, Left, Right
};
public class cShow3DPlane
{
public cShow3DPlane()
{
m_IsMoveOverIn
= true;
m_IsMoveOverOut
= true;

m_MoveSpeed
= 2;

sbTimeIn
= new Storyboard();
sbTimeOut
= new Storyboard();
SetTime(
10, 10);
sbTimeIn.Completed
+= new EventHandler(sbTimeIn_Completed);
sbTimeOut.Completed
+= new EventHandler(sbTimeOut_Completed);
}

private int m_TimeSpeed1, m_TimeSpeed2,m_MoveSpeed,m_PlaneSpeed,m_InEnd,m_OutEnd;
private double m_InLocalZ,m_OutLocalZ;
private PlaneProjection m_pInPlane,m_pOutPlane;
private Storyboard sbTimeIn, sbTimeOut;
private enumDirection m_Direction;
private bool m_IsMoveOverIn,m_IsMoveOverOut;

//根据方向初始化两个planeProjection的相关值
private void InitPlaneData()
{
m_pInPlane.RotationX
= 0;
m_pInPlane.RotationY
= 0;
m_pInPlane.RotationZ
= 0;
m_pInPlane.CenterOfRotationX
= 0.5;
m_pInPlane.CenterOfRotationY
= 0.5;
m_pInPlane.CenterOfRotationZ
= 0;

m_pOutPlane.RotationX
= 0;
m_pOutPlane.RotationY
= 0;
m_pOutPlane.RotationZ
= 0;
m_pOutPlane.CenterOfRotationX
= 0.5;
m_pOutPlane.CenterOfRotationY
= 0.5;
m_pOutPlane.CenterOfRotationZ
= 0;

m_pOutPlane.LocalOffsetZ
= m_OutLocalZ;
m_pOutPlane.GlobalOffsetZ
= -m_OutLocalZ;
m_pInPlane.LocalOffsetZ
= m_InLocalZ;
m_pInPlane.GlobalOffsetZ
= -m_InLocalZ;
switch (m_Direction)
{
case enumDirection.Up:
m_pInPlane.RotationX
= -90;
m_InEnd
= 0;

m_pOutPlane.RotationX
= 0;
m_OutEnd
= 90;

m_PlaneSpeed
= m_MoveSpeed;
break;
case enumDirection.Down:
m_pInPlane.RotationX
= 90;
m_InEnd
= 0;

m_pOutPlane.RotationX
= 0;
m_OutEnd
= -90;

m_PlaneSpeed
= -m_MoveSpeed;
break;
case enumDirection.Left:
m_pInPlane.RotationY
= 90;
m_InEnd
= 0;

m_pOutPlane.RotationY
= 0;
m_OutEnd
= -90;

m_PlaneSpeed
= -m_MoveSpeed;

break;
case enumDirection.Right:
m_pInPlane.RotationY
= -90;
m_InEnd
= 0;

m_pOutPlane.RotationY
= 0;
m_OutEnd
= 90;

m_PlaneSpeed
= m_MoveSpeed;
break;
}
}
public void Begin()
{

m_IsMoveOverIn
= false;
m_IsMoveOverOut
= false;

sbTimeIn.Begin();
sbTimeOut.Begin();
}
//设置进入和离开对象
public void SetInOutPlane(Grid gridIn, Grid gridOut, enumDirection eDirection)
{
m_pInPlane
= new PlaneProjection();
m_pOutPlane
= new PlaneProjection();

gridIn.Projection
= m_pInPlane;
gridOut.Projection
= m_pOutPlane;
if (eDirection == enumDirection.Left || eDirection == enumDirection.Right)
{
m_InLocalZ
= gridIn.ActualWidth / 2;
m_OutLocalZ
= gridOut.ActualWidth / 2;
}
else
{
m_InLocalZ
= gridIn.ActualHeight / 2;
m_OutLocalZ
= gridOut.ActualHeight / 2;
}
m_Direction
= eDirection;
InitPlaneData();
}
//重载
public void SetInOutPlane(Control controlIn, Control controlOut, enumDirection eDirection)
{
m_pInPlane
= new PlaneProjection();
m_pOutPlane
= new PlaneProjection();

controlIn.Projection
= m_pInPlane;
controlOut.Projection
= m_pOutPlane;

if (eDirection == enumDirection.Left || eDirection == enumDirection.Right)
{
m_InLocalZ
= controlIn.ActualWidth / 2;
m_OutLocalZ
= controlOut.ActualWidth / 2;
}
else
{
m_InLocalZ
= controlIn.ActualHeight / 2;
m_OutLocalZ
= controlOut.ActualHeight / 2;
}

m_Direction
= eDirection;

InitPlaneData();
}
public bool MoveOver()
{
if (!m_IsMoveOverIn || !m_IsMoveOverOut)
return false;
else
return true;

}
//设置进入和离开动画的速度
public void SetTime(int timeSpeed1, int timeSpeed2)
{
m_TimeSpeed1
= timeSpeed1;
m_TimeSpeed2
= timeSpeed2;
sbTimeIn.Duration
= new Duration(TimeSpan.FromMilliseconds(m_TimeSpeed1));
sbTimeOut.Duration
= new Duration(TimeSpan.FromMilliseconds(m_TimeSpeed2));
}
//离开对象的动画
void sbTimeOut_Completed(object sender, EventArgs e)
{
//throw new NotImplementedException();
if (m_Direction == enumDirection.Left || m_Direction == enumDirection.Right)
{
m_pOutPlane.RotationY
+= m_PlaneSpeed;
if (m_pOutPlane.RotationY == m_OutEnd) m_IsMoveOverOut = true;
}
if (m_Direction == enumDirection.Up || m_Direction == enumDirection.Down)
{
m_pOutPlane.RotationX
+= m_PlaneSpeed;
if (m_pOutPlane.RotationX == m_OutEnd) m_IsMoveOverOut = true;
}

if (!m_IsMoveOverOut)
sbTimeOut.Begin();
else
{
m_pOutPlane.LocalOffsetZ
= 0;
m_pOutPlane.GlobalOffsetZ
= 0;
}
}
//进入对象的动画
void sbTimeIn_Completed(object sender, EventArgs e)
{
//throw new NotImplementedException();
if (m_Direction == enumDirection.Left || m_Direction == enumDirection.Right)
{
m_pInPlane.RotationY
+= m_PlaneSpeed;
if (m_pInPlane.RotationY == m_InEnd) m_IsMoveOverIn = true;
}
if (m_Direction == enumDirection.Up || m_Direction == enumDirection.Down)
{
m_pInPlane.RotationX
+= m_PlaneSpeed;
if (m_pInPlane.RotationX == m_InEnd) m_IsMoveOverIn = true;
}
if (!m_IsMoveOverIn)
sbTimeIn.Begin();
else
{
m_pInPlane.LocalOffsetZ
= 0;
m_pInPlane.GlobalOffsetZ
= 0;
}
}
}
}

 

 

 

 

 

下面是应用例子:

 

-----------------(MainPage.xaml)------------------------------------------------

 

MainPage.xaml代码
<UserControl x:Class="_3dPlaneTest.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable
="d"
d:DesignHeight
="480" d:DesignWidth="640">

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition ></RowDefinition>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>

<Grid Grid.Row="0" Grid.Column="0">
<Button x:Name="btnUp" Content="" VerticalAlignment="Top" HorizontalAlignment="Center" Width="200" Margin="20" Click="btnUp_Click"></Button>
<Button x:Name="btnDown" Content="" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="200" Margin="20" Click="btnDown_Click"></Button>
<Button x:Name="btnLeft" Content="" VerticalAlignment="Center" HorizontalAlignment="Left" Height="200" Margin="20" Click="btnLeft_Click"></Button>
<Button x:Name="btnRight" Content="" VerticalAlignment="Center" HorizontalAlignment="Right" Height="200" Margin="20" Click="btnRight_Click"></Button>
<Grid x:Name="gridUp" Background="Red" Width="200" Height="100">
<TextBlock Text="这是上喔" Foreground="White" VerticalAlignment="Top" HorizontalAlignment="Center"/>
</Grid>
<Grid x:Name="gridDown" Background="Green" Width="200" Height="100">
<TextBlock Text="这是下喔" Foreground="White" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</Grid>
<Grid x:Name="gridLeft" Background="Blue" Width="200" Height="100">
<TextBlock Text="这是左喔" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Grid>
<Grid x:Name="gridRight" Background="Cornsilk" Width="200" Height="100">
<TextBlock Text="这是右喔" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Right"/>

</Grid>
</Grid>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition ></RowDefinition>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button x:Name="btnTest1" Content="QQ:16277488,返回了" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest1_Click"></Button>
<Button x:Name="btnTest2" Content="这是测试控件旋转" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest2_Click"></Button>
<Button x:Name="btnTest3" Content="mail:fanxiaokaitp@163.com,返回了" Grid.Row="1" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest3_Click"></Button>
<Button x:Name="btnTest4" Content="这也是测试控件旋转" Grid.Row="1" Width="220" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnTest4_Click"></Button>
</Grid>

</Grid>
</UserControl>

 

 

 

 

-----------------(MainPage.xaml.cs)------------------------------------------------

 

MainPage.xaml.cs代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using c3dplane;

namespace _3dPlaneTest
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();

PlaneProjection pp
= new PlaneProjection();
pp.RotationY
= 90;
gridUp.Projection
= pp;
gridDown.Projection
= pp;
gridLeft.Projection
= pp;

gridCur
= gridRight;
}

private cShow3DPlane c3d=new cShow3DPlane();
private Grid gridCur=new Grid();

private void btnUp_Click(object sender, RoutedEventArgs e)
{
if (gridCur ==gridUp ) { MessageBox.Show("现在已经是 上 了"); return; }
if (c3d.MoveOver())
{
c3d.SetInOutPlane(gridUp, gridCur, enumDirection.Up);
gridCur
= gridUp;
c3d.Begin();
}
}
private void btnRight_Click(object sender, RoutedEventArgs e)
{
if (gridCur == gridRight) { MessageBox.Show("现在已经是 右 了"); return; }
if (c3d.MoveOver())
{
c3d.SetInOutPlane(gridRight, gridCur, enumDirection.Right);
gridCur
= gridRight;
c3d.Begin();
}
}
private void btnLeft_Click(object sender, RoutedEventArgs e)
{
if (gridCur == gridLeft) { MessageBox.Show("现在已经是 左 了"); return; }
if (c3d.MoveOver())
{
c3d.SetInOutPlane(gridLeft, gridCur, enumDirection.Left);
gridCur
= gridLeft;
c3d.Begin();
}
}
private void btnDown_Click(object sender, RoutedEventArgs e)
{
if (gridCur == gridDown) { MessageBox.Show("现在已经是 下 了"); return; }
if (c3d.MoveOver())
{
c3d.SetInOutPlane(gridDown, gridCur, enumDirection.Down);
gridCur
= gridDown;
c3d.Begin();
}
}
private void btnTest2_Click(object sender, RoutedEventArgs e)
{
if (c3d.MoveOver())
{
c3d.SetInOutPlane(btnTest1, btnTest2, enumDirection.Left);
c3d.Begin();
}
}
private void btnTest1_Click(object sender, RoutedEventArgs e)
{
if (c3d.MoveOver())
{
c3d.SetInOutPlane(btnTest2, btnTest1, enumDirection.Right);
c3d.Begin();
}
}
private void btnTest3_Click(object sender, RoutedEventArgs e)
{
if (c3d.MoveOver())
{
c3d.SetInOutPlane(btnTest4, btnTest3, enumDirection.Up);
c3d.Begin();
}
}
private void btnTest4_Click(object sender, RoutedEventArgs e)
{
if (c3d.MoveOver())
{
c3d.SetInOutPlane(btnTest3, btnTest4, enumDirection.Down);
c3d.Begin();
}
}


}
}

 

 

 

 

以上是类和应用代码。

posted on 2010-05-21 01:11  ~范晓凯~  阅读(3270)  评论(7编辑  收藏  举报