ScrollViewer - 可用鼠标拖动滚动的列表框

ScrollViewer添加附加属性:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace TouchScrollViewer
{
    public class TouchScrolling : DependencyObject
    {
        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }

        public bool IsEnabled
        {
            get { return (bool)GetValue(IsEnabledProperty); }
            set { SetValue(IsEnabledProperty, value); }
        }

        public static readonly System.Windows.DependencyProperty IsEnabledProperty =
            System.Windows.DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged));

        static Dictionary<object, MouseCapture> _captures = new Dictionary<object, MouseCapture>();

        static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = d as ScrollViewer;
            if (target == null) return;

            if ((bool)e.NewValue)
            {
                target.Loaded += target_Loaded;
            }
            else
            {
                target.Unloaded += target_Unloaded;
            }
        }

        static void target_Unloaded(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Target Unloaded");

            var target = sender as ScrollViewer;
            if (target == null) return;

            _captures.Remove(sender);

            target.Loaded += target_Loaded;
            target.Unloaded -= target_Unloaded;
            target.PreviewMouseLeftButtonDown -= target_PreviewMouseLeftButtonDown;
            target.PreviewMouseMove -= target_PreviewMouseMove;

            target.PreviewMouseLeftButtonUp -= target_PreviewMouseLeftButtonUp;
        }

        static void target_Loaded(object sender, RoutedEventArgs e)
        {
            var target = sender as ScrollViewer;
            if (target == null) return;

            System.Diagnostics.Debug.WriteLine("Target Loaded");

            target.Loaded -= target_Loaded;
            target.Unloaded += target_Unloaded;

            target.PreviewMouseLeftButtonDown += target_PreviewMouseLeftButtonDown;
            target.PreviewMouseMove += target_PreviewMouseMove;

            target.PreviewMouseLeftButtonUp += target_PreviewMouseLeftButtonUp;
        }

        static void target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var target = sender as ScrollViewer;
            if (target == null) return;

            _captures[sender] = new MouseCapture
            {
                VerticalOffset = target.VerticalOffset,
                HorticalOffset = target.HorizontalOffset,
                Point = e.GetPosition(target),
            };
        }

        static void target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var target = sender as ScrollViewer;
            if (target == null) return;

            target.ReleaseMouseCapture();
        }

        static void target_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (!_captures.ContainsKey(sender)) return;

            if (e.LeftButton != MouseButtonState.Pressed)
            {
                _captures.Remove(sender);
                return;
            }

            var target = sender as ScrollViewer;
            if (target == null) return;

            var capture = _captures[sender];

            var point = e.GetPosition(target);

            var dy = point.Y - capture.Point.Y;
            var dx = point.X - capture.Point.X;

            if (Math.Abs(dy) > 5)
            {
                target.CaptureMouse();
            }
            if (Math.Abs(dx) > 5)
            {
                target.CaptureMouse();
            }

            target.ScrollToVerticalOffset(capture.VerticalOffset - dy / 50);
            target.ScrollToHorizontalOffset(capture.HorticalOffset - dx);
        }

        internal class MouseCapture
        {
            public Double VerticalOffset { get; set; }

            public Double HorticalOffset { get; set; }
            
            public Point Point { get; set; }
        }
    }
}

 

 

设置水平方向滚动条不显示:HorizontalScrollBarVisibility="Disabled"

设置垂直方向滚动条不显示:VerticalScrollBarVisibility="Disabled"

设置响应触摸操作的方式只有垂直有效:PanningMode="VerticalOnly" 

 

UI界面:

<Window
    x:Class="TouchScrollViewer.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:TouchScrollViewer"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="可触摸滚动的ScrollViewer"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <Grid.Resources>
            <Style TargetType="ItemsControl">
                <Style.Setters>
                    <Setter Property="Background" Value="Transparent" />
                    <Setter Property="Foreground" Value="Black" />
                    <Setter Property="BorderBrush" Value="Black" />
                    <Setter Property="FontSize" Value="18" />
                    <Setter Property="FontFamily" Value="新宋体" />
                    <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
                    <Setter Property="BorderThickness" Value="0,0,0,1" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ItemsControl">
                                <ScrollViewer
                                    local:TouchScrolling.IsEnabled="True"
                                    CanContentScroll="True"
                                    HorizontalScrollBarVisibility="Disabled"
                                    PanningMode="VerticalOnly"
                                    VerticalScrollBarVisibility="Disabled">
                                    <ItemsPresenter />
                                </ScrollViewer>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="ItemsPanel">
                        <Setter.Value>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Vertical" />
                            </ItemsPanelTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate DataType="local:Data">
                                <RadioButton Width="1000" Height="50">
                                    <RadioButton.Template>
                                        <ControlTemplate TargetType="RadioButton">
                                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                                                <Grid>
                                                    <TextBlock
                                                        VerticalAlignment="Center"
                                                        FontSize="30"
                                                        Text="{Binding TestData}" />
                                                </Grid>
                                            </Border>
                                        </ControlTemplate>
                                    </RadioButton.Template>
                                </RadioButton>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style.Setters>
            </Style>
        </Grid.Resources>
        <ItemsControl x:Name="ItemsControl" />
    </Grid>
</Window>

 

using System.Collections.Generic;
using System.Windows;

namespace TouchScrollViewer
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            ShowList = new List<Data>();
            for (int i = 0; i < 50; ++i)
            {
                ShowList.Add(new Data() {TestData = "测试文本" + i });
            }

            ItemsControl.ItemsSource = ShowList;
        }

        public List<Data> ShowList { get; set; }
    }

    public class Data
    {
        public string TestData { get; set; }
    }
}

 

效果展示:

 

 

文章参考:http://matthamilton.net/touchscrolling-for-scrollviewer

完整Demo下载地址:https://files.cnblogs.com/files/ly940120/TouchScrollViewerDemo.rar

 

posted @ 2019-12-12 18:00  Marching  阅读(928)  评论(0编辑  收藏  举报