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

TabView unloads currently selected tabitem when other tabs are removed #9880

Open
Mangepange opened this issue Aug 7, 2024 · 1 comment
Open
Labels
area-TabView bug Something isn't working team-Controls Issue for the Controls team

Comments

@Mangepange
Copy link

Describe the bug

When removing non-selected items from a TabView the currently selected TabViewItem recieves an Unloaded event once for each removed tab.

Steps to reproduce the bug

  1. Bind the TabItemsSource of a TabView to an ObservableCollection with some items in it.
  2. Trigger a method that removes items from the collection that are not currently selected.
  3. The selected tab is unloaded multiple times.

Example code (not full):

public class MainWindowViewModel : INotifyPropertyChanged
{
    public ObservableCollection<ItemViewModel> Items { get; } = [];

    public ObservableCollection<ItemViewModel> TabItems { get; } = [];

    public ItemViewModel? CurrentTabItem { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public void AddTabs()
    {
        CurrentTabItem = null;

        TabItems.Clear();
        TabItems.Add(new ItemViewModel { Name = "ViewModel A" });
        TabItems.Add(new ItemViewModel { Name = "ViewModel B" });
        TabItems.Add(new ItemViewModel { Name = "ViewModel C" });
        TabItems.Add(new ItemViewModel { Name = "ViewModel D" });
        CurrentTabItem = TabItems[0];
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentTabItem)));

        Items.Clear();
        foreach (var item in TabItems) {
            Items.Add(item);
        }
    }

    public void RemoveAllButCurrent()
    {
        foreach (var item in TabItems.ToList())
        {
            if (item != CurrentTabItem)
            {
                TabItems.Remove(item);
            }
        }
    }
}
public class ItemViewModel  : INotifyPropertyChanged
{
    public required string Name { get; set; }

    public int Loaded { get; private set; }

    public int Unloaded { get; private set; }

    public void Load()
    {
        Loaded++;
        OnPropertyChanged(nameof(Loaded));
    }

    public void Unload()
    {
        Unloaded++;
        OnPropertyChanged(nameof(Unloaded));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
}
<StackPanel Orientation="Vertical">

    <Button Content="Add tabs"
            Click="{x:Bind ViewModel.AddTabs}"/>
    
    <Button Content="Remove all but current tab"
            Click="{x:Bind ViewModel.RemoveAllButCurrent}"/>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TabView TabItemsSource="{x:Bind ViewModel.TabItems}"
                 SelectedItem="{x:Bind ViewModel.CurrentTabItem, Mode=TwoWay}"
                 VerticalAlignment="Stretch">
            <TabView.TabItemTemplate>
                <DataTemplate x:DataType="local:ItemViewModel">
                    <TabViewItem Header="{x:Bind Name}">

                        <TextBlock Text="{x:Bind Name}"
                                   Loaded="{x:Bind Load}"
                                   Unloaded="{x:Bind Unload}"/>
                    </TabViewItem>
                </DataTemplate>
            </TabView.TabItemTemplate>
        </TabView>

        <ListView Grid.Column="1" 
                  ItemsSource="{x:Bind ViewModel.Items}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:ItemViewModel">
                    <StackPanel Padding="4">
                        <TextBlock Text="{x:Bind Name}"/>
                        <TextBlock>
                            <Run Text="Loaded: "/>
                            <Run Text="{x:Bind Loaded, Mode=OneWay}"/>
                        </TextBlock>
                        <TextBlock>
                            <Run Text="Unloaded: "/>
                            <Run Text="{x:Bind Unloaded, Mode=OneWay}"/>
                        </TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </Grid>

</StackPanel>

Expected behavior

No response

Screenshots

image
Initial state. Note that the selected tab has been unloaded one time, does not seem correct to me.

image
After selecting each tab once.

image
After removing all non-selected tabs. Note that ViewModel D reports 3 extra unloaded events. It has also been loaded once again. But the loaded event comes first, and the three unloaded events come afterwards.

NuGet package version

WinUI 3 - Windows App SDK 1.5.5: 1.5.240627000

Windows version

Windows 11 (22H2): Build 22621

Additional context

No response

@Mangepange Mangepange added the bug Something isn't working label Aug 7, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the needs-triage Issue needs to be triaged by the area owners label Aug 7, 2024
@Mangepange
Copy link
Author

Could this be related to #1900? #8342?

@codendone codendone added area-TabView team-Controls Issue for the Controls team and removed needs-triage Issue needs to be triaged by the area owners labels Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-TabView bug Something isn't working team-Controls Issue for the Controls team
Projects
None yet
Development

No branches or pull requests

2 participants