chore: use file-scoped namespace

This commit is contained in:
NaBian committed 2022-03-13 20:28:58 +08:00
1 parent 99d2fafb72
commit bbf1b7d4c6
748 files changed
+57929 -58678

No files matched your search

@@ -10,289 +10,288 @@ using System.Windows.Media.Media3D;
using HandyControl.Data;
using HandyControl.Tools.Extension;
namespace HandyControl.Controls
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>
[TemplatePart(Name = ElementViewport3D, Type = typeof(Viewport3D))]
[TemplatePart(Name = ElementCamera, Type = typeof(ProjectionCamera))]
[TemplatePart(Name = ElementVisualParent, Type = typeof(ModelVisual3D))]
public class CoverFlow : Control
private const int MaxShowCountHalf = 3;
/// <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)
{
private const string ElementViewport3D = "PART_Viewport3D";
var ctl = (CoverFlow) d;
var v = (int) baseValue;
private const string ElementCamera = "PART_Camera";
private const string ElementVisualParent = "PART_VisualParent";
/// <summary>
/// 最大显示数量的一半
/// </summary>
private const int MaxShowCountHalf = 3;
/// <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)
if (v < 0)
{
var ctl = (CoverFlow) d;
var v = (int) baseValue;
return 0;
}
if (v >= ctl._contentDic.Count)
{
return ctl._contentDic.Count - 1;
}
return v;
}
if (v < 0)
{
return 0;
}
if (v >= ctl._contentDic.Count)
{
return ctl._contentDic.Count - 1;
}
return v;
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (CoverFlow) d;
ctl.UpdateIndex((int) e.NewValue);
}
/// <summary>
/// 是否循环
/// </summary>
public static readonly DependencyProperty LoopProperty = DependencyProperty.Register(
"Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox));
/// <summary>
/// 存储所有的内容
/// </summary>
private readonly Dictionary<int, object> _contentDic = new();
/// <summary>
/// 当前在显示范围内的项
/// </summary>
private readonly Dictionary<int, CoverFlowItem> _itemShowDic = new();
/// <summary>
/// 相机
/// </summary>
private ProjectionCamera _camera;
private Point3DAnimation _point3DAnimation;
/// <summary>
/// 3d画布
/// </summary>
private Viewport3D _viewport3D;
/// <summary>
/// 项容器
/// </summary>
private ModelVisual3D _visualParent;
/// <summary>
/// 显示范围内第一个项的编号
/// </summary>
private int _firstShowIndex;
/// <summary>
/// 显示范围内最后一个项的编号
/// </summary>
private int _lastShowIndex;
/// <summary>
/// 页码
/// </summary>
public int PageIndex
{
get => (int) GetValue(PageIndexProperty);
set => SetValue(PageIndexProperty, value);
}
/// <summary>
/// 是否循环
/// </summary>
public bool Loop
{
get => (bool) GetValue(LoopProperty);
set => SetValue(LoopProperty, ValueBoxes.BooleanBox(value));
}
public override void OnApplyTemplate()
{
if (_viewport3D != null)
{
_viewport3D.Children.Clear();
_itemShowDic.Clear();
_viewport3D.MouseLeftButtonDown -= Viewport3D_MouseLeftButtonDown;
}
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
base.OnApplyTemplate();
_viewport3D = GetTemplateChild(ElementViewport3D) as Viewport3D;
if (_viewport3D != null)
{
var ctl = (CoverFlow) d;
ctl.UpdateIndex((int) e.NewValue);
_viewport3D.MouseLeftButtonDown += Viewport3D_MouseLeftButtonDown;
}
/// <summary>
/// 是否循环
/// </summary>
public static readonly DependencyProperty LoopProperty = DependencyProperty.Register(
"Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox));
_camera = GetTemplateChild(ElementCamera) as ProjectionCamera;
_visualParent = GetTemplateChild(ElementVisualParent) as ModelVisual3D;
/// <summary>
/// 存储所有的内容
/// </summary>
private readonly Dictionary<int, object> _contentDic = new();
UpdateShowRange();
/// <summary>
/// 当前在显示范围内的项
/// </summary>
private readonly Dictionary<int, CoverFlowItem> _itemShowDic = new();
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * PageIndex, _camera.Position.Y, _camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
}
/// <summary>
/// 相机
/// </summary>
private ProjectionCamera _camera;
private Point3DAnimation _point3DAnimation;
/// <summary>
/// 3d画布
/// </summary>
private Viewport3D _viewport3D;
/// <summary>
/// 项容器
/// </summary>
private ModelVisual3D _visualParent;
/// <summary>
/// 显示范围内第一个项的编号
/// </summary>
private int _firstShowIndex;
/// <summary>
/// 显示范围内最后一个项的编号
/// </summary>
private int _lastShowIndex;
/// <summary>
/// 页码
/// </summary>
public int PageIndex
/// <summary>
/// 批量添加资源
/// </summary>
/// <param name="contentList"></param>
public void AddRange(IEnumerable<object> contentList)
{
foreach (var content in contentList)
{
get => (int) GetValue(PageIndexProperty);
set => SetValue(PageIndexProperty, value);
_contentDic.Add(_contentDic.Count, content);
}
}
/// <summary>
/// 添加一项资源
/// </summary>
/// <param name="uriString"></param>
public void Add(string uriString) => _contentDic.Add(_contentDic.Count, new Uri(uriString));
/// <summary>
/// 添加一项资源
/// </summary>
/// <param name="uri"></param>
public void Add(Uri uri) => _contentDic.Add(_contentDic.Count, uri);
public void Next() => PageIndex++;
public void Prev() => PageIndex--;
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
if (e.Delta < 0)
{
var index = PageIndex + 1;
PageIndex = index >= _contentDic.Count ? Loop ? 0 : _contentDic.Count - 1 : index;
}
else
{
var index = PageIndex - 1;
PageIndex = index < 0 ? Loop ? _contentDic.Count - 1 : 0 : index;
}
/// <summary>
/// 是否循环
/// </summary>
public bool Loop
{
get => (bool) GetValue(LoopProperty);
set => SetValue(LoopProperty, ValueBoxes.BooleanBox(value));
}
e.Handled = true;
}
public override void OnApplyTemplate()
/// <summary>
/// 删除指定位置的项
/// </summary>
/// <param name="pos"></param>
private void Remove(int pos)
{
if (!_itemShowDic.TryGetValue(pos, out var item)) return;
_visualParent.Children.Remove(item);
_itemShowDic.Remove(pos);
}
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var result = (RayMeshGeometry3DHitTestResult) VisualTreeHelper.HitTest(_viewport3D, e.GetPosition(_viewport3D));
if (result != null)
{
if (_viewport3D != null)
foreach (var item in _itemShowDic.Values)
{
_viewport3D.Children.Clear();
_itemShowDic.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;
UpdateShowRange();
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * PageIndex, _camera.Position.Y, _camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
}
/// <summary>
/// 批量添加资源
/// </summary>
/// <param name="contentList"></param>
public void AddRange(IEnumerable<object> contentList)
{
foreach (var content in contentList)
{
_contentDic.Add(_contentDic.Count, content);
if (item.HitTest(result.MeshHit))
{
PageIndex = item.Index;
break;
}
}
}
}
/// <summary>
/// 添加一项资源
/// </summary>
/// <param name="uriString"></param>
public void Add(string uriString) => _contentDic.Add(_contentDic.Count, new Uri(uriString));
/// <summary>
/// 添加一项资源
/// </summary>
/// <param name="uri"></param>
public void Add(Uri uri) => _contentDic.Add(_contentDic.Count, uri);
public void Next() => PageIndex++;
public void Prev() => PageIndex--;
protected override void OnMouseWheel(MouseWheelEventArgs e)
/// <summary>
/// 更新项的位置
/// </summary>
/// <param name="newIndex"></param>
private void UpdateIndex(int newIndex)
{
if (!IsLoaded)
{
base.OnMouseWheel(e);
return;
}
if (e.Delta < 0)
UpdateShowRange();
_itemShowDic.Do(item =>
{
if (item.Value.Index < _firstShowIndex || item.Value.Index > _lastShowIndex)
{
var index = PageIndex + 1;
PageIndex = index >= _contentDic.Count ? Loop ? 0 : _contentDic.Count - 1 : index;
Remove(item.Value.Index);
}
else
{
var index = PageIndex - 1;
PageIndex = index < 0 ? Loop ? _contentDic.Count - 1 : 0 : index;
item.Value.Move(PageIndex);
}
});
e.Handled = true;
}
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * newIndex, _camera.Position.Y,
_camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
/// <summary>
/// 删除指定位置的项
/// </summary>
/// <param name="pos"></param>
private void Remove(int pos)
{
if (!_itemShowDic.TryGetValue(pos, out var item)) return;
_visualParent.Children.Remove(item);
_itemShowDic.Remove(pos);
}
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var result = (RayMeshGeometry3DHitTestResult) VisualTreeHelper.HitTest(_viewport3D, e.GetPosition(_viewport3D));
if (result != null)
{
foreach (var item in _itemShowDic.Values)
{
if (item.HitTest(result.MeshHit))
{
PageIndex = item.Index;
break;
}
}
}
}
/// <summary>
/// 更新项的位置
/// </summary>
/// <param name="newIndex"></param>
private void UpdateIndex(int newIndex)
{
if (!IsLoaded)
{
return;
}
UpdateShowRange();
_itemShowDic.Do(item =>
{
if (item.Value.Index < _firstShowIndex || item.Value.Index > _lastShowIndex)
{
Remove(item.Value.Index);
}
else
{
item.Value.Move(PageIndex);
}
});
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * newIndex, _camera.Position.Y,
_camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
}
/// <summary>
/// 更新显示范围
/// </summary>
private void UpdateShowRange()
{
var newFirstShowIndex = Math.Max(PageIndex - MaxShowCountHalf, 0);
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _contentDic.Count - 1);
for (var i = newFirstShowIndex; i <= newLastShowIndex; i++)
{
if (!_itemShowDic.ContainsKey(i))
{
var cover = CreateCoverFlowItem(i, _contentDic[i]);
_itemShowDic[i] = cover;
_visualParent.Children.Add(cover);
}
}
_firstShowIndex = newFirstShowIndex;
_lastShowIndex = newLastShowIndex;
}
private CoverFlowItem CreateCoverFlowItem(int index, object content)
{
if (content is Uri uri)
{
try
{
return new CoverFlowItem(index, PageIndex, new Image
{
Source = BitmapFrame.Create(uri, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand)
});
}
catch
{
return new CoverFlowItem(index, PageIndex, new ContentControl());
}
}
return new CoverFlowItem(index, PageIndex, new ContentControl
{
Content = content
});
}
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
}
}
/// <summary>
/// 更新显示范围
/// </summary>
private void UpdateShowRange()
{
var newFirstShowIndex = Math.Max(PageIndex - MaxShowCountHalf, 0);
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _contentDic.Count - 1);
for (var i = newFirstShowIndex; i <= newLastShowIndex; i++)
{
if (!_itemShowDic.ContainsKey(i))
{
var cover = CreateCoverFlowItem(i, _contentDic[i]);
_itemShowDic[i] = cover;
_visualParent.Children.Add(cover);
}
}
_firstShowIndex = newFirstShowIndex;
_lastShowIndex = newLastShowIndex;
}
private CoverFlowItem CreateCoverFlowItem(int index, object content)
{
if (content is Uri uri)
{
try
{
return new CoverFlowItem(index, PageIndex, new Image
{
Source = BitmapFrame.Create(uri, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand)
});
}
catch
{
return new CoverFlowItem(index, PageIndex, new ContentControl());
}
}
return new CoverFlowItem(index, PageIndex, new ContentControl
{
Content = content
});
}
}
@@ -4,154 +4,153 @@ using System.Windows.Media;
using System.Windows.Media.Media3D;
using HandyControl.Tools;
namespace HandyControl.Controls
namespace HandyControl.Controls;
public class CoverFlowItem : ModelVisual3D
{
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 UIElement _uiElement;
internal int Index { get; set; }
public CoverFlowItem(int itemIndex, int currentIndex, UIElement element)
{
internal static readonly double Interval = .2;
Index = itemIndex;
_uiElement = element;
_uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
internal static readonly double AnimationSpeed = 400;
_rotation3D = new AxisAngleRotation3D(new Vector3D(0, 1, 0), GetAngleByPos(currentIndex));
_transform3D = new TranslateTransform3D(GetXByPos(currentIndex), 0, GetZByPos(currentIndex));
private readonly AxisAngleRotation3D _rotation3D;
var transformGroup = new Transform3DGroup();
transformGroup.Children.Add(new RotateTransform3D(_rotation3D));
transformGroup.Children.Add(_transform3D);
private readonly TranslateTransform3D _transform3D;
_model3DGroup = new Model3DGroup();
_model3DGroup.Children.Add(new GeometryModel3D(CreateItemGeometry(), new DiffuseMaterial(new VisualBrush(element))));
_model3DGroup.Transform = transformGroup;
private readonly Model3DGroup _model3DGroup;
Content = _model3DGroup;
}
private readonly UIElement _uiElement;
internal int Index { get; set; }
public CoverFlowItem(int itemIndex, int currentIndex, UIElement element)
/// <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
{
Index = itemIndex;
_uiElement = element;
_uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
p0,
p1,
p2,
p3
};
_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 VisualBrush(element))));
_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 triangleIndices = new Int32Collection
{
var positions = new Point3DCollection
{
p0,
p1,
p2,
p3
};
0,
1,
2,
2,
3,
0
};
var triangleIndices = new Int32Collection
{
0,
1,
2,
2,
3,
0
};
var textureCoordinates = new PointCollection
{
new(0, 1),
new(1, 1),
new(1, 0),
new(0, 0),
new(1, 0),
new(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 textureCoordinates = new PointCollection
{
var sx = _uiElement.DesiredSize.Width > _uiElement.DesiredSize.Height ? 0 : 1 - _uiElement.DesiredSize.Width / _uiElement.DesiredSize.Height;
var sy = _uiElement.DesiredSize.Width < _uiElement.DesiredSize.Height ? 0 : 1 - _uiElement.DesiredSize.Height / _uiElement.DesiredSize.Width;
new(0, 1),
new(1, 1),
new(1, 0),
new(0, 0),
new(1, 0),
new(1, 1)
};
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)
var normals = new Vector3DCollection
{
_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));
}
ArithmeticHelper.CalNormal(p0, p1, p2),
ArithmeticHelper.CalNormal(p2, p3, p0)
};
/// <summary>
/// 命中测试
/// </summary>
/// <param name="mesh"></param>
/// <returns></returns>
internal bool HitTest(MeshGeometry3D mesh)
var geometry3D = new MeshGeometry3D
{
foreach (var item in _model3DGroup.Children)
Positions = positions,
TriangleIndices = triangleIndices,
TextureCoordinates = textureCoordinates,
Normals = normals
};
geometry3D.Freeze();
return geometry3D;
}
/// <summary>
/// 创建内容形状
/// </summary>
/// <returns></returns>
private Geometry3D CreateItemGeometry()
{
var sx = _uiElement.DesiredSize.Width > _uiElement.DesiredSize.Height ? 0 : 1 - _uiElement.DesiredSize.Width / _uiElement.DesiredSize.Height;
var sy = _uiElement.DesiredSize.Width < _uiElement.DesiredSize.Height ? 0 : 1 - _uiElement.DesiredSize.Height / _uiElement.DesiredSize.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)
{
_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));
}
/// <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 (item is GeometryModel3D geometryModel3D)
if (Equals(geometryModel3D.Geometry, mesh))
{
if (Equals(geometryModel3D.Geometry, mesh))
{
return true;
}
return true;
}
}
return false;
}
return false;
}
}
}
@@ -6,419 +6,418 @@ using System.Windows.Data;
using HandyControl.Data;
using HandyControl.Tools;
namespace HandyControl.Controls
namespace HandyControl.Controls;
public class CoverView : RegularItemsControl
{
public class CoverView : RegularItemsControl
private readonly CoverViewContent _viewContent;
private CoverViewItem _selectedItem;
private IEnumerable _itemsSourceInternal;
private readonly Dictionary<object, CoverViewItem> _entryDic = new();
private bool _isRefresh;
public CoverView()
{
private readonly CoverViewContent _viewContent;
_viewContent = new CoverViewContent();
private CoverViewItem _selectedItem;
AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(CoverViewItem_OnSelected));
_viewContent.SetBinding(CoverViewContent.ContentHeightProperty, new Binding(ItemContentHeightProperty.Name) { Source = this });
_viewContent.SetBinding(WidthProperty, new Binding(ActualWidthProperty.Name) { Source = this });
}
private IEnumerable _itemsSourceInternal;
private readonly Dictionary<object, CoverViewItem> _entryDic = new();
private bool _isRefresh;
public CoverView()
private void CoverViewItem_OnSelected(object sender, RoutedEventArgs e)
{
if (e.OriginalSource is CoverViewItem item)
{
_viewContent = new CoverViewContent();
AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(CoverViewItem_OnSelected));
_viewContent.SetBinding(CoverViewContent.ContentHeightProperty, new Binding(ItemContentHeightProperty.Name) { Source = this });
_viewContent.SetBinding(WidthProperty, new Binding(ActualWidthProperty.Name) { Source = this });
}
private void CoverViewItem_OnSelected(object sender, RoutedEventArgs e)
{
if (e.OriginalSource is CoverViewItem item)
{
if (_selectedItem == null)
{
item.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.TrueBox);
_selectedItem = item;
if (_viewContent != null)
{
_viewContent.Content = item.Content;
_viewContent.ContentTemplate = ItemTemplate;
UpdateCoverViewContent(true);
}
return;
}
if (!Equals(_selectedItem, item))
{
_selectedItem.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.FalseBox);
item.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.TrueBox);
_selectedItem = item;
if (_viewContent != null)
{
_viewContent.Content = item.Content;
UpdateCoverViewContent(true);
}
return;
}
if (_viewContent != null)
{
_viewContent.Content = null;
_viewContent.ContentTemplate = null;
UpdateCoverViewContent(false);
}
_selectedItem.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.FalseBox);
_selectedItem = null;
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_viewContent.Style ??= CoverViewContentStyle;
if (_selectedItem != null)
{
UpdateCoverViewContent(_selectedItem != null);
}
}
protected override DependencyObject GetContainerForItemOverride() => new CoverViewItem();
private void SetBindingForItem(FrameworkElement item)
{
item.SetBinding(MarginProperty, new Binding(ItemMarginProperty.Name) { Source = this });
item.SetBinding(WidthProperty, new Binding(ItemWidthProperty.Name) { Source = this });
item.SetBinding(HeightProperty, new Binding(ItemHeightProperty.Name) { Source = this });
item.SetBinding(HeaderedSelectableItem.HeaderTemplateProperty, new Binding(ItemHeaderTemplateProperty.Name) { Source = this });
}
protected override bool IsItemItsOwnContainerOverride(object item) => item is CoverViewItem;
public static readonly DependencyProperty CoverViewContentStyleProperty = DependencyProperty.Register(
"CoverViewContentStyle", typeof(Style), typeof(CoverView), new PropertyMetadata(default(Style)));
public Style CoverViewContentStyle
{
get => (Style) GetValue(CoverViewContentStyleProperty);
set => SetValue(CoverViewContentStyleProperty, value);
}
internal static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
"Groups", typeof(int), typeof(CoverView),
new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsMeasure,
OnGroupsChanged), IsGroupsValid);
internal static void OnGroupsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CoverView ctl)
{
ctl.UpdateCoverViewContent(ctl._viewContent.IsOpen);
}
}
private static bool IsGroupsValid(object value)
{
var v = (int) value;
return v >= 1;
}
public int Groups
{
get => (int) GetValue(GroupsProperty);
set => SetValue(GroupsProperty, value);
}
public static readonly DependencyProperty ItemContentHeightProperty = DependencyProperty.Register(
"ItemContentHeight", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double300Box),
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double ItemContentHeight
{
get => (double) GetValue(ItemContentHeightProperty);
set => SetValue(ItemContentHeightProperty, value);
}
public static readonly DependencyProperty ItemContentHeightFixedProperty = DependencyProperty.Register(
"ItemContentHeightFixed", typeof(bool), typeof(CoverView), new PropertyMetadata(ValueBoxes.TrueBox));
public bool ItemContentHeightFixed
{
get => (bool) GetValue(ItemContentHeightFixedProperty);
set => SetValue(ItemContentHeightFixedProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty ItemHeaderTemplateProperty = DependencyProperty.Register(
"ItemHeaderTemplate", typeof(DataTemplate), typeof(CoverView), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ItemHeaderTemplate
{
get => (DataTemplate) GetValue(ItemHeaderTemplateProperty);
set => SetValue(ItemHeaderTemplateProperty, value);
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
Groups = (int) (sizeInfo.NewSize.Width / (ItemWidth + ItemMargin.Left + ItemMargin.Right));
}
protected override void Refresh()
{
if (ItemsHost == null) return;
_entryDic.Clear();
_isRefresh = true;
foreach (var item in Items)
{
AddItem(item);
}
_isRefresh = false;
GenerateIndex();
UpdateCoverViewContent(_viewContent.IsOpen);
}
/// <summary>
/// 更新内容视图
/// </summary>
private void UpdateCoverViewContent(bool isOpen)
{
if (_selectedItem == null) return;
ItemsHost.Children.Remove(_viewContent);
if (!ItemContentHeightFixed)
{
_viewContent.ManualHeight = 0;
if (_viewContent.Content is FrameworkElement element)
{
element.VerticalAlignment = VerticalAlignment.Top;
element.Arrange(new Rect(new Size(double.MaxValue, double.MaxValue)));
_viewContent.ManualHeight = element.ActualHeight;
}
}
UpdateCoverViewContentPosition();
if (_viewContent.CanSwitch)
{
_viewContent.IsOpen = isOpen;
}
}
/// <summary>
/// 更新内容视图位置
/// </summary>
private void UpdateCoverViewContentPosition()
{
if (_viewContent.Parent != null)
{
ItemsHost.Children.Remove(_viewContent);
}
if (_selectedItem == null)
{
item.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.TrueBox);
_selectedItem = item;
if (_viewContent != null)
{
_viewContent.Content = item.Content;
_viewContent.ContentTemplate = ItemTemplate;
UpdateCoverViewContent(true);
}
return;
}
var total = _entryDic.Count + 1;
var totalRow = total / Groups + (total % Groups > 0 ? 1 : 0);
if (total <= Groups)
if (!Equals(_selectedItem, item))
{
_selectedItem.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.FalseBox);
item.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.TrueBox);
_selectedItem = item;
if (_viewContent != null)
{
_viewContent.Content = item.Content;
UpdateCoverViewContent(true);
}
return;
}
if (_viewContent != null)
{
_viewContent.Content = null;
_viewContent.ContentTemplate = null;
UpdateCoverViewContent(false);
}
_selectedItem.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.FalseBox);
_selectedItem = null;
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_viewContent.Style ??= CoverViewContentStyle;
if (_selectedItem != null)
{
UpdateCoverViewContent(_selectedItem != null);
}
}
protected override DependencyObject GetContainerForItemOverride() => new CoverViewItem();
private void SetBindingForItem(FrameworkElement item)
{
item.SetBinding(MarginProperty, new Binding(ItemMarginProperty.Name) { Source = this });
item.SetBinding(WidthProperty, new Binding(ItemWidthProperty.Name) { Source = this });
item.SetBinding(HeightProperty, new Binding(ItemHeightProperty.Name) { Source = this });
item.SetBinding(HeaderedSelectableItem.HeaderTemplateProperty, new Binding(ItemHeaderTemplateProperty.Name) { Source = this });
}
protected override bool IsItemItsOwnContainerOverride(object item) => item is CoverViewItem;
public static readonly DependencyProperty CoverViewContentStyleProperty = DependencyProperty.Register(
"CoverViewContentStyle", typeof(Style), typeof(CoverView), new PropertyMetadata(default(Style)));
public Style CoverViewContentStyle
{
get => (Style) GetValue(CoverViewContentStyleProperty);
set => SetValue(CoverViewContentStyleProperty, value);
}
internal static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
"Groups", typeof(int), typeof(CoverView),
new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsMeasure,
OnGroupsChanged), IsGroupsValid);
internal static void OnGroupsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CoverView ctl)
{
ctl.UpdateCoverViewContent(ctl._viewContent.IsOpen);
}
}
private static bool IsGroupsValid(object value)
{
var v = (int) value;
return v >= 1;
}
public int Groups
{
get => (int) GetValue(GroupsProperty);
set => SetValue(GroupsProperty, value);
}
public static readonly DependencyProperty ItemContentHeightProperty = DependencyProperty.Register(
"ItemContentHeight", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double300Box),
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double ItemContentHeight
{
get => (double) GetValue(ItemContentHeightProperty);
set => SetValue(ItemContentHeightProperty, value);
}
public static readonly DependencyProperty ItemContentHeightFixedProperty = DependencyProperty.Register(
"ItemContentHeightFixed", typeof(bool), typeof(CoverView), new PropertyMetadata(ValueBoxes.TrueBox));
public bool ItemContentHeightFixed
{
get => (bool) GetValue(ItemContentHeightFixedProperty);
set => SetValue(ItemContentHeightFixedProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty ItemHeaderTemplateProperty = DependencyProperty.Register(
"ItemHeaderTemplate", typeof(DataTemplate), typeof(CoverView), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ItemHeaderTemplate
{
get => (DataTemplate) GetValue(ItemHeaderTemplateProperty);
set => SetValue(ItemHeaderTemplateProperty, value);
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
Groups = (int) (sizeInfo.NewSize.Width / (ItemWidth + ItemMargin.Left + ItemMargin.Right));
}
protected override void Refresh()
{
if (ItemsHost == null) return;
_entryDic.Clear();
_isRefresh = true;
foreach (var item in Items)
{
AddItem(item);
}
_isRefresh = false;
GenerateIndex();
UpdateCoverViewContent(_viewContent.IsOpen);
}
/// <summary>
/// 更新内容视图
/// </summary>
private void UpdateCoverViewContent(bool isOpen)
{
if (_selectedItem == null) return;
ItemsHost.Children.Remove(_viewContent);
if (!ItemContentHeightFixed)
{
_viewContent.ManualHeight = 0;
if (_viewContent.Content is FrameworkElement element)
{
element.VerticalAlignment = VerticalAlignment.Top;
element.Arrange(new Rect(new Size(double.MaxValue, double.MaxValue)));
_viewContent.ManualHeight = element.ActualHeight;
}
}
UpdateCoverViewContentPosition();
if (_viewContent.CanSwitch)
{
_viewContent.IsOpen = isOpen;
}
}
/// <summary>
/// 更新内容视图位置
/// </summary>
private void UpdateCoverViewContentPosition()
{
if (_viewContent.Parent != null)
{
ItemsHost.Children.Remove(_viewContent);
}
if (_selectedItem == null)
{
return;
}
var total = _entryDic.Count + 1;
var totalRow = total / Groups + (total % Groups > 0 ? 1 : 0);
if (total <= Groups)
{
ItemsHost.Children.Add(_viewContent);
}
else
{
var row = _selectedItem.Index / Groups + 1;
if (row == totalRow)
{
ItemsHost.Children.Add(_viewContent);
}
else
{
var row = _selectedItem.Index / Groups + 1;
if (row == totalRow)
{
ItemsHost.Children.Add(_viewContent);
}
else
{
ItemsHost.Children.Insert(row * Groups, _viewContent);
}
}
_viewContent.UpdatePosition(_selectedItem.Index, Groups, _selectedItem.DesiredSize.Width);
}
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (_itemsSourceInternal != null)
{
if (_itemsSourceInternal is INotifyCollectionChanged s)
{
s.CollectionChanged -= InternalCollectionChanged;
}
Items.Clear();
ClearItems();
}
_itemsSourceInternal = newValue;
if (_itemsSourceInternal != null)
{
if (_itemsSourceInternal is INotifyCollectionChanged s)
{
s.CollectionChanged += InternalCollectionChanged;
}
foreach (var item in _itemsSourceInternal)
{
AddItem(item);
}
}
if (ItemsHost != null)
{
GenerateIndex();
ItemsHost.Children.Insert(row * Groups, _viewContent);
}
}
private void ClearItems()
{
_selectedItem = null;
_viewContent.Content = null;
_viewContent.ContentTemplate = null;
_viewContent.UpdatePosition(_selectedItem.Index, Groups, _selectedItem.DesiredSize.Width);
}
if (ItemsHost != null)
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (_itemsSourceInternal != null)
{
if (_itemsSourceInternal is INotifyCollectionChanged s)
{
ItemsHost.Children.Remove(_viewContent);
ItemsHost.Children.Clear();
s.CollectionChanged -= InternalCollectionChanged;
}
_entryDic.Clear();
Items.Clear();
ClearItems();
}
_itemsSourceInternal = newValue;
if (_itemsSourceInternal != null)
{
if (_itemsSourceInternal is INotifyCollectionChanged s)
{
s.CollectionChanged += InternalCollectionChanged;
}
foreach (var item in _itemsSourceInternal)
{
AddItem(item);
}
}
private void RemoveItem(object item)
if (ItemsHost != null)
{
if (_entryDic.TryGetValue(item, out var entry))
GenerateIndex();
}
}
private void ClearItems()
{
_selectedItem = null;
_viewContent.Content = null;
_viewContent.ContentTemplate = null;
if (ItemsHost != null)
{
ItemsHost.Children.Remove(_viewContent);
ItemsHost.Children.Clear();
}
_entryDic.Clear();
}
private void RemoveItem(object item)
{
if (_entryDic.TryGetValue(item, out var entry))
{
if (ReferenceEquals(entry, _selectedItem))
{
if (ReferenceEquals(entry, _selectedItem))
_selectedItem = null;
if (_viewContent != null)
{
_selectedItem = null;
if (_viewContent != null)
{
_viewContent.Content = null;
_viewContent.IsOpen = false;
ItemsHost.Children.Remove(_viewContent);
}
_viewContent.Content = null;
_viewContent.IsOpen = false;
ItemsHost.Children.Remove(_viewContent);
}
ItemsHost.Children.Remove(entry);
Items.Remove(item);
_entryDic.Remove(item);
}
ItemsHost.Children.Remove(entry);
Items.Remove(item);
_entryDic.Remove(item);
}
}
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
private void InsertItem(int index, object item)
private void InsertItem(int index, object item)
{
if (ItemsHost == null)
{
if (ItemsHost == null)
Items.Insert(index, item);
_entryDic.Add(item, null);
}
else
{
DependencyObject container;
if (IsItemItsOwnContainerOverride(item))
{
Items.Insert(index, item);
_entryDic.Add(item, null);
container = item as DependencyObject;
}
else
{
DependencyObject container;
if (IsItemItsOwnContainerOverride(item))
{
container = item as DependencyObject;
}
else
{
container = GetContainerForItemOverride();
PrepareContainerForItemOverride(container, item);
}
if (container is CoverViewItem element)
{
SetBindingForItem(element);
element.Style = ItemContainerStyle;
element.Header ??= item;
_entryDic[item] = element;
ItemsHost.Children.Insert(index, element);
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
{
Items.Insert(index, item);
}
}
container = GetContainerForItemOverride();
PrepareContainerForItemOverride(container, item);
}
}
/// <summary>
/// 生成序号
/// </summary>
private void GenerateIndex()
{
var index = 0;
foreach (var item in _entryDic.Values)
if (container is CoverViewItem element)
{
item.Index = index++;
}
}
SetBindingForItem(element);
element.Style = ItemContainerStyle;
element.Header ??= item;
_entryDic[item] = element;
ItemsHost.Children.Insert(index, element);
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (ItemsHost == null) return;
if (e.Action == NotifyCollectionChangedAction.Reset)
{
if (_entryDic.Count == 0) return;
ClearItems();
Items.Clear();
return;
}
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
{
RemoveItem(item);
Items.Insert(index, item);
}
}
if (e.NewItems != null)
{
if (_viewContent.IsOpen)
{
ItemsHost.Children.Remove(_viewContent);
}
var count = 0;
foreach (var item in e.NewItems)
{
var index = e.NewStartingIndex + count++;
InsertItem(index, item);
}
}
GenerateIndex();
if (_viewContent.IsOpen)
{
UpdateCoverViewContentPosition();
}
}
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_itemsSourceInternal != null) return;
InternalCollectionChanged(sender, e);
}
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
{
}
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
{
}
}
}
/// <summary>
/// 生成序号
/// </summary>
private void GenerateIndex()
{
var index = 0;
foreach (var item in _entryDic.Values)
{
item.Index = index++;
}
}
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (ItemsHost == null) return;
if (e.Action == NotifyCollectionChangedAction.Reset)
{
if (_entryDic.Count == 0) return;
ClearItems();
Items.Clear();
return;
}
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
{
RemoveItem(item);
}
}
if (e.NewItems != null)
{
if (_viewContent.IsOpen)
{
ItemsHost.Children.Remove(_viewContent);
}
var count = 0;
foreach (var item in e.NewItems)
{
var index = e.NewStartingIndex + count++;
InsertItem(index, item);
}
}
GenerateIndex();
if (_viewContent.IsOpen)
{
UpdateCoverViewContentPosition();
}
}
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_itemsSourceInternal != null) return;
InternalCollectionChanged(sender, e);
}
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
{
}
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
{
}
}
@@ -5,118 +5,117 @@ using HandyControl.Expression.Drawing;
using HandyControl.Tools;
using HandyControl.Tools.Extension;
namespace HandyControl.Controls
namespace HandyControl.Controls;
[TemplatePart(Name = ElementTriangle, Type = typeof(FrameworkElement))]
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
public class CoverViewContent : ContentControl
{
[TemplatePart(Name = ElementTriangle, Type = typeof(FrameworkElement))]
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
public class CoverViewContent : ContentControl
private const string ElementTriangle = "PART_Triangle";
private const string ElementContent = "PART_Content";
private FrameworkElement _triangle;
private FrameworkElement _content;
internal bool WaitForUpdate { get; set; }
private int _index;
private int _groups;
private double _itemWidth;
internal bool CanSwitch { get; set; } = true;
private bool _isOpen;
internal bool IsOpen
{
private const string ElementTriangle = "PART_Triangle";
private const string ElementContent = "PART_Content";
private FrameworkElement _triangle;
private FrameworkElement _content;
internal bool WaitForUpdate { get; set; }
private int _index;
private int _groups;
private double _itemWidth;
internal bool CanSwitch { get; set; } = true;
private bool _isOpen;
internal bool IsOpen
get => _isOpen;
set
{
get => _isOpen;
set
{
if (_isOpen == value) return;
_isOpen = value;
OpenSwitch(value);
}
}
internal static readonly DependencyProperty ManualHeightProperty = DependencyProperty.Register(
"ManualHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double0Box), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
internal double ManualHeight
{
get => (double) GetValue(ManualHeightProperty);
set => SetValue(ManualHeightProperty, value);
}
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
"ContentHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double300Box),
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double ContentHeight
{
get => (double) GetValue(ContentHeightProperty);
set => SetValue(ContentHeightProperty, value);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_triangle = GetTemplateChild(ElementTriangle) as FrameworkElement;
_content = GetTemplateChild(ElementContent) as FrameworkElement;
if (WaitForUpdate)
{
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((_index % _groups + .5) * _itemWidth - _triangle.Width / 2, 0, 0, 0)));
OpenSwitch(_isOpen);
WaitForUpdate = false;
}
}
internal void UpdatePosition(int index, int groups, double itemWidth)
{
if (_triangle == null)
{
_index = index;
_groups = groups;
_itemWidth = itemWidth;
WaitForUpdate = true;
return;
}
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((index % groups + .5) * itemWidth - _triangle.Width / 2, 0, 0, 0)));
if (IsOpen)
{
if (ManualHeight > 0 && !MathHelper.AreClose(ManualHeight, ContentHeight))
{
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ManualHeight));
}
else
{
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ContentHeight));
}
}
}
private void OpenSwitch(bool isOpen)
{
if (_content == null) return;
var animation = AnimationHelper.CreateAnimation(isOpen ? ManualHeight > 0 ? ManualHeight : ContentHeight : 0);
_triangle.Show(false);
this.Show(true);
animation.Completed += (s, e) =>
{
CanSwitch = true;
this.Show(IsOpen);
if (IsOpen)
{
_triangle.Show(true);
}
};
CanSwitch = false;
_content.BeginAnimation(HeightProperty, animation);
if (_isOpen == value) return;
_isOpen = value;
OpenSwitch(value);
}
}
}
internal static readonly DependencyProperty ManualHeightProperty = DependencyProperty.Register(
"ManualHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double0Box), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
internal double ManualHeight
{
get => (double) GetValue(ManualHeightProperty);
set => SetValue(ManualHeightProperty, value);
}
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
"ContentHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double300Box),
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double ContentHeight
{
get => (double) GetValue(ContentHeightProperty);
set => SetValue(ContentHeightProperty, value);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_triangle = GetTemplateChild(ElementTriangle) as FrameworkElement;
_content = GetTemplateChild(ElementContent) as FrameworkElement;
if (WaitForUpdate)
{
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((_index % _groups + .5) * _itemWidth - _triangle.Width / 2, 0, 0, 0)));
OpenSwitch(_isOpen);
WaitForUpdate = false;
}
}
internal void UpdatePosition(int index, int groups, double itemWidth)
{
if (_triangle == null)
{
_index = index;
_groups = groups;
_itemWidth = itemWidth;
WaitForUpdate = true;
return;
}
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((index % groups + .5) * itemWidth - _triangle.Width / 2, 0, 0, 0)));
if (IsOpen)
{
if (ManualHeight > 0 && !MathHelper.AreClose(ManualHeight, ContentHeight))
{
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ManualHeight));
}
else
{
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ContentHeight));
}
}
}
private void OpenSwitch(bool isOpen)
{
if (_content == null) return;
var animation = AnimationHelper.CreateAnimation(isOpen ? ManualHeight > 0 ? ManualHeight : ContentHeight : 0);
_triangle.Show(false);
this.Show(true);
animation.Completed += (s, e) =>
{
CanSwitch = true;
this.Show(IsOpen);
if (IsOpen)
{
_triangle.Show(true);
}
};
CanSwitch = false;
_content.BeginAnimation(HeightProperty, animation);
}
}
@@ -1,7 +1,6 @@
namespace HandyControl.Controls
namespace HandyControl.Controls;
public class CoverViewItem : HeaderedSelectableItem
{
public class CoverViewItem : HeaderedSelectableItem
{
internal int Index { get; set; }
}
}
internal int Index { get; set; }
}