diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index 81ed48f5b1..54d7e76d73 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -96,10 +96,6 @@ namespace Avalonia.Controls.Presenters /// public ContentPresenter() { - var dataContext = this.GetObservable(ContentProperty) - .Select(x => x is IControl ? AvaloniaProperty.UnsetValue : x); - - Bind(Control.DataContextProperty, dataContext); } /// @@ -221,39 +217,36 @@ namespace Avalonia.Controls.Presenters /// public void UpdateChild() { - var old = Child; var content = Content; - var result = content as IControl; + var oldChild = Child; + var newChild = content as IControl; - if (result == null) + if (content != null && newChild == null) { - DataContext = content; - - if (content != null) + // We have content and it isn't a control, so first try to recycle the existing + // child control to display the new data by querying if the template that created + // the child can recycle items and that it also matches the new data. + if (oldChild != null && + _dataTemplate != null && + _dataTemplate.SupportsRecycling && + _dataTemplate.Match(content)) { - if (old != null && - _dataTemplate != null && - _dataTemplate.SupportsRecycling && - _dataTemplate.Match(content)) - { - result = old; - } - else - { - _dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? FuncDataTemplate.Default; - result = _dataTemplate.Build(content); - - var controlResult = result as Control; - - if (controlResult != null) - { - NameScope.SetNameScope(controlResult, new NameScope()); - } - } + newChild = oldChild; } else { - _dataTemplate = null; + // We couldn't recycle an existing control so find a data template for the data + // and use it to create a control. + _dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? FuncDataTemplate.Default; + newChild = _dataTemplate.Build(content); + + // Try to give the new control its own name scope. + var controlResult = newChild as Control; + + if (controlResult != null) + { + NameScope.SetNameScope(controlResult, new NameScope()); + } } } else @@ -261,30 +254,35 @@ namespace Avalonia.Controls.Presenters _dataTemplate = null; } - if (result != old) + // Remove the old child if we're not recycling it. + if (oldChild != null && newChild != oldChild) { - if (old != null) - { - VisualChildren.Remove(old); - } + VisualChildren.Remove(oldChild); + } - if (result != null) - { - ((ISetInheritanceParent)result).SetParent(this); + // Set the DataContext if the data isn't a control. + if (!(content is IControl)) + { + DataContext = content; + } - Child = result; + // Update the Child. + if (newChild == null) + { + Child = null; + } + else if (newChild != oldChild) + { + ((ISetInheritanceParent)newChild).SetParent(this); - if (result.Parent == null) - { - ((ISetLogicalParent)result).SetParent((ILogical)this.TemplatedParent ?? this); - } + Child = newChild; - VisualChildren.Add(result); - } - else + if (newChild.Parent == null) { - Child = null; + ((ISetLogicalParent)newChild).SetParent((ILogical)this.TemplatedParent ?? this); } + + VisualChildren.Add(newChild); } _createdChild = true; diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs index ce2dc4ab6c..dcbc71b9a1 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs @@ -370,6 +370,7 @@ namespace Avalonia.Controls.UnitTests target.Presenter.ApplyTemplate(); var dataContexts = target.Presenter.Panel.Children + .Do(x => (x as ContentPresenter)?.UpdateChild()) .Cast() .Select(x => x.DataContext) .ToList(); diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests.cs index cd24631661..5c26ba5a5e 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests.cs @@ -143,13 +143,15 @@ namespace Avalonia.Controls.UnitTests.Presenters } [Fact] - public void Assigning_NonControl_To_Content_Should_Set_DataContext() + public void Assigning_NonControl_To_Content_Should_Set_DataContext_On_UpdateChild() { var target = new ContentPresenter { Content = "foo", }; + target.UpdateChild(); + Assert.Equal("foo", target.DataContext); } diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs index 9f76767ec1..da1558439f 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs @@ -312,6 +312,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var dataContexts = target.Panel.Children .Cast() + .Do(x => x.UpdateChild()) .Select(x => x.DataContext) .ToList();