diff --git a/HandyControl/Controls/Base/HeaderedSelectableItem.cs b/HandyControl/Controls/Base/HeaderedSelectableItem.cs new file mode 100644 index 00000000..480be514 --- /dev/null +++ b/HandyControl/Controls/Base/HeaderedSelectableItem.cs @@ -0,0 +1,16 @@ +using System.Windows; + +namespace HandyControl.Controls +{ + public class HeaderedSelectableItem : SelectableItem + { + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( + "Header", typeof(object), typeof(HeaderedSelectableItem), new PropertyMetadata(default(object))); + + public object Header + { + get => GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Base/ISelectable.cs b/HandyControl/Controls/Base/ISelectable.cs new file mode 100644 index 00000000..ce254ea3 --- /dev/null +++ b/HandyControl/Controls/Base/ISelectable.cs @@ -0,0 +1,11 @@ +using System.Windows; + +namespace HandyControl.Controls +{ + public interface ISelectable + { + event RoutedEventHandler Selected; + + bool IsSelected { get; set; } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Base/RegularItemsControl.cs b/HandyControl/Controls/Base/RegularItemsControl.cs new file mode 100644 index 00000000..4faca069 --- /dev/null +++ b/HandyControl/Controls/Base/RegularItemsControl.cs @@ -0,0 +1,41 @@ +using System.Windows; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + /// + /// 规则ItemsControl + /// + /// + /// 该类的每一项都具有相同的大小和外边距 + /// + public class RegularItemsControl : SimpleItemsControl + { + public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register( + "ItemWidth", typeof(double), typeof(RegularItemsControl), new PropertyMetadata(ValueBoxes.Double200Box)); + + public double ItemWidth + { + get => (double) GetValue(ItemWidthProperty); + set => SetValue(ItemWidthProperty, value); + } + + public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register( + "ItemHeight", typeof(double), typeof(RegularItemsControl), new PropertyMetadata(ValueBoxes.Double200Box)); + + public double ItemHeight + { + get => (double) GetValue(ItemHeightProperty); + set => SetValue(ItemHeightProperty, value); + } + + public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register( + "ItemMargin", typeof(Thickness), typeof(RegularItemsControl), new PropertyMetadata(default(Thickness))); + + public Thickness ItemMargin + { + get => (Thickness) GetValue(ItemMarginProperty); + set => SetValue(ItemMarginProperty, value); + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Base/SelectableItem.cs b/HandyControl/Controls/Base/SelectableItem.cs new file mode 100644 index 00000000..a64292d6 --- /dev/null +++ b/HandyControl/Controls/Base/SelectableItem.cs @@ -0,0 +1,56 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public class SelectableItem : ContentControl, ISelectable + { + private bool _isMouseLeftButtonDown; + + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseLeave(e); + + _isMouseLeftButtonDown = false; + } + + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + _isMouseLeftButtonDown = true; + } + + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonUp(e); + + if (_isMouseLeftButtonDown) + { + RaiseEvent(new RoutedEventArgs(SelectedEvent, this)); + _isMouseLeftButtonDown = false; + } + } + + public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( + "IsSelected", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox)); + + public bool IsSelected + { + get => (bool)GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + public static readonly RoutedEvent SelectedEvent = + EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, + typeof(RoutedEventHandler), typeof(SelectableItem)); + + public event RoutedEventHandler Selected + { + add => AddHandler(SelectedEvent, value); + remove => RemoveHandler(SelectedEvent, value); + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/Base/SimpleItemsControl.cs b/HandyControl/Controls/Base/SimpleItemsControl.cs index d88cf20d..e466722a 100644 --- a/HandyControl/Controls/Base/SimpleItemsControl.cs +++ b/HandyControl/Controls/Base/SimpleItemsControl.cs @@ -7,7 +7,9 @@ using System.Windows.Markup; namespace HandyControl.Controls { - [DefaultEvent("OnItemsChanged")] + /// + /// ItemsControl的轻量级版本 + /// [DefaultProperty("Items")] [ContentProperty("Items")] [TemplatePart(Name = ElementPanel, Type = typeof(Panel))] diff --git a/HandyControl/Controls/CoverFlow/CoverFlow.cs b/HandyControl/Controls/CoverFlow/CoverFlow.cs new file mode 100644 index 00000000..5cbdecaf --- /dev/null +++ b/HandyControl/Controls/CoverFlow/CoverFlow.cs @@ -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 +{ + /// + /// 封面流 + /// + [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"; + + /// + /// 最大显示数量的一半 + /// + private const int MaxShowCountHalf = 7; + + /// + /// 页码 + /// + 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); + } + + /// + /// 是否循环 + /// + public static readonly DependencyProperty LoopProperty = DependencyProperty.Register( + "Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox)); + + /// + /// 存储所有的资源标识符 + /// + private readonly Dictionary _uriList = new Dictionary(); + + /// + /// 当前在显示范围内的项 + /// + private readonly Dictionary _itemShowList = new Dictionary(); + + /// + /// 相机 + /// + private ProjectionCamera _camera; + + /// + /// 3d画布 + /// + private Viewport3D _viewport3D; + + /// + /// 项容器 + /// + private ModelVisual3D _visualParent; + + /// + /// 显示范围内第一个项的编号 + /// + private int _firstShowIndex; + + /// + /// 显示范围内最后一个项的编号 + /// + private int _lastShowIndex; + + /// + /// 在获取新的模板后是否需要更新项 + /// + private bool _updateItems; + + private bool _isLoaded; + + /// + /// 跳转编号 + /// + private int _jumpToIndex = -1; + + public CoverFlow() + { + Loaded += (s, e) => + { + if (_isLoaded) return; + _isLoaded = true; + if (_updateItems) + { + UpdateShowRange(); + _updateItems = false; + } + if (_jumpToIndex > 0) + { + PageIndex = _jumpToIndex; + } + }; + } + + /// + /// 页码 + /// + public int PageIndex + { + get => (int) GetValue(PageIndexProperty); + internal set => SetValue(PageIndexProperty, value); + } + + /// + /// 是否循环 + /// + 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); + } + } + + /// + /// 批量添加资源 + /// + /// + public void AddRange(List uriList) + { + foreach (var uri in uriList) + { + _uriList.Add(_uriList.Count, uri); + } + _updateItems = true; + } + + /// + /// 添加一项资源 + /// + /// + public void Add(string uriString) + { + _uriList.Add(_uriList.Count, new Uri(uriString)); + _updateItems = true; + } + + /// + /// 添加一项资源 + /// + /// + public void Add(Uri uri) + { + _uriList.Add(_uriList.Count, uri); + _updateItems = true; + } + + /// + /// 跳转 + /// + 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; + } + } + + /// + /// 删除指定位置的项 + /// + /// + private void Remove(int pos) + { + var item = _itemShowList[pos]; + _visualParent.Children.Remove(item); + _itemShowList.Remove(pos); + } + + /// + /// 移动项到指定的位置 + /// + /// + /// + 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; + } + } + } + } + + /// + /// 更新项的位置 + /// + /// + /// + 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); + } + + /// + /// 更新显示范围 + /// + 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; + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/CoverFlow/CoverFlowItem.cs b/HandyControl/Controls/CoverFlow/CoverFlowItem.cs new file mode 100644 index 00000000..634911a9 --- /dev/null +++ b/HandyControl/Controls/CoverFlow/CoverFlowItem.cs @@ -0,0 +1,169 @@ +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; + } + + /// + /// 创建网格形状 + /// + /// + /// + /// + /// + /// + 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; + } + + /// + /// 创建内容形状 + /// + /// + 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) + { + Console.WriteLine(Index * Interval + Math.Sign(Index - index) * 1.5); + return Index * Interval + Math.Sign(Index - index) * 1.5; + } + + private double GetZByPos(int index) => Index == index ? 1 : 0; + + /// + /// 移动 + /// + 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); + } + } + + /// + /// 命中测试 + /// + /// + /// + 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; + } + } +} \ No newline at end of file diff --git a/HandyControl/Controls/CoverView/CoverView.cs b/HandyControl/Controls/CoverView/CoverView.cs index 12e65563..862eb11f 100644 --- a/HandyControl/Controls/CoverView/CoverView.cs +++ b/HandyControl/Controls/CoverView/CoverView.cs @@ -4,7 +4,7 @@ using HandyControl.Data; namespace HandyControl.Controls { - public class CoverView : SimpleItemsControl + public class CoverView : RegularItemsControl { private readonly CoverViewContent _viewContent; @@ -14,7 +14,7 @@ namespace HandyControl.Controls { _viewContent = new CoverViewContent {ContentHeight = ItemContentHeight}; - AddHandler(CoverViewItem.SelectedEvent, new RoutedEventHandler(CoverViewItem_OnSelected)); + AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(CoverViewItem_OnSelected)); _viewContent.SetBinding(WidthProperty, new Binding(ActualWidthProperty.Name) { Source = this }); } @@ -87,33 +87,6 @@ namespace HandyControl.Controls set => SetValue(CoverViewContentStyleProperty, value); } - public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register( - "ItemWidth", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double200Box)); - - public double ItemWidth - { - get => (double) GetValue(ItemWidthProperty); - set => SetValue(ItemWidthProperty, value); - } - - public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register( - "ItemHeight", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double200Box)); - - public double ItemHeight - { - get => (double) GetValue(ItemHeightProperty); - set => SetValue(ItemHeightProperty, value); - } - - public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register( - "ItemMargin", typeof(Thickness), typeof(CoverView), new PropertyMetadata(default(Thickness))); - - public Thickness ItemMargin - { - get => (Thickness) GetValue(ItemMarginProperty); - set => SetValue(ItemMarginProperty, value); - } - internal static readonly DependencyProperty GroupsProperty = DependencyProperty.Register( "Groups", typeof(int), typeof(CoverView), new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsMeasure, OnGroupsChanged), IsGroupsValid); diff --git a/HandyControl/Controls/CoverView/CoverViewItem.cs b/HandyControl/Controls/CoverView/CoverViewItem.cs index 986f59fc..f3ae61a5 100644 --- a/HandyControl/Controls/CoverView/CoverViewItem.cs +++ b/HandyControl/Controls/CoverView/CoverViewItem.cs @@ -1,58 +1,7 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using HandyControl.Data; - -namespace HandyControl.Controls +namespace HandyControl.Controls { - public class CoverViewItem : HeaderedContentControl - { - private bool _isMouseLeftButtonDown; - - protected override void OnMouseLeave(MouseEventArgs e) - { - base.OnMouseLeave(e); - - _isMouseLeftButtonDown = false; - } - - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - base.OnMouseLeftButtonDown(e); - - _isMouseLeftButtonDown = true; - } - - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) - { - base.OnMouseLeftButtonUp(e); - - if (_isMouseLeftButtonDown) - { - RaiseEvent(new RoutedEventArgs(SelectedEvent, this)); - _isMouseLeftButtonDown = false; - } - } - - public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( - "IsSelected", typeof(bool), typeof(CoverViewItem), new PropertyMetadata(ValueBoxes.FalseBox)); - - public bool IsSelected - { - internal get => (bool) GetValue(IsSelectedProperty); - set => SetValue(IsSelectedProperty, value); - } - - public static readonly RoutedEvent SelectedEvent = - EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, - typeof(RoutedEventHandler), typeof(CoverViewItem)); - - public event RoutedEventHandler Selected - { - add => AddHandler(SelectedEvent, value); - remove => RemoveHandler(SelectedEvent, value); - } - + public class CoverViewItem : HeaderedSelectableItem + { internal int Index { get; set; } } } \ No newline at end of file diff --git a/HandyControl/Controls/Rate/Rate.cs b/HandyControl/Controls/Rate/Rate.cs index 95b9af84..907bb1d6 100644 --- a/HandyControl/Controls/Rate/Rate.cs +++ b/HandyControl/Controls/Rate/Rate.cs @@ -7,16 +7,13 @@ using HandyControl.Tools; namespace HandyControl.Controls { - public class Rate : SimpleItemsControl + public class Rate : RegularItemsControl { - public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register( - "ItemMargin", typeof(Thickness), typeof(Rate), new PropertyMetadata(default(Thickness))); - - public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register( - "ItemWidth", typeof(double), typeof(Rate), new PropertyMetadata(ValueBoxes.Double20Box)); - - public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register( - "ItemHeight", typeof(double), typeof(Rate), new PropertyMetadata(ValueBoxes.Double20Box)); + static Rate() + { + ItemWidthProperty.OverrideMetadata(typeof(Rate), new PropertyMetadata(ValueBoxes.Double20Box)); + ItemHeightProperty.OverrideMetadata(typeof(Rate), new PropertyMetadata(ValueBoxes.Double20Box)); + } public static readonly DependencyProperty AllowHalfProperty = DependencyProperty.Register( "AllowHalf", typeof(bool), typeof(Rate), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits)); @@ -42,6 +39,9 @@ namespace HandyControl.Controls public static readonly DependencyProperty ShowTextProperty = DependencyProperty.Register( "ShowText", typeof(bool), typeof(Rate), new PropertyMetadata(ValueBoxes.FalseBox)); + public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register( + "IsReadOnly", typeof(bool), typeof(Rate), new PropertyMetadata(ValueBoxes.FalseBox)); + private bool _isLoaded; public Rate() @@ -69,24 +69,6 @@ namespace HandyControl.Controls }; } - public Thickness ItemMargin - { - get => (Thickness) GetValue(ItemMarginProperty); - set => SetValue(ItemMarginProperty, value); - } - - public double ItemWidth - { - get => (double) GetValue(ItemWidthProperty); - set => SetValue(ItemWidthProperty, value); - } - - public double ItemHeight - { - get => (double) GetValue(ItemHeightProperty); - set => SetValue(ItemHeightProperty, value); - } - public bool AllowHalf { get => (bool) GetValue(AllowHalfProperty); @@ -135,6 +117,12 @@ namespace HandyControl.Controls set => SetValue(ShowTextProperty, value); } + public bool IsReadOnly + { + get => (bool)GetValue(IsReadOnlyProperty); + set => SetValue(IsReadOnlyProperty, value); + } + private void RateItemValueChanged(object sender, RoutedEventArgs e) { Value = @@ -201,9 +189,11 @@ namespace HandyControl.Controls UpdateItems(); } - private void UpdateItems() + protected override void UpdateItems() { + if (!_isLoaded) return; var count = (int) Value; + for (var i = 0; i < count; i++) { if (Items[i] is RateItem rateItem) diff --git a/HandyControl/Controls/Rate/RateItem.cs b/HandyControl/Controls/Rate/RateItem.cs index 3a297fb6..bdf2d878 100644 --- a/HandyControl/Controls/Rate/RateItem.cs +++ b/HandyControl/Controls/Rate/RateItem.cs @@ -20,6 +20,8 @@ namespace HandyControl.Controls public static readonly DependencyProperty IconProperty = Rate.IconProperty.AddOwner(typeof(RateItem)); + public static readonly DependencyProperty IsReadOnlyProperty = Rate.IsReadOnlyProperty.AddOwner(typeof(RateItem)); + internal static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( "IsSelected", typeof(bool), typeof(RateItem), new PropertyMetadata(ValueBoxes.FalseBox, OnIsSelectedChanged)); @@ -71,6 +73,12 @@ namespace HandyControl.Controls set => SetValue(IsSelectedProperty, value); } + public bool IsReadOnly + { + get => (bool)GetValue(IsReadOnlyProperty); + set => SetValue(IsReadOnlyProperty, value); + } + internal bool IsHalf { get => _isHalf; @@ -123,6 +131,7 @@ namespace HandyControl.Controls private void RateItem_MouseMove(object sender, MouseEventArgs e) { + if (IsReadOnly) return; if (!AllowHalf) return; var p = e.GetPosition(this); IsHalf = p.X < ActualWidth / 2; @@ -145,7 +154,7 @@ namespace HandyControl.Controls protected override void OnMouseEnter(MouseEventArgs e) { base.OnMouseEnter(e); - + if (IsReadOnly) return; _isSentValue = false; IsSelected = true; RaiseEvent(new RoutedEventArgs(SelectedChangedEvent) {Source = this}); @@ -154,21 +163,21 @@ namespace HandyControl.Controls protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); - + if (IsReadOnly) return; _isMouseLeftButtonDown = true; } protected override void OnMouseLeave(MouseEventArgs e) { base.OnMouseLeave(e); - + if (IsReadOnly) return; _isMouseLeftButtonDown = false; } protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); - + if (IsReadOnly) return; if (_isMouseLeftButtonDown) { if (Index == 1 && AllowClear) diff --git a/HandyControl/Controls/Window/BlurWindow.cs b/HandyControl/Controls/Window/BlurWindow.cs index e9ccb82c..44582434 100644 --- a/HandyControl/Controls/Window/BlurWindow.cs +++ b/HandyControl/Controls/Window/BlurWindow.cs @@ -30,7 +30,7 @@ namespace HandyControl.Controls } else { - accentPolicy.AccentState = ExternDllHelper.ACCENTSTATE.ACCENT_ENABLE_TRANSPARENTGRADIENT; + return; } accentPolicy.AccentFlags = 2; diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj index 08d93472..77f6eba7 100644 --- a/HandyControl/HandyControl.csproj +++ b/HandyControl/HandyControl.csproj @@ -117,7 +117,13 @@ + + + + + + @@ -379,6 +385,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -415,6 +425,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/HandyControl/Themes/Styles/Base/CoverFlowBaseStyle.xaml b/HandyControl/Themes/Styles/Base/CoverFlowBaseStyle.xaml new file mode 100644 index 00000000..e0817918 --- /dev/null +++ b/HandyControl/Themes/Styles/Base/CoverFlowBaseStyle.xaml @@ -0,0 +1,49 @@ + + + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml b/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml index 5e96b5cb..1ac7de1f 100644 --- a/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml +++ b/HandyControl/Themes/Styles/Base/ProgressBarBaseStyle.xaml @@ -83,7 +83,7 @@ - + diff --git a/HandyControl/Themes/Styles/Base/RateBaseStyle.xaml b/HandyControl/Themes/Styles/Base/RateBaseStyle.xaml index 16835414..2d327fe2 100644 --- a/HandyControl/Themes/Styles/Base/RateBaseStyle.xaml +++ b/HandyControl/Themes/Styles/Base/RateBaseStyle.xaml @@ -14,6 +14,7 @@ + diff --git a/HandyControl/Themes/Styles/CoverFlow.xaml b/HandyControl/Themes/Styles/CoverFlow.xaml new file mode 100644 index 00000000..db772bff --- /dev/null +++ b/HandyControl/Themes/Styles/CoverFlow.xaml @@ -0,0 +1,10 @@ + + + + + + +