Browse Source

feat(ContentPresenter): Content of ContentPresenter should become DataContext of the subtree whenever ContentTemplate is not null

pull/7008/head
Giuseppe Lippolis 4 years ago
parent
commit
ccbd277e8b
  1. 53
      src/Avalonia.Controls/Presenters/ContentPresenter.cs

53
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@ -107,9 +107,6 @@ namespace Avalonia.Controls.Presenters
AffectsRender<ContentPresenter>(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty); AffectsRender<ContentPresenter>(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty);
AffectsArrange<ContentPresenter>(HorizontalContentAlignmentProperty, VerticalContentAlignmentProperty); AffectsArrange<ContentPresenter>(HorizontalContentAlignmentProperty, VerticalContentAlignmentProperty);
AffectsMeasure<ContentPresenter>(BorderThicknessProperty, PaddingProperty); AffectsMeasure<ContentPresenter>(BorderThicknessProperty, PaddingProperty);
ContentProperty.Changed.AddClassHandler<ContentPresenter>((x, e) => x.ContentChanged(e));
ContentTemplateProperty.Changed.AddClassHandler<ContentPresenter>((x, e) => x.ContentChanged(e));
TemplatedParentProperty.Changed.AddClassHandler<ContentPresenter>((x, e) => x.TemplatedParentChanged(e));
} }
public ContentPresenter() public ContentPresenter()
@ -240,6 +237,21 @@ namespace Avalonia.Controls.Presenters
} }
} }
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
switch (change.Property.Name)
{
case nameof(Content):
case nameof(ContentTemplate):
ContentChanged(change);
break;
case nameof(TemplatedParent):
TemplatedParentChanged(change);
break;
}
}
/// <summary> /// <summary>
/// Updates the <see cref="Child"/> control based on the control's <see cref="Content"/>. /// Updates the <see cref="Child"/> control based on the control's <see cref="Content"/>.
/// </summary> /// </summary>
@ -254,8 +266,14 @@ namespace Avalonia.Controls.Presenters
public void UpdateChild() public void UpdateChild()
{ {
var content = Content; var content = Content;
UpdateChild(content);
}
private void UpdateChild(object? content)
{
var contentTemplate = ContentTemplate;
var oldChild = Child; var oldChild = Child;
var newChild = CreateChild(); var newChild = CreateChild(content, oldChild, contentTemplate);
var logicalChildren = Host?.LogicalChildren ?? LogicalChildren; var logicalChildren = Host?.LogicalChildren ?? LogicalChildren;
// Remove the old child if we're not recycling it. // Remove the old child if we're not recycling it.
@ -271,7 +289,7 @@ namespace Avalonia.Controls.Presenters
} }
// Set the DataContext if the data isn't a control. // Set the DataContext if the data isn't a control.
if (!(content is IControl)) if (contentTemplate is { } || !(content is IControl))
{ {
DataContext = content; DataContext = content;
} }
@ -299,6 +317,7 @@ namespace Avalonia.Controls.Presenters
} }
_createdChild = true; _createdChild = true;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -325,18 +344,23 @@ namespace Avalonia.Controls.Presenters
{ {
var content = Content; var content = Content;
var oldChild = Child; var oldChild = Child;
return CreateChild(content, oldChild, ContentTemplate);
}
private IControl? CreateChild(object? content, IControl? oldChild, IDataTemplate? template)
{
var newChild = content as IControl; var newChild = content as IControl;
// We want to allow creating Child from the Template, if Content is null. // We want to allow creating Child from the Template, if Content is null.
// But it's important to not use DataTemplates, otherwise we will break content presenters in many places, // But it's important to not use DataTemplates, otherwise we will break content presenters in many places,
// otherwise it will blow up every ContentPresenter without Content set. // otherwise it will blow up every ContentPresenter without Content set.
if (newChild == null if ((newChild == null
&& (content != null || ContentTemplate != null)) && (content != null || template != null)) || (newChild is { } && template is { }))
{ {
var dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? var dataTemplate = this.FindDataTemplate(content, template) ??
( (
RecognizesAccessKey RecognizesAccessKey
? FuncDataTemplate.Access ? FuncDataTemplate.Access
: FuncDataTemplate.Default : FuncDataTemplate.Default
); );
@ -446,7 +470,14 @@ namespace Avalonia.Controls.Presenters
if (((ILogical)this).IsAttachedToLogicalTree) if (((ILogical)this).IsAttachedToLogicalTree)
{ {
UpdateChild(); if (e.Property.Name == nameof(Content))
{
UpdateChild(e.NewValue);
}
else
{
UpdateChild();
}
} }
else if (Child != null) else if (Child != null)
{ {

Loading…
Cancel
Save