Handle ListView reorder with groups (#331)
Handle ListView reorder with groups
This commit is contained in:
Родитель
7f101015b2
Коммит
f62131a5a8
|
@ -131,6 +131,7 @@
|
|||
<Compile Include="Data\Engine\Groups\Descriptions\CollectionViewGroupDescription.cs" />
|
||||
<Compile Include="Data\Engine\IncrementalLoading\PlaceholderInfoType.cs" />
|
||||
<Compile Include="Data\Engine\DataProviders\ViewChangingEventArgs.cs" />
|
||||
<Compile Include="Data\Engine\ItemReorderPlacement.cs" />
|
||||
<Compile Include="Data\IDataViewCollection.cs" />
|
||||
<Compile Include="Data\IncrementalLoading\BatchLoadingEventArgs.cs" />
|
||||
<Compile Include="Data\IncrementalLoading\BatchLoadingMode.cs" />
|
||||
|
|
|
@ -260,7 +260,7 @@ namespace Telerik.Data.Core
|
|||
/// Notify that changes were applied that would alter the data results.
|
||||
/// Queues an automatic <see cref="Refresh"/>.
|
||||
/// </summary>
|
||||
protected void Invalidate()
|
||||
internal void Invalidate()
|
||||
{
|
||||
if (!this.invalidated)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
namespace Telerik.Data.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the dragged item should be placed before or after the destination item.
|
||||
/// </summary>
|
||||
public enum ItemReorderPlacement
|
||||
{
|
||||
/// <summary>
|
||||
/// The dragged item should be placed before the destination item.
|
||||
/// </summary>
|
||||
Before,
|
||||
|
||||
/// <summary>
|
||||
/// The dragged item should be placed after the destination item.
|
||||
/// </summary>
|
||||
After
|
||||
}
|
||||
}
|
|
@ -59,8 +59,11 @@
|
|||
<Compile Include="DataForm\View\Editors\SegmentedControlCustomEditor.cs" />
|
||||
<Compile Include="DataForm\View\Editors\SliderCustomEditor.cs" />
|
||||
<Compile Include="ListView\Data\ListViewDataView.cs" />
|
||||
<Compile Include="ListView\View\Controls\ListViewGroupHeader.IDragDropElement.cs" />
|
||||
<Compile Include="ListView\View\Controls\ListViewGroupHeader.Reorder.cs" />
|
||||
<Compile Include="ListView\View\Controls\ListViewLoadDataUICommand.cs" />
|
||||
<Compile Include="ListView\View\RadListView.Data.cs" />
|
||||
<Compile Include="ListView\View\Reorder\ListViewReorderItemsCoordinator.cs" />
|
||||
<Compile Include="ListView\View\Services\Commands\GroupHeaderTapCommand.cs" />
|
||||
<Compile Include="ListView\View\Services\Commands\ItemHoldCommand.cs" />
|
||||
<Compile Include="ListView\View\Services\Commands\ItemHoldContext.cs" />
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
using Telerik.UI.Xaml.Controls.Data.ListView.View.Controls;
|
||||
using Telerik.UI.Xaml.Controls.Primitives.DragDrop;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Telerik.UI.Xaml.Controls.Data.ListView.Primitives
|
||||
{
|
||||
public partial class ListViewGroupHeader : IDragDropElement
|
||||
{
|
||||
bool IDragDropElement.SkipHitTest { get; set; }
|
||||
|
||||
bool IDragDropElement.CanDrop(DragContext dragContext)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IDragDropElement.CanStartDrag(DragDropTrigger trigger, object initializeContext)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IDragDropElement.DragEnter(DragContext context)
|
||||
{
|
||||
var positionMode = this.Owner.Orientation == Orientation.Vertical ?
|
||||
DragPositionMode.RailY : DragPositionMode.RailX;
|
||||
|
||||
DragDrop.SetDragPositionMode(this, positionMode);
|
||||
}
|
||||
|
||||
void IDragDropElement.DragLeave(DragContext context)
|
||||
{
|
||||
}
|
||||
|
||||
void IDragDropElement.DragOver(DragContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var data = context.PayloadData as ReorderItemsDragOperation;
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var position = context.GetDragPosition(this);
|
||||
|
||||
if (!this.ShouldReorder(position, data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.Owner.swipedItem == data.Item)
|
||||
{
|
||||
this.Owner.ResetActionContent();
|
||||
}
|
||||
|
||||
var newIndex = this.reorderCoordinator.ReorderItem(data.CurrentSourceReorderIndex, this);
|
||||
|
||||
data.CurrentSourceReorderIndex = newIndex;
|
||||
}
|
||||
|
||||
DragStartingContext IDragDropElement.DragStarting(DragDropTrigger trigger, object initializeContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
void IDragDropElement.OnDragDropComplete(DragCompleteContext dragContext)
|
||||
{
|
||||
}
|
||||
|
||||
void IDragDropElement.OnDragging(DragContext dragContext)
|
||||
{
|
||||
}
|
||||
|
||||
void IDragDropElement.OnDragVisualCleared(DragCompleteContext dragContext)
|
||||
{
|
||||
}
|
||||
|
||||
void IDragDropElement.OnDrop(DragContext dragContext)
|
||||
{
|
||||
}
|
||||
|
||||
private bool ShouldReorder(Point position, ReorderItemsDragOperation data)
|
||||
{
|
||||
if (this.reorderCoordinator == null || data.CurrentSourceReorderIndex == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sourceElement = this.reorderCoordinator.Host.ElementAt(data.CurrentSourceReorderIndex);
|
||||
|
||||
if (sourceElement == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var startPosition = this.Owner.Orientation == Orientation.Horizontal ? position.X : position.Y;
|
||||
var itemLength = this.Owner.Orientation == Orientation.Horizontal ? this.ActualWidth : this.ActualHeight;
|
||||
|
||||
return (startPosition >= itemLength / 2 + DragInitializer.DefaultStartTreshold &&
|
||||
startPosition <= itemLength && this.logicalIndex > data.CurrentSourceReorderIndex) ||
|
||||
(startPosition <= itemLength / 2 - DragInitializer.DefaultStartTreshold &&
|
||||
startPosition >= 0 && this.logicalIndex < data.CurrentSourceReorderIndex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Telerik.UI.Xaml.Controls.Data.ListView.Primitives
|
||||
{
|
||||
public partial class ListViewGroupHeader : IReorderItem
|
||||
{
|
||||
private ReorderItemsCoordinator reorderCoordinator;
|
||||
private int logicalIndex;
|
||||
|
||||
DependencyObject IReorderItem.Visual
|
||||
{
|
||||
get
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
int IReorderItem.LogicalIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.logicalIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.logicalIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
Point IReorderItem.ArrangePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Point(Canvas.GetLeft(this), Canvas.GetTop(this));
|
||||
}
|
||||
set
|
||||
{
|
||||
Canvas.SetLeft(this, value.X);
|
||||
Canvas.SetTop(this, value.Y);
|
||||
}
|
||||
}
|
||||
|
||||
Size IReorderItem.ActualSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.RenderSize;
|
||||
}
|
||||
}
|
||||
|
||||
ReorderItemsCoordinator IReorderItem.Coordinator
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.reorderCoordinator;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.reorderCoordinator = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView.Primitives
|
|||
/// <summary>
|
||||
/// Allows a user to view a header and expand that header to see further details, or to collapse a section up to a header.
|
||||
/// </summary>
|
||||
public class ListViewGroupHeader : RadContentControl, IArrangeChild
|
||||
public partial class ListViewGroupHeader : RadContentControl, IArrangeChild
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies the IsExpanded dependency property.
|
||||
|
|
|
@ -38,6 +38,12 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView.View.Controls
|
|||
this.owner.visualStateService.RegisterDataLoadingListener(loadDataControl);
|
||||
}
|
||||
|
||||
var reorderItem = element.Container as IReorderItem;
|
||||
if (reorderItem != null)
|
||||
{
|
||||
reorderItem.LogicalIndex = element.ItemInfo.Id;
|
||||
}
|
||||
|
||||
var listItem = element.Container as RadListViewItem;
|
||||
if (listItem != null)
|
||||
{
|
||||
|
@ -45,9 +51,6 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView.View.Controls
|
|||
|
||||
this.owner.PrepareContainerForItem(listItem, element.ItemInfo.Item);
|
||||
listItem.PrepareSwipeDragHandles();
|
||||
|
||||
var reorderItem = listItem as IReorderItem;
|
||||
reorderItem.LogicalIndex = element.ItemInfo.Id;
|
||||
this.owner.PrepareReorderItem(listItem);
|
||||
}
|
||||
|
||||
|
@ -74,6 +77,7 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView.View.Controls
|
|||
|
||||
groupHeader.IsExpanded = context.IsExpanded;
|
||||
this.owner.PrepareContainerForGroupHeader(groupHeader, context);
|
||||
this.owner.PrepareReorderItem(groupHeader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +105,7 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView.View.Controls
|
|||
item.ArrangeSize.Height = 0;
|
||||
item.ArrangeSize.Width = 0;
|
||||
|
||||
this.owner.CleanupReorderItem(item);
|
||||
this.owner.ClearContainerForGroupHeader(item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Telerik.Data.Core;
|
||||
using Telerik.UI.Xaml.Controls.Data.ListView.Commands;
|
||||
using Telerik.UI.Xaml.Controls.Data.ListView.View.Controls;
|
||||
using Telerik.UI.Xaml.Controls.Primitives.DragDrop;
|
||||
|
@ -26,18 +27,18 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView
|
|||
{
|
||||
if (trigger == DragDropTrigger.MouseDrag && !this.IsHandleEnabled)
|
||||
{
|
||||
return this.ListView.IsItemReorderEnabled && this.listView.GroupDescriptors.Count == 0;
|
||||
return this.ListView.IsItemReorderEnabled;
|
||||
}
|
||||
|
||||
if (trigger == DragDropTrigger.Hold)
|
||||
{
|
||||
return this.ListView.IsItemReorderEnabled && this.ListView.GroupDescriptors.Count == 0 && !this.IsHandleEnabled;
|
||||
return this.ListView.IsItemReorderEnabled && !this.IsHandleEnabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.isHandleEnabled && initializeContext == this.reorderHandle)
|
||||
{
|
||||
return this.ListView.IsItemReorderEnabled && this.ListView.GroupDescriptors.Count == 0 && this.IsHandleEnabled;
|
||||
return this.ListView.IsItemReorderEnabled && this.IsHandleEnabled;
|
||||
}
|
||||
|
||||
return this.ListView.IsActionOnSwipeEnabled && !(this.ListView.ReorderMode == ListViewReorderMode.Handle && this.ListView.IsItemReorderEnabled == true);
|
||||
|
@ -265,8 +266,45 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView
|
|||
{
|
||||
this.FinalizeReorder(context);
|
||||
|
||||
object destinationDataItem = this.GetDestinationDataItem(data.CurrentSourceReorderIndex);
|
||||
bool isExecuted = this.ListView.commandService.ExecuteCommand(CommandId.ItemReorderComplete, new ItemReorderCompleteContext(data.Data, destinationDataItem, this));
|
||||
var dataItem = data.Data;
|
||||
var destinationDataItem = this.GetDestinationDataItem(data.CurrentSourceReorderIndex);
|
||||
|
||||
IDataGroup dataGroup = null;
|
||||
IDataGroup destinationDataGroup = null;
|
||||
|
||||
if (this.listView.GroupDescriptors.Count > 0)
|
||||
{
|
||||
dataGroup = this.listView.Model.FindItemParentGroup(dataItem);
|
||||
destinationDataGroup = this.listView.Model.FindItemParentGroup(destinationDataItem);
|
||||
}
|
||||
|
||||
ItemReorderPlacement placement;
|
||||
|
||||
if (data.InitialSourceIndex < data.CurrentSourceReorderIndex)
|
||||
{
|
||||
placement = ItemReorderPlacement.After;
|
||||
}
|
||||
else
|
||||
{
|
||||
placement = ItemReorderPlacement.Before;
|
||||
}
|
||||
|
||||
var commandContext = new ItemReorderCompleteContext(dataItem, dataGroup, destinationDataItem, destinationDataGroup, placement);
|
||||
var isExecuted = this.ListView.commandService.ExecuteCommand(CommandId.ItemReorderComplete, commandContext);
|
||||
|
||||
if (isExecuted)
|
||||
{
|
||||
// TODO: Data provider does not handle well reordering of items in groups.
|
||||
// Remove this workaround once we fix the reordering in the data provider.
|
||||
if (this.listView.GroupDescriptors.Count > 0)
|
||||
{
|
||||
this.listView.updateService.RegisterUpdate((int)UpdateFlags.AffectsData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.reorderCoordinator.CancelReorderOperation(this, data.InitialSourceIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -113,7 +113,21 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView
|
|||
|
||||
(dragVisual as IDragDropElement).SkipHitTest = true;
|
||||
|
||||
DragDrop.SetDragPositionMode(this, this.ListView.Orientation == Orientation.Vertical ? DragPositionMode.RailY : DragPositionMode.RailX);
|
||||
var dragPositionMode = DragPositionMode.Free;
|
||||
|
||||
if (this.ListView.LayoutDefinition is StackLayoutDefinition)
|
||||
{
|
||||
if (this.ListView.Orientation == Orientation.Vertical)
|
||||
{
|
||||
dragPositionMode = DragPositionMode.RailY;
|
||||
}
|
||||
else
|
||||
{
|
||||
dragPositionMode = DragPositionMode.RailX;
|
||||
}
|
||||
}
|
||||
|
||||
DragDrop.SetDragPositionMode(this, dragPositionMode);
|
||||
|
||||
this.Opacity = 0.0;
|
||||
|
||||
|
@ -136,9 +150,13 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView
|
|||
{
|
||||
this.ListView.DragBehavior.OnDragDropCompleted(this, context.DragSuccessful);
|
||||
|
||||
var itemReordered = context.DragSuccessful;
|
||||
|
||||
if (!itemReordered && this.reorderCoordinator != null)
|
||||
if (this.reorderCoordinator != null)
|
||||
{
|
||||
if (context.DragSuccessful)
|
||||
{
|
||||
this.reorderCoordinator.CommitReorderOperation(data.InitialSourceIndex, data.CurrentSourceReorderIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.reorderCoordinator.CancelReorderOperation(this, data.InitialSourceIndex);
|
||||
}
|
||||
|
@ -147,3 +165,4 @@ namespace Telerik.UI.Xaml.Controls.Data.ListView
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -68,7 +68,7 @@ namespace Telerik.UI.Xaml.Controls.Data
|
|||
{
|
||||
}
|
||||
|
||||
internal void PrepareReorderItem(RadListViewItem reorderItem)
|
||||
internal void PrepareReorderItem(DependencyObject reorderItem)
|
||||
{
|
||||
if (reorderItem != null)
|
||||
{
|
||||
|
@ -77,7 +77,7 @@ namespace Telerik.UI.Xaml.Controls.Data
|
|||
}
|
||||
}
|
||||
|
||||
internal void CleanupReorderItem(RadListViewItem reorderItem)
|
||||
internal void CleanupReorderItem(DependencyObject reorderItem)
|
||||
{
|
||||
if (reorderItem != null)
|
||||
{
|
||||
|
@ -106,7 +106,7 @@ namespace Telerik.UI.Xaml.Controls.Data
|
|||
|
||||
private void InitializeReorder()
|
||||
{
|
||||
this.reorderCoordinator = new ReorderItemsCoordinator(this);
|
||||
this.reorderCoordinator = new ListViewReorderItemsCoordinator(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Telerik.UI.Xaml.Controls.Data.ListView;
|
||||
using Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Telerik.UI.Xaml.Controls.Data
|
||||
{
|
||||
internal class ListViewReorderItemsCoordinator : ReorderItemsCoordinator
|
||||
{
|
||||
public ListViewReorderItemsCoordinator(IReorderItemsHost host)
|
||||
: base(host)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void UpdatePositionAndIndices(IReorderItem source, IReorderItem destination)
|
||||
{
|
||||
var listView = (RadListView)this.Host;
|
||||
|
||||
if (listView.GroupDescriptors.Count == 0 || listView.LayoutDefinition is StackLayoutDefinition)
|
||||
{
|
||||
base.UpdatePositionAndIndices(source, destination);
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceIndex = source.LogicalIndex;
|
||||
var destinationIndex = destination.LogicalIndex;
|
||||
var childrenPanel = listView.childrenPanel;
|
||||
var reorderItems = childrenPanel.Children.OfType<IReorderItem>()
|
||||
.OrderBy(reorderItem => reorderItem.LogicalIndex).ToArray();
|
||||
var firstItem = reorderItems[0];
|
||||
var layoutItem = (IArrangeChild)firstItem;
|
||||
var layoutSlot = layoutItem.LayoutSlot;
|
||||
var arrangePosition = firstItem.ArrangePosition;
|
||||
|
||||
for (int logicalIndex = 0; logicalIndex < reorderItems.Length; logicalIndex++)
|
||||
{
|
||||
IReorderItem reorderItem;
|
||||
|
||||
if (logicalIndex == destinationIndex)
|
||||
{
|
||||
reorderItem = reorderItems[sourceIndex];
|
||||
}
|
||||
else if (logicalIndex >= sourceIndex && logicalIndex < destinationIndex)
|
||||
{
|
||||
reorderItem = reorderItems[logicalIndex + 1];
|
||||
}
|
||||
else if (logicalIndex > destinationIndex && logicalIndex <= sourceIndex)
|
||||
{
|
||||
reorderItem = reorderItems[logicalIndex - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
reorderItem = reorderItems[logicalIndex];
|
||||
}
|
||||
|
||||
reorderItem.LogicalIndex = logicalIndex;
|
||||
|
||||
var actualSize = reorderItem.ActualSize;
|
||||
|
||||
if (listView.Orientation == Orientation.Vertical)
|
||||
{
|
||||
if (arrangePosition.X + actualSize.Width > childrenPanel.ActualWidth)
|
||||
{
|
||||
arrangePosition.X = 0;
|
||||
arrangePosition.Y += layoutSlot.Height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arrangePosition.Y + actualSize.Height > childrenPanel.ActualHeight)
|
||||
{
|
||||
arrangePosition.Y = 0;
|
||||
arrangePosition.X += layoutSlot.Width;
|
||||
}
|
||||
}
|
||||
|
||||
if (arrangePosition != reorderItem.ArrangePosition)
|
||||
{
|
||||
this.AnimateItem(source, reorderItem, arrangePosition);
|
||||
}
|
||||
|
||||
if (listView.Orientation == Orientation.Vertical)
|
||||
{
|
||||
arrangePosition.X += actualSize.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
arrangePosition.Y += actualSize.Height;
|
||||
}
|
||||
|
||||
layoutItem = (IArrangeChild)reorderItem;
|
||||
layoutSlot = layoutItem.LayoutSlot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace Telerik.UI.Xaml.Controls.Data.ListView.Commands
|
||||
using Telerik.Data.Core;
|
||||
|
||||
namespace Telerik.UI.Xaml.Controls.Data.ListView.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// The context that is passed as a parameter to the <see cref="ItemReorderCompleteCommand"/>.
|
||||
|
@ -8,11 +10,21 @@
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemReorderCompleteContext"/> class.
|
||||
/// </summary>
|
||||
public ItemReorderCompleteContext(object dataItem, object destinationItem, RadListViewItem container)
|
||||
public ItemReorderCompleteContext(object dataItem, object destinationItem, ItemReorderPlacement placement)
|
||||
: this(dataItem, null, destinationItem, null, placement)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemReorderCompleteContext"/> class.
|
||||
/// </summary>
|
||||
public ItemReorderCompleteContext(object dataItem, IDataGroup dataGroup, object destinationItem, IDataGroup destinationGroup, ItemReorderPlacement placement)
|
||||
{
|
||||
this.Item = dataItem;
|
||||
this.Group = dataGroup;
|
||||
this.DestinationItem = destinationItem;
|
||||
this.Container = container;
|
||||
this.DestinationGroup = destinationGroup;
|
||||
this.Placement = placement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -20,11 +32,24 @@
|
|||
/// </summary>
|
||||
public object Item { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data group that corresponds to the <see cref="RadListViewItem"/> that is being interacted with.
|
||||
/// </summary>
|
||||
public IDataGroup Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data item that corresponds to the location where the dragged item has been released.
|
||||
/// </summary>
|
||||
public object DestinationItem { get; set; }
|
||||
|
||||
internal RadListViewItem Container { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the data group that corresponds to the location where the dragged item has been released.
|
||||
/// </summary>
|
||||
public IDataGroup DestinationGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dragged item should be placed before or after the destination item.
|
||||
/// </summary>
|
||||
public ItemReorderPlacement Placement { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
|
@ -20,11 +17,8 @@ namespace Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder
|
|||
public ReorderItemsCoordinator(IReorderItemsHost host)
|
||||
{
|
||||
this.Host = host;
|
||||
this.ReorderWithAnimation = true;
|
||||
}
|
||||
|
||||
internal bool ReorderWithAnimation { get; set; }
|
||||
|
||||
internal IReorderItemsHost Host
|
||||
{
|
||||
get;
|
||||
|
@ -71,11 +65,17 @@ namespace Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder
|
|||
this.UpdatePositionAndIndices(sourceItem, destinationItem);
|
||||
}
|
||||
|
||||
protected virtual void AnimateItem(IReorderItem item, Point position, Action actionCompleted)
|
||||
protected void AnimateItem(IReorderItem source, IReorderItem destination, Point position)
|
||||
{
|
||||
var dragPositionMode = DragDrop.GetDragPositionMode(item.Visual);
|
||||
var dragPositionMode = DragDrop.GetDragPositionMode(destination.Visual);
|
||||
|
||||
Storyboard b = new Storyboard();
|
||||
Action actionCompleted = () =>
|
||||
{
|
||||
destination.ArrangePosition = position;
|
||||
this.animatingElements.Remove(destination);
|
||||
this.Host.OnItemsReordered(source, destination);
|
||||
};
|
||||
|
||||
this.runningAnimations.Add(b, actionCompleted);
|
||||
|
||||
|
@ -86,7 +86,7 @@ namespace Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder
|
|||
topAnimation.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseIn };
|
||||
topAnimation.To = position.Y;
|
||||
Storyboard.SetTargetProperty(topAnimation, "(Canvas.Top)");
|
||||
Storyboard.SetTarget(topAnimation, item.Visual);
|
||||
Storyboard.SetTarget(topAnimation, destination.Visual);
|
||||
b.Children.Add(topAnimation);
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ namespace Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder
|
|||
leftAnimation.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseIn };
|
||||
leftAnimation.To = position.X;
|
||||
Storyboard.SetTargetProperty(leftAnimation, "(Canvas.Left)");
|
||||
Storyboard.SetTarget(leftAnimation, item.Visual);
|
||||
Storyboard.SetTarget(leftAnimation, destination.Visual);
|
||||
b.Children.Add(leftAnimation);
|
||||
}
|
||||
|
||||
|
@ -110,46 +110,7 @@ namespace Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder
|
|||
b.Begin();
|
||||
}
|
||||
|
||||
private static Point GetRearangePosition(IReorderItem targetItem, IReorderItem adjasentItem)
|
||||
{
|
||||
Point position;
|
||||
|
||||
if (targetItem.LogicalIndex > adjasentItem.LogicalIndex)
|
||||
{
|
||||
position = adjasentItem.ArrangePosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x = -1;
|
||||
double y = -1;
|
||||
var dragPositionMode = DragDrop.GetDragPositionMode(targetItem.Visual);
|
||||
|
||||
if (dragPositionMode == DragPositionMode.RailY || dragPositionMode == DragPositionMode.Free)
|
||||
{
|
||||
x = adjasentItem.ArrangePosition.X;
|
||||
y = adjasentItem.ArrangePosition.Y + adjasentItem.ActualSize.Height - targetItem.ActualSize.Height;
|
||||
}
|
||||
|
||||
if (dragPositionMode == DragPositionMode.RailX || dragPositionMode == DragPositionMode.Free)
|
||||
{
|
||||
x = adjasentItem.ArrangePosition.X + adjasentItem.ActualSize.Width - targetItem.ActualSize.Width;
|
||||
y = adjasentItem.ArrangePosition.Y;
|
||||
}
|
||||
position = new Point(x, y);
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
private void ReorderItems(IReorderItem source, IReorderItem destination)
|
||||
{
|
||||
if (source != destination && !this.animatingElements.Contains(destination) && !this.animatingElements.Contains(source))
|
||||
{
|
||||
this.UpdatePositionAndIndices(source, destination);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePositionAndIndices(IReorderItem source, IReorderItem destination)
|
||||
protected virtual void UpdatePositionAndIndices(IReorderItem source, IReorderItem destination)
|
||||
{
|
||||
var step = source.LogicalIndex < destination.LogicalIndex ? 1 : -1;
|
||||
|
||||
|
@ -167,28 +128,50 @@ namespace Telerik.UI.Xaml.Controls.Primitives.DragDrop.Reorder
|
|||
|
||||
this.animatingElements.Add(currentDestinationItem);
|
||||
|
||||
var destinationPosition = ReorderItemsCoordinator.GetRearangePosition(currentDestinationItem, source);
|
||||
source.ArrangePosition = ReorderItemsCoordinator.GetRearangePosition(source, currentDestinationItem);
|
||||
var destinationPosition = GetRearrangePosition(currentDestinationItem, source);
|
||||
source.ArrangePosition = GetRearrangePosition(source, currentDestinationItem);
|
||||
|
||||
var index = source.LogicalIndex;
|
||||
source.LogicalIndex = currentDestinationItem.LogicalIndex;
|
||||
currentDestinationItem.LogicalIndex = index;
|
||||
|
||||
Action moveCompletedAction = () =>
|
||||
{
|
||||
currentDestinationItem.ArrangePosition = destinationPosition;
|
||||
this.animatingElements.Remove(currentDestinationItem);
|
||||
this.Host.OnItemsReordered(source, currentDestinationItem);
|
||||
};
|
||||
this.AnimateItem(source, currentDestinationItem, destinationPosition);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ReorderWithAnimation)
|
||||
private static Point GetRearrangePosition(IReorderItem targetItem, IReorderItem adjacentItem)
|
||||
{
|
||||
this.AnimateItem(currentDestinationItem, destinationPosition, moveCompletedAction);
|
||||
}
|
||||
else
|
||||
var position = targetItem.ArrangePosition;
|
||||
var dragPositionMode = DragDrop.GetDragPositionMode(targetItem.Visual);
|
||||
|
||||
if (dragPositionMode == DragPositionMode.RailY || dragPositionMode == DragPositionMode.Free)
|
||||
{
|
||||
moveCompletedAction();
|
||||
}
|
||||
position.Y = adjacentItem.ArrangePosition.Y;
|
||||
|
||||
if (targetItem.LogicalIndex < adjacentItem.LogicalIndex)
|
||||
{
|
||||
position.Y += adjacentItem.ActualSize.Height - targetItem.ActualSize.Height;
|
||||
}
|
||||
}
|
||||
|
||||
if (dragPositionMode == DragPositionMode.RailX || dragPositionMode == DragPositionMode.Free)
|
||||
{
|
||||
position.X = adjacentItem.ArrangePosition.X;
|
||||
|
||||
if (targetItem.LogicalIndex < adjacentItem.LogicalIndex)
|
||||
{
|
||||
position.X += adjacentItem.ActualSize.Width - targetItem.ActualSize.Width;
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
private void ReorderItems(IReorderItem source, IReorderItem destination)
|
||||
{
|
||||
if (source != destination && !this.animatingElements.Contains(destination) && !this.animatingElements.Contains(source))
|
||||
{
|
||||
this.UpdatePositionAndIndices(source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
<Example DisplayName="Pull to Refresh" ClassName="SDKExamples.UWP.Listview.PullToRefresh" />
|
||||
<Example DisplayName="Grouping" ClassName="SDKExamples.UWP.Listview.Grouping" />
|
||||
<Example DisplayName="Reorder" ClassName="SDKExamples.UWP.Listview.Reorder" />
|
||||
<Example DisplayName="Reorder with Groups" ClassName="SDKExamples.UWP.Listview.ReorderWithGroups" />
|
||||
<Example DisplayName="Load on Demand" ClassName="SDKExamples.UWP.Listview.LoadOnDemand" />
|
||||
<Example DisplayName="Filtering" ClassName="SDKExamples.UWP.Listview.Filtering" />
|
||||
<Example DisplayName="Item Animations" ClassName="SDKExamples.UWP.Listview.ItemAnimations" />
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<local:ExamplePageBase x:Class="SDKExamples.UWP.Listview.ReorderWithGroups"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:SDKExamples.UWP"
|
||||
xmlns:data="using:Telerik.UI.Xaml.Controls.Data"
|
||||
xmlns:dataCore="using:Telerik.Data.Core"
|
||||
xmlns:example="using:SDKExamples.UWP.Listview"
|
||||
x:Name="page">
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{Binding Title, ElementName=page}"
|
||||
Style="{StaticResource ExampleHeaderTextBlockStyle}" />
|
||||
<data:RadListView Grid.Row="1"
|
||||
IsItemReorderEnabled="True"
|
||||
ReorderMode="Default"
|
||||
ItemsSource="{Binding Items}">
|
||||
<data:RadListView.Commands>
|
||||
<example:ListViewGroupReorderCommand Id="ItemReorderComplete" />
|
||||
</data:RadListView.Commands>
|
||||
<data:RadListView.GroupDescriptors>
|
||||
<dataCore:PropertyGroupDescriptor PropertyName="Category" />
|
||||
</data:RadListView.GroupDescriptors>
|
||||
<data:RadListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</data:RadListView.ItemTemplate>
|
||||
</data:RadListView>
|
||||
</Grid>
|
||||
</local:ExamplePageBase>
|
|
@ -0,0 +1,113 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Telerik.Data.Core;
|
||||
using Telerik.UI.Xaml.Controls.Data.ListView.Commands;
|
||||
|
||||
namespace SDKExamples.UWP.Listview
|
||||
{
|
||||
public sealed partial class ReorderWithGroups : ExamplePageBase
|
||||
{
|
||||
public ReorderWithGroups()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContext = new ViewModel();
|
||||
}
|
||||
|
||||
public class ViewModel
|
||||
{
|
||||
public ObservableCollection<Item> Items { get; }
|
||||
|
||||
public ViewModel()
|
||||
{
|
||||
this.Items = new ObservableCollection<Item>();
|
||||
|
||||
for (int index = 0; index < 100; index++)
|
||||
{
|
||||
var item = new Item
|
||||
{
|
||||
Category = $"Category {index / 10}",
|
||||
Name = $"Item {index}"
|
||||
};
|
||||
|
||||
this.Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Item : INotifyPropertyChanged
|
||||
{
|
||||
private string category;
|
||||
private string name;
|
||||
|
||||
public string Category
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.category;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.category != value)
|
||||
{
|
||||
this.category = value;
|
||||
this.OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.name != value)
|
||||
{
|
||||
this.name = value;
|
||||
this.OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ListViewGroupReorderCommand : ListViewCommand
|
||||
{
|
||||
public override bool CanExecute(object parameter)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Execute(object parameter)
|
||||
{
|
||||
var items = (IList<ReorderWithGroups.Item>)this.Owner.ItemsSource;
|
||||
var context = (ItemReorderCompleteContext)parameter;
|
||||
var sourceItem = (ReorderWithGroups.Item)context.Item;
|
||||
|
||||
items.Remove(sourceItem);
|
||||
|
||||
var destinationItem = (ReorderWithGroups.Item)context.DestinationItem;
|
||||
var destinationGroup = context.DestinationGroup;
|
||||
var destinationIndex = items.IndexOf(destinationItem);
|
||||
|
||||
if (context.Placement == ItemReorderPlacement.After)
|
||||
{
|
||||
destinationIndex++;
|
||||
}
|
||||
|
||||
sourceItem.Category = (string)destinationGroup.Key;
|
||||
items.Insert(destinationIndex, sourceItem);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -355,6 +355,9 @@
|
|||
<Compile Include="Examples\ListView\Reorder.xaml.cs">
|
||||
<DependentUpon>Reorder.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Examples\ListView\ReorderWithGroups.xaml.cs">
|
||||
<DependentUpon>ReorderWithGroups.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Examples\ListView\ScrollIndexIntoView.xaml.cs">
|
||||
<DependentUpon>ScrollIndexIntoView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -789,6 +792,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Examples\ListView\ReorderWithGroups.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Examples\ListView\ScrollIndexIntoView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
Загрузка…
Ссылка в новой задаче