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);
            }

 顯示效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM