简易的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>
效果如下:


浙公网安备 33010602011771号