0

I want to create a drag and drop interface in my Universal Windows App. Users will be able to drag and drop images from a ListView (or similar) to a Canvas where they can resize and move the images.

I have found how to move the images, but now I can't seem to find a way to accept multitouch, find the appropriate image to resize, and resize the image itself.

Is there a simple way to do this?

vrwim
  • 13,020
  • 13
  • 63
  • 118
  • http://stackoverflow.com/questions/31896930/moving-image-in-scrollviewer-uwp/31900806#31900806 – Justin XL Aug 26 '15 at 09:31
  • @JustinXL So you're saying I should use some container instead of painting the images on the canvas myself? Which container do you suggest? Is it necessary to use a `ScrollViewer`? – vrwim Aug 26 '15 at 09:35
  • `ScrollViewer` has built-in support for zooming. If you look for a *simple* way then give it a try, otherwise, I still recommend to handle gestures manually. – Justin XL Aug 26 '15 at 09:37
  • How can I dynamically add items to the `ScrollViewer` (when I drag&drop them onto the `ScrollViewer`)? Also, when I drag when the image is scaled, the scale is also applied to the translation (when zoomed in, the image moves too fast). – vrwim Aug 26 '15 at 12:47
  • Well you can dynamically create a sv and wrap the item with it on drop. Translation should be the distance / zoom factor when zoomed. – Justin XL Aug 26 '15 at 12:50
  • Where can I get the zoom factor from? I tried `Image.ActualWidth`, `Transform.ScaleY`, `e.Delta.Scale`. – vrwim Aug 26 '15 at 12:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/87998/discussion-between-vrwim-and-justin-xl). – vrwim Aug 26 '15 at 13:06

1 Answers1

2

This is what I eventually went with:

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;

namespace KindEnGezin.Windows.Views.MenuItems
{
    public sealed partial class DrawView : Page
    {
        public DrawView()
        {
            InitializeComponent();
        }

        private void Image_OnManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
        {
            ((Image)sender).Opacity = 0.4;
        }

        private void Image_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            var image = (Image)sender;
            var transform = (CompositeTransform)image.RenderTransform;

            // LEFT-RIGHT bounds
            if (e.Delta.Translation.X < 0) // Going left
            {
                if (DrawingArea.ActualWidth / 2 + (transform.TranslateX + e.Delta.Translation.X) - image.ActualWidth / 2 > 0)
                {
                    // Staying inside, apply translation
                    transform.TranslateX += e.Delta.Translation.X;
                }
                else
                {
                    // Trying to go outside, because scale sucks to work with, move image back inside
                    transform.TranslateX = image.ActualWidth / 2 - DrawingArea.ActualWidth / 2;
                }
            }
            else // Going right
            {
                if (DrawingArea.ActualWidth / 2 - (transform.TranslateX + e.Delta.Translation.X) +
                    image.ActualWidth * (0.5 - transform.ScaleX) > 0)
                {
                    // Staying inside, apply translation
                    transform.TranslateX += e.Delta.Translation.X;
                }
                else
                {
                    // Trying to go outside, because scale sucks to work with, move image back inside
                    transform.TranslateX = image.ActualWidth * (0.5 - transform.ScaleX) + DrawingArea.ActualWidth / 2;
                }
            }

            // UP-DOWN bounds
            if (e.Delta.Translation.Y < 0) // Going up
            {
                if (DrawingArea.ActualHeight / 2 + (transform.TranslateY + e.Delta.Translation.Y) - image.ActualHeight / 2 > 0)
                {
                    // Staying inside, apply translation
                    transform.TranslateY += e.Delta.Translation.Y;
                }
                else
                {
                    // Trying to go outside, because scale sucks to work with, move image back inside
                    transform.TranslateY = image.ActualHeight / 2 - DrawingArea.ActualHeight / 2;
                }
            }
            else // Going down
            {
                if (DrawingArea.ActualHeight / 2 - (transform.TranslateY + e.Delta.Translation.Y) +
                    image.ActualHeight * (0.5 - transform.ScaleY) > 0)
                {
                    // Staying inside, apply translation
                    transform.TranslateY += e.Delta.Translation.Y;
                }
                else
                {
                    // Trying to go outside, because scale sucks to work with, move image back inside
                    transform.TranslateY = image.ActualHeight * (0.5 - transform.ScaleY) + DrawingArea.ActualHeight / 2;
                }
            }

        }

        // Only allow scaling when both dimensions are smaller than the drawingarea
        if (image.ActualHeight*(transform.ScaleY*e.Delta.Scale) < DrawingArea.ActualHeight &&
            image.ActualWidth*(transform.ScaleX*e.Delta.Scale) < DrawingArea.ActualWidth)
        {
            transform.ScaleX *= e.Delta.Scale;
            transform.ScaleY *= e.Delta.Scale;
        }

        private void Image_OnManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {
            ((Image)sender).Opacity = 1;
        }
    }
}

and the XAML:

<Grid
    Name="DrawingArea">
    <Image
        Source="../../Assets/Images/BigLogo.png"
        Width="150"
        Height="150"
        ManipulationMode="TranslateX , TranslateY, Scale"
        ManipulationStarted="Image_OnManipulationStarted"
        ManipulationDelta="Image_OnManipulationDelta"
        ManipulationCompleted="Image_OnManipulationCompleted">
        <Image.RenderTransform>
            <CompositeTransform/>
        </Image.RenderTransform>
    </Image>
</Grid>

This is only using one static name, for the Grid that contains these images. Doing this allows one to add images dynamically to the Grid.

I have been messing around with trying to block scaling the image when it goes outside of the bounds, but I had a lot of trouble trying to implement it, so I just move it to the boundary when I detect it's trying to move outside of the bounds.

vrwim
  • 13,020
  • 13
  • 63
  • 118