support for .NET framework 3.5

Still have bugs
This commit is contained in:
NaBian committed 2019-01-21 00:43:10 +08:00
1 parent 5878039e21
commit 7d6b491f25
704 files changed
+48273 -33

No files matched your search

@@ -0,0 +1,338 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using HandyControl.Data;
namespace HandyControl.Controls
{
/// <summary>
/// 封面流
/// </summary>
[TemplatePart(Name = ElementViewport3D, Type = typeof(Viewport3D))]
[TemplatePart(Name = ElementCamera, Type = typeof(ProjectionCamera))]
[TemplatePart(Name = ElementVisualParent, Type = typeof(ModelVisual3D))]
public class CoverFlow : Control
{
private const string ElementViewport3D = "PART_Viewport3D";
private const string ElementCamera = "PART_Camera";
private const string ElementVisualParent = "PART_VisualParent";
/// <summary>
/// 最大显示数量的一半
/// </summary>
private const int MaxShowCountHalf = 7;
/// <summary>
/// 页码
/// </summary>
public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register(
"PageIndex", typeof(int), typeof(CoverFlow),
new PropertyMetadata(ValueBoxes.Int0Box, OnPageIndexChanged, CoercePageIndex));
private static object CoercePageIndex(DependencyObject d, object baseValue)
{
var ctl = (CoverFlow) d;
var v = (int) baseValue;
if (v < 0)
{
return 0;
}
if (v >= ctl._uriList.Count)
{
return ctl._uriList.Count - 1;
}
return v;
}
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (CoverFlow) d;
ctl.UpdateIndex((int)e.NewValue, (int)e.OldValue);
}
/// <summary>
/// 是否循环
/// </summary>
public static readonly DependencyProperty LoopProperty = DependencyProperty.Register(
"Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox));
/// <summary>
/// 存储所有的资源标识符
/// </summary>
private readonly Dictionary<int, Uri> _uriList = new Dictionary<int, Uri>();
/// <summary>
/// 当前在显示范围内的项
/// </summary>
private readonly Dictionary<int, CoverFlowItem> _itemShowList = new Dictionary<int, CoverFlowItem>();
/// <summary>
/// 相机
/// </summary>
private ProjectionCamera _camera;
/// <summary>
/// 3d画布
/// </summary>
private Viewport3D _viewport3D;
/// <summary>
/// 项容器
/// </summary>
private ModelVisual3D _visualParent;
/// <summary>
/// 显示范围内第一个项的编号
/// </summary>
private int _firstShowIndex;
/// <summary>
/// 显示范围内最后一个项的编号
/// </summary>
private int _lastShowIndex;
/// <summary>
/// 在获取新的模板后是否需要更新项
/// </summary>
private bool _updateItems;
private bool _isLoaded;
/// <summary>
/// 跳转编号
/// </summary>
private int _jumpToIndex = -1;
public CoverFlow()
{
Loaded += (s, e) =>
{
if (_isLoaded) return;
_isLoaded = true;
if (_updateItems)
{
UpdateShowRange();
_updateItems = false;
}
if (_jumpToIndex > 0)
{
PageIndex = _jumpToIndex;
}
};
}
/// <summary>
/// 页码
/// </summary>
public int PageIndex
{
get => (int) GetValue(PageIndexProperty);
internal set => SetValue(PageIndexProperty, value);
}
/// <summary>
/// 是否循环
/// </summary>
public bool Loop
{
get => (bool)GetValue(LoopProperty);
set => SetValue(LoopProperty, value);
}
public override void OnApplyTemplate()
{
if (_viewport3D != null)
{
_viewport3D.Children.Clear();
_itemShowList.Clear();
_viewport3D.MouseLeftButtonDown -= Viewport3D_MouseLeftButtonDown;
}
base.OnApplyTemplate();
_viewport3D = GetTemplateChild(ElementViewport3D) as Viewport3D;
if (_viewport3D != null)
{
_viewport3D.MouseLeftButtonDown += Viewport3D_MouseLeftButtonDown;
}
_camera = GetTemplateChild(ElementCamera) as ProjectionCamera;
_visualParent = GetTemplateChild(ElementVisualParent) as ModelVisual3D;
if (_isLoaded)
{
UpdateShowRange();
_camera.Position = new Point3D(CoverFlowItem.Interval * PageIndex, _camera.Position.Y,
_camera.Position.Z);
}
}
/// <summary>
/// 批量添加资源
/// </summary>
/// <param name="uriList"></param>
public void AddRange(List<Uri> uriList)
{
foreach (var uri in uriList)
{
_uriList.Add(_uriList.Count, uri);
}
_updateItems = true;
}
/// <summary>
/// 添加一项资源
/// </summary>
/// <param name="uriString"></param>
public void Add(string uriString)
{
_uriList.Add(_uriList.Count, new Uri(uriString));
_updateItems = true;
}
/// <summary>
/// 添加一项资源
/// </summary>
/// <param name="uri"></param>
public void Add(Uri uri)
{
_uriList.Add(_uriList.Count, uri);
_updateItems = true;
}
/// <summary>
/// 跳转
/// </summary>
public void JumpTo(int index) => _jumpToIndex = index;
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
if (e.Delta < 0)
{
var index = PageIndex + 1;
PageIndex = index >= _uriList.Count ? (Loop ? 0 : _uriList.Count - 1) : index;
}
else
{
var index = PageIndex - 1;
PageIndex = index < 0 ? (Loop ? _uriList.Count - 1 : 0) : index;
}
}
/// <summary>
/// 删除指定位置的项
/// </summary>
/// <param name="pos"></param>
private void Remove(int pos)
{
var item = _itemShowList[pos];
_visualParent.Children.Remove(item);
_itemShowList.Remove(pos);
}
/// <summary>
/// 移动项到指定的位置
/// </summary>
/// <param name="index"></param>
/// <param name="animated"></param>
private void Move(int index, bool animated) => _itemShowList[index].Move(PageIndex, animated);
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var result = (RayMeshGeometry3DHitTestResult) VisualTreeHelper.HitTest(_viewport3D, e.GetPosition(_viewport3D));
if (result != null)
{
foreach (var item in _itemShowList.Values)
{
if (item.HitTest(result.MeshHit))
{
PageIndex = item.Index;
break;
}
}
}
}
/// <summary>
/// 更新项的位置
/// </summary>
/// <param name="newIndex"></param>
/// <param name="oldIndex"></param>
private void UpdateIndex(int newIndex, int oldIndex)
{
var animate = Math.Abs(newIndex - oldIndex) < MaxShowCountHalf;
UpdateShowRange();
if (newIndex > oldIndex)
{
if (oldIndex < _firstShowIndex)
{
oldIndex = _firstShowIndex;
}
for (var i = oldIndex; i <= newIndex; i++)
{
Move(i, animate);
}
}
else
{
if (oldIndex > _lastShowIndex)
{
oldIndex = _lastShowIndex;
}
for (var i = oldIndex; i >= newIndex; i--)
{
Move(i, animate);
}
}
_camera.Position = new Point3D(CoverFlowItem.Interval * newIndex, _camera.Position.Y,
_camera.Position.Z);
}
/// <summary>
/// 更新显示范围
/// </summary>
private void UpdateShowRange()
{
var newFirstShowIndex = Math.Max(PageIndex - MaxShowCountHalf, 0);
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _uriList.Count - 1);
if (_firstShowIndex < newFirstShowIndex)
{
for (var i = _firstShowIndex; i < newFirstShowIndex; i++)
{
Remove(i);
}
}
else if (newLastShowIndex < _lastShowIndex)
{
for (var i = newLastShowIndex; i < _lastShowIndex; i++)
{
Remove(i);
}
}
for (var i = newFirstShowIndex; i <= newLastShowIndex; i++)
{
if (!_itemShowList.ContainsKey(i))
{
var cover = new CoverFlowItem(i, PageIndex, BitmapFrame.Create(_uriList[i]));
_itemShowList[i] = cover;
_visualParent.Children.Add(cover);
}
}
_firstShowIndex = newFirstShowIndex;
_lastShowIndex = newLastShowIndex;
}
}
}
@@ -0,0 +1,165 @@
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using HandyControl.Tools;
namespace HandyControl.Controls
{
public class CoverFlowItem : ModelVisual3D
{
internal static readonly double Interval = .2;
internal static readonly double AnimationSpeed = 400;
private readonly AxisAngleRotation3D _rotation3D;
private readonly TranslateTransform3D _transform3D;
private readonly Model3DGroup _model3DGroup;
private readonly ImageSource _source;
internal int Index { get; set; }
public CoverFlowItem(int itemIndex, int currentIndex, ImageSource source)
{
Index = itemIndex;
_source = source;
_rotation3D = new AxisAngleRotation3D(new Vector3D(0, 1, 0), GetAngleByPos(currentIndex));
_transform3D = new TranslateTransform3D(GetXByPos(currentIndex), 0, GetZByPos(currentIndex));
var transformGroup = new Transform3DGroup();
transformGroup.Children.Add(new RotateTransform3D(_rotation3D));
transformGroup.Children.Add(_transform3D);
_model3DGroup = new Model3DGroup();
_model3DGroup.Children.Add(new GeometryModel3D(CreateItemGeometry(), new DiffuseMaterial(new ImageBrush(_source))));
_model3DGroup.Transform = transformGroup;
Content = _model3DGroup;
}
/// <summary>
/// 创建网格形状
/// </summary>
/// <param name="p0"></param>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <param name="p3"></param>
/// <returns></returns>
private static MeshGeometry3D CreateMeshGeometry(Point3D p0, Point3D p1, Point3D p2, Point3D p3)
{
var positions = new Point3DCollection
{
p0,
p1,
p2,
p3
};
var triangleIndices = new Int32Collection
{
0,
1,
2,
2,
3,
0
};
var textureCoordinates = new PointCollection
{
new Point(0, 1),
new Point(1, 1),
new Point(1, 0),
new Point(0, 0),
new Point(1, 0),
new Point(1, 1)
};
var normals = new Vector3DCollection
{
ArithmeticHelper.CalNormal(p0, p1, p2),
ArithmeticHelper.CalNormal(p2, p3, p0)
};
var geometry3D = new MeshGeometry3D
{
Positions = positions,
TriangleIndices = triangleIndices,
TextureCoordinates = textureCoordinates,
Normals = normals
};
geometry3D.Freeze();
return geometry3D;
}
/// <summary>
/// 创建内容形状
/// </summary>
/// <returns></returns>
private Geometry3D CreateItemGeometry()
{
var sx = _source.Width > _source.Height ? 0 : 1 - _source.Width / _source.Height;
var sy = _source.Width < _source.Height ? 0 : 1 - _source.Height / _source.Width;
var p0 = new Point3D(-1 + sx, -1 + sy, 0);
var p1 = new Point3D(1 - sx, -1 + sy, 0);
var p2 = new Point3D(1 - sx, 1 - sy, 0);
var p3 = new Point3D(-1 + sx, 1 - sy, 0);
return CreateMeshGeometry(p0, p1, p2, p3);
}
private double GetAngleByPos(int index) => Math.Sign(Index - index) * -90;
private double GetXByPos(int index) => Index * Interval + Math.Sign(Index - index) * 1.5;
private double GetZByPos(int index) => Index == index ? 1 : 0;
/// <summary>
/// 移动
/// </summary>
internal void Move(int currentIndex, bool animated)
{
if (animated || _rotation3D.HasAnimatedProperties)
{
_rotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty,
AnimationHelper.CreateAnimation(GetAngleByPos(currentIndex), AnimationSpeed));
_transform3D.BeginAnimation(TranslateTransform3D.OffsetXProperty,
AnimationHelper.CreateAnimation(GetXByPos(currentIndex), AnimationSpeed));
_transform3D.BeginAnimation(TranslateTransform3D.OffsetZProperty,
AnimationHelper.CreateAnimation(GetZByPos(currentIndex), AnimationSpeed));
}
else
{
_rotation3D.Angle = GetAngleByPos(currentIndex);
_transform3D.OffsetX = GetXByPos(currentIndex);
_transform3D.OffsetZ = GetZByPos(currentIndex);
}
}
/// <summary>
/// 命中测试
/// </summary>
/// <param name="mesh"></param>
/// <returns></returns>
internal bool HitTest(MeshGeometry3D mesh)
{
foreach (var item in _model3DGroup.Children)
{
if (item is GeometryModel3D geometryModel3D)
{
if (Equals(geometryModel3D.Geometry, mesh))
{
return true;
}
}
}
return false;
}
}
}