Browse Source

Refresh containers when relevant property changes.

When `ItemsControl.DisplayMemberBinding` or `ItemTemplate` changes, refresh the containers.
pull/9677/head
Steven Kirk 4 years ago
parent
commit
000f393be7
  1. 10
      src/Avalonia.Controls/ItemsControl.cs
  2. 8
      src/Avalonia.Controls/Presenters/ItemsPresenter.cs
  3. 2
      src/Avalonia.Controls/Presenters/PanelContainerGenerator.cs
  4. 4
      src/Avalonia.Controls/VirtualizingPanel.cs
  5. 58
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

10
src/Avalonia.Controls/ItemsControl.cs

@ -426,12 +426,14 @@ namespace Avalonia.Controls
{
if (change.NewValue is not null && DisplayMemberBinding is not null)
throw new InvalidOperationException("Cannot set both DisplayMemberBinding and ItemTemplate.");
RefreshContainers();
}
else if (change.Property == DisplayMemberBindingProperty)
{
if (change.NewValue is not null && ItemTemplate is not null)
throw new InvalidOperationException("Cannot set both DisplayMemberBinding and ItemTemplate.");
_displayMemberItemTemplate = null;
RefreshContainers();
}
}
@ -455,6 +457,14 @@ namespace Avalonia.Controls
SubscribeToItems(newValue);
}
/// <summary>
/// Refreshes the containers displayed by the control.
/// </summary>
/// <remarks>
/// Causes all containers to be unrealized and re-realized.
/// </remarks>
protected void RefreshContainers() => Presenter?.Refresh();
/// <summary>
/// Called when the <see cref="INotifyCollectionChanged.CollectionChanged"/> event is
/// raised on <see cref="Items"/>.

8
src/Avalonia.Controls/Presenters/ItemsPresenter.cs

@ -84,6 +84,14 @@ namespace Avalonia.Controls.Presenters
}
}
internal void Refresh()
{
if (Panel is VirtualizingPanel v)
v.Refresh();
else
_generator?.Refresh();
}
private void ResetState()
{
_generator?.Dispose();

2
src/Avalonia.Controls/Presenters/PanelContainerGenerator.cs

@ -45,6 +45,8 @@ namespace Avalonia.Controls.Presenters
_presenter.Panel?.Children.Clear();
}
internal void Refresh() => OnItemsChanged(null, CollectionUtils.ResetEventArgs);
private void OnItemsControlPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ItemsControl.ItemsProperty)

4
src/Avalonia.Controls/VirtualizingPanel.cs

@ -176,6 +176,8 @@ namespace Avalonia.Controls
Children.Clear();
}
internal void Refresh() => OnItemsControlItemsChanged(null, CollectionUtils.ResetEventArgs);
private ItemsControl EnsureItemsControl()
{
if (ItemsControl is null)
@ -189,7 +191,7 @@ namespace Avalonia.Controls
{
if (e.OldValue is INotifyCollectionChanged inccOld)
inccOld.CollectionChanged -= OnItemsControlItemsChanged;
OnItemsControlItemsChanged(null, CollectionUtils.ResetEventArgs);
Refresh();
if (e.NewValue is INotifyCollectionChanged inccNew)
inccNew.CollectionChanged += OnItemsControlItemsChanged;
}

58
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@ -35,6 +35,31 @@ namespace Avalonia.Controls.UnitTests
Assert.IsType<Canvas>(container.Child);
}
[Fact]
public void ItemTemplate_Can_Be_Changed()
{
var target = new ItemsControl
{
Template = GetTemplate(),
ItemTemplate = new FuncDataTemplate<string>((_, __) => new Canvas()),
};
target.Items = new[] { "Foo" };
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
var container = (ContentPresenter)target.Presenter.Panel.Children[0];
container.UpdateChild();
Assert.IsType<Canvas>(container.Child);
target.ItemTemplate = new FuncDataTemplate<string>((_, __) => new Border());
container = (ContentPresenter)target.Presenter.Panel.Children[0];
container.UpdateChild();
Assert.IsType<Border>(container.Child);
}
[Fact]
public void Panel_Should_Have_TemplatedParent_Set_To_ItemsControl()
{
@ -708,6 +733,32 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(container.Child!.GetValue(TextBlock.TextProperty), "3");
}
[Fact]
public void DisplayMemberBinding_Can_Be_Changed()
{
var target = new ItemsControl
{
Template = GetTemplate(),
DisplayMemberBinding = new Binding("Value")
};
target.Items = new[] { new Item("Foo", "Bar") };
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
var container = (ContentPresenter)target.Presenter.Panel.Children[0];
container.UpdateChild();
Assert.Equal(container.Child!.GetValue(TextBlock.TextProperty), "Bar");
target.DisplayMemberBinding = new Binding("Caption");
container = (ContentPresenter)target.Presenter.Panel.Children[0];
container.UpdateChild();
Assert.Equal(container.Child!.GetValue(TextBlock.TextProperty), "Foo");
}
[Fact]
public void Cannot_Set_Both_DisplayMemberBinding_And_ItemTemplate_1()
{
@ -740,6 +791,13 @@ namespace Avalonia.Controls.UnitTests
Value = value;
}
public Item(string caption, string value)
{
Caption = caption;
Value = value;
}
public string Caption { get; }
public string Value { get; }
}

Loading…
Cancel
Save