UWP ListView的触摸拖动行为 [英] UWP ListView drag behavior for touch

查看:92
本文介绍了UWP ListView的触摸拖动行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用触摸触发ListView项的拖放操作时,在WinRT(Windows 8/8.1)和UWP(Windows 10)应用程序之间,行为似乎已更改.

When using touch to trigger a drag and drop action for a ListView item, it would appear that the behavior has changed between WinRT (Windows 8/8.1) and UWP (Windows 10) apps.

在WinRT中,向左或向右撕裂"一个项目将使其脱离,从而启动拖动行为.在UWP中,用户必须点击并按住一会儿一小段时间,然后移动它会启动拖动动作.

In WinRT, "tearing" an item to the left or right would cause it to get detached, initiating the drag behavior. In UWP, the user has to tap and hold an item for a short while, after which moving it initiates the drag action.

我的问题是:有没有办法恢复/实现旧的WinRT风格的行为?这种新方法不是很明显,在有限的用户测试中,我还没有看到有人在不向他们解释的情况下解决问题.

My question is: is there a way to revert to/implement the old WinRT-style behavior? The new way is not very obvious and in limited user testing I haven't seen one person work it out without having it explained to them.

作为一个简单的示例,以下XAML既适用于WinRT,也适用于UWP,但是在WinRT中可以发现很多基于触摸的交互.

As a quick example, the following XAML works for both WinRT and UWP, however the touch-based interactions are much discoverable in WinRT.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView AllowDrop="True" CanReorderItems="True">
        <ListView.Items>
            <x:String>Item 1</x:String>
            <x:String>Item 2</x:String>
            <x:String>Item 3</x:String>
            <x:String>Item 4</x:String>
            <x:String>Item 5</x:String>
        </ListView.Items>
    </ListView>
</Grid>

推荐答案

我终于弄清楚了如何恢复ListView的旧Windows 8.1行为.如果垂直于滚动轴滑动,它仍然允许触摸滚动并开始一个项的拖动操作.它基于 Comet库,并由自定义ListView实现.这个想法是允许ListViewItem中的TranslateX/TranslateY和系统操作.为此,您需要覆盖默认的ListViewItem样式.

I've finally figured out how to get back the old Windows 8.1 behavior for the ListView. It still allows Scrolling with touch and starts a drag operation of one item if you swipe perpendicularly to the scroll axis. It's based on the Comet library and is implemented by a custom ListView. The idea is to allow TranslateX/TranslateY and System Manipulations in the ListViewItem. For this you need to override the default ListViewItem's style.

如果要使用控件,则必须牢记以下几点:

If you want to use the control, you have to bear in mind a few things:

  1. 在Themes/Generic.xaml中复制样式,并改编local2命名空间.
  2. 如果使用水平滚动的ListView,则必须相应地设置ListView的Orientation属性.该控件未检测到已使用的ItemsPanel.
  3. 您仍然可以使用常规的UWP拖放拖放机制,但是您必须预订另一个名为ItemStartDragging的事件才能进行旧的Windows 8.1样式的拖动.
  4. 如果在使用8.1样式拖动时处理Drop事件,则可以在DragEventArgs.DataView中找到数据,而在使用DragItemStarting(= default事件)时可以在DragEventArgs.Data.GetView()中找到数据.不知道他们为什么表现不同.
  5. 样式非常基本.您可能需要更改它们,并使它们更类似于原始的ListViewItem样式.

这是代码:

public class DraggingListView : ListView
{
    public DraggingListView()
    {
    }

    protected override DependencyObject GetContainerForItemOverride()
    {
        if (Orientation == Orientation.Horizontal)
            return new HorizontalDraggingListItem(this);
        else
            return new VerticalDraggingListItem(this);
    }

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);
        (element as DraggingListItem).DataContext = item;
        (element as DraggingListItem).MouseSlidingEnabled = MouseSlidingEnabled;
    }

    public event EventHandler<ListItemStartDraggingEventArgs> ItemStartDragging;

    public void OnChildItemDragged(DraggingListItem item, Windows.ApplicationModel.DataTransfer.DataPackage data)
    {
        if (ItemStartDragging == null)
            return;
        ItemStartDragging(this, new ListItemStartDraggingEventArgs(data, item.DataContext));
    }

    public Orientation Orientation
    {
        get { return (Orientation)GetValue(OrientationProperty); }
        set { SetValue(OrientationProperty, value); }
    }
    public static readonly DependencyProperty OrientationProperty =
        DependencyProperty.Register("Orientation", typeof(Orientation), typeof(DraggingListView), new PropertyMetadata(Orientation.Vertical));

    /// <summary>
    /// Gets or sets the ability to slide the control with the mouse. False by default
    /// </summary>
    public bool MouseSlidingEnabled
    {
        get { return (bool)GetValue(MouseSlidingEnabledProperty); }
        set { SetValue(MouseSlidingEnabledProperty, value); }
    }
    public static readonly DependencyProperty MouseSlidingEnabledProperty =
        DependencyProperty.Register("MouseSlidingEnabled", typeof(bool), typeof(DraggingListView), new PropertyMetadata(false));

}

