原理是使用StackPanel 的margin属性的偏移来实现轮播的效果

废话不多说直接上代码

AutoPlayCarousel核心代码

[ContentProperty(nameof(Children))]
[TemplatePart(Name = "PART_StackPanel", Type = typeof(StackPanel))]
public class AutoPlayCarousel : Control
{
#region Identifier
/// <summary>
/// 视图区域
/// </summary>
private StackPanel _stkMain;
/// <summary>
///
/// </summary>
private DispatcherTimer _dtAutoPlay;
#endregion #region Constructor
static AutoPlayCarousel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoPlayCarousel), new FrameworkPropertyMetadata(typeof(AutoPlayCarousel)));
}
public AutoPlayCarousel()
{
Loaded += AutoScrollCarousel_Loaded;
SizeChanged += AutoScrollCarousel_SizeChanged;
}
#endregion #region RoutedEvent
public static readonly RoutedEvent IndexChangedEvent = EventManager.RegisterRoutedEvent("IndexChanged", RoutingStrategy.Bubble, typeof(IndexChangedEventHandler), typeof(AutoPlayCarousel));
public event IndexChangedEventHandler IndexChanged
{
add => AddHandler(IndexChangedEvent, value);
remove => RemoveHandler(IndexChangedEvent, value);
}
void RaiseIndexChanged(int newValue)
{
var arg = new IndexChangedEventArgs(newValue, IndexChangedEvent);
RaiseEvent(arg);
}
#endregion #region Property
/// <summary>
/// get the children collection.
/// </summary>
public ObservableCollection<FrameworkElement> Children
{
get => (ObservableCollection<FrameworkElement>)GetValue(ChildrenProperty);
private set => SetValue(ChildrenProperty, value);
} public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.Register("Children", typeof(ObservableCollection<FrameworkElement>), typeof(AutoPlayCarousel), new PropertyMetadata(new ObservableCollection<FrameworkElement>()));
/// <summary>
/// get or set orientation
/// </summary>
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
} public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(AutoPlayCarousel), new PropertyMetadata(Orientation.Horizontal)); /// <summary>
/// get or set index
/// </summary>
public int Index
{
get => (int)GetValue(IndexProperty);
set => SetValue(IndexProperty, value);
} public static readonly DependencyProperty IndexProperty =
DependencyProperty.Register("Index", typeof(int), typeof(AutoPlayCarousel), new PropertyMetadata(0, OnIndexChanged)); /// <summary>
/// Gets or sets animation duration.
/// </summary>
public TimeSpan AnimateDuration
{
get => (TimeSpan)GetValue(AnimateDurationProperty);
set => SetValue(AnimateDurationProperty, value);
} public static readonly DependencyProperty AnimateDurationProperty =
DependencyProperty.Register("AnimateDuration", typeof(TimeSpan), typeof(AutoPlayCarousel), new PropertyMetadata(TimeSpan.FromSeconds(0.5))); /// <summary>
/// Gets or sets recyclable.
/// </summary>
public bool Recyclable
{
get => (bool)GetValue(RecyclableProperty);
set => SetValue(RecyclableProperty, value);
} public static readonly DependencyProperty RecyclableProperty =
DependencyProperty.Register("Recyclable", typeof(bool), typeof(AutoPlayCarousel), new PropertyMetadata(false)); public TimeSpan AutoPlayInterval
{
get => (TimeSpan)GetValue(AutoPlayIntervalProperty);
set => SetValue(AutoPlayIntervalProperty, value);
} public static readonly DependencyProperty AutoPlayIntervalProperty =
DependencyProperty.Register("AutoPlayInterval", typeof(TimeSpan), typeof(AutoPlayCarousel), new PropertyMetadata(OnAutoPlayIntervalChanged)); #endregion #region Event Handler
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_stkMain = GetTemplateChild("PART_StackPanel") as StackPanel;
}
private void AutoScrollCarousel_SizeChanged(object sender, SizeChangedEventArgs e)
{
foreach (FrameworkElement children in Children)
{
children.Width = ActualWidth;
children.Height = ActualHeight;
}
}
private void AutoScrollCarousel_Loaded(object sender, RoutedEventArgs e)
{
if (Children == null)
return;
Loaded -= AutoScrollCarousel_Loaded;
foreach (FrameworkElement child in Children)
{
child.Width = ActualWidth;
child.Height = ActualHeight;
}
} private static void OnAutoPlayIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var autoScrollCarousel = d as AutoPlayCarousel;
autoScrollCarousel?.RestartAutoPlayTimer();
} private void DispatcherTimerAutoPlay_Tick(object sender, EventArgs e)
{
Index++;
} private static void OnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var autoScrollCarousel = d as AutoPlayCarousel;
if (autoScrollCarousel == null || !autoScrollCarousel.IsLoaded)
return; var targetIndex = 0;
if (!autoScrollCarousel.Recyclable)
targetIndex = autoScrollCarousel.Index > (autoScrollCarousel.Children.Count - 1) ? autoScrollCarousel.Children.Count - 1 : (autoScrollCarousel.Index < 0 ? 0 : autoScrollCarousel.Index);
else
targetIndex = autoScrollCarousel.Index > (autoScrollCarousel.Children.Count - 1) ? 0 : (autoScrollCarousel.Index < 0 ? autoScrollCarousel.Children.Count - 1 : autoScrollCarousel.Index); if (targetIndex != autoScrollCarousel.Index)
{
autoScrollCarousel.Index = targetIndex;
return;
} autoScrollCarousel.ResetAutoPlayTimer();
if (autoScrollCarousel.Orientation == Orientation.Vertical)
{
autoScrollCarousel._stkMain.BeginAnimation(StackPanel.MarginProperty, new ThicknessAnimation()
{
To = new Thickness(0, -1 * autoScrollCarousel.ActualHeight * autoScrollCarousel.Index, 0, 0),
Duration = autoScrollCarousel.AnimateDuration,
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
});
}
else
{
autoScrollCarousel._stkMain.BeginAnimation(StackPanel.MarginProperty, new ThicknessAnimation()
{
To = new Thickness(-1 * autoScrollCarousel.ActualWidth * autoScrollCarousel.Index, 0, 0, 0),
Duration = autoScrollCarousel.AnimateDuration,
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
});
}
autoScrollCarousel.RaiseIndexChanged(targetIndex);
} #endregion #region Function
private void RestartAutoPlayTimer()
{
if (_dtAutoPlay != null)
{
_dtAutoPlay.Stop();
}
if (AutoPlayInterval.TotalSeconds != 0)
{
_dtAutoPlay = new DispatcherTimer()
{
Interval = AutoPlayInterval,
};
_dtAutoPlay.Tick += DispatcherTimerAutoPlay_Tick;
_dtAutoPlay.Start();
}
} private void ResetAutoPlayTimer()
{
if (_dtAutoPlay != null)
{
_dtAutoPlay.Stop();
_dtAutoPlay.Start();
}
} #endregion
}

  一些辅助代码

