【WPF】实现横向滚动UserControl,点击滚动一个显示宽度

一.预期实现效果

点击左右Button,每次点击移动一个显示的距离(我的项目中是动态的,这边展示的是两个,即点击以下滚动两个)

二.代码

xaml代码

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>
        <RepeatButton Click="Button_Click_1" Style="{StaticResource Style_Button_ImageAreaRPButton}" Width="20" Height="36">
            <Image Source="{StaticResource left}" Margin="5"/>
        </RepeatButton>
        <scr:SmoothScrollViewer x:Name="sc1" Grid.Column="1" ScrollViewer.HorizontalScrollBarVisibility="Hidden" 
                 ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollChanged="sc1_ScrollChanged" Margin="-10 0">
            <ItemsControl ItemsSource="{Binding ElementName=ItemSlidCtrl, Path=ItemsResource, UpdateSourceTrigger=PropertyChanged}"
                          Style="{Binding ElementName=ItemSlidCtrl, Path=ItemsStyle, UpdateSourceTrigger=PropertyChanged}">
                
            </ItemsControl>
        </scr:SmoothScrollViewer>
        <RepeatButton Grid.Column="2" Click="Button_Click" Style="{StaticResource Style_Button_ImageAreaRPButton}" Width="20" Height="36">
            <Image Source="{StaticResource right}" Margin="5"/> //换成自己按钮的资源
        </RepeatButton>
    </Grid>

xaml.cs代码

        double m_ScrollStepRatio = 0.0;     //滚动条的归一化步进长度
        double m_ScrollPositionRatio = 0.0; //滚动条的归一化位置
        bool flag;

        public ItemSlidUserCtrl()
        {
            InitializeComponent();
        }

        public object ItemsResource
        {
            get { return (object)GetValue(ItemsResourceProperty); }
            set { SetValue(ItemsResourceProperty, value); }
        }

        //注册ItemsResource依赖属性
        public static readonly DependencyProperty ItemsResourceProperty =
            DependencyProperty.Register("ItemsResource", typeof(object), typeof(ItemSlidUserCtrl), new PropertyMetadata(null));
        public Style ItemsStyle
        {
            get { return (Style)GetValue(ItemsStyleProperty); }
            set { SetValue(ItemsStyleProperty, value); }
        }

        //注册VerticalScrollRatio依赖属性
        public static readonly DependencyProperty ItemsStyleProperty =
            DependencyProperty.Register("ItemsStyle", typeof(Style), typeof(ItemSlidUserCtrl), new PropertyMetadata(null));
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            sc1.LineLeft();//向右滚动
            m_ScrollPositionRatio = sc1.ContentHorizontalOffset / sc1.ScrollableWidth;
            flag = true;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            sc1.LineRight();//向右滚动
            m_ScrollPositionRatio = sc1.ContentHorizontalOffset / sc1.ScrollableWidth;
            flag = true;
        }
        private void sc1_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            try
            {
                if (flag)
                {
                    m_ScrollStepRatio = sc1.ViewportWidth / (sc1.ExtentWidth - sc1.ViewportWidth);
                    if (e.HorizontalChange < 0)
                        sc1.SmoothScroll(m_ScrollStepRatio, m_ScrollPositionRatio, ScrollDirection.Left);
                    else if (e.HorizontalChange > 0)
                        sc1.SmoothScroll(m_ScrollStepRatio, m_ScrollPositionRatio, ScrollDirection.Right);
                    flag = false;
                }
            }
            catch(Exception ex)
            {
                LogOutput.WriteErrorLog("sc1_ScrollChanged error : " + ex.Message);
            }
        }

flag是控制判断每次滚动一次的标志,去除的话则是一滚到底。

辅助类

    public class SmoothScrollViewer : ScrollViewer
    {
        /// <summary>
        /// 垂直归一化步进长度
        /// </summary>
        public double VerticalScrollRatio
        {
            get { return (double)GetValue(VerticalScrollRatioProperty); }
            set { SetValue(VerticalScrollRatioProperty, value); }
        }

        //注册VerticalScrollRatio依赖属性
        public static readonly DependencyProperty VerticalScrollRatioProperty =
            DependencyProperty.Register("VerticalScrollRatio", typeof(double), typeof(SmoothScrollViewer), new PropertyMetadata(0.0, new PropertyChangedCallback(V_ScrollRatioChangedCallBack)));

        private static void V_ScrollRatioChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var scrollViewer = (ScrollViewer)(d);
            if (scrollViewer != null)
            {
                scrollViewer.ScrollToVerticalOffset((double)(e.NewValue) * scrollViewer.ScrollableHeight);
            }
        }

        /// <summary>
        /// 水平归一化步进长度
        /// </summary>
        public double HorizontalScrollRatio
        {
            get { return (double)GetValue(HorizontalScrollRatioProperty); }
            set { SetValue(HorizontalScrollRatioProperty, value); }
        }

        //注册HorizontalScrollRatio依赖属性
        public static readonly DependencyProperty HorizontalScrollRatioProperty =
            DependencyProperty.Register("HorizontalScrollRatio", typeof(double), typeof(SmoothScrollViewer), new PropertyMetadata(0.0, new PropertyChangedCallback(H_ScrollRatioChangedCallBack)));

        private static void H_ScrollRatioChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var scrollViewer = (ScrollViewer)(d);
            if (scrollViewer != null)
            {
                scrollViewer.ScrollToHorizontalOffset((double)(e.NewValue) * scrollViewer.ScrollableWidth);
            }
        }
    }

具体使用

 <users:ItemSlidUserCtrl x:Name="popularList"  Grid.Row="1" Background="Transparent" ItemsResource="{Binding PopularAppList}" ItemsStyle="{StaticResource Style_APP_PolpularList}" </users:ItemSlidUserCtrl>

这边把ItemSource换成自己的集合,style换成内部的空间

说明

本文章提供的是一个较为通用的滚动外包控件,可以理解为ScrollView的灵活变换

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值