简易的AutoPlayCarousel 轮播控件
原理是使用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 轮播控件的更多相关文章
- 简易的DragDropCarousel 拖拽轮播控件
上一篇文章有写到 自动轮播的控件 简易的AutoPlayCarousel 轮播控件 - 黄高林 - 博客园 (cnblogs.com) 本章是基于自动轮播的一种衍生,通过拖拽鼠标进切换 直接上代码 ...
- WPF 控件库——轮播控件
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- 第四十六篇、UICollectionView广告轮播控件
这是利用人的视觉错觉来实现无限轮播,UICollectionView 有很好的重用机制,这只是部分核心代码,后期还要继续完善和代码重构. #import <UIKit/UIKit.h> # ...
- Android之仿京东淘宝的自动无限轮播控件
在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于Re ...
- Android图片轮播控件
Android广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 使用步骤 Step 1.依赖banner Gradle dependenci ...
- jquery轮播控件
网上找了一个轮播控件,效果不错,而且很容易改,需要的同学去下载咯 地址是:http://download.csdn.net/detail/jine515073/7704143
- Android-----------广告图片轮播控件
Banner广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 很多Android APP中都有广告栏,我也用过很多次了,特来写一篇博文. 先 ...
- 一起写一个Android图片轮播控件
注:本文提到的Android轮播控件Demo地址: Android图片轮播控件 1. 轮播控件的组成部分 我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成: 首先我们要有用 ...
- Android 开发最牛的图片轮播控件,基本什么都包含了。
Android图片轮播控件 源码下载地址: Android 图片轮播 现在的绝大数app都有banner界面,实现循环播放多个广告图片和手动滑动循环等功能.因为ViewPager并不支持循环翻页, ...
随机推荐
- bitmap技术解析:redis与roaringBitmap
bitmap的表象意义是,使用一个01标识位来表示是否的状态,可以达到节省空间和高效判定的效果.在我们的实际工作中,也有着许多的应用场景,相信了解bitmap定会给你带来一些额外的收获. 1. bit ...
- distroless 镜像介绍及 基于cbl-mariner的.NET distroless 镜像的容器
1.概述 容器改变了我们看待技术基础设施的方式.这是我们运行应用程序方式的一次巨大飞跃.容器编排和云服务一起为我们提供了一种近乎无限规模的无缝扩展能力. 根据定义,容器应该包含 应用程序 及其 运行时 ...
- 整理orcal常用sql语句
1.表插入列 alter table XMJ_ONE add column1 NUMBER(38) default 0;comment on column XMJ_ONE.column1 is '字段 ...
- 揭秘GaussDB(for Redis):全面对比Codis
摘要:Codis集群在国内Redis生态圈很流行,社区已停止维护.本文从架构和特性两方面对比,带你感受华为云GaussDB(for Redis)的全新价值. 本文分享自华为云社区<华为云Gaus ...
- 利用MATLAB仿真最小发射功率下WSN的连通性和覆盖率
一.目的 (1)在固定节点个数的前提下,仿真求得使网络保持连通的最小通信半径(最低能级). (2)在上述节点个数和通信半径的前提下,计算随机布撒的节点的覆盖率. 二.方法描述 (1)首先假设通信半径都 ...
- Python迷宫生成器
作为一项古老的智力游戏,千百年来迷宫都散发着迷人的魅力.但是,手工设计迷宫费时又耗(脑)力,于是,我们有必要制作一个程序:迷宫生成器-- 好吧,我编不下去了.但是,从上面的文字中,我们可以看出,我们此 ...
- Solution -「ABC 217」题解
D - Cutting Woods 记录每一个切割点,每次求前驱后驱就好了,注意简单判断一下开闭区间. 考场上采用的 FHQ_Treap 无脑莽. #include <cstdio> #i ...
- 【Codeforces1706A】 Another String Minimization Problem
官方标签 贪心.字符串 题目描述 输入 输出 样例输入 6 4 5 1 1 3 1 1 5 2 4 1 1 1 1 1 2 4 1 3 2 7 7 5 4 5 5 5 3 5 样例输出 ABABA B ...
- 基于ABP实现DDD--实体创建和更新
本文主要介绍了通过构造函数和领域服务创建实体2种方式,后者多用于在创建实体时需要其它业务规则检测的场景.最后介绍了在应用服务层中如何进行实体的更新操作. 一.通过构造函数创建实体 假如Issue的 ...
- Linux 加密安全和私有CA的搭建方法
常用安全技术 3A: 认证:身份确认 授权:权限分配 审计:监控做了什么 安全通信 加密算法和协议 对称加密: 非对称加密 单向加密:哈希(hash)加密 认证协议 对称加密: 加密和解密使用的是同一 ...