Csaba
Csaba

Reputation: 351

MAUI GraphicsView mouse click event

I'm new to .Net Maui. Trying to draw my own shapes using GraphicsView and IDrawable. I would like to have the shapes clickable.

Is there a way how to achieve that? Maybe there is another interface something like IClickable I'm not aware of. Or I should use different approach thanGraphicsView.

Thanks :-)

Upvotes: 5

Views: 3326

Answers (5)

Miiike
Miiike

Reputation: 11

Here is how is found a solution to the question.

My base class is implementing the GraphicsView, IDrawable and using the Draw method that you seam already be familliar with when using Maui.

First you need a class that contains your actions and list of the class

private readonly List<ClickableRectangle> _rectangles = new();

public class ClickableRectangle
{
    public RectF Bounds { get; set; }
    public Action OnClick { get; set; }

    public ClickableRectangle(RectF bounds, Action onClick)
    {
        Bounds = bounds;
        OnClick = onClick;
    }

    public bool Contains(Point point)
    {
        return Bounds.Contains((float)point.X, (float)point.Y);
    }
}

Then we can add a TapGestureRecognizer to our GraphicsView

public View2D()
{
    Drawable = this;
    Initialize();

    var tapGesture = new TapGestureRecognizer();
    tapGesture.Tapped += OnTapped;
    GestureRecognizers.Add(tapGesture);

    AddRectangle(new RectF(10, 10, 100, 100), () => Debug.WriteLine("Rectangle clicked!"));
}

public void AddRectangle(RectF bounds, Action onClick)
{
    _rectangles.Add(new ClickableRectangle(bounds, onClick));
}

private void OnTapped(object sender, TappedEventArgs e)
{
    var touchPoint = new Point(e.GetPosition(this).Value.X, e.GetPosition(this).Value.Y);

    foreach (var rectangle in _rectangles)
    {
        if (rectangle.Contains(touchPoint))
        {
            rectangle.OnClick?.Invoke();
            break;
        }
    }
}

public void Draw(ICanvas canvas, RectF dirtyRect)
{
    foreach (var rectangle in _rectangles)
    {
        canvas.FillColor = Colors.Red;
        canvas.FillRectangle(rectangle.Bounds);
    }
}

Upvotes: 0

Tobias
Tobias

Reputation: 69

Via XAML you would add a TapGestureRecognizer like this:

<GraphicsView
    x:Name="xyz"
    Drawable="{StaticResource drawable}"
    .../>
    <GraphicsView.GestureRecognizers>
        <TapGestureRecognizer Tapped="OnGraphicsViewTapped"/>
    </GraphicsView.GestureRecognizers>
</GraphicsView>

The EventHandler looks like this:

private void OnTapGestureRecognizerTapped(object sender, TappedEventArgs args)
{
}

Alternatively, the PointerGestureRecognizer is also available. ( Swipe, Pinch, Pan, Pointer Drag and Drop GestureRecognizer are also available and used similarly. )

Upvotes: 0

AndreasW
AndreasW

Reputation: 167

You have to use StartInteraction/EndInteraction. These are two event handlers of GraphicsView. StartInteraction gets the ButtonDown event and EndInteraction gets the ButtonUp event.

view.StartInteraction += OnStartInteraction;
view.EndInteraction += OnEndInteraction;


void OnStartInteraction(object Sender, TouchEventArgs evt) {
        PointF p = evt.Touches.FirstOrDefault();
        Trace.WriteLine($"Touch/click at {p}");
}

void OnEndInteraction(object Sender, TouchEventArgs evt) {
        PointF p = evt.Touches.LastOrDefault();
        Trace.WriteLine($"Released at {p}");
}

Upvotes: 1

user12868530
user12868530

Reputation: 11

GraphicsView has a 'StartInteraction' event that can be used to get click/touch information.

See more here: IGraphicsView.StartInteraction(PointF[])

Upvotes: 1

Gec
Gec

Reputation: 497

I was able to get this to work using the TapGestureRecognizer and a class that implements ICommand.

In this example I have the GraphicsView as a member called _view in the same class that implements both IDrawable and ICommand, but your design could be different and it should still work.

public class Block : IDrawable, ICommand
{
    protected GraphicsView _view = new GraphicsView();

    public Block()
    {
        _view.Drawable = this;

        _view.GestureRecognizers.Add(new TapGestureRecognizer
        {
            Command = this
        });
    }

    void ICommand.Execute(object cmdObject) 
    {
        // Handle the Clicked event here
    }

    bool ICommand.CanExecute(object cmdObject)
    {
        return true;
    }

    event EventHandler ICommand.CanExecuteChanged
    {
        add { }
        remove { }
    }

    public void Draw(ICanvas canvas, RectF dirtyRect)
    {
        // Draw on canvas here
    }
}

Upvotes: 2

Related Questions