Browse Source

Merge pull request #10511 from AvaloniaUI/fixes/10398-treeview-datatemplate

Fix TreeView data template handling
pull/10555/head
Dan Walmsley 4 years ago
committed by GitHub
parent
commit
9232e82e49
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      src/Avalonia.Controls/ItemsControl.cs
  2. 47
      src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs
  3. 25
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

9
src/Avalonia.Controls/ItemsControl.cs

@ -383,14 +383,7 @@ namespace Avalonia.Controls
{
hic.Header = item;
hic.HeaderTemplate = itemTemplate;
itemTemplate ??= hic.FindDataTemplate(item) ?? this.FindDataTemplate(item);
if (itemTemplate is ITreeDataTemplate treeTemplate)
{
if (item is not null && treeTemplate.ItemsSelector(item) is { } itemsBinding)
BindingOperations.Apply(hic, ItemsProperty, itemsBinding, null);
}
hic.PrepareItemContainer();
}
}

47
src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs

@ -1,6 +1,8 @@
using System;
using Avalonia.Collections;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.LogicalTree;
namespace Avalonia.Controls.Primitives
@ -10,6 +12,9 @@ namespace Avalonia.Controls.Primitives
/// </summary>
public class HeaderedItemsControl : ItemsControl, IContentPresenterHost
{
private IDisposable? _itemsBinding;
private bool _prepareItemContainerOnAttach;
/// <summary>
/// Defines the <see cref="Header"/> property.
/// </summary>
@ -60,6 +65,17 @@ namespace Avalonia.Controls.Primitives
/// <inheritdoc/>
IAvaloniaList<ILogical> IContentPresenterHost.LogicalChildren => LogicalChildren;
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
if (_prepareItemContainerOnAttach)
{
PrepareItemContainer();
_prepareItemContainerOnAttach = false;
}
}
/// <inheritdoc/>
bool IContentPresenterHost.RegisterContentPresenter(IContentPresenter presenter)
{
@ -81,6 +97,37 @@ namespace Avalonia.Controls.Primitives
return false;
}
internal void PrepareItemContainer()
{
_itemsBinding?.Dispose();
_itemsBinding = null;
var item = Header;
if (item is null)
{
_prepareItemContainerOnAttach = false;
return;
}
var headerTemplate = HeaderTemplate;
if (headerTemplate is null)
{
if (((ILogical)this).IsAttachedToLogicalTree)
headerTemplate = this.FindDataTemplate(item);
else
_prepareItemContainerOnAttach = true;
}
if (headerTemplate is ITreeDataTemplate treeTemplate &&
treeTemplate.Match(item) &&
treeTemplate.ItemsSelector(item) is { } itemsBinding)
{
_itemsBinding = BindingOperations.Apply(this, ItemsProperty, itemsBinding, null);
}
}
private void HeaderChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.OldValue is ILogical oldChild)

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

@ -100,6 +100,31 @@ namespace Avalonia.Controls.UnitTests
Assert.All(items, x => Assert.Same(theme, x.ItemContainerTheme));
}
[Fact]
public void Finds_Correct_DataTemplate_When_Application_DataTemplate_Is_Present()
{
// #10398
using var app = UnitTestApplication.Start();
Avalonia.Application.Current.DataTemplates.Add(new FuncDataTemplate<object>((x, _) => new Canvas()));
AvaloniaLocator.CurrentMutable.Bind<IGlobalDataTemplates>().ToConstant(Avalonia.Application.Current);
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = CreateTestTreeData(),
};
var root = new TestRoot(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
Assert.Equal(new[] { "Root" }, ExtractItemHeader(target, 0));
Assert.Equal(new[] { "Child1", "Child2", "Child3" }, ExtractItemHeader(target, 1));
Assert.Equal(new[] { "Grandchild2a" }, ExtractItemHeader(target, 2));
}
[Fact]
public void Root_ItemContainerGenerator_Containers_Should_Be_Root_Containers()
{

Loading…
Cancel
Save