AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
26.09k stars 2.26k forks source link

Desync between `Popup` opening and pointer events #13036

Open TomEdwardsEnscape opened 1 year ago

TomEdwardsEnscape commented 1 year ago

If a Popup is opened in a PointerEntered event and closed by a PointerExited event, then when the mouse is moved quickly across the screen it is possible for the Popup to open after the mouse has already moved away from it. In this situation, the Popup will not close.

To Reproduce Create this UserControl:

<UserControl xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="AvaloniaApplication.PopupTile" mc:Ignorable="d" 
        Width="100" Height="100" Margin="10" PointerEntered="OpenPopup">
    <Border Name="BG" Background="BurlyWood">
        <Popup Name="Popup" Placement="Center" PlacementTarget="BG">
            <Border Width="110" Height="110" Background="ForestGreen" PointerExited="ClosePopup"/>
        </Popup>
    </Border>
</UserControl>
using Avalonia.Controls;
using Avalonia.Input;

namespace AvaloniaApplication
{
    public partial class PopupTile : UserControl
    {
        public PopupTile()
        {
            InitializeComponent();
        }

        private void OpenPopup(object? sender, PointerEventArgs e)
        {
            Popup.IsOpen = true;
        }

        private void ClosePopup(object? sender, PointerEventArgs e)
        {
            Popup.IsOpen = false;
        }
    }
}

Now insert this grid into a window:

<UniformGrid Columns="4">
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
    <local:PopupTile/>
</UniformGrid>

When the mouse is moved slowly over the PopupTile controls, the popup opens and closes as expected. Only one popup is open at any time.

But if the mouse is moved rapidly, then the popups start to open without closing. The PointerExited event is never raised. The popups close when the mouse is moved back over them and then away again.

Expected behavior The popup should open and acquire pointer state synchronously. In the example control, the popup should always start in the "pointer over" state and should raise PointerExited if the pointer is no longer over it when it opens.

Screenshots image

Desktop (please complete the following information):

timunie commented 1 year ago

can you attach the sample shown? I guess there is a mouse capture missing somewhere.

TomEdwardsEnscape commented 1 year ago

Issue13036.zip