首先上效果圖:
因項目要求,需要把圖片以“好看”、“炫”的效果展示出來,特地研究了一下WPF關於3D方面的制作,奈何最終成果只是能夠畫出一個立方體並使之旋轉。
項目時間僅剩兩天,只好放棄3D另找出路,於是就想起了Flash中各種“炫麗”的動畫效果,圖片按橢圓排列,並且旋轉。
於是開始代碼,然后發現關於橢圓啊、正玄余玄、x,y,r等等數學知識都忘得光光了,僅有思路沒有進展,無奈之下開始百度惡補數學知識。圖形變換、3D是很考驗數學知識的,本人對於3D方面的學習就敗在數學之下,高中數學學的還不錯的,現在……哎,不提也罷。
然后找到這么一篇博文——javascript-按圓形排列DIV元素(三)實例---- 圖片按橢圓形轉動,是js代碼,在此感謝這位船長op大大的無私奉獻。
下面正式上代碼:
定義ImageInfo類,實現INotifyPropertyChanged接口,屬性沒有寫說明,不過看名稱我想各位也能知道是什么含義了。

public class ImageInfo : INotifyPropertyChanged { private int _zIndex; public int ZIndex { get { return _zIndex; } set { if (value != _zIndex) { _zIndex = value; this.NotifyPropertyChanged("ZIndex"); } } } private double _left; public double Left { get { return _left; } set { if (value != _left) { _left = value; this.NotifyPropertyChanged("Left"); } } } private double _top; public double Top { get { return _top; } set { if (value != _top) { _top = value; this.NotifyPropertyChanged("Top"); } } } private double _width; public double Width { get { return _width; } set { if (value != _width) { _width = value; this.NotifyPropertyChanged("Width"); } } } private double _height; public double Height { get { return _height; } set { if (value != _height) { _height = value; this.NotifyPropertyChanged("Height"); } } } private double _opacity = 1.0; public double Opactity { get { return _opacity; } set { if (value != _opacity) { _opacity = value; this.NotifyPropertyChanged("Opactity"); } } } private string _imagePath; public string ImagePath { get { return _imagePath; } set { if (value != _imagePath) { _imagePath = value; this.NotifyPropertyChanged("ImagePath"); } } } public ImageInfo(string path) { this.ImagePath = path; } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (null != handler) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
在xaml中binding ImageInfo 中的對應的屬性,在后台代碼中使用計時器來定時更改ImageInfo中的屬性,當屬性值發生改變時就會通知到界面,於是就實現了動畫效果了。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WPF_ImageShow" x:Class="WPF_ImageShow.MainWindow" Title="MainWindow" Height="600" Width="800" > <Window.Resources> <local:DoubleConverter x:Key="doubleConverter"/> </Window.Resources> <Grid> <ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" Loaded="lv_Loaded" ScrollViewer.VerticalScrollBarVisibility="Disabled" x:Name="lv" Background="Black"> <!--<ListView.ItemTemplate> <DataTemplate> <Border> <StackPanel> <Image Source="{Binding ImagePath, Mode=OneWay}" x:Name="img" Stretch="UniformToFill" Width="{Binding Width, Mode=OneWay}" Height="{Binding Height, Mode=OneWay}"/> <Rectangle RenderTransformOrigin="1,0.5" Height="{Binding Height, Converter={StaticResource doubleConverter}, Mode=OneWay}"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=img}" /> </Rectangle.Fill> <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform ScaleY="-1" /> </TransformGroup> </Rectangle.RenderTransform> <Rectangle.OpacityMask> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Offset="0.3" Color="Transparent" /> <GradientStop Offset="1" Color="#44000000" /> </LinearGradientBrush> </Rectangle.OpacityMask> </Rectangle> </StackPanel> </Border> </DataTemplate> </ListView.ItemTemplate>--> <ListView.Resources> <Style TargetType="{x:Type ListViewItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListViewItem}" > <Border> <StackPanel> <Image Source="{Binding ImagePath, Mode=OneWay}" x:Name="img" Stretch="UniformToFill" Width="{Binding Width, Mode=OneWay}" Height="{Binding Height, Mode=OneWay}"/> <Rectangle RenderTransformOrigin="1,0.5" Height="{Binding Height, Converter={StaticResource doubleConverter}, Mode=OneWay}"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=img}" /> </Rectangle.Fill> <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform ScaleY="-1" /> </TransformGroup> </Rectangle.RenderTransform> <Rectangle.OpacityMask> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Offset="0.3" Color="Transparent" /> <GradientStop Offset="1" Color="#44000000" /> </LinearGradientBrush> </Rectangle.OpacityMask> </Rectangle> </StackPanel> </Border> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="Opacity" Value="{Binding Opactity, Mode=OneWay}"/> <Setter Property="Canvas.Left" Value="{Binding Left, Mode=OneWay}"/> <Setter Property="Canvas.Top" Value="{Binding Top, Mode=OneWay}"/> <Setter Property="Panel.ZIndex" Value="{Binding ZIndex, Mode=OneWay}"/> </Style> </ListView.Resources> <ListView.ItemsPanel> <ItemsPanelTemplate> <Canvas/> </ItemsPanelTemplate> </ListView.ItemsPanel> </ListView> </Grid> </Window>

