Skip to content

Commit

Permalink
Merge pull request AvaloniaUI#2646 from AvaloniaUI/fix-2561
Browse files Browse the repository at this point in the history
Fix 2561
  • Loading branch information
kekekeks authored Jun 11, 2019
2 parents fedbe11 + 57e0613 commit a8c45cb
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 9 deletions.
11 changes: 9 additions & 2 deletions src/Avalonia.Build.Tasks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;

namespace Avalonia.Build.Tasks
Expand All @@ -11,8 +12,14 @@ static int Main(string[] args)
{
if (args.Length != 3)
{
Console.Error.WriteLine("input references output");
return 1;
if (args.Length == 1)
args = new[] {"original.dll", "references", "out.dll"}
.Select(x => Path.Combine(args[0], x)).ToArray();
else
{
Console.Error.WriteLine("input references output");
return 1;
}
}

return new CompileAvaloniaXamlTask()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlA
if (!(node is XamlIlAstObjectNode on
&& on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
return node;

var parent = context.ParentNodes().OfType<XamlIlAstObjectNode>()
.FirstOrDefault(x => x.Type.GetClrType().FullName == "Avalonia.Styling.Style");
.FirstOrDefault(p => p.Type.GetClrType().FullName == "Avalonia.Styling.Style");

if (parent == null)
throw new XamlIlParseException(
"Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node);
Expand Down Expand Up @@ -53,8 +55,7 @@ public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlA
.OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode)
{
var propType = avaloniaPropertyNode.Property.Getter?.ReturnType
?? avaloniaPropertyNode.Property.Setters.First().Parameters[0];
var propType = avaloniaPropertyNode.AvaloniaPropertyType;
if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
propType, out var converted))
throw new XamlIlParseException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class AvaloniaXamlIlWellKnownTypes
public IXamlIlType BindingPriority { get; }
public IXamlIlType AvaloniaObjectExtensions { get; }
public IXamlIlType AvaloniaProperty { get; }
public IXamlIlType AvaloniaPropertyT { get; }
public IXamlIlType IBinding { get; }
public IXamlIlMethod AvaloniaObjectBindMethod { get; }
public IXamlIlMethod AvaloniaObjectSetValueMethod { get; }
Expand All @@ -26,6 +27,7 @@ public AvaloniaXamlIlWellKnownTypes(XamlIlAstTransformationContext ctx)
IAvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.IAvaloniaObject");
AvaloniaObjectExtensions = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions");
AvaloniaProperty = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty");
AvaloniaPropertyT = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty`1");
BindingPriority = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.BindingPriority");
IBinding = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.IBinding");
IDisposable = ctx.Configuration.TypeSystem.GetType("System.IDisposable");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, IXaml
return true;
}

public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context,
public static IXamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context,
string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo)
{
XamlIlAstNamePropertyReference forgedReference;
Expand All @@ -63,8 +63,14 @@ public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationConte
xmlOwner += parsedPropertyName.owner;

var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);
forgedReference = new XamlIlAstNamePropertyReference(lineInfo,
tref, parsedPropertyName.name, tref);

var propertyFieldName = parsedPropertyName.name + "Property";
var found = tref.Type.GetAllFields()
.FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName);
if (found == null)
throw new XamlIlParseException(
$"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo);
return new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found);
}

var clrProperty =
Expand All @@ -75,13 +81,20 @@ public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationConte
clrProperty);
}
}

interface IXamlIlAvaloniaPropertyNode : IXamlIlAstValueNode
{
IXamlIlType AvaloniaPropertyType { get; }
}

class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode
class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode
{
public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, XamlIlAstClrProperty property) : base(lineInfo)
{
Type = new XamlIlAstClrTypeReference(this, type, false);
Property = property;
AvaloniaPropertyType = Property.Getter?.ReturnType
?? Property.Setters.First().Parameters[0];
}

public XamlIlAstClrProperty Property { get; }
Expand All @@ -93,6 +106,46 @@ public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeG
throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this);
return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
}

public IXamlIlType AvaloniaPropertyType { get; }
}

class XamlIlAvaloniaPropertyFieldNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode
{
private readonly IXamlIlField _field;

public XamlIlAvaloniaPropertyFieldNode(AvaloniaXamlIlWellKnownTypes types,
IXamlIlLineInfo lineInfo, IXamlIlField field) : base(lineInfo)
{
_field = field;
var avaloniaPropertyType = field.FieldType;
while (avaloniaPropertyType != null)
{
if (avaloniaPropertyType.GenericTypeDefinition?.Equals(types.AvaloniaPropertyT) == true)
{
AvaloniaPropertyType = avaloniaPropertyType.GenericArguments[0];
return;
}

avaloniaPropertyType = avaloniaPropertyType.BaseType;
}

throw new XamlIlParseException(
$"{field.Name}'s type {field.FieldType} doesn't inherit from AvaloniaProperty<T>, make sure to use typed properties",
lineInfo);

}



public IXamlIlAstTypeReference Type => new XamlIlAstClrTypeReference(this, _field.FieldType, false);
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
{
codeGen.Ldsfld(_field);
return XamlIlNodeEmitResult.Type(0, _field.FieldType);
}

public IXamlIlType AvaloniaPropertyType { get; }
}

interface IXamlIlAvaloniaProperty
Expand Down
42 changes: 42 additions & 0 deletions tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,33 @@ public void Design_Mode_DataContext_Should_Be_Set()
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'/>", typeof(XamlIlTests).Assembly);
Assert.Equal(Design.GetDataContext(loaded), SomeStaticProperty);
}

[Fact]
public void Attached_Properties_From_Static_Types_Should_Work_In_Style_Setters_Bug_2561()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{

var parsed = (Window)AvaloniaXamlLoader.Parse(@"
<Window
xmlns='https://github.com/avaloniaui'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests;assembly=Avalonia.Markup.Xaml.UnitTests'
>
<Window.Styles>
<Style Selector='TextBox'>
<Setter Property='local:XamlIlBugTestsStaticClassWithAttachedProperty.TestInt' Value='100'/>
</Style>
</Window.Styles>
<TextBox/>
</Window>
");
var tb = ((TextBox)parsed.Content);
parsed.Show();
tb.ApplyTemplate();
Assert.Equal(100, XamlIlBugTestsStaticClassWithAttachedProperty.GetTestInt(tb));
}
}
}

public class XamlIlBugTestsEventHandlerCodeBehind : Window
Expand Down Expand Up @@ -272,4 +299,19 @@ public class XamlIlClassWithPrecompiledXaml : UserControl
{
}

public static class XamlIlBugTestsStaticClassWithAttachedProperty
{
public static readonly AvaloniaProperty<int> TestIntProperty = AvaloniaProperty
.RegisterAttached<Control, int>("TestInt", typeof(XamlIlBugTestsStaticClassWithAttachedProperty));

public static void SetTestInt(Control control, int value)
{
control.SetValue(TestIntProperty, value);
}

public static int GetTestInt(Control control)
{
return (int)control.GetValue(TestIntProperty);
}
}
}

0 comments on commit a8c45cb

Please sign in to comment.