public class IndexChangedEventArgs : RoutedEventArgs
{
public IndexChangedEventArgs(int currentIndex, RoutedEvent routedEvent) : base(routedEvent)
{
CurrentIndex = currentIndex;
} public int CurrentIndex { get; set; }
} public delegate void IndexChangedEventHandler(object sender, IndexChangedEventArgs e);

  AutoPlayCarousel默认的样式


<sys:Double x:Key="DefaultFontSize">14</sys:Double>
<sys:Boolean x:Key="DefaultSnapsToDevicePixels">false</sys:Boolean>


<Style TargetType="{x:Type local:AutoPlayCarousel}">
<Setter Property="SnapsToDevicePixels" Value="{StaticResource DefaultSnapsToDevicePixels}" />
<Setter Property="FontSize" Value="{StaticResource DefaultFontSize}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AutoPlayCarousel}">
<StackPanel x:Name="PART_StackPanel" Orientation="{TemplateBinding Orientation}">
<ItemsControl x:Name="PART_ItemsControl" ItemsSource="{TemplateBinding Children}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Orientation="{Binding Orientation,RelativeSource={RelativeSource AncestorType=local:AutoPlayCarousel}}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

  

页面使用

<customControl:AutoPlayCarousel
x:Name="Carousel"
AutoPlayInterval="0:0:3"
Recyclable="True"
Height="1080">
<Grid Background="Red" >
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="1" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Grid>
<Grid Background="Green" > <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="2" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid> </Grid>
<Grid Background="Yellow" >
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="3" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Grid>
<Grid Background="Blue" >
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="500" Width="500" Background="Black"> <TextBlock Text="4" FontSize="20" Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</Grid>
</customControl:AutoPlayCarousel>

  效果如下:

