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

Detaching ItemsControl multiple times crashes #3487

Closed
MarchingCube opened this issue Jan 28, 2020 · 1 comment · Fixed by #3546
Closed

Detaching ItemsControl multiple times crashes #3487

MarchingCube opened this issue Jan 28, 2020 · 1 comment · Fixed by #3546
Assignees
Labels

Comments

@MarchingCube
Copy link
Collaborator

MarchingCube commented Jan 28, 2020

I've found out that detaching ItemsControl from the parent and then attaching it to the same parent again will crash it when we try to detach again.

Managed to reproduce it in ControlCatalog with such codebehind:

    public class TestVm
    {
        public string Name { get; set; }
    }

    public class ButtonPage : UserControl
    {
        private readonly Decorator _panelHost;
        private readonly ItemsControl _panel;

        public ButtonPage()
        {
            AvaloniaXamlLoader.Load(this);

            _panelHost = this.FindControl<Decorator>("PanelHost");
            _panel = this.FindControl<ItemsControl>("Panel");

            _panel.Items = new List<TestVm>
            {
                new TestVm { Name = "Test 0" },
                new TestVm { Name = "Test 1" },
                new TestVm { Name = "Test 2" },
                new TestVm { Name = "Test 3" }
            };
        }

        public void MovePanel(object sender, RoutedEventArgs e)
        {
            _panelHost.Child = null;

            _panelHost.Child = _panel;
        }
    }

And XAML:

<Decorator x:Name="PanelHost">
      <ItemsControl x:Name="Panel">
        <DataTemplate>
          <Border BorderThickness="1" Background="{DynamicResource ThemeBorderMidColor}"
                  BorderBrush="{DynamicResource ThemeBorderMidColor}" Margin="0,0,2,0">
            <StackPanel Orientation="Horizontal">
              <TextBlock Margin="4,0,0,0" Text="{Binding Name}" />
              <Rectangle Margin="2,0,0,0" Width="1"
                         Fill="{DynamicResource ThemeBorderMidColor}" />
              <Panel Background="#373737" />
            </StackPanel>
          </Border>
        </DataTemplate>
      </ItemsControl>
    </Decorator>

After calling MovePanel once all items in ItemsControl will get Parent set to null. Second call will crash with: https://gist.github.com/MarchingCube/055e69b9737157f986fec5334de0d127

@MarchingCube MarchingCube changed the title Detaching ItemsControl Detaching ItemsControl crashes Jan 28, 2020
@MarchingCube MarchingCube changed the title Detaching ItemsControl crashes Detaching ItemsControl multiple times crashes Jan 28, 2020
@kekekeks kekekeks added the bug label Jan 28, 2020
@grokys
Copy link
Member

grokys commented Feb 11, 2020

Ok, worked out what's happening here:

  1. ItemsControl is detached, along with the ContentPresenters which display the items.
    • ItemsControl.LogicalChildren remains unchanged - it contains the children of each ContentPresenter
  2. ItemsControl is reattached, ContentPresenter.OnAttachedToLogicalTree() is called which resets the child creation state: we're now in a new tree, so we need to re-evaluate the DataTemplate which produced the Child
    • ItemsControl.LogicalChildren remains unchanged
  3. A measure takes place, ContentPresenter.UpdateChild() is called which re-evaluates the DataTemplate, creating a new control. The old control is removed
    • ItemsControl.LogicalChildren remains unchanged, but now the control it contains has been removed
  4. The ItemsControl is detached
  5. The ItemsControl is re-attached. OnAttachedToLogicalTree is fired along the added tree, but the tree now contains controls in ItemsControl.LogicalChildren that have actually been removed
  6. It throws, this is invalid state

This is very similar to #3328, but with a different cause. It only occurs in ItemsControl and not e.g. ListBox because in ListBox a ListBoxItem container is added to the logical tree instead of adding the control directly.

grokys added a commit that referenced this issue Feb 11, 2020
grokys added a commit that referenced this issue Feb 11, 2020
Exposing the `ContentPresenter.Child` in `ItemsControl.LogicalChildren` was causing problems when detaching and reattaching an `ItemsControl` to the logical tree. Instead, expose the `ContentPresenter` itself in effect meaning that `ItemsControl` has a "container" type just like the controls derived from it.

Fixes #3487
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants