Search code examples
drag-and-dropevent-handlingpixelsensescatterview

Catch SurfaceDragDropEventArgs in ScatterViews with different Layers (zIndex)


I'm trying to implement a photo sharing application with two Android phones and a surface application using the toolkit for Windows Touch Beta. Therefore, I created a ScatterView called MainScatterView as basic Layout. Each time a user touches the screen, a Blob will be created in this MainScatterView. The Blob itself is a ScatterViewItem that contains a ScatterView named Blob. This Blob contains the photos of a specific album on the Android phone.

Dragging & Dropping photos between two blobs works well, but if I want to drop an item on the MainScatterView the dependant onDrop method is never called. My assumption is that this problem depends on the different Layers that a Blob ScatterView and the MainScatterView have, but that's only an assumption. Here's my XAML code:

<s:SurfaceWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="FotoSharing.SurfaceWindow1"
Width="1920" Height="1080" BorderThickness="5" BorderBrush="White" WindowStyle="None">

<s:SurfaceWindow.Resources>
    <ImageBrush x:Key="WindowBackground" Stretch="None" Opacity="0.6" ImageSource="pack://application:,,,/Resources/WindowBackground.jpg"/>
</s:SurfaceWindow.Resources>

<s:SurfaceWindow.Background>
    <LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
        <GradientStop Color="Black"/>
        <GradientStop Color="#FFA784C8" Offset="1"/>
    </LinearGradientBrush>
</s:SurfaceWindow.Background>
<s:ScatterView x:Name="MainScatterView" Margin="0" Width="1920" Height="1080" AllowDrop="True" s:SurfaceDragDrop.Drop="OnDrop" PreviewTouchDown="OnDragSourcePreviewTouchDown">
    <s:ScatterViewItem x:Name="sviBlob1" Width="600" Height="600" Orientation="0" CanMove="False" CanRotate="False" CanScale="False" Visibility="Collapsed">
        <Viewbox x:Name="ViewBoxBlob1">
            <s:ScatterView x:Name="Blob1" Width="600" Height="600" AllowDrop="True" s:SurfaceDragDrop.Drop="OnDrop" PreviewTouchDown="OnDragSourcePreviewTouchDown">
                <s:ScatterView.Background>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="#FFA784C8" Offset="1"/>
                    </LinearGradientBrush>
                </s:ScatterView.Background>
                <s:ScatterViewItem x:Name="sviBlob1Header" Width="600" Height="40" CanRotate="False" CanMove="False" CanScale="False" Orientation="0" Center="300,20" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
                    <s:ScatterViewItem.Background>
                        <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
                            <GradientStop Color="#FFA4B4BD" Offset="0"/>
                            <GradientStop Color="#FF65438F" Offset="1"/>
                        </LinearGradientBrush>
                    </s:ScatterViewItem.Background>
                    <Canvas x:Name="Blob1Header" Height="40" Width="600">
                        <Image x:Name="Blob1NavigateLeft" Height="40" Width="50" Source="Icons\navigate_left_256.png" Canvas.Left="480" TouchDown="handleTouchDownNavigateLeft" Visibility="Hidden"/>
                        <Image x:Name="Blob1NavigateRight" Height="40" Width="50" Source="Icons\navigate_right_256.png" Canvas.Left="535" TouchDown="handleTouchDownNavigateRight" Visibility="Hidden"/>
                        <Image x:Name="Blob1ZoomIn" Height="40" Width="50" Source="Icons\zoom_in_128.png" Canvas.Left="294" TouchDown="handleTouchDownZoomIn"/>
                        <Image x:Name="Blob1ZoomOut" Height="40" Width="50" Source="Icons\zoom_out_128.png" Canvas.Left="360" TouchDown="handleTouchDownZoomOut"/>
                        <Image x:Name="Blob1Pin" Height="50" Width="50" Source="Icons\pin_black_128.png" Canvas.Left="480" TouchDown="handleTouchDownPin"/>
                        <Image x:Name="Blob1DragDrop" Height="40" Width="46" Source="Icons\dragdrop.png" Canvas.Left="430" TouchDown="handleTouchDownDragDrop"/>
                        <Image x:Name="Blob1Close" Height="40" Width="50" Source="Icons\delete_blob_128.png" Canvas.Left="535" TouchDown="handleTouchDownClose"/>
                        <Image x:Name="Blob1Album" Height="40" Width="50" Source="Icons\album_128.png"/>
                        <Label x:Name="Blob1AlbumName" Content="Label" Width="250" Height="40" Canvas.Left="52" FontSize="26.667" Canvas.Top="-4" FontWeight="Bold" FontStyle="Italic"/>
                    </Canvas></s:ScatterViewItem>
            </s:ScatterView>
        </Viewbox>
    </s:ScatterViewItem>
    <s:ScatterViewItem x:Name="sviBlob2" Width="600" Height="600" Orientation="0" CanMove="False" CanRotate="False" CanScale="False" Visibility="Collapsed">
        <Viewbox x:Name="ViewBoxBlob2">
            <s:ScatterView x:Name="Blob2" Width="600" Height="600" AllowDrop="True" s:SurfaceDragDrop.Drop="OnDrop" PreviewTouchDown="OnDragSourcePreviewTouchDown">
                <s:ScatterView.Background>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="Black" Offset="0"/>
                        <GradientStop Color="#FFA784C8" Offset="1"/>
                    </LinearGradientBrush>
                </s:ScatterView.Background>
                <s:ScatterViewItem x:Name="sviBlob2Header" Width="600" Height="40" CanRotate="False" CanMove="False" CanScale="False" Orientation="0" Center="300,20" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
                    <s:ScatterViewItem.Background>
                        <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
                            <GradientStop Color="#FFA4B4BD" Offset="0"/>
                            <GradientStop Color="#FF65438F" Offset="1"/>
                        </LinearGradientBrush>
                    </s:ScatterViewItem.Background>
                    <Canvas x:Name="Blob2Header" Height="40" Width="600">
                        <Image x:Name="Blob2NavigateLeft" Height="40" Width="50" Source="Icons\navigate_left_256.png" Canvas.Left="480" TouchDown="handleTouchDownNavigateLeft" Visibility="Hidden"/>
                        <Image x:Name="Blob2NavigateRight" Height="40" Width="50" Source="Icons\navigate_right_256.png" Canvas.Left="535" TouchDown="handleTouchDownNavigateRight" Visibility="Hidden"/>
                        <Image x:Name="Blob2ZoomIn" Height="40" Width="50" Source="Icons\zoom_in_128.png" Canvas.Left="294" TouchDown="handleTouchDownZoomIn"/>
                        <Image x:Name="Blob2ZoomOut" Height="40" Width="50" Source="Icons\zoom_out_128.png" Canvas.Left="360" TouchDown="handleTouchDownZoomOut"/>
                        <Image x:Name="Blob2Pin" Height="50" Width="50" Source="Icons\pin_black_128.png" Canvas.Left="480" TouchDown="handleTouchDownPin"/>
                        <Image x:Name="Blob2DragDrop" Height="40" Width="46" Source="Icons\dragdrop.png" Canvas.Left="430" TouchDown="handleTouchDownDragDrop"/>
                        <Image x:Name="Blob2Close" Height="40" Width="50" Source="Icons\delete_blob_128.png" Canvas.Left="535" TouchDown="handleTouchDownClose"/>
                        <Image x:Name="Blob2Album" Height="40" Width="50" Source="Icons\album_128.png"/>
                        <Label x:Name="Blob2AlbumName" Content="Label" Width="250" Height="40" Canvas.Left="52" FontSize="26.667" Canvas.Top="-4" FontWeight="Bold" FontStyle="Italic"/>
                    </Canvas></s:ScatterViewItem>
            </s:ScatterView>
        </Viewbox>
    </s:ScatterViewItem>
