Xaml 用于触摸的UWP ListView拖动行为
使用触摸键触发ListView项目的拖放操作时,WinRT(Windows 8/8.1)和UWP(Windows 10)应用程序之间的行为似乎发生了变化 在WinRT中,向左或向右“撕裂”一个项目会导致它分离,从而启动拖动行为。在UWP中,用户必须轻触并按住一个项目一段时间,然后移动它启动拖动操作 我的问题是:有没有办法恢复/实现旧的WinRT风格的行为?新的方法不是很明显,在有限的用户测试中,我没有看到一个人在没有向他们解释的情况下解决它 举个简单的例子,下面的XAML适用于WinRT和UWP,但是基于触摸的交互在WinRT中很容易发现Xaml 用于触摸的UWP ListView拖动行为,xaml,listview,drag-and-drop,uwp,Xaml,Listview,Drag And Drop,Uwp,使用触摸键触发ListView项目的拖放操作时,WinRT(Windows 8/8.1)和UWP(Windows 10)应用程序之间的行为似乎发生了变化 在WinRT中,向左或向右“撕裂”一个项目会导致它分离,从而启动拖动行为。在UWP中,用户必须轻触并按住一个项目一段时间,然后移动它启动拖动操作 我的问题是:有没有办法恢复/实现旧的WinRT风格的行为?新的方法不是很明显,在有限的用户测试中,我没有看到一个人在没有向他们解释的情况下解决它 举个简单的例子,下面的XAML适用于WinRT和UWP
<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>
项目1
项目2
项目3
项目4
项目5
在WinRT中,向左或向右“撕裂”一个项目会导致它分离,从而启动拖动行为。在UWP中,用户必须轻触并按住一个项目一段时间,然后移动它启动拖动操作
是的,在UWP应用程序中启动拖动操作的行为已更改
我的问题是:有没有办法恢复/实现旧的WinRT风格的行为
可能的方法是创建拖动行为并附加到ListView,在该行为中,我们可以处理相关的触摸事件,并使用以编程方式启动拖放操作,以查找当前ListViewItem
public class FrameworkElementDragBehavior : DependencyObject, IBehavior
{
private bool isMouseClicked = false;
public DependencyObject AssociatedObject { get; private set; }
public void Attach(DependencyObject associatedObject)
{
var control = associatedObject as Control;
if (control == null)
throw new ArgumentException(
"FrameworkElementDragBehavior can be attached only to Control");
AssociatedObject = associatedObject;
((FrameworkElement)this.AssociatedObject).Holding += FrameworkElementDragBehavior_Holding;
((FrameworkElement)this.AssociatedObject).DragStarting += FrameworkElementDragBehavior_DragStarting;
}
private void FrameworkElementDragBehavior_Holding(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs e)
{
//Just for example, not the completed code
var obj = ((ListView)sender).SelectedItem as ListViewItem;
if (obj != null)
{
//Call the UIElement.StartDragAsync method
}
}
private void FrameworkElementDragBehavior_DragStarting(UIElement sender, DragStartingEventArgs args)
{
throw new NotImplementedException();
}
public void Detach()
{
AssociatedObject = null;
}
}
我想要类似的行为,因为我对默认的win10行为感到恼火。也许有更好的解决方案,但这是我想到的
<GridView Name="MySourceGridView" ItemsSource="{x:Bind Animals}" ScrollViewer.VerticalScrollMode="Disabled" >
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Animal">
<StackPanel Margin="20" Width="200" Height="200" PointerPressed="StackPanel_PointerPressed" DragStarting="StackPanel_DragStarting">
<StackPanel.Background>
<SolidColorBrush Color="{x:Bind Color}" />
</StackPanel.Background>
<TextBlock Text="{x:Bind Name}" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
你也有一个指针。拖动从stackpanel上开始以移动数据
private void StackPanel_DragStarting(UIElement sender, DragStartingEventArgs args)
{
var senderElement = sender as FrameworkElement;
var ani = (Animal)senderElement.DataContext;
args.Data.SetText(ani.ID.ToString());
args.Data.RequestedOperation = DataPackageOperation.Copy;
}
Rest只是在我成功地将动物列表中的动物ID向前传递之后捕获的正常数据
private void MyTargetRectangle_DragEnter(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Copy;
e.DragUIOverride.Caption = "Kokeiles";
e.DragUIOverride.IsCaptionVisible = true;
e.DragUIOverride.IsContentVisible = true;
e.DragUIOverride.IsGlyphVisible = false;
}
private async void MyTargetRectangle_Drop(object sender, DragEventArgs e)
{
var droppedAnimalId = await e.DataView.GetTextAsync();
Animal ani = Animals.Where(p => p.ID == int.Parse(droppedAnimalId)).FirstOrDefault();
MyTargetRectangle.Fill = new SolidColorBrush(ani.Color);
}
我希望这对某人有所帮助,而且答案不会太长。我终于找到了恢复ListView旧的Windows 8.1行为的方法。如果您垂直于滚动轴滑动,它仍然允许触摸滚动,并启动一个项目的拖动操作。它基于,由自定义ListView实现。其思想是允许在ListViewItem中进行TranslateX/TranslateY和系统操作。为此,您需要覆盖默认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
}
公共类DraggingListView:ListView
{
公共DraggingListView()
{
}
受保护的覆盖依赖对象GetContainerForItemOverride()
{
如果(方向==方向.水平)
返回新的HorizontalDraggingListItem(此项);
其他的
返回新的垂直拖动列表项(此项);
}
受保护的覆盖void PrepareContainerForItemOverride(DependencyObject元素,对象项)
{
base.PrepareContainerForItemOverride(元素、项);
(元素作为DraggingListItem);
(元素作为DraggingListItem)。MouseSlidingEnabled=MouseSlidingEnabled;
}
公共事件处理程序ItemStartDraging;
public void onChildItemDraged(DraggingListItem项,Windows.ApplicationModel.DataTransfer.DataPackage数据)
{
if(ItemStartDragging==null)
返回;
ItemStartDraging(这是新的ListItemStartDragingEventArgs(数据,item.DataContext));
}
公众导向
{
获取{return(Orientation)GetValue(OrientationProperty);}
set{SetValue(方向属性,值);}
}
公共静态只读DependencyProperty方向属性=
DependencyProperty.Register(“方向”、typeof(方向)、typeof(DraggingListView)、new PropertyMetadata(方向.垂直));
///
///获取或设置使用鼠标滑动控件的能力。默认情况下为False
///
公共场所的鼠标可滑动
{
获取{return(bool)GetValue(MouseSlidingEnabledProperty);}
set{SetValue(MouseSlidingEnabledProperty,value);}
}
public static readonly dependencProperty MouseSlidingEnabledProperty=
DependencyProperty.Register(“MouseSlidingEnabled”、typeof(bool)、typeof(DraggingListView)、new PropertyMetadata(false));
}
公共类ListItemStartDragingEventArgs:EventArgs
{
public Windows.ApplicationModel.DataTransfer.DataPackage数据{get;private set;}
公共对象项{get;private set;}
公共列表项StartDragingEventArgs(Windows.ApplicationModel.DataTransfer.DataPackage数据,对象项)
{
数据=数据;
项目=项目;
}
}
公共类HorizontalDraggingListItem:DraggingListItem
{
公共水平DraggingListItem(DraggingListView listView):基础(listView)
{
this.DefaultStyleKey=typeof(HorizontalDraggingListItem);
}
受保护的超控布尔检测梯度(操纵增量)
{
返回Math.Abs(delta.Translation.Y)>2;
}
}
公共类垂直
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
}
<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>