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

[GTK Linux] NavigationView - Can't remove NavigationViewItem #8584

Open
SergeyRoznyuk opened this issue Apr 21, 2022 · 7 comments
Open

[GTK Linux] NavigationView - Can't remove NavigationViewItem #8584

SergeyRoznyuk opened this issue Apr 21, 2022 · 7 comments
Assignees
Labels
area/items-repeater Categorizes an issue or PR as relevant the ItemsRepeater control area/navigationview 🧭 Categorizes an issue or PR as relevant to the NavigationView control difficulty/challenging 🤯 Categorizes an issue for which the difficulty level is reachable with internals understanding kind/bug Something isn't working project/navigation-lifecycle 🧬 Categorizes an issue or PR as relevant to the navigation and lifecycle (NavigationView, AppBar, ...)

Comments

@SergeyRoznyuk
Copy link

SergeyRoznyuk commented Apr 21, 2022

Current behavior

I create new pages and dynamically (from the code behind) add the NavigationViewItem corresponding to this page. When the page is closed by the user (the "X" button placed on the page), the previously added NavigationViewItem is also removed. The first closing of the page and removal of the NavigationViewItem is successful. All subsequent attempts lead to the following situation: NavigationViewItem is removed from MenuItems with the next error

Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')".
Call stack - at System.Collections.Generic.List`1.get_Item(Int32 index)
   at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
   at Microsoft.UI.Xaml.Controls.InspectingDataSource.GetAtCore(Int32 index) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\InspectingDataSource.cs:line 90
   at Microsoft.UI.Xaml.Controls.ItemsSourceView.GetAt(Int32 index) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\ItemsSourceView.cs:line 44
   at Microsoft.UI.Xaml.Controls.SelectionModel.<>c.<get_SelectedItems>b__17_1(IList`1 infos, Int32 index) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\SelectionModel.cs:line 201
   at Microsoft.UI.Xaml.Controls.SelectedItems`1.get_Item(Int32 index) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\SelectedItems.cs:line 37
   at Microsoft.UI.Xaml.Controls.SelectionModel.get_SelectedItem() in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\SelectionModel.cs:line 150
   at Microsoft.UI.Xaml.Controls.NavigationView.OnSelectionModelSelectionChanged(SelectionModel selectionModel, SelectionModelSelectionChangedEventArgs e) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\NavigationView\NavigationView.cs:line 282
   at Microsoft.UI.Xaml.Controls.SelectionModel.OnSelectionChanged() in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\SelectionModel.cs:line 572
   at Microsoft.UI.Xaml.Controls.SelectionModel.OnSelectionInvalidatedDueToCollectionChange() in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\SelectionModel.cs:line 494
   at Microsoft.UI.Xaml.Controls.SelectionNode.OnSourceListChanged(Object dataSource, NotifyCollectionChangedEventArgs args) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\SelectionNode.cs:line 515
   at Microsoft.UI.Xaml.Controls.ItemsSourceView.OnItemsSourceChanged(NotifyCollectionChangedEventArgs args) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\ItemsSourceView.cs:line 62
   at Microsoft.UI.Xaml.Controls.InspectingDataSource.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) in C:\a\1\s\src\Uno.UI\Microsoft\UI\Xaml\Controls\Repeater\InspectingDataSource.cs:line 165
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.RemoveItem(Int32 index)
   at System.Collections.ObjectModel.Collection`1.RemoveAt(Int32 index)
   at AxisUno.Views.MainView.PageClose(String pageId) in /home/microinvest/RiderProjects/AxisUno/AxisUno.Shared/Views/MainView.xaml.cs:line 241

It works correctly on Windows, but makes a mistake on Linux!

Expected behavior

NavigationViewItem is removed successfully (without errors) from the MenuItems of NavigationView

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

  1. Create project: dotnet new unoapp-winui-net6 -o MyUnoApp
  2. Open project in VS 2022 (Windows) and create MainPage with NavigationView
  3. Create several pages with button to close page (behavior like button to close Form in WinForms)
  4. Click by existing NavigationViewItem create new page and new NavigationViewItem below
  5. Next steps are described above

Workaround

No response

Works on UWP/WinUI

Yes

Environment

No response

NuGet package version(s)

Uno.CommunityToolkit.WinUI.UI.Behaviors" Version="7.1.100-dev.7.g758154cb81"
Uno.Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.3.0"
Uno.WinUI.Skia.Gtk" Version="4.1.9"
Uno.WinUI.RemoteControl" Version="4.1.9" Condition="'$(Configuration)'=='Debug'"
Uno.UI.Adapter.Microsoft.Extensions.Logging" Version="4.1.9"
Uno.CommunityToolkit.WinUI.UI.Controls.DataGrid" Version="7.1.100-dev.7.g758154cb81"
Uno.CommunityToolkit.WinUI.UI.Controls.Layout" Version="7.1.100-dev.7.g758154cb81"

Affected platforms

Skia (GTK on Linux/macOS/Windows)

IDE

Visual Studio 2022

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

I use Rider to run my app on Linux.

@SergeyRoznyuk SergeyRoznyuk added difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working triage/untriaged Indicates an issue requires triaging or verification labels Apr 21, 2022
@jeromelaban
Copy link
Member