/// <summary> /// 設置動畫 /// </summary> void Run() { //動畫速率 double speed = 0.0; //定時器,定時修改ImageInfo中各屬性,從而實現動畫效果 DispatcherTimer timer = new DispatcherTimer(); //時間間隔 timer.Interval = TimeSpan.FromMilliseconds(100); timer.Tick += (ss, ee) => { #region //設置圓心x,y double centerX = this.ActualWidth / 2; double centerY = this.ActualHeight / 2 - 50;//減去適當的值,因為會設置最下面的圖片最大,上面的圖片較小 //設置圖片最大的寬、高 double maxWidth = 300; double maxHeight = 200; //設置橢圓的長邊和短邊 double a = centerX - maxWidth / 2.0; double b = centerY - maxHeight / 2.0; //運動一周后恢復為0 speed = speed < 360 ? speed : 0.0; //運運的速度 此“增值”和 timer.Interval對動畫的流暢性有影響 speed += 0.5; //運動距離,即運動的弧度數; var ainhd = speed * Math.PI / 180; //每個圖片之間相隔的角度 var angle = (360.0 / data.Count) * Math.PI / 180.0; //圖片序號 int index = 0; foreach (var img in data) { //最下面一張圖ZIndex最大,Opacity最大,長寬最大 img.ZIndex = (int)img.Top; //當前圖片與最下面一張圖片的Y的比值 var allpers = img.Top / (centerY + b); //不要小於0.2,太小了就看不見了,可以適當調整 allpers = Math.Max(0.2, allpers); //設置圖片大小 img.Width = allpers * maxWidth; img.Height = allpers * maxHeight; //設置透明度 img.Opactity = Math.Max(allpers * 1.5, 0.4); //公式:x=sin * a //+ centerX因為默認wpf默認左上角為坐標原點;//- img.Width / 2.0是以圖片中心點作為運動軌跡 img.Left = Math.Sin((angle * index + ainhd)) * a + centerX - img.Width / 2.0;//x=sin * a //y=cos * b img.Top = Math.Cos((angle * index + ainhd)) * b + centerY - img.Height / 2.0; index++; } #endregion }; //啟動計時器,開始動畫 timer.Start(); } private void lv_Loaded(object sender, RoutedEventArgs e) { //准備數據源 ObservableCollection<T> data = new ObservableCollection<ImageInfo>(); //獲取程序所在目錄中的images文件夾 DirectoryInfo di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "images"); //添加此目錄中的圖片文件到data中 foreach (var file in di.GetFiles()) { //驗證是否為圖片文件 (可以寫一個方法來進行驗證,此處僅支持jpg和png) if (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png") { data.Add(new ImageInfo(file.FullName)); } } //設置ListView的ItemsSource lv.ItemsSource = data; Run(); }
最后上一個簡單的Demo:WPF_ImageShow