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:
We plan to do it by using drag and drop with either mouse or touch.
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;
}
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;
}
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.
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);
}
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;
}
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':
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 drop
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.
This article is part of a series exploring concepts about inking and XAML Shapes. Here are all links:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.