public class ListItemStartDraggingEventArgs : EventArgs
{
    public Windows.ApplicationModel.DataTransfer.DataPackage Data { get; private set; }
    public object Item { get; private set; }

    public ListItemStartDraggingEventArgs(Windows.ApplicationModel.DataTransfer.DataPackage data, object item)
    {
        Data = data;
        Item = item;
    }
}

public class HorizontalDraggingListItem : DraggingListItem
{
    public HorizontalDraggingListItem(DraggingListView listView) : base(listView)
    {
        this.DefaultStyleKey = typeof(HorizontalDraggingListItem);
    }

    protected override bool DetectDrag(ManipulationDelta delta)
    {
        return Math.Abs(delta.Translation.Y) > 2;
    }
}

public class VerticalDraggingListItem : DraggingListItem
{
    public VerticalDraggingListItem(DraggingListView listView) : base(listView)
    {
        this.DefaultStyleKey = typeof(VerticalDraggingListItem);
    }

    protected override bool DetectDrag(ManipulationDelta delta)
    {
        return Math.Abs(delta.Translation.X) > 2;
    }
}

[TemplatePart(Name = PART_CONTENT_GRID, Type = typeof(Grid))]
public abstract class DraggingListItem : ListViewItem
{
    const string PART_CONTENT_GRID = "ContentGrid";
    private Grid contentGrid;

    private DraggingListView _listView;

    public DraggingListItem(DraggingListView listView)
    {
        _listView = listView;
        this.DragStarting += OnDragStarting;
    }

    private void OnDragStarting(UIElement sender, DragStartingEventArgs args)
    {
        _listView.OnChildItemDragged(this, args.Data);
    }

    protected override void OnApplyTemplate()
    {
        contentGrid = this.GetTemplateChild(PART_CONTENT_GRID) as Grid;

        contentGrid.ManipulationDelta += ContentGrid_ManipulationDelta;
        contentGrid.ManipulationCompleted += ContentGrid_ManipulationCompleted;
        contentGrid.PointerPressed += ContentGrid_PointerPressed;

        base.OnApplyTemplate();
    }

    private PointerPoint pp = null;
    private void ContentGrid_PointerPressed(object sender, PointerRoutedEventArgs e)
    {
        if (!MouseSlidingEnabled && e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
            return;

        pp = e.GetCurrentPoint(sender as UIElement);
    }

    private void ContentGrid_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
    {
        if (!MouseSlidingEnabled && e.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
            return;

        pp = null;
    }

    private async void ContentGrid_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
    {
        if (!MouseSlidingEnabled && e.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
            return;

        if (DetectDrag(e.Delta) && pp != null)
        {
            var pointer = pp;
            pp = null;
            await StartDragAsync(pointer);
        }
    }

    protected abstract bool DetectDrag(ManipulationDelta delta);

    #region Dependency Properties

    /// <summary>
    /// Gets or sets the ability to slide the control with the mouse. False by default
    /// </summary>
    public bool MouseSlidingEnabled
    {
        get { return (bool)GetValue(MouseSlidingEnabledProperty); }
        set { SetValue(MouseSlidingEnabledProperty, value); }
    }
    public static readonly DependencyProperty MouseSlidingEnabledProperty =
        DependencyProperty.Register("MouseSlidingEnabled", typeof(bool), typeof(DraggingListItem), new PropertyMetadata(false));

    #endregion
}

这是Generic.xaml中的XAML:

And this is the XAML in Generic.xaml:

 <Style TargetType="local2:HorizontalDraggingListItem" >
    <Setter Property="VerticalAlignment" Value="Stretch"></Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local2:HorizontalDraggingListItem">
                <Grid ManipulationMode="TranslateY,System" x:Name="ContentGrid" Background="{TemplateBinding Background}">
                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="local2:VerticalDraggingListItem" >
    <Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local2:VerticalDraggingListItem">
                <Grid ManipulationMode="TranslateX,System" x:Name="ContentGrid" Background="{TemplateBinding Background}">
                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这篇关于UWP ListView的触摸拖动行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