Browse Source

WIP: Trying to use Style priority for ControlTemplate values.

pull/7679/head
Steven Kirk 5 years ago
parent
commit
ba8026b1b9
  1. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  2. 37
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplatePriorityTransformer.cs
  3. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  4. 41
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

1
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -65,6 +65,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new AvaloniaXamlIlCompiledBindingsMetadataRemover() new AvaloniaXamlIlCompiledBindingsMetadataRemover()
); );
Transformers.Add(new AvaloniaXamlIlControlTemplatePriorityTransformer());
Transformers.Add(new AvaloniaXamlIlMetadataRemover()); Transformers.Add(new AvaloniaXamlIlMetadataRemover());
Transformers.Add(new AvaloniaXamlIlRootObjectScope()); Transformers.Add(new AvaloniaXamlIlRootObjectScope());

37
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplatePriorityTransformer.cs

@ -0,0 +1,37 @@
using System.Linq;
using XamlX.Ast;
using XamlX.Transform;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
/// <summary>
/// Transforms property assignments within ControlTemplates to use Style priority where possible.
/// </summary>
class AvaloniaXamlIlControlTemplatePriorityTransformer : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
var bindingPriorityType = context.GetAvaloniaTypes().BindingPriority;
if (node is XamlPropertyAssignmentNode prop &&
prop.Property is XamlIlAvaloniaProperty avaloniaProperty &&
context.ParentNodes().Any(IsControlTemplate))
{
// If there are any setters which accept a binding priority, then add the Style
// binding priority as a value.
if (avaloniaProperty.Setters.Any(x => x.Parameters[0] == bindingPriorityType))
{
prop.Values.Insert(0, new XamlConstantNode(node, bindingPriorityType, 1));
}
}
return node;
}
private static bool IsControlTemplate(IXamlAstNode node)
{
return node is AvaloniaXamlIlTargetTypeMetadataNode tt &&
tt.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate;
}
}
}

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -15,6 +15,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType AvaloniaObjectExtensions { get; } public IXamlType AvaloniaObjectExtensions { get; }
public IXamlType AvaloniaProperty { get; } public IXamlType AvaloniaProperty { get; }
public IXamlType AvaloniaPropertyT { get; } public IXamlType AvaloniaPropertyT { get; }
public IXamlType StyledPropertyT { get; }
public IXamlType AvaloniaAttachedPropertyT { get; } public IXamlType AvaloniaAttachedPropertyT { get; }
public IXamlType IBinding { get; } public IXamlType IBinding { get; }
public IXamlMethod AvaloniaObjectBindMethod { get; } public IXamlMethod AvaloniaObjectBindMethod { get; }
@ -94,6 +95,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
AvaloniaObjectExtensions = cfg.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions"); AvaloniaObjectExtensions = cfg.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions");
AvaloniaProperty = cfg.TypeSystem.GetType("Avalonia.AvaloniaProperty"); AvaloniaProperty = cfg.TypeSystem.GetType("Avalonia.AvaloniaProperty");
AvaloniaPropertyT = cfg.TypeSystem.GetType("Avalonia.AvaloniaProperty`1"); AvaloniaPropertyT = cfg.TypeSystem.GetType("Avalonia.AvaloniaProperty`1");
StyledPropertyT = cfg.TypeSystem.GetType("Avalonia.StyledProperty`1");
AvaloniaAttachedPropertyT = cfg.TypeSystem.GetType("Avalonia.AttachedProperty`1"); AvaloniaAttachedPropertyT = cfg.TypeSystem.GetType("Avalonia.AttachedProperty`1");
BindingPriority = cfg.TypeSystem.GetType("Avalonia.Data.BindingPriority"); BindingPriority = cfg.TypeSystem.GetType("Avalonia.Data.BindingPriority");
IBinding = cfg.TypeSystem.GetType("Avalonia.Data.IBinding"); IBinding = cfg.TypeSystem.GetType("Avalonia.Data.IBinding");

41
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@ -189,7 +189,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
CustomAttributes = original.CustomAttributes; CustomAttributes = original.CustomAttributes;
if (!original.CustomAttributes.Any(ca => ca.Type.Equals(types.AssignBindingAttribute))) if (!original.CustomAttributes.Any(ca => ca.Type.Equals(types.AssignBindingAttribute)))
Setters.Insert(0, new BindingSetter(types, original.DeclaringType, field)); Setters.Insert(0, new BindingSetter(types, original.DeclaringType, field));
if (field.FieldType.GenericTypeDefinition == types.StyledPropertyT)
{
var propertyType = field.FieldType.GenericArguments[0];
Setters.Insert(1, new SetValueWithPrioritySetter(types, original.DeclaringType, field, propertyType));
}
Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field)); Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field));
} }
@ -240,6 +246,39 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
} }
class SetValueWithPrioritySetter : AvaloniaPropertyCustomSetter
{
public SetValueWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty,
IXamlType propertyType)
: base(types, declaringType, avaloniaProperty)
{
Parameters = new[] { types.BindingPriority, propertyType };
}
public override void Emit(IXamlILEmitter emitter)
{
var method = Types.AvaloniaObject
.FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "SetValue"
&& m.Parameters.Count == 3
&& m.Parameters[0].Name == "StyledPropertyBase`1"
&& m.Parameters[2].Equals(Types.BindingPriority));
if (method == null)
throw new XamlTypeSystemException(
$"Unable to find AvaloniaObject.SetValue<T>(StyledPropertyBase<T>, T, BindingPriority).");
method = method.MakeGenericMethod(new[] { Parameters[1] });
using (var bloc = emitter.LocalsPool.GetLocal(Parameters[1]))
emitter
.Stloc(bloc.Local)
.Ldsfld(AvaloniaProperty)
.Ldloc(bloc.Local)
.Ldc_I4(0)
.EmitCall(method, true);
}
}
class UnsetValueSetter : AvaloniaPropertyCustomSetter class UnsetValueSetter : AvaloniaPropertyCustomSetter
{ {
public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty) public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty)

Loading…
Cancel
Save