WPF自定义控件一:StackPanel 控件轮播

实现效果

带定时器的轮播图

using引用

using System.Windows;


using System.Windows.Controls;


using System.Windows.Markup;


using System.Windows.Media;


using System.Windows.Media.Animation;


using System.Windows.Threading;

 

自定义Control

 

 /// <summary>
    /// 轮播控件
    /// </summary>
    [ContentProperty(nameof(Children))]
    public class CarRoundPlay:Control
    {

        private StackPanel stackPanel;

        private DispatcherTimer _DtAutoPlay;
        static CarRoundPlay()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CarRoundPlay), new FrameworkPropertyMetadata(typeof(CarRoundPlay)));
        }
        /// <summary>
        /// 构造方法
        /// </summary>
        public CarRoundPlay()
        {
            Children = new ObservableCollection<UIElement>();
            Loaded += CarRoundPlay_Load;
            SizeChanged += CarRoundPlay_Changed;
        }

        /// <summary>
        /// 大小发生改变时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CarRoundPlay_Changed(object sender, SizeChangedEventArgs e)
        {
            foreach (FrameworkElement child in Children)
            {
                child.Width = ActualWidth;
                child.Height = ActualHeight;
            }
        }

        /// <summary>
        /// 控件初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CarRoundPlay_Load(object sender, RoutedEventArgs e)
        {
            //判断子集合是否为空
            if (Children == null)
                return;
            //便利子集布局并将当前容器宽高赋予子集布局控件
            foreach (FrameworkElement child in Children)
            {
                child.Width = ActualWidth;
                child.Height = ActualHeight;
            }
        }


        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            //获取当前显示布局控件
            stackPanel = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 0) as StackPanel;
        }
        /// <summary>
        /// 图片大小发生改变时
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var carousel = d as CarRoundPlay;
            if (!carousel.IsLoaded)
                return;
            var targetIndex = 0;
            if (!carousel.Recyclable)
                targetIndex = carousel.Index > (carousel.Children.Count - 1) ? carousel.Children.Count - 1 : (carousel.Index < 0 ? 0 : carousel.Index);
            else
                targetIndex = carousel.Index > (carousel.Children.Count - 1) ? 0 : (carousel.Index < 0 ? carousel.Children.Count - 1 : carousel.Index);

            if (targetIndex != carousel.Index)
            {
                carousel.Index = targetIndex;
                return;
            }
            carousel.ResetAutoPlayTimer();
            ///判断控件布局触发动画
            if (carousel.Orientation == Orientation.Vertical)
            {
                carousel.stackPanel.BeginAnimation(StackPanel.MarginProperty, new ThicknessAnimation()
                {
                    To = new Thickness(0, -1 * carousel.ActualHeight * carousel.Index, 0, 0),
                    Duration = carousel.AnimateDuration,
                    EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
                });
            }
            else
            {
                carousel.stackPanel.BeginAnimation(StackPanel.MarginProperty, new ThicknessAnimation()
                {
                    To = new Thickness(-1 * carousel.ActualWidth * carousel.Index, 0, 0, 0),
                    Duration = carousel.AnimateDuration,
                    EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut }
                });
            }
            carousel.RaiseIndexChanged(targetIndex);
        }
        private static void OnAutoPlayIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var carousel = d as CarRoundPlay;
            carousel.RestartAutoPlayTimer();
        }
        /// <summary>
        /// 定时切换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DispatcherTimerAutoPlay_Tick(object sender, EventArgs e)
        {
            Index++;
        }
        public T FindFirstVisualChild<T>(DependencyObject obj, string childName) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is T && child.GetValue(NameProperty).ToString() == childName)
                {
                    return (T)child;
                }
                else
                {
                    T childOfChild = FindFirstVisualChild<T>(child, childName);
                    if (childOfChild != null)
                    {
                        return childOfChild;
                    }
                }
            }
            return null;
        }

        #region 公共

        /// <summary>
        /// 子集合控件
        /// </summary>
        public ObservableCollection<UIElement> Children
        {
            get { return (ObservableCollection<UIElement>)GetValue(ChildrenProperty); }
            private set { SetValue(ChildrenProperty, value); }
        }

        public static readonly DependencyProperty ChildrenProperty =
            DependencyProperty.Register("Children", typeof(ObservableCollection<UIElement>), typeof(CarRoundPlay));


        /// <summary>
        /// 布局方向
        /// </summary>
        public Orientation  Orientation
        {
            get { return (Orientation)GetValue( OrientationProperty); }
            set { SetValue( OrientationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for  Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty  OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(CarRoundPlay), new PropertyMetadata(Orientation.Horizontal));


        /// <summary>
        /// 
        /// </summary>
        public int Index
        {
            get { return (int)GetValue(IndexProperty); }
            set { SetValue(IndexProperty, value); }
        }

        public static readonly DependencyProperty IndexProperty =
            DependencyProperty.Register("Index", typeof(int), typeof(CarRoundPlay), new PropertyMetadata(0, OnIndexChanged));

        /// <summary>
        /// 动画耗时
        /// </summary>
        public TimeSpan AnimateDuration
        {
            get { return (TimeSpan)GetValue(AnimateDurationProperty); }
            set { SetValue(AnimateDurationProperty, value); }
        }

        public static readonly DependencyProperty AnimateDurationProperty =
            DependencyProperty.Register("AnimateDuration", typeof(TimeSpan), typeof(CarRoundPlay), new PropertyMetadata(TimeSpan.FromSeconds(0.5)));

        /// <summary>
        /// 设置获取
        /// </summary>
        public bool Recyclable
        {
            get { return (bool)GetValue(RecyclableProperty); }
            set { SetValue(RecyclableProperty, value); }
        }

        public static readonly DependencyProperty RecyclableProperty =
            DependencyProperty.Register("Recyclable", typeof(bool), typeof(CarRoundPlay), new PropertyMetadata(false));

        /// <summary>
        /// 自动动画
        /// </summary>
        public TimeSpan AutoPlayInterval
        {
            get { return (TimeSpan)GetValue(AutoPlayIntervalProperty); }
            set { SetValue(AutoPlayIntervalProperty, value); }
        }

        public static readonly DependencyProperty AutoPlayIntervalProperty =
            DependencyProperty.Register("AutoPlayInterval", typeof(TimeSpan), typeof(CarRoundPlay), new PropertyMetadata(OnAutoPlayIntervalChanged));


    
        #endregion



        #region RoutedEvent(路由事件)
        /// <summary>
        /// 轮播index
        /// </summary>
        public static readonly RoutedEvent IndexChangedEvent = EventManager.RegisterRoutedEvent("IndexChanged", RoutingStrategy.Bubble, typeof(IndexChangedEventHandler), typeof(CarRoundPlay));
        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 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);

 

样式

    <Style TargetType="{x:Type Modules:CarRoundPlay}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Modules:CarRoundPlay}">
                    <Grid Background="{TemplateBinding Background}"
                          ClipToBounds="True">
                        <StackPanel Orientation="{TemplateBinding Orientation}">
                            <ItemsControl ItemsSource="{TemplateBinding Children}"
                                          VerticalAlignment="Stretch"
                                          HorizontalAlignment="Stretch">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <StackPanel Orientation="{Binding Orientation,RelativeSource={RelativeSource AncestorType=Modules:CarRoundPlay}}" />
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <ContentControl  Content="{Binding}" />
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </StackPanel>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 

调用方法

方法一

xmlns:Zt="clr-namespace:RoundPlay.Modules"

  <Grid>
            <Zt:CarRoundPlay 
                       BorderBrush="LightGray"
                                 BorderThickness="1
Recyclable="True" AutoPlayInterval="0:0:1"
Height="300" Index="3" Width="300"> <Grid Background="#F15D26"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Text="Page1/44" /> </Grid> <Grid Background="Beige"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Text="Page1/44" /> </Grid> <Grid Background="Blue"> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Text="Page1/44" /> </Grid> </Zt:CarRoundPlay> </Grid>

 方法二

            SolidColorBrush[] brushes = new SolidColorBrush[4] { Brushes.White, Brushes.Red, Brushes.Green, Brushes.Yellow };
            Random rnd = new Random();
            MainViewModel viewmodel = (this.DataContext as MainViewModel);
            for (int i = 0; i < viewmodel.ComWorldLists.Count; i++)
            {
                Grid grid = new Grid();
                int random = rnd.Next(0, brushes.Length - 1);
                grid.Background = brushes[random];
                TextBlock text = new TextBlock() { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, FontSize = 24, FontWeight = FontWeights.Bold };
                text.SetBinding(TextBlock.TextProperty, new Binding($"ComWorldLists[{i}].Name"));
                grid.Children.Add(text);
                Caruousel.Children.Add(grid);
            }

 显示效果

posted @ 2020-11-23 10:43  可乐_加冰  阅读(1081)  评论(1编辑  收藏  举报