1
votes

I'm using the Items Page template from the Windows 8.1 Windows Store Apps templates in XAML. The page features a large GridView control with multiple item elements.

I would like to enable the dragging and reordering of items, but only after a user long clicks one of the items (similar to how it's done on the Windows Tablet Start menu and the iOS/Android home screen).

I've tried binding to the Holding event and enabling CanDragItems and CanReorderItems, but the user cannot start dragging the item during the Holding event.

Here's the GridView definition:

<GridView
        x:Name="itemGridView"
        AutomationProperties.AutomationId="ItemsGridView"
        AutomationProperties.Name="Items"
        TabIndex="1"
        Grid.RowSpan="2"
        Padding="116,136,116,46"
        ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
        SelectionMode="None"
        IsSwipeEnabled="False"
        IsItemClickEnabled="True"
        CanReorderItems="False"
        AllowDrop="False"
        CanDragItems="False" 
        ItemClick="itemGridView_ItemClick"
        >

With this in the code behind:

void OnHolding(object sender, HoldingRoutedEventArgs e)
    {
        if( e.HoldingState == Windows.UI.Input.HoldingState.Started)
        {
            Debug.WriteLine("Drag Start");
            itemGridView.CanDragItems = true;
            itemGridView.IsSwipeEnabled = true;
            itemGridView.CanReorderItems = true;
            itemGridView.AllowDrop = true;
        }
        else
        {
            Debug.WriteLine("Drag End");
            itemGridView.CanDragItems = false;
            itemGridView.IsSwipeEnabled = false;
            itemGridView.CanReorderItems = false;
            itemGridView.AllowDrop = false;
        }
    }

Thanks!

2

2 Answers

1
votes

After much fuss and chasing down events, I was able to get the intended effect on pen, mouse, and touch devices.

The following code is not guaranteed to be the best way to accomplish the long click drag, but it is functioning on my devices with Windows 8.1. I encourage someone to find a better solution, since this one is kind of messy.

Code behind looks like this:

    private bool isHolding = false;
    private bool canUserDragItem = false;

    // If a user moves their pointer outside the item's area or releases their pointer, stop all holding/dragging actions.
    private void Grid_StopAllowDrag(object sender, PointerRoutedEventArgs e)
    {
        canUserDragItem = false;
        isHolding = false;
    }

    // If a user starts dragging an item, check and see if they are holding the item first.
    private void itemGridView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
    {
        if (!canUserDragItem) e.Cancel = true;
    }

    private async void Grid_PointerPressed(object sender, PointerRoutedEventArgs e)
    {
        // Whenever a user presses the pointer inside the item, wait for half a second, then decide if the user is holding the item.
        isHolding = true;

        await Task.Delay(500); // Wait for some amount of time before allowing them to drag

        if (isHolding) // If the user is still holding, allow them to drag the item.
        { 
            canUserDragItem = true; // Allow them to drag now
            // TODO: Make it apparent that the user is able to drag the item now.
        }
    }

And the XAML looks like this:

<GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemsGridView"
            AutomationProperties.Name="Items"
            TabIndex="1"
            Grid.RowSpan="2"
            Padding="116,136,116,46"
            ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
            SelectionMode="None"
            IsSwipeEnabled="True" <!-- Enable dragging on touch devices -->
            CanReorderItems="True" <!-- Allow users to try to start dragging -->
            AllowDrop="True"
            CanDragItems="True"
            DragItemsStarting="itemGridView_DragItemsStarting" <!-- Stop dragging while not holding -->
            >
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Grid HorizontalAlignment="Left" Width="250" Height="250"
                          <!-- Items must be given these event handlers -->
                          PointerPressed="Grid_PointerPressed"
                          PointerReleased="Grid_StopAllowDrag"
                          PointerCanceled="Grid_StopAllowDrag"
                          PointerCaptureLost="Grid_StopAllowDrag"
                          PointerExited="Grid_StopAllowDrag"
                          >
0
votes

You need another else case. Your logic looks like this.

If they started doing something. Set properties to true. While they are still holding the properties will be set to false.

You probably want two separate events. Holding started and Holding stopped. Not just a blanket else there.