</s:ScatterView>

The two depending Methods onDrop and OnDragPreviewTouchDown look like this:

private void OnDragSourcePreviewTouchDown(object sender, TouchEventArgs e)
    {
        if (allowDragDrop == true)
        {
            if (e.OriginalSource is Image)
            {
                if ((e.OriginalSource as Image).Parent is ScatterViewItem) // prevent that image of Hederline is handled as foto
                {
                    Image foto = (Image)e.OriginalSource;
                    string fotoID = (string)foto.DataContext;
                    ScatterViewItem draggedElement = (ScatterViewItem)(e.OriginalSource as Image).Parent;
                    double width = draggedElement.ActualWidth;
                    double height = draggedElement.ActualHeight;
                    double orientation = draggedElement.ActualOrientation;
                    ScatterViewItemDataContext context = (ScatterViewItemDataContext)draggedElement.DataContext;
                    context.originCenter = draggedElement.ActualCenter;
                    ScatterView dragSource = (ScatterView)draggedElement.Parent;
                    ScatterViewItem clonedDraggedElement = createScatterViewItemClone(width, height, orientation, context, fotoID);

                    // Create the cursor visual.
                    ContentControl cursorVisual = new ContentControl()
                    {
                        Content = clonedDraggedElement
                    };

                    // Create a list of input devices. Add the touches that
                    // are currently captured within the dragged element and
                    // the current touch (if it isn't already in the list).
                    List<InputDevice> devices = new List<InputDevice>();
                    devices.Add(e.TouchDevice);
                    foreach (TouchDevice touch in draggedElement.TouchesCapturedWithin)
                    {
                        if (touch != e.TouchDevice)
                        {
                            devices.Add(touch);
                        }
                    }

                    SurfaceDragCursor startDragOkay =
                        SurfaceDragDrop.BeginDragDrop(
                            dragSource,                 // The ScatterView object that the cursor is dragged out from.
                            draggedElement,             // The ScatterViewItem object that is dragged from the drag source.
                            cursorVisual,               // The visual element of the cursor.
                            draggedElement,             // The data attached with the cursor.
                            devices,                    // The input devices that start dragging the cursor.
                            System.Windows.DragDropEffects.Move);      // The allowed drag-and-drop effects of the operation.

                    // This if-clause causes, that the scatterviewitems are not deleted on the dragsource!
                    if (startDragOkay != null)
                    {
                        // Set e.Handled to true, otherwise the ScatterViewItem will capture the touch 
                        // and cause the BeginDragDrop to fail.
                        e.Handled = true;
                        // Hide the ScatterViewItem.
                        draggedElement.Visibility = Visibility.Hidden;
                    }
                }
            }
        }
    }

    private void OnDrop(object sender, SurfaceDragDropEventArgs e)
    {
        e.Handled = false;
        Console.WriteLine(sender.ToString());
        if (sender is ScatterView)
        {
            // Get drag source SV and drop SV
            ScatterView dropScatterView = sender as ScatterView;
            ScatterView dragSource = (ScatterView)e.Cursor.DragSource;
            // Receive dragged Element from Cursor
            ScatterViewItem draggedElement = (ScatterViewItem)e.Cursor.Data;
            Image foto = (Image)draggedElement.Content;
            // Get informations to clone dragged item
            string fotoID = (string)foto.DataContext;
            double width = draggedElement.ActualWidth;
            double height = draggedElement.ActualHeight;
            double orientation = draggedElement.ActualOrientation;
            ScatterViewItemDataContext context = (ScatterViewItemDataContext)draggedElement.DataContext;
            // Clone dragged item
            ScatterViewItem clonedDraggedElement = createScatterViewItemClone(width, height, orientation, context, fotoID);
            clonedDraggedElement.Center = e.Cursor.GetPosition(dropScatterView);

            // Remove Item from Drag-Source
            dragSource.Items.Remove(draggedElement);

            // Item was droppeded in the same Blob
            if (dragSource.Equals(dropScatterView))
            {
                dropScatterView.Items.Add(clonedDraggedElement);
                // Update Center of Blob with Animation
                PointAnimation pa = new PointAnimation();
                pa.From = e.Cursor.GetPosition(dropScatterView);
                pa.To = context.originCenter;
                pa.Duration = TimeSpan.FromMilliseconds(500);
                pa.FillBehavior = FillBehavior.HoldEnd;
                clonedDraggedElement.BeginAnimation(ScatterViewItem.CenterProperty, pa);
            }
            else if (dropScatterView.Equals(MainScatterView) == false) // Foto was dropped to another Blob!
            {
                BlobInfo blobInfoDropSV = (BlobInfo)dropScatterView.DataContext;
                // Add new fotoID to array of fotoIDs
                blobInfoDropSV.fotoIDs.Add(fotoID);

                // Add dragged foto to grid of Blob
                FotoSampler fotoSampler = new FotoSampler();
                Image dropFoto = fotoSampler.getImageByFotoID(fotoID);
                ScatterViewItem sviToDrop = calculateFotoInGridPosition(blobInfoDropSV.fotoIDs.Count-1, dropFoto);
                dropScatterView.Items.Add(sviToDrop);

                PointAnimation pa = new PointAnimation();
                pa.From = e.Cursor.GetPosition(dropScatterView);
                pa.To = sviToDrop.Center;
                pa.Duration = TimeSpan.FromMilliseconds(500);
                pa.FillBehavior = FillBehavior.Stop;
                sviToDrop.BeginAnimation(ScatterViewItem.CenterProperty, pa);

                // refresh drag-Blob
                BlobInfo blobInfoDragSV = (BlobInfo)dragSource.DataContext;
                removeFotosFromBlob(dragSource);
                int nbrOfFotosBeforeRefresh = blobInfoDragSV.fotoIDs.Count;
                int idOfFotoToDelete = 0;
                for (int i = 0; i < nbrOfFotosBeforeRefresh; i++) // remove FotoID from List of FotoIDs
                {
                    if (blobInfoDragSV.fotoIDs[i].Equals(fotoID) == true)
                    {
                        idOfFotoToDelete = i;
                    }
                }
                blobInfoDragSV.fotoIDs.RemoveAt(idOfFotoToDelete); // delete draggedElement
                createFotosInBlob(blobInfoDragSV.blobNbr, blobInfoDragSV.fotoIDs, blobInfoDragSV.zoomLevel); // calculate and order fotos again

                // send Message mit Item to User
                TcpClient client = new TcpClient(blobInfoDropSV.user.ip);
                client.sendeNachricht("01#"+fotoID+"#");
            }
        }
    }

I really tried a lot to solve this problem but nothing results in a comfortable solution.


Solution

  • I've recognized, that the ScatterView-Property Background has to be defined. Only if this property is set, events like the SurfaceDragDropEventArgs can be catched. Crazy!