Thanks for the report. Could you create a small repro app which shows the issue, so we can discuss the exact same behavior?

@jeromelaban jeromelaban added triage/needs-information Indicates an issue needs more information in order to work on it. area/navigationview 🧭 Categorizes an issue or PR as relevant to the NavigationView control project/navigation-lifecycle 🧬 Categorizes an issue or PR as relevant to the navigation and lifecycle (NavigationView, AppBar, ...) labels Apr 21, 2022
@SergeyRoznyuk
Copy link
Author

SergeyRoznyuk commented Apr 26, 2022

Send you link to small app to show the issue: https://github.com/OnSwitchOff/MyUnoAppSer.git. The issue is in PageClose method (MainPage).

I've added TextBox, DatePicker and CalendarDatePicker due to behaviour of them on Linux:
TextBox - pointer is not visible (maybe it has white foreground) so I Can't see position in which I will write;
DatePicker - selection date is not correct sometimes;
CalendarDatePicker - I can't change month.

GitHub
Contribute to OnSwitchOff/MyUnoAppSer development by creating an account on GitHub.

@jeromelaban jeromelaban removed triage/needs-information Indicates an issue needs more information in order to work on it. triage/untriaged Indicates an issue requires triaging or verification labels Apr 26, 2022
@MartinZikmund MartinZikmund added area/items-repeater Categorizes an issue or PR as relevant the ItemsRepeater control difficulty/challenging 🤯 Categorizes an issue for which the difficulty level is reachable with internals understanding and removed difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. labels Jul 24, 2023
@MartinZikmund MartinZikmund changed the title Linux-NavigationView-Can't remove NavigationViewItem from [GTK Linux] NavigationView - Can't remove NavigationViewItem Jul 25, 2023
@Youssef1313
Copy link
Member

Youssef1313 commented Nov 22, 2023

Minimized repro:

XAML:

    <NavigationView x:Name="navigationView" IsBackButtonVisible="Collapsed" IsBackEnabled="False">
        <NavigationView.MenuItems>
            <NavigationViewItem Content="Sale" />
            <NavigationViewItemSeparator/>
            <NavigationViewItemHeader Content="Sales"/>
        </NavigationView.MenuItems>

    </NavigationView>

Code behind:

    public sealed partial class MainPage : Page
    {
        private int count = 0;

        public MainPage()
        {
            this.InitializeComponent();
            
            this.navigationView.ItemInvoked += this.NavigationView_ItemInvoked;
        }

        private void NavigationView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
        {
            NavigationViewItem saleItem = new NavigationViewItem() { IsSelected = true };

            this.navigationView.MenuItems.Add(saleItem);
            this.navigationView.SelectedItem = saleItem;
            if (++count == 2)
            {
                PageClose(this.navigationView.MenuItems.Last() as NavigationViewItem);
                PageClose(this.navigationView.MenuItems.Last() as NavigationViewItem);
            }
        }

        private void PageClose(NavigationViewItem item)
        {
            this.navigationView.MenuItems.Remove(item);
            this.navigationView.SelectedItem = this.navigationView.MenuItems.Last();
        }

    }

IMPORTANT: This is only reproducible with MUXC version of NavigationView. So, for testing in samples app, make sure to include muxc xmlns and use it.

@Youssef1313
Copy link
Member

Use this commit for easier debugging in Uno.

@Youssef1313
Copy link
Member

It's getting tricky to understand what is going on.

One important observation is

image

ItemsSourceView maintains a count cache that gets out of sync with the actual count; or more specifically, it's likely that we are in a state where we are using the count cache and it's not yet updated (but it will). This could happen for example if there are two subscribers to collection change:

  1. First (and the order matter): is some subscriber that ends up modifying the count
  2. Second: the subscriber that updates the count cache.

However, even if I try to give up using the cache and instead get the count directly, the code still crashes, but happens at a later point with different stack trace.

@Youssef1313
Copy link
Member

Here is why the count cache was out of sync.

There are (at least) two instances of ItemsSourceView that are operating on the SAME observable collection.
Both subscribe to collection changes for sure. What happens is:

  1. The first ItemsSourceView gets notified about the removal of an item
  2. Then, it updates its count cache.
  3. As part of the work the first ItemsSourceView does is that, magically, the stack trace ends up being operating on the second ItemsSourceView, but it wasn't yet notified of the removal of the item and has outdated count cache.

The stack trace is large so split into two screenshots:

image

image

  • Marked blue is the first ItemsSourceView which got its cache count updated.
  • Marked red is the second ItemsSourceView which hasn't yet got its cache count updated.

@Youssef1313
Copy link
Member

In the above stack trace, there is a measure happening which DOES NOT happen in WinUI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/items-repeater Categorizes an issue or PR as relevant the ItemsRepeater control area/navigationview 🧭 Categorizes an issue or PR as relevant to the NavigationView control difficulty/challenging 🤯 Categorizes an issue for which the difficulty level is reachable with internals understanding kind/bug Something isn't working project/navigation-lifecycle 🧬 Categorizes an issue or PR as relevant to the navigation and lifecycle (NavigationView, AppBar, ...)
Projects
None yet
Development

No branches or pull requests

5 participants