diff --git a/HandyControl/Controls/Carousel.xaml b/HandyControl/Controls/Carousel.xaml new file mode 100644 index 00000000..1281770d --- /dev/null +++ b/HandyControl/Controls/Carousel.xaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Controls/Carousel.xaml.cs b/HandyControl/Controls/Carousel.xaml.cs new file mode 100644 index 00000000..c1cbde80 --- /dev/null +++ b/HandyControl/Controls/Carousel.xaml.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Threading; +using HandyControl.Tools; + +namespace HandyControl.Controls +{ + /// + /// Carousel.xaml 的交互逻辑 + /// + [DefaultProperty("Items")] + [ContentProperty("Items")] + public partial class Carousel + { + public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register( + "AutoRun", typeof(bool), typeof(Carousel), new PropertyMetadata(default(bool), (o, args) => + { + var ctl = (Carousel)o; + ctl.TimerSwitch((bool)args.NewValue); + })); + + public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register( + "Interval", typeof(TimeSpan), typeof(Carousel), new PropertyMetadata(TimeSpan.FromSeconds(2))); + + public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( + "ItemsSource", typeof(IEnumerable), typeof(Carousel), new PropertyMetadata(default(IEnumerable), + (o, args) => + { + var ctl = (Carousel)o; + ctl.UpdatePageButtons(); + })); + + public static readonly DependencyProperty ExtendWidthProperty = DependencyProperty.Register( + "ExtendWidth", typeof(double), typeof(Carousel), new PropertyMetadata(default(double))); + + public double ExtendWidth + { + get => (double)GetValue(ExtendWidthProperty); + set => SetValue(ExtendWidthProperty, value); + } + + public static readonly DependencyProperty IsCenterProperty = DependencyProperty.Register( + "IsCenter", typeof(bool), typeof(Carousel), new PropertyMetadata(default(bool))); + + public bool IsCenter + { + get => (bool)GetValue(IsCenterProperty); + set => SetValue(IsCenterProperty, value); + } + + private int _pageIndex = -1; + + private Button _selectedButton; + + private DispatcherTimer _updateTimer; + + private readonly List _widthList = new List(); + + public Carousel() + { + InitializeComponent(); + + Loaded += (s, e) => UpdatePageButtons(); + } + + /// + /// 是否自动跳转 + /// + public bool AutoRun + { + get => (bool)GetValue(AutoRunProperty); + set => SetValue(AutoRunProperty, value); + } + + /// + /// 跳转时间间隔 + /// + public TimeSpan Interval + { + get => (TimeSpan)GetValue(IntervalProperty); + set => SetValue(IntervalProperty, value); + } + + /// + /// 页码 + /// + public int PageIndex + { + get => _pageIndex; + set + { + if (Items.Count == 0) return; + if (_pageIndex == value) return; + if (value < 0) + _pageIndex = Items.Count - 1; + else if (value >= Items.Count) + _pageIndex = 0; + else + _pageIndex = value; + UpdatePageButtons(_pageIndex); + } + } + + public IEnumerable ItemsSource + { + get => (IEnumerable)GetValue(ItemsSourceProperty); + set => SetValue(ItemsSourceProperty, value); + } + + public ItemCollection Items => ListBoxMain.Items; + + /// + /// 计时器开关 + /// + private void TimerSwitch(bool run) + { + if (run) + { + _updateTimer = new DispatcherTimer + { + Interval = Interval + }; + _updateTimer.Tick += UpdateTimer_Tick; + _updateTimer.Start(); + } + else + { + _updateTimer.Tick -= UpdateTimer_Tick; + _updateTimer.Stop(); + _updateTimer = null; + } + } + + private void UpdateTimer_Tick(object sender, EventArgs e) + { + if (IsMouseOver) return; + PageIndex++; + } + + /// + /// 更新页按钮 + /// + public void UpdatePageButtons(int? index = null) + { + if (index == null) + { + var count = Items.Count; + _widthList.Clear(); + _widthList.Add(0); + var width = .0; + foreach (FrameworkElement item in ListBoxMain.Items) + { + width += item.Width + item.Margin.Left + item.Margin.Right; + _widthList.Add(width); + } + + ListBoxMain.Width = _widthList.Last() + ExtendWidth; + PanelPage.Children.Clear(); + for (var i = 0; i < count; i++) + PanelPage.Children.Add(CreatePateButton()); + if (count > 0) + { + var button = PanelPage.Children[0]; + button.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, button)); + } + } + else + { + if (index >= 0 && index < PanelPage.Children.Count) + { + var button = PanelPage.Children[(int)index]; + button.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, button)); + UpdateItemsPosition(); + } + } + } + + /// + /// 更新项的位置 + /// + private void UpdateItemsPosition() + { + if (Items.Count == 0 || PageIndex == -1) return; + if (!IsCenter) + { + ListBoxMain.BeginAnimation(MarginProperty, + AnimationHelper.CreateAnimation(new Thickness(-_widthList[PageIndex], 0, 0, 0))); + } + else + { + var ctl = (FrameworkElement)Items[PageIndex]; + var ctlWidth = ctl.Width + ctl.Margin.Left + ctl.Margin.Right; + ListBoxMain.BeginAnimation(MarginProperty, + AnimationHelper.CreateAnimation( + new Thickness(-_widthList[PageIndex] + (ActualWidth - ctlWidth) / 2, 0, 0, 0))); + } + } + + protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) + { + base.OnRenderSizeChanged(sizeInfo); + UpdateItemsPosition(); + } + + /// + /// 创建页按钮 + /// + /// + private Button CreatePateButton() + { + var button = new Button + { + Style = TryFindResource("ButtonOpacityStyle") as Style, + Content = new Border + { + Width = 10, + Height = 10, + CornerRadius = new CornerRadius(5), + Background = Brushes.White, + Margin = new Thickness(5, 0, 5, 0), + BorderThickness = new Thickness(1), + BorderBrush = TryFindResource("PrimaryBrush") as Brush + } + }; + return button; + } + + private void ButtonPages_OnClick(object sender, RoutedEventArgs e) + { + if (_selectedButton != null && _selectedButton.Content is Border borderOri) + borderOri.Background = Brushes.White; + _selectedButton = e.OriginalSource as Button; + if (_selectedButton != null && _selectedButton.Content is Border border) + border.Background = TryFindResource("PrimaryBrush") as Brush; + var index = PanelPage.Children.IndexOf(_selectedButton); + if (index != -1) + PageIndex = index; + } + + private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) + { + PageIndex--; + } + + private void ButtonNext_OnClick(object sender, RoutedEventArgs e) + { + PageIndex++; + } + } +} \ No newline at end of file diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj index d8a19cdc..bec70150 100644 --- a/HandyControl/HandyControl.csproj +++ b/HandyControl/HandyControl.csproj @@ -31,6 +31,9 @@ 4 + + Carousel.xaml + ColorPicker.xaml @@ -102,6 +105,10 @@ + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -162,6 +169,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -186,6 +197,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/HandyControl/Themes/Styles/Base/ListBoxBaseStyle.xaml b/HandyControl/Themes/Styles/Base/ListBoxBaseStyle.xaml new file mode 100644 index 00000000..ba965654 --- /dev/null +++ b/HandyControl/Themes/Styles/Base/ListBoxBaseStyle.xaml @@ -0,0 +1,71 @@ + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/ListBox.xaml b/HandyControl/Themes/Styles/ListBox.xaml new file mode 100644 index 00000000..6fab421d --- /dev/null +++ b/HandyControl/Themes/Styles/ListBox.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HandyControl/Themes/Styles/Style.xaml b/HandyControl/Themes/Styles/Style.xaml index 42d4f76e..46b6e18e 100644 --- a/HandyControl/Themes/Styles/Style.xaml +++ b/HandyControl/Themes/Styles/Style.xaml @@ -20,11 +20,11 @@ - --> + diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj index ee7f0f79..e50567a1 100644 --- a/HandyControlDemo/HandyControlDemo.csproj +++ b/HandyControlDemo/HandyControlDemo.csproj @@ -73,5 +73,12 @@ HandyControl + + + + + + + \ No newline at end of file diff --git a/HandyControlDemo/MainWindow.xaml b/HandyControlDemo/MainWindow.xaml index 8da76a79..a15f8e15 100644 --- a/HandyControlDemo/MainWindow.xaml +++ b/HandyControlDemo/MainWindow.xaml @@ -376,7 +376,7 @@ - +