Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C# Markup?] OnPointerReleased not triggered on ScrollViewer #2563

Open
3 of 16 tasks
kucint opened this issue Sep 23, 2024 · 2 comments
Open
3 of 16 tasks

[C# Markup?] OnPointerReleased not triggered on ScrollViewer #2563

kucint opened this issue Sep 23, 2024 · 2 comments
Labels
kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification.

Comments

@kucint
Copy link

kucint commented Sep 23, 2024

Current behavior

Issue 1;
OnPointerReleased is not triggered in Template Control

Issue 2
Inconsistent OriginalSource type of OnPointerReleased


Issue 1;
This Issue is tricky.

Create following Control as shown below.
override OnPointerReleased. This method should be called when control is Left-Mouse-Clicked.
Unfortunately in some scenarios the method is not called.

The control shows a collection of items on Canvas in some container.
image

internal sealed class MyControl : Control
{
    public MyControl()
    {
        DefaultStyleKey = typeof(MyControl);

        Style = new Style<MyControl>()
            .Setters(s => s
            .Template(ctrl => CreateTemplate(ctrl)));
    }

    private UIElement CreateTemplate(MyControl ctrl)
        => ScrollViewerContainer()                  //  not working -> when replaced with FrameContainer() will work
        .Background(Colors.LightSeaGreen)
        .Content(new ItemsRepeater()
            .ItemsSource(x => x.Source(this).Binding(() => this.Items))
            .Layout(new CanvasNonVirtualizingLayout())
            .ItemTemplate(() => CreateNodeCtrl())   // not working -> when replaced with CreateNodeRect() will work
        );

    #region containers:
    private static ScrollViewer ScrollViewerContainer() => new ScrollViewer()
            .HorizontalScrollMode(ScrollMode.Auto)
            .VerticalScrollMode(ScrollMode.Auto)
            .HorizontalScrollBarVisibility(ScrollBarVisibility.Auto)
            .VerticalScrollBarVisibility(ScrollBarVisibility.Auto);

    private static Frame FrameContainer() => new Frame();
    #endregion

    #region children:
    private static NodeCtrl CreateNodeCtrl() => new NodeCtrl();

    private static Rectangle CreateNodeRect() => new Rectangle()
        .Width(100)
        .Height(80)
        .Fill(Colors.LightPink)
        .Stroke(Colors.Black)
        .StrokeThickness(1);
    #endregion

    protected override void OnPointerReleased(PointerRoutedEventArgs e)
    {
        Debug.WriteLine("OnPointerReleased");          // does not trigger !!!
        base.OnPointerReleased(e);
    }
}

You can use one of containers: ScrollViewer and Frame to embed ItemsRepeater:

  • when ScrollViewer is used, the OnPointerReleased is not triggered.
  • when Frame is used, the OnPointerReleased is triggered as expected.

You can use one Item templates: simple Rectangle or a NodeCtrl, NodeCtrl is another Control that shows simple Rectangle.

  • when Rectangle is used, the OnPointerReleased is triggered as expected.
  • when NodeCtrl is used, the OnPointerReleased is not triggered.

So, I observe following behavior of OnPointerReleased:

|               |   Rectangle    |     NodeCtrl
|---------------|----------------|--------------------
| Frame         |      OK        |        OK
| ScrollViewer  |      OK        |    not triggered
|---------------|--------------- |--------------------

As you see, I cannot tell if the issue is related to ScrollViewer, or to NodeCtrl.
The implementation of NodeCtrl is straight forward:

internal sealed class NodeCtrl : Control
{
    public NodeCtrl()
    {
        DefaultStyleKey = typeof(NodeCtrl);

        this.Style(Create());
    }

    private static Style<NodeCtrl> Create() => new Style<NodeCtrl>()
        .Setters(s => s.Template(ctrl => CreateTemplate(ctrl)));

    private static Rectangle CreateTemplate(NodeCtrl ctrl) => new Rectangle()
        .Width(100)
        .Height(80)
        .Fill(Colors.LightPink)
        .Stroke(Colors.Black)
        .StrokeThickness(1);
}

I suppose, the issue is related to ScrollViewer.


Issue 2
Inconsistent value of OriginalSource of PointerRoutedEventArgs delivered by OnPointerReleased:

While Left-mouse-button does not trigger the method, Right-mouse-button and Middle-mouse-button are not affected and work fine in all scenarios.
if you check a value of OriginalSource of PointerRoutedEventArgs, you will notice that unfortunately it is initialized differently in Desktop and WindowsSDK:

  • Desktop: an object of type ScrollContentPresenter is delivered
  • WindowsSDK: an object of type Grid is delivered

I suppose, this issue is related to C# Markup (not sure...)

Expected behavior

Issue 1
OnPointerReleased shall be triggered in all scenarios.

Issue 2
OriginalSource shall be consistent cross platform. An object of type ScrollContentPresenter seems to be the right one.

How to reproduce it (as minimally and precisely as possible)

MINIMAL REPRO PROJECT:
Uno.OnPointerReleasedApp.zip

STEPS TO REPRODUCE

  • Run the App on Windows using Desktop or WindowsSdk (both are affected).
  • left click on green surface
  • Observe that OnPointerReleased in not triggered
  • change container to Frame or Item to Rectangle and rebuild
  • run the App
  • left click on green surface
  • Observe that OnPointerReleased in triggered as expected

Environment

Nuget Package (s):

"Uno.Sdk": "5.3.108"

Package Version(s):

Affected platform(s):

  • iOS
  • macOS (AppKit)
  • Mac Catalyst
  • Android
  • WebAssembly
  • Windows
  • Skia (WPF)
  • Skia (GTK on Linux/macOS/Windows)
  • Skia (Linux Framebuffer)
  • Build tasks

Visual Studio:

  • 2019 (version: )
  • 2022 (version: )
  • Visual Studio Code (version: )
  • Rider Windows (version: )
  • Rider macOS (version: )

Relevant plugins:

  • Resharper (version: )

Anything else we need to know?

Issue 2 seems to have the same nature as #2416

@kucint kucint added kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification. labels Sep 23, 2024
@MartinZikmund MartinZikmund self-assigned this Sep 25, 2024
@MartinZikmund
Copy link
Member

Issue 1

The behavior is caused by the following logic in ScrollViewer:

image

This comes directly from WinUI and it is actually a quite recent change, see also a discussion here unoplatform/uno#18303.

To be able to handle the event even though it was already handled by ScrollViewer, you can use AddHandler instead:

public MyControl()
{
    ...
    this.AddHandler(UIElement.PointerReleasedEvent, new PointerEventHandler(OnPointerReleased), handledEventsToo: true);
}

private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
    // Handle the event
}

The handledEventsToo ensures that even handled events are propagated up. Please note that this way all the events will come through, including events handled by Buttons etc. It is likely that you will need to check what is the original source of the event and only continue with your logic in some cases

@MartinZikmund
Copy link
Member

I will be looking into issue 2 separately, I am suspecting C# markup here

@MartinZikmund MartinZikmund removed their assignment Oct 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification.
Projects
None yet
Development

No branches or pull requests

2 participants