当前位置:   article > 正文

WPF自定义控件(教程含源码)-轮播控件、仿 layui Carousel 控件_wpf carousel

wpf carousel

控件需求

制作一个轮播控件。要求包含左右翻页按钮、索引指示、索引点击跳转。

控件效果

rcarousel

 控件基本元素

  • Button:控制左右滑动。

Button 由一个透明的 Ellispe 和 描绘箭头的 Path 公共组成,这里直接重写 Button 的 模板即可,xaml代码样式如下:

  1. <Style x:Key="carouselButton" TargetType="{x:Type Button}">
  2. <Setter Property="RenderTransformOrigin" Value=".5 .5" />
  3. <Setter Property="Width" Value="40" />
  4. <Setter Property="Height" Value="40" />
  5. <Setter Property="Template">
  6. <Setter.Value>
  7. <ControlTemplate TargetType="{x:Type Button}">
  8. <Grid>
  9. <Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Fill="#33000000" x:Name="root" />
  10. <Path Data="M25,10 L13,20 L25,30" StrokeThickness="2" Stroke="White" />
  11. </Grid>
  12. <ControlTemplate.Triggers>
  13. <Trigger Property="IsMouseOver" Value="true">
  14. <Setter TargetName="root" Property="Fill" Value="#5a000000" />
  15. </Trigger>
  16. </ControlTemplate.Triggers>
  17. </ControlTemplate>
  18. </Setter.Value>
  19. </Setter>
  20. </Style>
  • RWrapPanel:放置内容项目,实现平滑滚动。

参考上一篇文章:实现可以平滑滚动的Panel 控件

  • RCarouselIndicator:索引显示,索引跳转。

RCarouselIndicator 继承 ListView,新增 Count 属性,通过Count 属性控制圆点个数。使用时间 SelectedIndex 与 RCarousel 的 Index 进行双向绑定。

RCarouselIndicatorSelected 通过传入 SelectedIndex 和 Value(存放在Tag内)控制控件是否选中。

RCarouselIndicator的 xaml 代码 和 c# 代码如下:

  1. <local:RCarouselIndicatorSelected x:Key="RCarouselIndicatorSelected" />
  2. <Style x:Key="indexPoint" TargetType="Ellipse">
  3. <Setter Property="Fill" Value="#7dffffff" />
  4. <Setter Property="Width" Value="14" />
  5. <Setter Property="Height" Value="14" />
  6. <Setter Property="Margin" Value="3" />
  7. </Style>
  8. <Style TargetType="local:RCarouselIndicator">
  9. <Setter Property="Template">
  10. <Setter.Value>
  11. <ControlTemplate TargetType="local:RCarouselIndicator">
  12. <Border SnapsToDevicePixels="True" Background="#33000000" VerticalAlignment="Bottom" Margin="0 0 0 15" HorizontalAlignment="Center" MinWidth="14" CornerRadius="13">
  13. <WrapPanel VerticalAlignment="Center" Margin="3" IsItemsHost="True" />
  14. </Border>
  15. </ControlTemplate>
  16. </Setter.Value>
  17. </Setter>
  18. <Setter Property="ItemContainerStyle">
  19. <Setter.Value>
  20. <Style TargetType="ListViewItem">
  21. <Setter Property="Template">
  22. <Setter.Value>
  23. <ControlTemplate TargetType="ListViewItem">
  24. <ContentPresenter />
  25. </ControlTemplate>
  26. </Setter.Value>
  27. </Setter>
  28. </Style>
  29. </Setter.Value>
  30. </Setter>
  31. <Setter Property="ItemTemplate">
  32. <Setter.Value>
  33. <DataTemplate>
  34. <Grid>
  35. <Ellipse Style="{StaticResource indexPoint}" Tag="{Binding}" Cursor="Hand">
  36. <Ellipse.Fill>
  37. <MultiBinding Converter="{StaticResource RCarouselIndicatorSelected}">
  38. <Binding Path="SelectedIndex" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=local:RCarouselIndicator}" />
  39. <Binding Path="Tag" RelativeSource="{RelativeSource Mode=Self}" />
  40. </MultiBinding>
  41. </Ellipse.Fill>
  42. </Ellipse>
  43. </Grid>
  44. </DataTemplate>
  45. </Setter.Value>
  46. </Setter>
  47. </Style>
  1. public partial class RCarouselIndicator: ListView {
  2. static RCarouselIndicator() {
  3. DefaultStyleKeyProperty.OverrideMetadata(typeof(RCarouselIndicator), new FrameworkPropertyMetadata(typeof(RCarouselIndicator)));
  4. }
  5. public static readonly DependencyProperty CountProperty =
  6. DependencyProperty.Register("Count", typeof(int), typeof(RCarouselIndicator), new FrameworkPropertyMetadata(1, CountChanged));
  7. static void CountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
  8. if (d is RCarouselIndicator control) {
  9. var count = Convert.ToInt32(e.NewValue);
  10. control.Items.Clear();
  11. Enumerable.Range(0, count).ToList().ForEach(t => control.Items.Add(t));
  12. }
  13. }
  14. public int Count {
  15. get => (int)GetValue(CountProperty);
  16. set => SetValue(CountProperty, value);
  17. }
  18. }
  19. public class RCarouselIndicatorSelected : IMultiValueConverter {
  20. public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
  21. if (values.Length == 2 && values[0] is int v1 && values[1] is int v2 && v1 == v2) {
  22. return Brushes.White;
  23. } else {
  24. return new SolidColorBrush(Color.FromArgb(0x7d, 0xff, 0xff, 0xff));
  25. }
  26. }
  27. public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
  28. throw new NotImplementedException();
  29. }
  30. }

