We are very proud to be the first (and still only) Windows Forms component suite to provide full multi-touch support and API. As discussed in the sneak peek blog Get Ready to Touch’n’Roll with RadControls for WinForms, the powerful touch API that our components expose allow you to handle the touch gestures that occur on the screen and take some actions depending on what your touch scenario is.
Now that Q3 2011 is a fact, allow us to introduce the main aspects of the touch API. These aspects will allow you to unleash the power of windows forms under touch-enabled devices, and build the applications of the future today! After discussing the touch API, we will demonstrate how we managed to greatly enhance the end-user experience of our PhotoAlbum application thanks to that API.
Let’s start with the EnableGesture and DisableGesture methods. As the names imply, they enable or disable the gestures that can be applied to a control. In case you want to enable some gestures, while disabling others, you can use the following members of the GestureType enumeration:
this
.radButton1.EnableGesture(GestureType.All);
this
.radButton1.DisableGesture(GestureType.Zoom);
RadControls and RadElements fire a number of events for the gesture operations enlisted by the GestureType enumerator. The events are fired only if the corresponding GestureType is enabled for a control or element. The events are:
Last, but not least, in the process of building a touch enabled application you will find useful the event arguments that come from the above events. These events arguments inherit from the GestureEventArgs type, hence they share the following properties:
To demonstrate how all this works, let’s analyze the gestures demonstrated in the sneak peek video of our PhotoAlbum application (which starts at 0.56 min in the video below).
The first gesture here is the pan gesture. Thanks to it, we can drag a photo around with our finger. To make this possible, we first enabled the Pan gesture for the RadPhotoAlbumViewer control:
this
.EnableGesture(GestureType.All);
As a result, the PanGesture event is fired when we pan one of the PhotoElements that displays the pictures. We can either handle the event, or override the OnGesture method in the body of our PhotoElement class:
void
photoElement_PanGesture(
object
sender, PanGestureEventArgs e)
{
PhotoElement photo = sender
as
PhotoElement;
if
(e.IsBegin)
{
this
.BringToFront();
}
if
(!e.IsBegin && !e.IsEnd)
{
Size offset = e.Offset;
if
(photo.ControlBoundingRectangle.X + offset.Width < 0 && offset.Width < 0)
{
offset.Width = -photo.ControlBoundingRectangle.X;
}
if
(photo.ControlBoundingRectangle.Right + offset.Width > photo.Parent.ControlBoundingRectangle.Right && offset.Width > 0)
{
offset.Width = photo.Parent.ControlBoundingRectangle.Right - photo.ControlBoundingRectangle.Right;
}
if
(photo.ControlBoundingRectangle.Y + offset.Height < 0 && offset.Height < 0)
{
offset.Height = -photo.ControlBoundingRectangle.Y;
}
if
(photo.ControlBoundingRectangle.Bottom + offset.Height > photo.Parent.ControlBoundingRectangle.Bottom && offset.Height > 0)
{
offset.Height = photo.Parent.ControlBoundingRectangle.Bottom - photo.ControlBoundingRectangle.Bottom;
}
this
.Location =
new
System.Drawing.Point(
this
.Location.X + offset.Width,
this
.Location.Y + offset.Height); ;
}
}
This code will allow us to move a photo:
Next comes the rotate gesture. Thanks to this gesture we can rotate a photo by using two fingers. We first enabled All gestures as this also enabled to zoom gesture:
this
.EnableGesture(GestureType.All);
Now you would ask: “Why then we should enable the Pan gesture explicitly? Can’t we just set the All value once?”
Well, the Pan gesture message is processed a bit differently. While the All value of the GestureType will still allow you to move your photos, the Pan value will give you better control over the moved object.
After the rotate gesture has been enabled, we can handle the RotateGesture event:
void
photoElement_RotateGesture(
object
sender, RotateGestureEventArgs e)
{
PhotoElement photo = sender
as
PhotoElement;
if
(e.GestureType == GestureType.Rotate)
{
RotateGestureEventArgs rotateArgs = e;
Console.WriteLine((
float
)(rotateArgs.Angle * 180.0 / Math.PI));
float
newAngle = photo.AngleTransform - (
float
)(rotateArgs.Angle * 180.0 / Math.PI);
PropertySetting setting =
new
PropertySetting(RadElement.AngleTransformProperty, newAngle);
setting.ApplyValue(photo);
}
}
As a result we will be able to successfully rotate a photo:
Finally, the zoom gesture. As the name suggests, this gesture allows us to zoom in and out a photo. Since we have already enabled All gestures, we do not need to do it again. We only need to handle the ZoomGesture event of the PhotoElement:
void
photoElement_ZoomGesture(
object
sender, ZoomGestureEventArgs e)
{
PhotoElement photo = sender
as
PhotoElement;
if
(e.GestureType == GestureType.Zoom)
{
ZoomGestureEventArgs zoomArgs = e;
photo.ScaleTransform =
new
System.Drawing.SizeF(photo.ScaleTransform.Width * (
float
)zoomArgs.ZoomFactor, photo.ScaleTransform.Height * (
float
)zoomArgs.ZoomFactor);
PointF oldDir =
new
PointF(
this
.Location.X - zoomArgs.Center.X,
this
.Location.Y - zoomArgs.Center.Y);
PointF newDir =
new
PointF(oldDir.X * (
float
)zoomArgs.ZoomFactor, oldDir.Y * (
float
)zoomArgs.ZoomFactor);
PointF offset =
new
PointF(newDir.X - oldDir.X, newDir.Y - oldDir.Y);
this
.Location =
new
Point(
this
.Location.X + (
int
)offset.X,
this
.Location.Y + (
int
)offset.Y);
}
}
And here is the expected result:
Voila! With a bit of math, and thanks to the RadControls for WinForms touch API we managed to put our PhotoAlbum application into the list of the modern touch-friendly applications.
You can find the full source code of the application here.
Happy coding!
Nikolay Diyanov Diyanov is the Product Manager of the Native Mobile UI division at Progress. Delivering outstanding solutions that make developers' lives easier is his passion and the biggest reward in his work. In his spare time, Nikolay enjoys travelling around the world, hiking, sun-bathing and kite-surfing.
Find him on Twitter @n_diyanov or on LinkedIn.