简易的AutoPlayCarousel 轮播控件的更多相关文章

  1. 简易的DragDropCarousel 拖拽轮播控件

    上一篇文章有写到 自动轮播的控件  简易的AutoPlayCarousel 轮播控件 - 黄高林 - 博客园 (cnblogs.com) 本章是基于自动轮播的一种衍生,通过拖拽鼠标进切换 直接上代码 ...

  2. WPF 控件库——轮播控件

    WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...

  3. 第四十六篇、UICollectionView广告轮播控件

    这是利用人的视觉错觉来实现无限轮播,UICollectionView 有很好的重用机制,这只是部分核心代码,后期还要继续完善和代码重构. #import <UIKit/UIKit.h> # ...

  4. Android之仿京东淘宝的自动无限轮播控件

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于Re ...

  5. Android图片轮播控件

    Android广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 使用步骤 Step 1.依赖banner Gradle dependenci ...

  6. jquery轮播控件

    网上找了一个轮播控件,效果不错,而且很容易改,需要的同学去下载咯 地址是:http://download.csdn.net/detail/jine515073/7704143

  7. Android-----------广告图片轮播控件

    Banner广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 很多Android APP中都有广告栏,我也用过很多次了,特来写一篇博文. 先 ...

  8. 一起写一个Android图片轮播控件

    注:本文提到的Android轮播控件Demo地址: Android图片轮播控件 1. 轮播控件的组成部分 我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成: 首先我们要有用 ...

  9. Android 开发最牛的图片轮播控件,基本什么都包含了。

    Android图片轮播控件  源码下载地址: Android 图片轮播 现在的绝大数app都有banner界面,实现循环播放多个广告图片和手动滑动循环等功能.因为ViewPager并不支持循环翻页, ...

随机推荐

  1. 解决Windows微软账户无法登录

    更新记录 2022年4月16日:本文迁移自Panda666原博客,原发布时间:2021年8月25日. 将DNS的服务器地址修改为4.2.2.1或者4.2.2.2就可以解决无法登录microsoft账户 ...

  2. SAP 实例- 页签tabsrip

    屏幕页签:项目上有一需求,对标准TCODE 一个屏幕增加一个页签.于是做了个例子. 下面屏幕有两个页签. 我们来看一下屏幕结构.100屏幕是主屏幕,101,102是子屏幕,对应页签test1,test ...

  3. SAP 日期计算

    1. CONVERSION_EXIT_IDATE_OUTPUT     INPUT:      20200601     OUTPUT:   03FEB2008 2. CONVERT_DATE_TO_ ...

  4. ssh空闲一段时间后自动断网

    ssh空闲一段时间后自动断网 用客户端工具,例如securecrt连接linux服务器,有的会出现过一段时间没有任何操作,客户端与服务器就断开了连接. 造成这个的原因,主要是因为客户端与服务器之间存在 ...

  5. 10.5 详解Android Studio项目结构

    Android项目的结构很复杂,并不像HTML项目,最简单的直接一个HTML文件就行了,相信学完上一节的同学就明白,哪怕是一个HelloWorld这样一个项目的文件可能都有几十个,所以我们需要搞清楚, ...

  6. hs-black 杂题选讲

    [POI2011]OKR-Periodicity 考虑递归地构造,设 \(\text{solve(s)}\) 表示字典序最小的,\(\text{border}\) 集合和 \(S\) 的 \(\tex ...

  7. Go flag 详解,实现二级子命令

    前言 日常开发使用到的命令行工具大都支持如下特性: 文档自动生成(如 -h --help) 多级子命令(如 docker exec -it) 支持参数(如 ls -color=auto) 长短选项(如 ...

  8. HMS Core音频编辑服务支持7种音频特效,助力一站式音频处理

    多媒体时代,音频作为内容传播中的重要形式,因其不受空间限制.认知负担小.声音元素多样化等特点,广泛应用于短视频制作.儿童在线教育.有声阅读.游戏等领域产品,在各种形式的音频呈现过程中,合理添加音效能够 ...

  9. 时间模块之datatime模块、os模块、sys模块、json模块、json模块实操

    目录 一.模块的绝对导入和相对导入 二.包的概念 三.编程思想的转变 四.软件开发目录规范 五.常见的内置模块 一.时间模块之datatime模块 1.datetime.datetime.today( ...

  10. Linux系统上传公钥不生效问题

    Authentication refused: bad ownership or modes for file /home/yanbo.xu/.ssh/authorized_keys 原因: sshd ...