将基本元素组合

RCarousel 的 xaml代码

  1. <Style x:Key="RCarousel_Item" TargetType="ListBoxItem">
  2. <Setter Property="Template">
  3. <Setter.Value>
  4. <ControlTemplate TargetType="ListBoxItem">
  5. <ContentPresenter />
  6. </ControlTemplate>
  7. </Setter.Value>
  8. </Setter>
  9. </Style>
  10. <ControlTemplate x:Key="RCarousel_Template" TargetType="local:RCarousel">
  11. <Border SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
  12. <Grid>
  13. <ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" CanContentScroll="True">
  14. <local:RWrapPanel IsItemsHost="True" x:Name="panel" />
  15. </ScrollViewer>
  16. <local:RCarouselIndicator Count="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Items.Count, Mode=OneWay}"
  17. SelectedIndex="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Index, Mode=TwoWay}" />
  18. <Button Style="{StaticResource carouselButton}" HorizontalAlignment="Left" Margin="15 0 0 0" Visibility="Collapsed" x:Name="btn1"/>
  19. <Button Style="{StaticResource carouselButton}" HorizontalAlignment="Right" Margin="0 0 15 0" Visibility="Collapsed" x:Name="btn2">
  20. <Button.RenderTransform>
  21. <RotateTransform Angle="180" />
  22. </Button.RenderTransform>
  23. </Button>
  24. </Grid>
  25. </Border>
  26. <ControlTemplate.Triggers>
  27. <Trigger Property="IsMouseOver" Value="true" >
  28. <Setter TargetName="btn1" Property="Visibility" Value="Visible" />
  29. <Setter TargetName="btn2" Property="Visibility" Value="Visible" />
  30. </Trigger>
  31. </ControlTemplate.Triggers>
  32. </ControlTemplate>
  33. <Style TargetType="local:RCarousel">
  34. <Setter Property="Template" Value="{StaticResource RCarousel_Template}" />
  35. <Setter Property="ItemContainerStyle" Value="{StaticResource RCarousel_Item}" />
  36. </Style>

RCarousel 的 c# 代码 

  1. public partial class RCarousel: ListBox {
  2. RWrapPanel panel;
  3. static RCarousel() {
  4. DefaultStyleKeyProperty.OverrideMetadata(typeof(RCarousel), new FrameworkPropertyMetadata(typeof(RCarousel)));
  5. }
  6. public static readonly DependencyProperty IndexProperty =
  7. DependencyProperty.Register("Index", typeof(int), typeof(RCarousel), new FrameworkPropertyMetadata(0, IndexChanged));
  8. static void IndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
  9. if (d is RCarousel control) {
  10. var index = Convert.ToInt32(e.NewValue);
  11. control.panel.SetHorizontalOffset(index * control.ActualWidth);
  12. }
  13. }
  14. public int Index {
  15. get => (int)GetValue(IndexProperty);
  16. set => SetValue(IndexProperty, value);
  17. }
  18. public override void OnApplyTemplate() {
  19. base.OnApplyTemplate();
  20. panel = GetTemplateChild("panel") as RWrapPanel;
  21. Button btn1 = GetTemplateChild("btn1") as Button;
  22. Button btn2 = GetTemplateChild("btn2") as Button;
  23. btn1.Click += Btn1_Click;
  24. btn2.Click += Btn2_Click;
  25. var count = this.Items.Count;
  26. }
  27. private void Btn1_Click(object sender, RoutedEventArgs e) {
  28. panel.PageLeft();
  29. if (Index > 0) Index--;
  30. }
  31. private void Btn2_Click(object sender, RoutedEventArgs e) {
  32. panel.PageRight();
  33. if (Index < Items.Count - 1) Index++;
  34. }
  35. }

在xaml 内调用该控件

  1. <UserControl x:Class="WPFCustomControl.Pages.RCarouselDemo"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. xmlns:local="clr-namespace:WPFCustomControl.Pages"
  7. xmlns:cr="clr-namespace:WPFCustomControl.Controls"
  8. mc:Ignorable="d"
  9. d:DesignHeight="450" d:DesignWidth="800">
  10. <Grid>
  11. <cr:RCarousel x:Name="root" >
  12. <Border Background="#009688" Width="{Binding ElementName=root, Path=ActualWidth}" Height="{Binding ElementName=root, Path=ActualHeight}">
  13. <TextBlock Text="项目1" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
  14. </Border>
  15. <Border Background="#5FB878" Width="{Binding ElementName=root, Path=ActualWidth}" Height="{Binding ElementName=root, Path=ActualHeight}">
  16. <TextBlock Text="项目2" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
  17. </Border>
  18. <Border Background="#009688" Width="{Binding ElementName=root, Path=ActualWidth}" Height="{Binding ElementName=root, Path=ActualHeight}">
  19. <TextBlock Text="项目3" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
  20. </Border>
  21. <Border Background="#5FB878" Width="{Binding ElementName=root, Path=ActualWidth}" Height="{Binding ElementName=root, Path=ActualHeight}">
  22. <TextBlock Text="项目4" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
  23. </Border>
  24. </cr:RCarousel>
  25. </Grid>
  26. </UserControl>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/537625
推荐阅读
相关标签
  

闽ICP备14008679号