UWP ListView的触摸拖动行为 [英] UWP ListView drag behavior for touch
问题描述
使用触摸触发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:
- 在Themes/Generic.xaml中复制样式,并改编local2命名空间.
- 如果使用水平滚动的ListView,则必须相应地设置ListView的Orientation属性.该控件未检测到已使用的ItemsPanel.
- 您仍然可以使用常规的UWP拖放拖放机制,但是您必须预订另一个名为ItemStartDragging的事件才能进行旧的Windows 8.1样式的拖动.
- 如果在使用8.1样式拖动时处理Drop事件,则可以在DragEventArgs.DataView中找到数据,而在使用DragItemStarting(= default事件)时可以在DragEventArgs.Data.GetView()中找到数据.不知道他们为什么表现不同.
- 样式非常基本.您可能需要更改它们,并使它们更类似于原始的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屋!