Skip to content

Latest commit

 

History

History
96 lines (61 loc) · 5.78 KB

README.md

File metadata and controls

96 lines (61 loc) · 5.78 KB

MR.Gestures

MR.Gestures adds events and Commands for handling touch and mouse gestures to all the .NET MAUI elements.

With version 5 and the end of support for Xamarin.Forms I released it as open source under the MIT license.

To get started you

  1. install the NuGet package to your MAUI project,
  2. initialize it with a call to ConfigureMRGestures() in your MauiProgram
  3. and then use the elements from MR.Gestures instead of Microsoft.Maui.Controls.

The official website with a more detailed description is at www.mrgestures.com.

The GestureSample app demos how all the elements are used and what you get in the EventArgs.

Architecture

If you want to develop MR.Gestures yourself or want to know, how everything works, then read on. The rest of this page describes how MR.Gestures works and what the most important classes are for.

Shared Elements

MR.Gestures adds various properties and events to each and every element. The proper way to do this would be to add them to some base class like Element. But as an external library I cannot do this. I also couldn't add attached properties because I needed to override some methods of the native controls. C# also cannot inherit from two base classes.

So I needed my own class which inherits from the respective MAUI class and adds all the properties and events which MR.Gesture needs - 18 events and 36 properties in every class.

Of course I did not want to add the functionality in every class. The functionality is in GestureHandler. All the controls hold an instance of that class and forward their calls to the GestureHandler.

But even defining and forwarding those 18 x (1 event + 2 properties) in each class is a lot of code. So I wrote a T4 template to do that. T4 could generate any kind of files long before source generators were introduced in Roslyn. Unfortunately it never got much love from Microsoft. There was no intellisense in VS, so writing them is a lot of trial-and-error.

At the time of this writing the T4 file Controls.tt is 186 lines long and generates Controls.cs with 29,894 lines.

Handlers

MAUI Handlers translate the shared MAUI element to the respective native user control. It's similar to the renderers in Xamarin.Forms. Again, this is much repetitive code and again it will be generated by T4 templates.

File Generates Description
Handlers.json defines all the data I need. It is a list of all handler names (some of which are used for multiple elements) and their respective native control on each platform. This file is read by all T4 templates in the Handlersfolder.
Handlers.tt Handlers.cs This contains the part of the handler which is the same on every platform. It maps the event and command property names to the method HandlerHelper.MapPropertyChanged.
Handlers.Android.tt Handlers.Android.cs The Android handlers are a bit complicated. To add my gesture handling, I need to override DispatchTouchEvent and DispatchGenericMotionEvent in every native view. Therefore I need to define such a native view for each element and use that instead of the MAUI view.
Handlers.iOS.tt Handlers.iOS.cs This is currently not used.
Handlers.Windows.tt Handlers.Windows.cs This is currently not used.

The other files in the Handlers folder are for cases where the MAUI team did not adhere to their own naming conventions or did not migrate the Xamarin.Forms renderers to MAUI handlers. In these cases the T4 templates could not be used.

Platform dependent code

The PlatformSpecific folder contains a folder for each platform and within those

  • PlatformSpecific/Android/AndroidGestureHandler.cs
  • PlatformSpecific/iOS/iOSGestureHandler.cs
  • PlatformSpecific/Windows/WinUIGestureHandler.cs

are the most important files.

They each define static methods

  • AddInstance
  • RemoveInstance
  • OnElementPropertyChanged

The static methods are called from the handlers. They create instances of the respective *GestureHandler classes which do everything they need to do to handle the touch gestures on the native platform.

Raising events

Each PlatformSpecific/platform folder has a subfolder EventArgs. These inherit from the respective shared EventArgs and define constructors which convert the data from the native gesture objects to MR.Gesture.*EventArgs.

E.g.

namespace MR.Gestures.Android.EventArgs;

public class AndroidPanEventArgs : MR.Gestures.PanEventArgs
{
    public AndroidPanEventArgs(MotionEvent previous, MotionEvent current, PanEventArgs prevArgs, global::Android.Views.View view)

When the AndroidGestureHandler or one of its helper classes recognizes a pan gesture, then it creates a new AndroidPanEventArgs and sends it to IGestureListener.

IGestureListener is implemented by multiple classes which use a Chain of Responsibility pattern.

Class Description
GestureThrottler Some gestures can be configured to only raise when a certain minimum value is reached. E.g. Settings.MinimumDeltaDistance defines a minimum distance. If the delta distance between two pan gestures is lower than this value, then the event will not be raised. If it is above, then the gesture will be forwarded to its inner IGestureListener.
GestureFilter This only looks at the elements InputTransparent property. Îf it is True, then no events are raised. If it is False, then the gesture will be forwarded to its inner IGestureListener.
GestureHandler This class finally calls the event handler and/or command in the respective element.