Browse Source

Reimplement DisplayMemberBinding.

Use a slightly different approach to the one that was previously there: create an item template that contains `DisplayMemberBinding`. This is the approach that WPF broadly uses too.
pull/9677/head
Steven Kirk 4 years ago
parent
commit
004103a925
  1. 35
      src/Avalonia.Controls/ItemsControl.cs
  2. 25
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

35
src/Avalonia.Controls/ItemsControl.cs

@ -83,6 +83,7 @@ namespace Avalonia.Controls
private int _itemCount;
private ItemContainerGenerator? _itemContainerGenerator;
private EventHandler<ChildIndexChangedEventArgs>? _childIndexChanged;
private IDataTemplate? _displayMemberItemTemplate;
/// <summary>
/// Initializes static members of the <see cref="ItemsControl"/> class.
@ -291,19 +292,19 @@ namespace Avalonia.Controls
else if (item is not Visual)
hcc.Header = item;
if (ItemTemplate is { } it)
if (GetEffectiveItemTemplate() is { } it)
hcc.HeaderTemplate = it;
}
else if (container is ContentControl cc)
{
cc.Content = item;
if (ItemTemplate is { } it)
if (GetEffectiveItemTemplate() is { } it)
cc.ContentTemplate = it;
}
else if (container is ContentPresenter p)
{
p.Content = item;
if (ItemTemplate is { } it)
if (GetEffectiveItemTemplate() is { } it)
p.ContentTemplate = it;
}
}
@ -431,6 +432,17 @@ namespace Avalonia.Controls
throw new NotImplementedException();
////_itemContainerGenerator.ItemContainerTheme = change.GetNewValue<ControlTheme?>();
}
else if (change.Property == ItemTemplateProperty)
{
if (change.NewValue is not null && DisplayMemberBinding is not null)
throw new InvalidOperationException("Cannot set both DisplayMemberBinding and ItemTemplate.");
}
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;
}
}
/// <summary>
@ -568,6 +580,23 @@ namespace Avalonia.Controls
}
}
private IDataTemplate? GetEffectiveItemTemplate()
{
if (ItemTemplate is { } itemTemplate)
return itemTemplate;
if (_displayMemberItemTemplate is null && DisplayMemberBinding is { } binding)
{
_displayMemberItemTemplate = new FuncDataTemplate<object?>((_, _) =>
new TextBlock
{
[!TextBlock.TextProperty] = binding,
});
}
return _displayMemberItemTemplate;
}
/// <summary>
/// Called when the <see cref="ItemTemplate"/> changes.
/// </summary>

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

@ -708,6 +708,31 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(container.Child!.GetValue(TextBlock.TextProperty), "3");
}
[Fact]
public void Cannot_Set_Both_DisplayMemberBinding_And_ItemTemplate_1()
{
var target = new ItemsControl
{
Template = GetTemplate(),
DisplayMemberBinding = new Binding("Length")
};
Assert.Throws<InvalidOperationException>(() =>
target.ItemTemplate = new FuncDataTemplate<string>((_, _) => new TextBlock()));
}
[Fact]
public void Cannot_Set_Both_DisplayMemberBinding_And_ItemTemplate_2()
{
var target = new ItemsControl
{
Template = GetTemplate(),
ItemTemplate = new FuncDataTemplate<string>((_, _) => new TextBlock()),
};
Assert.Throws<InvalidOperationException>(() => target.DisplayMemberBinding = new Binding("Length"));
}
private class Item
{
public Item(string value)

Loading…
Cancel
Save