diff --git a/Wpf_AiSportsMicrospace/Home.xaml b/Wpf_AiSportsMicrospace/Home.xaml
index cc11610..3532627 100644
--- a/Wpf_AiSportsMicrospace/Home.xaml
+++ b/Wpf_AiSportsMicrospace/Home.xaml
@@ -4,6 +4,8 @@
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
Title="CoverFlow Demo" Height="400" Width="800">
-
+
+
+
diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Home.xaml.cs
index ccf3fc3..f56b0d9 100644
--- a/Wpf_AiSportsMicrospace/Home.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Home.xaml.cs
@@ -33,8 +33,8 @@ namespace Wpf_AiSportsMicrospace
new CoverImage( System.IO.Path.Combine(albumPath, "5.jpg"), System.IO.Path.Combine(projectRoot, "Resources/Img/Badge/5.jpg")),
};
- // 设置 CoverFlow 图片
- coverFlow.SetImages(images, defaultSelectedIndex: 2);
+ // 设置 CoverFlow 图片s
+ //coverFlow.SetImages(images, defaultSelectedIndex: 2);
}
}
}
\ No newline at end of file
diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml
new file mode 100644
index 0000000..0c9b038
--- /dev/null
+++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+ <_3DTools:Interactive3DDecorator>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs
new file mode 100644
index 0000000..d169a80
--- /dev/null
+++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs
@@ -0,0 +1,359 @@
+using _3DTools;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Imaging;
+using System.Windows.Media.Media3D;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Wpf_AiSportsMicrospace.MyUserControl
+{
+ ///
+ /// CoverFlowControl1.xaml 的交互逻辑
+ ///
+ public partial class CoverFlowControl1 : UserControl
+ {
+ public CoverFlowControl1()
+ {
+ InitializeComponent();
+ InitControl();
+ }
+
+ #region 依赖属性注册
+ public static readonly DependencyProperty CurrentMidIndexProperty =
+ DependencyProperty.Register(
+ "CurrentMidIndex", typeof(double), typeof(CoverFlowControl),
+ new FrameworkPropertyMetadata(new PropertyChangedCallback(CurrentMidIndexPropertyChangedCallback)));
+
+ private static void CurrentMidIndexPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
+ {
+ var ctrl = sender as CoverFlowControl1;
+ ctrl?.ReLayoutInteractiveVisual3D();
+ }
+
+ public double CurrentMidIndex
+ {
+ get => (double)GetValue(CurrentMidIndexProperty);
+ set => SetValue(CurrentMidIndexProperty, value);
+ }
+
+ public static readonly DependencyProperty ModelAngleProperty =
+ DependencyProperty.Register(
+ "ModelAngle", typeof(double), typeof(CoverFlowControl),
+ new FrameworkPropertyMetadata(70.0, new PropertyChangedCallback(ModelAnglePropertyChangedCallback)));
+
+ private static void ModelAnglePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
+ {
+ var ctrl = sender as CoverFlowControl1;
+ ctrl?.ReLayoutInteractiveVisual3D();
+ }
+
+ public double ModelAngle
+ {
+ get => (double)GetValue(ModelAngleProperty);
+ set => SetValue(ModelAngleProperty, value);
+ }
+
+ public static readonly DependencyProperty XDistanceBetweenModelsProperty =
+ DependencyProperty.Register(
+ "XDistanceBetweenModels", typeof(double), typeof(CoverFlowControl),
+ new FrameworkPropertyMetadata(0.5, XDistanceBetweenModelsPropertyChangedCallback));
+
+ private static void XDistanceBetweenModelsPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
+ {
+ var ctrl = sender as CoverFlowControl1;
+ ctrl?.ReLayoutInteractiveVisual3D();
+ }
+
+ public double XDistanceBetweenModels
+ {
+ get => (double)GetValue(XDistanceBetweenModelsProperty);
+ set => SetValue(XDistanceBetweenModelsProperty, value);
+ }
+
+ public static readonly DependencyProperty ZDistanceBetweenModelsProperty =
+ DependencyProperty.Register(
+ "ZDistanceBetweenModels", typeof(double), typeof(CoverFlowControl),
+ new FrameworkPropertyMetadata(0.5, ZDistanceBetweenModelsPropertyChangedCallback));
+
+ private static void ZDistanceBetweenModelsPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
+ {
+ var ctrl = sender as CoverFlowControl1;
+ ctrl?.ReLayoutInteractiveVisual3D();
+ }
+
+ public double ZDistanceBetweenModels
+ {
+ get => (double)GetValue(ZDistanceBetweenModelsProperty);
+ set => SetValue(ZDistanceBetweenModelsProperty, value);
+ }
+
+ public static readonly DependencyProperty MidModelDistanceProperty =
+ DependencyProperty.Register(
+ "MidModelDistance", typeof(double), typeof(CoverFlowControl),
+ new FrameworkPropertyMetadata(1.5, MidModelDistancePropertyChangedCallback));
+
+ private static void MidModelDistancePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
+ {
+ var ctrl = sender as CoverFlowControl1;
+ ctrl?.ReLayoutInteractiveVisual3D();
+ }
+
+ public double MidModelDistance
+ {
+ get => (double)GetValue(MidModelDistanceProperty);
+ set => SetValue(MidModelDistanceProperty, value);
+ }
+ #endregion
+ private void InitControl()
+ {
+ this.LoadImageToViewport3D(this.GetUserImages());
+
+ // 鼠标事件改为控件自身
+ this.MouseDown += (s, e) =>
+ {
+ if (e.LeftButton == MouseButtonState.Pressed)
+ this.CurrentMidIndex++;
+ else
+ this.CurrentMidIndex--;
+ };
+ }
+
+ ///
+ /// 获取当前用户的图片文件夹中的图片(不包含子文件夹)
+ ///
+ /// 返回图片路径列表
+ private List GetUserImages()
+ {
+ List images = new List();
+
+ string path = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
+ DirectoryInfo dir = new DirectoryInfo(path);
+ FileInfo[] files = dir.GetFiles("*.jpg", SearchOption.AllDirectories);
+ if (files != null)
+ {
+ foreach (FileInfo file in files)
+ {
+ images.Add(file.FullName);
+ }
+ }
+
+ return images;
+ }
+
+ ///
+ /// 添加图片到视口
+ ///
+ ///
+ private void LoadImageToViewport3D(List images)
+ {
+ if (images == null)
+ {
+ return;
+ }
+
+ for (int i = 0; i < images.Count; i++)
+ {
+ string imageFile = images[i];
+
+ InteractiveVisual3D iv3d = this.CreateInteractiveVisual3D(imageFile, i);
+
+ this.viewport3D.Children.Add(iv3d);
+ }
+
+ this.ReLayoutInteractiveVisual3D();
+ }
+ private InteractiveVisual3D CreateInteractiveVisual3D(string imageFile, int index)
+ {
+ InteractiveVisual3D iv3d = new InteractiveVisual3D();
+ iv3d.Visual = this.CreateVisual(imageFile, index);
+ iv3d.Geometry = this.CreateGeometry3D();
+ iv3d.Transform = this.CreateEmptyTransform3DGroup();
+
+ return iv3d;
+ }
+ ///
+ /// 创建一个空的Transform3DGroup
+ ///
+ ///
+ private Transform3DGroup CreateEmptyTransform3DGroup()
+ {
+ Transform3DGroup group = new Transform3DGroup();
+ group.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0)));
+ group.Children.Add(new TranslateTransform3D(new Vector3D()));
+ group.Children.Add(new ScaleTransform3D());
+
+ return group;
+ }
+
+ ///
+ /// 创建3D图形
+ ///
+ /// 创建的3D图形
+ private Geometry3D CreateGeometry3D()
+ {
+ MeshGeometry3D geometry = new MeshGeometry3D();
+
+ geometry.Positions = new Point3DCollection();
+ geometry.Positions.Add(new Point3D(-1, 1, 0));
+ geometry.Positions.Add(new Point3D(-1, -1, 0));
+ geometry.Positions.Add(new Point3D(1, -1, 0));
+ geometry.Positions.Add(new Point3D(1, 1, 0));
+
+ geometry.TriangleIndices = new Int32Collection();
+ geometry.TriangleIndices.Add(0);
+ geometry.TriangleIndices.Add(1);
+ geometry.TriangleIndices.Add(2);
+ geometry.TriangleIndices.Add(0);
+ geometry.TriangleIndices.Add(2);
+ geometry.TriangleIndices.Add(3);
+
+ geometry.TextureCoordinates = new PointCollection();
+ geometry.TextureCoordinates.Add(new Point(0, 0));
+ geometry.TextureCoordinates.Add(new Point(0, 1));
+ geometry.TextureCoordinates.Add(new Point(1, 1));
+ geometry.TextureCoordinates.Add(new Point(1, 0));
+
+ return geometry;
+ }
+
+
+ ///
+ /// 由指定的图片路径创建一个可视对象
+ ///
+ /// 图片路径
+ /// 创建的可视对象
+ private Visual CreateVisual(string imageFile, int index)
+ {
+ BitmapImage bmp = null;
+
+ try
+ {
+ bmp = new BitmapImage(new Uri(imageFile));
+ }
+ catch
+ {
+ }
+
+ Image img = new Image();
+ img.Width = 50;
+ img.Source = bmp;
+
+ Border outBordre = new Border();
+ outBordre.BorderBrush = Brushes.White;
+ outBordre.BorderThickness = new Thickness(0.5);
+ outBordre.Child = img;
+
+ outBordre.MouseDown += delegate (object sender, MouseButtonEventArgs e)
+ {
+ this.CurrentMidIndex = index;
+ e.Handled = true;
+ };
+
+ return outBordre;
+
+ }
+
+ ///
+ /// 重新布局3D内容
+ ///
+ private void ReLayoutInteractiveVisual3D()
+ {
+ int j = 0;
+ for (int i = 0; i < this.viewport3D.Children.Count; i++)
+ {
+ InteractiveVisual3D iv3d = this.viewport3D.Children[i] as InteractiveVisual3D;
+ if (iv3d != null)
+ {
+ double angle = 0;
+ double offsetX = 0;
+ double offsetZ = 0;
+ this.GetTransformOfInteractiveVisual3D(j++, this.CurrentMidIndex, out angle, out offsetX, out offsetZ);
+
+
+ NameScope.SetNameScope(this, new NameScope());
+ this.RegisterName("iv3d", iv3d);
+ Duration time = new Duration(TimeSpan.FromSeconds(0.3));
+
+ DoubleAnimation angleAnimation = new DoubleAnimation(angle, time);
+ DoubleAnimation xAnimation = new DoubleAnimation(offsetX, time);
+ DoubleAnimation zAnimation = new DoubleAnimation(offsetZ, time);
+
+ Storyboard story = new Storyboard();
+ story.Children.Add(angleAnimation);
+ story.Children.Add(xAnimation);
+ story.Children.Add(zAnimation);
+
+ Storyboard.SetTargetName(angleAnimation, "iv3d");
+ Storyboard.SetTargetName(xAnimation, "iv3d");
+ Storyboard.SetTargetName(zAnimation, "iv3d");
+
+ Storyboard.SetTargetProperty(
+ angleAnimation,
+ new PropertyPath("(ModelVisual3D.Transform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation).(AxisAngleRotation3D.Angle)"));
+
+ Storyboard.SetTargetProperty(
+ xAnimation,
+ new PropertyPath("(ModelVisual3D.Transform).(Transform3DGroup.Children)[1].(TranslateTransform3D.OffsetX)"));
+ Storyboard.SetTargetProperty(
+ zAnimation,
+ new PropertyPath("(ModelVisual3D.Transform).(Transform3DGroup.Children)[1].(TranslateTransform3D.OffsetZ)"));
+
+ story.Begin(this);
+
+ }
+ }
+ }
+
+ ///
+ /// 依照InteractiveVisual3D在列表中的序号来变换其位置等
+ ///
+ /// 在列表中的序号
+ /// 列表中被作为中间项的序号
+ private void GetTransformOfInteractiveVisual3D(int index, double midIndex, out double angle, out double offsetX, out double offsetZ)
+ {
+ double disToMidIndex = index - midIndex;
+
+
+ //旋转,两翼的图片各旋转一定的度数
+ angle = 0;
+ if (disToMidIndex < 0)
+ {
+ angle = this.ModelAngle;//左边的旋转N度
+ }
+ else if (disToMidIndex > 0)
+ {
+ angle = (-this.ModelAngle);//右边的旋转-N度
+ }
+
+
+
+ //平移,两翼的图片逐渐向X轴负和正两个方向展开
+ offsetX = 0;//中间的不平移
+ if (Math.Abs(disToMidIndex) <= 1)
+ {
+ offsetX = disToMidIndex * this.MidModelDistance;
+ }
+ else if (disToMidIndex != 0)
+ {
+ offsetX = disToMidIndex * this.XDistanceBetweenModels + (disToMidIndex > 0 ? this.MidModelDistance : -this.MidModelDistance);
+ }
+
+
+ //两翼的图片逐渐向Z轴负方向移动一点,造成中间突出(离观众较近的效果)
+ offsetZ = Math.Abs(disToMidIndex) * -this.ZDistanceBetweenModels;
+
+ }
+ }
+}