Browse Source

Support multiple `InheritDataTypeFromItems`.

To allow binding both `ItemsControl.Items` and `ItemsSource` we need to support multiple `InheritDataTypeFromItems` attributes.
pull/10590/head
Steven Kirk 4 years ago
parent
commit
57c997bed7
  1. 2
      src/Avalonia.Base/Metadata/InheritDataTypeFromItemsAttribute.cs
  2. 2
      src/Avalonia.Controls/ItemsControl.cs
  3. 1
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  4. 43
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs

2
src/Avalonia.Base/Metadata/InheritDataTypeFromItemsAttribute.cs

@ -9,7 +9,7 @@ namespace Avalonia.Metadata;
/// A typical usage example is a ListBox control, where <see cref="InheritDataTypeFromItemsAttribute"/> is defined on the ItemTemplate property,
/// allowing the template to inherit the data type from the Items collection binding.
/// </remarks>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class InheritDataTypeFromItemsAttribute : Attribute
{
/// <summary>

2
src/Avalonia.Controls/ItemsControl.cs

@ -95,6 +95,7 @@ namespace Avalonia.Controls
/// </summary>
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
[InheritDataTypeFromItems(nameof(Items))]
public IBinding? DisplayMemberBinding
{
get => GetValue(DisplayMemberBindingProperty);
@ -218,6 +219,7 @@ namespace Avalonia.Controls
/// Gets or sets the data template used to display the items in the control.
/// </summary>
[InheritDataTypeFromItems(nameof(ItemsSource))]
[InheritDataTypeFromItems(nameof(Items))]
public IDataTemplate? ItemTemplate
{
get => GetValue(ItemTemplateProperty);

1
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -235,6 +235,7 @@ namespace Avalonia.Controls.Primitives
/// </summary>
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
[InheritDataTypeFromItems(nameof(Items))]
public IBinding? SelectedValueBinding
{
get => GetValue(SelectedValueBindingProperty);

43
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs

@ -73,27 +73,32 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
// Infer data type from collection binding on a control that displays items.
var property = context.ParentNodes().OfType<XamlPropertyAssignmentNode>().FirstOrDefault();
var attributeType = context.GetAvaloniaTypes().InheritDataTypeFromItemsAttribute;
var attribute = property?.Property?.GetClrProperty().CustomAttributes
.FirstOrDefault(a => a.Type == attributeType);
if (attribute is not null)
var attributes = property?.Property?.GetClrProperty().CustomAttributes
.Where(a => a.Type == attributeType).ToList();
if (attributes?.Count > 0)
{
var propertyName = (string)attribute.Parameters.First();
XamlAstConstructableObjectNode parentObject;
if (attribute.Properties.TryGetValue("AncestorType", out var type)
&& type is IXamlType xamlType)
{
parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>()
.FirstOrDefault(n => n.Type.GetClrType().FullName == xamlType.FullName);
}
else
foreach (var attribute in attributes)
{
parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault();
}
if (parentObject != null)
{
inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject, propertyName);
var propertyName = (string)attribute.Parameters.First();
XamlAstConstructableObjectNode parentObject;
if (attribute.Properties.TryGetValue("AncestorType", out var type)
&& type is IXamlType xamlType)
{
parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>()
.FirstOrDefault(n => n.Type.GetClrType().FullName == xamlType.FullName);
}
else
{
parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault();
}
if (parentObject != null)
{
inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject, propertyName);
if (inferredDataContextTypeNode != null)
break;
}
}
}

Loading…
Cancel
Save