dotnet / dotnet/maui

TapGestureRecognizer and PointerGestureRecognizer lack public controller interfaces for custom backends

Open
#34,161 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

s/triaged
Dominant language
C#
Stars
23.3k
Forks
2k
Avg merge
1d 14h
Merged PRs (30d)
296

Description

Related to

  • Parent issue: #34104 (internal APIs blocking custom platform backends)

Problem

Custom platform backends need to fire gesture events when native gestures are recognized. MAUI provides public controller interfaces for some gesture types but not others:

Gesture Public Interface Status
Swipe ISwipeGestureController ✅ Public — SendSwipe() + DetectSwipe()
Pinch IPinchGestureController ✅ Public — SendPinch() etc.
Pan IPanGestureController ✅ Public — SendPan() etc.
Tap ❌ None SendTapped() is internal
Pointer ❌ None SendPointerEntered/Exited/Moved/Pressed/Released() are all internal
TapGestureRecognizer

TapGestureRecognizer.SendTapped(View) is internal. A custom backend must use reflection:

var sendTapped = typeof(TapGestureRecognizer).GetMethod(
    "SendTapped", BindingFlags.Instance | BindingFlags.NonPublic);
sendTapped.Invoke(gesture, new object[] { parentView });

An ITapGestureController with a public SendTapped() method (matching the pattern of ISwipeGestureController) would solve this.

PointerGestureRecognizer

SendPointerEntered(View, Func<IElement?, Point?>, PlatformPointerEventArgs, ButtonsMask) and the other SendPointer* methods are all internal. Custom backends must reflect:

var sendEntered = typeof(PointerGestureRecognizer).GetMethod(
    "SendPointerEntered", BindingFlags.Instance | BindingFlags.NonPublic);
sendEntered.Invoke(gesture, new object[] { view, getPositionFunc, null, ButtonsMask.Primary });

An IPointerGestureController interface (or making the existing SendPointer* methods public) would allow backends to properly implement pointer tracking without reflection.

Impact

Without these public APIs, custom platform backends (macOS/AppKit, Linux/GTK, etc.) are:

  • Forced to use reflection, which is fragile across MAUI versions
  • Subject to trimming/AOT failures since the internal methods aren't preserved
  • Unable to properly validate parameter signatures at compile time (we shipped a bug where we passed 2 args to a 4-param method, silently failing)

Proposed Solution

Add public controller interfaces matching the existing pattern:

public interface ITapGestureController
{
    void SendTapped(View sender);
}

public interface IPointerGestureController
{
    void SendPointerEntered(View sender, Func<IElement?, Point?>? getPosition);
    void SendPointerExited(View sender, Func<IElement?, Point?>? getPosition);
    void SendPointerMoved(View sender, Func<IElement?, Point?>? getPosition);
    void SendPointerPressed(View sender, Func<IElement?, Point?>? getPosition);
    void SendPointerReleased(View sender, Func<IElement?, Point?>? getPosition);
}

Or alternatively, make the existing internal methods public.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating TapGestureRecognizer.SendTapped and the internal SendPointer* methods, then compare them with the existing ISwipeGestureController, IPinchGestureController, and IPanGestureController patterns. Decide whether to add public controller interfaces or expose the existing methods, and verify that custom backends can invoke the gesture events without reflection and with the documented parameter signatures.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
desktop-dev, frontend, mobile-dev
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.