Microsoft

You use the Inking platform to get inputs for lines/shapes' drawing. You may want to provide the users the ability to modify and move the shapes created. Ok, let's do it!

Another time again, we start with the sample code related to the article Use the UWP Inking platform as input for advanced scenarios. This code is using the Inking platform to allow the user to draw lines and we replace the strokes drawn by XAML Lines.

It is now time to jump to another step and allow direct manipulations of these lines like:

  • Moving the entire line
  • Changing the size of the line by moving the origin or the end of the line

We plan to do it by using drag and drop with either mouse or touch.

 

 

Starting code

For the explanations please refer to the article mentioned earlier. Here is the XAML and the code behind:

<Grid>
	<InkCanvas x:Name="inkCanvas" />

	<!-- Canvas for displaying the "recognized" XAML Shapes -->
	<Canvas x:Name="ShapesCanvas" />
</Grid>
public MainPage()
{
	this.InitializeComponent();

	// Initialize the InkCanvas
	inkCanvas.InkPresenter.InputDeviceTypes =
		Windows.UI.Core.CoreInputDeviceTypes.Mouse |
		Windows.UI.Core.CoreInputDeviceTypes.Pen |
		Windows.UI.Core.CoreInputDeviceTypes.Touch;

	// When the user finished to draw something on the InkCanvas
	inkCanvas.InkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
}

private void InkPresenter_StrokesCollected(
	Windows.UI.Input.Inking.InkPresenter sender,
	Windows.UI.Input.Inking.InkStrokesCollectedEventArgs args)
{
	InkStroke stroke = inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Last();

	// Action 1 = We use a function that we will implement just after to create the XAML Line
	Line line = ConvertStrokeToXAMLLine(stroke);
	// Action 2 = We add the Line in the second Canvas
	ShapesCanvas.Children.Add(line);

	// We delete the InkStroke from the InkCanvas
	stroke.Selected = true;
	inkCanvas.InkPresenter.StrokeContainer.DeleteSelected();
}

private Line ConvertStrokeToXAMLLine(InkStroke stroke)
{
	var line = new Line();
	line.Stroke = new SolidColorBrush(Windows.UI.Colors.Green);
	line.StrokeThickness = 6;
	// The origin = (X1, Y1)
	line.X1 = stroke.GetInkPoints().First().Position.X;
	line.Y1 = stroke.GetInkPoints().First().Position.Y;
	// The end = (X2, Y2)
	line.X2 = stroke.GetInkPoints().Last().Position.X;
	line.Y2 = stroke.GetInkPoints().Last().Position.Y;

	return line;
}

 

 

Moving a line by drag and drop

The goal here is to be able to touch/click on a line to do a drag and drop in order to move it on the surface. Of course, we will take care of the direct feedback to really see the line moving with the finger/mouse. We use the Manipulation events.

First, with the ManipulationMode property, we can restrict for a certain type of manipulation. For example, only horizontal if the application needs it. In our sample, the line can be moved in any direction.

line.ManipulationMode = ManipulationModes.TranslateX |
	ManipulationModes.TranslateY;

After, we subscribe to the manipulation events:

line.ManipulationStarted += Line_ManipulationStarted;
line.ManipulationDelta += Line_ManipulationDelta;
line.ManipulationCompleted += Line_ManipulationCompleted; ;

We have to handle these events for each line we create, the best place is in the ConvertStrokeToXAMLLine function:

private Line ConvertStrokeToXAMLLine(InkStroke stroke)
{
	var line = new Line();
	// ... 
	// ... 
    
	// We use the manipulation events in order to move the shapes
	line.ManipulationMode = ManipulationModes.TranslateX |
		ManipulationModes.TranslateY;

	line.ManipulationStarted += Line_ManipulationStarted;
	line.ManipulationDelta += Line_ManipulationDelta;
	line.ManipulationCompleted += Line_ManipulationCompleted; ;

	return line;
}

 

 

1. Initiating the manipulation

First, we create a field to keep track of the transformation applied to the line for which we ar doing the drag & drop. We use a TranslateTransform object. It allows us to apply a translation transformation on the line in the 2D plan. That means, changing the x/y coordinates of the object.

// XAML Shapes manipulations
private TranslateTransform dragTranslation;

So, when we click or touch the line, we hit the Line_ManipulationStarted event handler.

  • We first, get the object on which we clicked/touched. In our case, this object is a XAML Line but you manipulate more generic shapes, you will have adapt the code.
  • We instantiate our dragTranslation object and assign it to the RenderTransform property of the Line object. This way, the Line will be affected by the transformation if we modify it.
  • Just to give an extra visual feedback, we just change the color of the line.
private void Line_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
	Line l = (Line)sender;
	// Initialize the Render transform that will be used to manipulate the shape
	dragTranslation = new TranslateTransform();
	l.RenderTransform = dragTranslation;
	l.Stroke = new SolidColorBrush(Windows.UI.Colors.Orange);
}

 

 

2. Giving real time visual feedback

When the user maintains the right click or the finger on the device, we hit the Line_ManipulationDelta event handler for every move. We can then provide the visual feedback we want, like display the coordinates of the move or simply effectively move the shape. This is easily done by affecting to dragTranslation object the X/Y translations that were performed since the previous event.

Note: By modifying the dragTranslation X and Y, we modify the coordinates of the Line we are holding because we previously affected dragTranslation (a TranslateTransform object) to the RenderTransform property of the Line.

private void Line_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
	dragTranslation.X += e.Delta.Translation.X;
	dragTranslation.Y += e.Delta.Translation.Y;
}

 

 

3. Ending the manipulation

Finally, when we release the click or the finger from the device surface, we hit the Line_ManipulationCompleted event handler. We can now terminate the 'drag & drop':

  • We first 'reset' the translation applied to the line because we will permanently modify the coordinates.
  • We get the total translation on the X axis and Y axis with the event handler parameter ManipulationCompletedRoutedEventArgs.Cumulative.Translation.
  • We add this translation to the original coordinates of the line object.
  • As usual, we modify the color of the line to give the feedback about the end of the 'drag & drop'.
private void Line_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
	Line l = (Line)sender;
	l.RenderTransform = null;

	// Get the cumulative move
	double x = e.Cumulative.Translation.X;
	double y = e.Cumulative.Translation.Y;
	// Change the origin (X1,Y1) and the end of the line (X2,Y2)
	l.X1 += x;
	l.X2 += x;
	l.Y1 += y;
	l.Y2 += y;

	l.Stroke = new SolidColorBrush(Windows.UI.Colors.Black);
}

Do you want to see the result in action? Here it is:

 

XAML Shapes Manipulations by drag and dropXAML Shapes Manipulations by drag and drop

 

 

Wrapping up

This code starts to be interesting about the possibilities that we have to create a powerful drawing application. In the sample, we move by drag & drop only lines but this code will apply to any XAML Shapes like Ellipse, Polygon, Rectangle or even a complex Path. Also, we just focus in this code to provide a live visual feedback for the shape's movement but you can imagine creating some control to snap to some region or to a grid and also display the coordinates of the actual position while moving.

Free your mind and code!

 

--

 

All the source is on GitHub - https://github.com/microsoft/Windows-AppConsult-Samples-UWP/

@sbovo for the AppConsult team.

 

 

Inking series' articles

This article is part of a series exploring concepts about inking and XAML Shapes. Here are all links:

  1. Use the UWP Inking platform as input for advanced scenarios
  2. Handling zoom in Inking applications
  3. Turning to the dark side of inking = UnprocessedInput
  4. Free your mind: Start manipulating XAML Shapes ⇐ You are here

 

 

References

www.000webhost.com