【问题标题】:UWP ListView scroll bar not selectable in touch modeUWP ListView 滚动条在触摸模式下不可选
【发布时间】:2016-12-15 04:17:43
【问题描述】:

我在通用 Windows 应用中有一个简单的ListView。它在支持触摸的设备和我的本地机器上都可以很好地滚动。在触摸设备上,我希望能够点击并拖动滚动条拇指以快速滚动列表(与使用鼠标单击并拖动滚动拇指相同)。但是,当我尝试选择滚动条拇指时,它不起作用;拇指不可选择。

起初我认为滚动拇指太小,所以我摆弄了ScrollBar的默认样式以增加宽度。然后我尝试调整默认ScrollViewer 样式中的其他值,例如ScrollingIndicatorModeScrollingIndicatorStates,以便它们始终使用MouseIndicator,并确保所有IsHitTestVisible 都是True。无济于事。

似乎默认样式中必须有一些东西允许这样做,但我无法通过反复试验找到它,而且 MSDN 文档中似乎没有任何地方可以解决这种样式。

这在触摸模式下可行吗?

【问题讨论】:

  • 我最近有类似的问题,不仅是拇指,而且“Horizo​​ntalLargeIncrease”repeatButton 在触摸模式下不起作用。

标签: c# touch win-universal-app uwp


【解决方案1】:

这在触摸模式下可行吗?

AFAIK,目前这是不可能的。 ScrollBar的滚动事件只能通过滚动内容或鼠标移动Thumb来触发。

这是设计使然,但是在触控设备上,如果我们想要快速滚动列表,我们只需快速滑动一小段距离即可,ListView 会先加速滚动,然后减速,最后停止。其他包含ScrollViewer 的控件行为相同,在视口(@98​​7654325@ 的内容)中,当在触摸设备中时,移动拇指不起作用,为了加快滚动速度,您只能在视口上进行快速滑动手势.

我们的建议是,您可以通过 Windows 反馈工具提交添加此新功能以进行开发的请求。

【讨论】:

  • 惯性滚动(快速滑动)不是遍历大列表的准确方法。如果您有大量姓名(例如联系人),那么能够抓住滚动条并按字母顺序浏览(如 Android)会更好。我将提交请求。
  • Grace Feng,我已经接受了我自己的答案,其中包含一个可行的解决方法,但我想再次感谢您确认没有内置功能。
【解决方案2】:

为了后人的缘故,我想发布我的工作,结果实际上并没有我想象的那么困难,而且现在看起来真的很好。

基本思想是使用垂直方向的Slider 控件(具有可选择、可拖动和沿轨道移动的Thumb)并同步Slider 的@ 987654324@ 属性(拖动时会发生变化)到ListViewScrollIntoView 方法,因此您可以在Slider Thumb 被拖动时滚动ListView。反之亦然(当ListView 正常滚动时移动Slider Thumb)也需要干净、无缝的体验。我在下面有一些代码示例可以帮助您入门(并非所有内容都可以立即工作)。此外,编辑Slider的默认Style模板,使其看起来完全像一个滚动条(甚至添加工具提示以在拖动时显示当前值)。

注意:我在代码隐藏中使用 WinRTXamlToolkit 轻松遍历VisualTree

后面的代码:

public sealed partial class MainPage : Page
{
    private bool _isScroll = false;
    private bool _isSlide = false;

    public MainPage()
    {
        this.InitializeComponent();
        var vm = new ViewModel();
        vm.ValueChanged += LetterSliderValueChanged;
        DataContext = vm;
    }

    /// <summary>
    /// Bring list items into view on the screen based on the value (letter) of the slider
    /// </summary>
    /// <param name="sender">The view model to bring into view</param>
    private void LetterSliderValueChanged(object sender, RoutedEventArgs e)
    {
        if (_isScroll) return;
        if (sender == null) return;

        _isSlide = true;

        ListView?.ScrollIntoView(sender, ScrollIntoViewAlignment.Leading);
    }


    /// <summary>
    /// Update the position of the slider when the ListView is scrolling from a normal touch
    /// </summary>
    private void ScrollViewerViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
    {
        if (_isSlide)
        {
            _isSlide = false;
            return;
        }

        _isScroll = true;

        var scrollViewer = sender as ScrollViewer;
        var scrollBars = scrollViewer.GetDescendantsOfType<ScrollBar>();
        var verticalBar = scrollBars.FirstOrDefault(x => x.Orientation == Orientation.Vertical);

        // Normalize the scales to move the slider thumb in sync with scrolling
        var sliderTotal = LetterSlider.Maximum - LetterSlider.Minimum;
        var barTotal = verticalBar.Maximum - verticalBar.Minimum;
        var barPercent = verticalBar.Value / barTotal;
        LetterSlider.Value = (barPercent * sliderTotal) + LetterSlider.Minimum;

        _isScroll = false;
    }

    /// <summary>
    /// Add the slider method to the ListView's ScrollViewer Viewchanged event
    /// </summary>
    private void ListViewLoaded(object sender, RoutedEventArgs e)
    {
        var listview = sender as ListView;
        if (listview == null) return;
        var scrollViewer = listview.GetFirstDescendantOfType<ScrollViewer>();
        scrollViewer.ViewChanged -= ScrollViewerViewChanged;
        scrollViewer.ViewChanged += ScrollViewerViewChanged;
    }
}

XAML:

<Slider x:Name="LetterSlider" Orientation="Vertical"
            Value="{Binding SliderValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
            Maximum="{Binding MaxSliderLetter, Mode=OneTime}" 
            Minimum="{Binding MinSliderLetter, Mode=OneTime}" 
            RenderTransformOrigin="0.5,0.5">
        <Slider.RenderTransform>
            <RotateTransform Angle="180"/>
        </Slider.RenderTransform>
</Slider>

查看模型:

    //Method to update the ListView to show items based on the letter of the slider
    public RoutedEventHandler ValueChanged;

    public int SliderValue
    {
        get { return _sliderValue; }
        set
        {
            _sliderValue = value;
            NotifyPropertyChanged("SliderValue");

            char letter = (char)_sliderValue;
            var items = ItemsGroup.FirstOrDefault(i => (char)i.Key == letter);
            if (items == null) return;
            ValueChanged(items.FirstOrDefault(), new RoutedEventArgs());
        }
    }

【讨论】:

    猜你喜欢
    • 2014-01-14
    • 1970-01-01
    • 2015-12-30
    • 2017-08-15
    • 1970-01-01
    • 2016-02-25
    • 2018-05-13
    • 2012-10-19
    • 1970-01-01
    相关资源
    最近更新 更多