Question

In my ScatterView i want to drag&drop items onto a SurfaceButton to add them to a SurfaceListBox. At this point everything is working fine.

Here is my XAML-Code of the ScatterView:

<UserControl x:Class="Ctms.Presentation.Views.ResultView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:p="clr-namespace:Ctms.Presentation.Properties"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:waf="http://waf.codeplex.com/schemas"
             xmlns:vm="clr-namespace:Ctms.Applications.ViewModels;assembly=Ctms.Applications"
             xmlns:ps="clr-namespace:PieInTheSky;assembly=PieInTheSky"
             xmlns:s="http://schemas.microsoft.com/surface/2008"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:blakenui="clr-namespace:Blake.NUI.WPF.Gestures;assembly=Blake.NUI.WPF"
             IsEnabled="{Binding IsEnabled}"
             waf:ValidationHelper.IsValid="{Binding IsValid, Mode=OneWayToSource}">


    <Grid>
        <s:ScatterView Name="MainScatterView" ItemsSource="{Binding Results}" ItemTemplate="{StaticResource ScatterViewItemDataTemplate}"
                   s:SurfaceDragDrop.DragCanceled="Results_OnDragCanceled"
                   s:SurfaceDragDrop.DragCompleted="Results_OnDragCompleted"
                   blakenui:Events.DoubleTapGesture="Results_DoubleTapGesture"
                   PreviewTouchDown="Results_PreviewTouchDown">
        </s:ScatterView>
    </Grid>
</UserControl>

Here is my handler for the DragStart

private void Results_PreviewTouchDown(object sender, TouchEventArgs e)
{
    FrameworkElement findSource = e.OriginalSource as FrameworkElement;
    ScatterViewItem draggedElement = null;

    // Find the ScatterViewItem object that is being touched.
    while (draggedElement == null && findSource != null)
    {
        if ((draggedElement = findSource as ScatterViewItem) == null)
        {
            findSource = VisualTreeHelper.GetParent(findSource) as FrameworkElement;
        }
    }

    if (draggedElement == null)
    {
        return;
    }

    ResultDataModel data = draggedElement.Content as ResultDataModel;

    // Set the dragged element. This is needed in case the drag operation is canceled.
    data.DraggedElement = draggedElement;

    // Create the cursor visual.
    ContentControl cursorVisual = new ContentControl()
    {
        Content = draggedElement.DataContext,
        Style = FindResource("ResultCursorStyle") as Style
    };

    // Create a list of input devices, 
    // and add the device passed to this event handler.
    List<InputDevice> devices = new List<InputDevice>();
    devices.Add(e.TouchDevice);

    // If there are touch devices captured within the element,
    // add them to the list of input devices.
    foreach (InputDevice device in draggedElement.TouchesCapturedWithin)
    {
        if (device != e.TouchDevice)
        {
            devices.Add(device);
        }
    }

    // Get the drag source object.
    ItemsControl dragSource = ItemsControl.ItemsControlFromItemContainer(draggedElement);

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

    e.Handled = (cursor != null);
}

In the ResourceDictionary, where the ScatterViewItem-Template is placed i also added a SizeChanged-Listener:

private void ResultWrapper_SizeChanged(object sender, SizeChangedEventArgs e)
{
    FrameworkElement scatterViewItem = e.Source as FrameworkElement;
    ResultDataModel result = scatterViewItem.DataContext as ResultDataModel;

    //do some stuff when scaling
}

Now, when i disable the DragStart-Handler, my SizeChanged-Handler gets called. But if i enable the DragStart-Handler, i can't resize the ScatterViewItems, cause DragStart gets immediately called.

Is there any solution where i can capture both events, drag&drop, as well as scaling?

Was it helpful?

Solution

Ok then it's very simple. Use ScatterViewItem.ContainerDeactivated event.It fires when IsContainerActive switches to false (when the container is not manipulated any more). Now all you have to do is to test whether is over one of your buttons. Use ActualCenter property to know where your SVI is placed.

EDIT: Here is some code

I've set a very simple window:

<Grid>
    <Canvas>
        <Button x:Name="btnButton1" Canvas.Left="100" Canvas.Top="200" Width="200" Height="200">Button 1</Button>
        <Button x:Name="btnButton2" Canvas.Left="500" Canvas.Top="300" Width="200" Height="200">Button 2</Button>
    </Canvas>

    <s:ScatterView x:Name="containerScatterView" s:ScatterViewItem.ContainerDeactivated="ScatterView_ContainerDeactivated">

        <s:ScatterViewItem>
            <Rectangle Fill="Red" Width="100" Height="100"/>
        </s:ScatterViewItem>

        <s:ScatterViewItem>
            <Rectangle Fill="Green" Width="100" Height="100"/>
        </s:ScatterViewItem>

    </s:ScatterView>
</Grid>

Now the code of the event Handler:

private void ScatterView_ContainerDeactivated(object sender, RoutedEventArgs e)
{
    ScatterViewItem sourceSVI =  (ScatterViewItem)e.OriginalSource;

    //Retrieve Button1 size
    Rect btn1Bounds = VisualTreeHelper.GetDescendantBounds(btnButton1);
    //Get the transform between SV and the button1. We need it because ActualCenter is relative to SV.
    GeneralTransform transform1 = containerScatterView.TransformToVisual(btnButton1);

    if (btn1Bounds.Contains(transform1.Transform(sourceSVI.ActualCenter)))
    {
        //If ActualPoint is in bounds of the button1 then do something
        Console.WriteLine("Dropped on Button 1");
    }

    //Retrieve Button2 size
    Rect btn2Bounds = VisualTreeHelper.GetDescendantBounds(btnButton2);
    //Get the transform between SV and the button1. We need it because ActualCenter is relative to SV.
    GeneralTransform transform2 = containerScatterView.TransformToVisual(btnButton2);

    if (btn2Bounds.Contains(transform2.Transform(sourceSVI.ActualCenter)))
    {
        //If ActualPoint is in bounds of the button2 then do something else
        Console.WriteLine("Dropped on Button 2");
    }
}

I used here the simplest way to test whether the point is over the button. I just test whether the point is inside the bounding rect of the button. It is also possible to use WPF HitTesting.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top