Telerik blogs

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.

The Telerik WinForms Touch 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:

  • All
  • Pan
  • Rotate
  • Zoom
  • TwoFingerTap
  • PressAndTap

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:

  • PanGesture: Fires when the user slides with his finger across the area of the control.
  • ZoomGesture: Fires when the user slides with his two fingers in opposite directions.
  • RotateGesture: Fires when the user slides with his two fingers in a circular direction.
  • TwoFingerTapGesture: Fires when the user taps the screen with his two fingers at the same time.
  • PressAndTapGesture: Fires when the user has pressed the screen with a finger and taps with a second finger.

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:

  • IsBegin: Indicates that the gesture is starting.
  • IsEnd: Indicates that the gesture is ending.
  • IsInertia: Indicates that the event is caused by inertia.
  • Location: Indicates the location in control coordinates at which the gesture has occurred.
  • Handled: Indicates if the event has already been handled by some of the elements in the control.

Employing the touch API in PhotoAlbum application

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).

Pan Gesture

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:

Pan touch gesture

Rotate Gesture

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:

Rotate touch gesture

Zoom Gesture

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:

Zoom touch gesture

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!

 

Download RadControls for WinForms by Telerik


About the Author

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.

Related Posts

Comments

Comments are disabled in preview mode.