From 58de2aaac09bd2ad2897bdf2c1eef653aa968abd Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 15 Feb 2019 17:19:38 +0300 Subject: [PATCH] WIP2 --- samples/ControlCatalog/MainView.xaml.cs | 16 +++++++ samples/ControlCatalog/MainWindow.xaml | 33 ++++++++++++++- src/Avalonia.Base/AvaloniaProperty.cs | 21 +++++----- src/Markup/Avalonia.Markup.Xaml/Extensions.cs | 16 ++++++- .../StaticResourceExtension.cs | 33 +++++++-------- .../Templates/TemplateContent.cs | 7 +++- .../XamlIl/AvaloniaXamlIlRuntimeCompiler.cs | 2 +- .../AvaloniaXamlIlLanguage.cs | 3 +- .../Transformers/AddNameScopeRegistration.cs | 42 +++++++++---------- .../Transformers/XNameTransformer.cs | 7 +++- .../XamlIl/Runtime/XamlIlRuntimeHelpers.cs | 7 ++++ .../Avalonia.Markup.Xaml/XamlIl/xamlil.github | 2 +- .../Avalonia.Markup/Data/MultiBinding.cs | 2 +- 13 files changed, 130 insertions(+), 61 deletions(-) diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs index a498b17bdd..07304404c0 100644 --- a/samples/ControlCatalog/MainView.xaml.cs +++ b/samples/ControlCatalog/MainView.xaml.cs @@ -1,8 +1,11 @@ +using System; using System.Collections; using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; +using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.Styling; +using Avalonia.Markup.Xaml.XamlIl; using Avalonia.Platform; using ControlCatalog.Pages; @@ -28,8 +31,20 @@ namespace ControlCatalog }); } +/* var light = AvaloniaXamlLoader.Parse(@""); var dark = AvaloniaXamlLoader.Parse(@""); + */ + var light = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) + { + Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default") + }; + var dark = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog")) + { + Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default") + }; + + var themes = this.Find("Themes"); themes.SelectionChanged += (sender, e) => { @@ -49,6 +64,7 @@ namespace ControlCatalog private void InitializeComponent() { AvaloniaXamlLoader.Load(this); + AvaloniaXamlIlRuntimeCompiler.DumpRuntimeCompilationResults(); } } } diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 4bae60b2a6..7f62827d86 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -1,8 +1,39 @@  - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index 953132116c..db25de6188 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -19,7 +19,7 @@ namespace Avalonia /// /// Represents an unset property value. /// - public static readonly object UnsetValue = new Unset(); + public static readonly object UnsetValue = new UnsetValueType(); private static int s_nextId; private readonly Subject _initialized; @@ -546,16 +546,17 @@ namespace Avalonia } } + + } + /// + /// Class representing the . + /// + public class UnsetValueType + { /// - /// Class representing the . + /// Returns the string representation of the . /// - private class Unset - { - /// - /// Returns the string representation of the . - /// - /// The string "(unset)". - public override string ToString() => "(unset)"; - } + /// The string "(unset)". + public override string ToString() => "(unset)"; } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Extensions.cs b/src/Markup/Avalonia.Markup.Xaml/Extensions.cs index 716c8bc08b..c6b914ba72 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Extensions.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Extensions.cs @@ -1,14 +1,16 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using Avalonia.Markup.Xaml.XamlIl.Runtime; +using Portable.Xaml; using Portable.Xaml.Markup; namespace Avalonia.Markup.Xaml { internal static class Extensions { - public static T GetService(this IServiceProvider sp) => (T)sp.GetService(typeof(T)); + public static T GetService(this IServiceProvider sp) => (T)sp?.GetService(typeof(T)); public static Uri GetContextBaseUri(this IServiceProvider ctx) @@ -37,6 +39,18 @@ namespace Avalonia.Markup.Xaml (ITypeDescriptorContext)ctx); } + public static IEnumerable GetParents(this IServiceProvider sp) + { + var stack = sp.GetService(); + if (stack != null) + return stack.Parents.OfType(); + + var context = (ITypeDescriptorContext)sp; + var schemaContext = context.GetService().SchemaContext; + var ambientProvider = context.GetService(); + return ambientProvider.GetAllAmbientValues(schemaContext.GetXamlType(typeof(T))).OfType(); + } + public static Type ResolveType(this IServiceProvider ctx, string namespacePrefix, string type) { var tr = ctx.GetService(); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index af4916097c..ac9a23d907 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -28,36 +28,31 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public override object ProvideValue(IServiceProvider serviceProvider) { - var context = (ITypeDescriptorContext)serviceProvider; - var schemaContext = context.GetService().SchemaContext; - var ambientProvider = context.GetService(); - var resourceProviderType = schemaContext.GetXamlType(typeof(IResourceNode)); - var ambientValues = ambientProvider.GetAllAmbientValues(resourceProviderType); + // Look upwards though the ambient context for IResourceProviders which might be able // to give us the resource. - foreach (var ambientValue in ambientValues) + foreach (var resourceProvider in serviceProvider.GetParents()) { // We override XamlType.CanAssignTo in BindingXamlType so the results we get back // from GetAllAmbientValues aren't necessarily of the correct type. - if (ambientValue is IResourceNode resourceProvider) + + if (resourceProvider is IControl control && control.StylingParent != null) { - if (resourceProvider is IControl control && control.StylingParent != null) - { - // If we've got to a control that has a StylingParent then it's probably - // a top level control and its StylingParent is pointing to the global - // styles. If this is case just do a FindResource on it. - return control.FindResource(ResourceKey); - } - else if (resourceProvider.TryGetResource(ResourceKey, out var value)) - { - return value; - } + // If we've got to a control that has a StylingParent then it's probably + // a top level control and its StylingParent is pointing to the global + // styles. If this is case just do a FindResource on it. + return control.FindResource(ResourceKey); } + else if (resourceProvider.TryGetResource(ResourceKey, out var value)) + { + return value; + } + } // The resource still hasn't been found, so add a delayed one-time binding. - var provideTarget = context.GetService(); + var provideTarget = serviceProvider.GetService(); if (provideTarget.TargetObject is IControl target && provideTarget.TargetProperty is PropertyInfo property) diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs index 63fb9f193c..ff367c0e13 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using Avalonia.Controls; using System.Collections.Generic; @@ -37,7 +38,11 @@ namespace Avalonia.Markup.Xaml.Templates public static IControl Load(object templateContent) { + if (templateContent is Func direct) + { + return (IControl)direct(null); + } return ((TemplateContent)templateContent).Load(); } } -} \ No newline at end of file +} diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs index 9f91b44fda..782ac5e5b5 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs @@ -28,7 +28,7 @@ namespace Avalonia.Markup.Xaml.XamlIl var saveMethod = _asm.GetType().GetMethods() .FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1); if (saveMethod == null) - throw new PlatformNotSupportedException(); + return; try { _builder.CreateGlobalFunctions(); diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 65678e692c..7186e9d00e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -48,7 +48,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions }, MarkupExtensionCustomResultTypes = { - bindingType + bindingType, + typeSystem.GetType("Avalonia.UnsetValueType") }, MarkupExtensionCustomResultHandler = runtimeHelpers.FindMethod(m => m.Name == "ApplyNonMatchingMarkupExtensionV1"), diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs index 4241eae6dc..5e5f5b1aa0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs @@ -1,3 +1,4 @@ +using System; using XamlIl.Ast; using XamlIl.Transform; using XamlIl.TypeSystem; @@ -35,44 +36,39 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { + var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions"); + var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope"); + var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register"); using (var nameLoc = context.GetLocal(context.Configuration.WellKnownTypes.String)) using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) - + using (var nameScopeLoc = context.GetLocal(findNameScope.ReturnType)) { - var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions"); - var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope"); - var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register"); var exit = codeGen.DefineLabel(); - var call = codeGen.DefineLabel(); + + // var target = {target} + codeGen.Stloc(targetLoc.Local); + // var name = {EmitName()} context.Emit(Value, codeGen, _property.PropertyType); - - codeGen - // var name = {EmitName()} - .Stloc(nameLoc.Local) - // var target = {target} - .Dup() - .Stloc(targetLoc.Local) - // {target}.Name = name - .Dup() + codeGen.Stloc(nameLoc.Local) + // target.Name = name + .Ldloc(targetLoc.Local) .Ldloc(nameLoc.Local) .EmitCall(_property.Setter) - // var scope = {target}.FindNameScope() + // var scope = target.FindNameScope() + .Ldloc(targetLoc.Local) .EmitCall(findNameScope) + .Stloc(nameScopeLoc.Local) // if({scope} != null) goto call; - .Dup() - .Brtrue(call) - // goto: exit - .Pop() - .Br(exit) - // call: {scope}.Register(name, target); - .MarkLabel(call) + .Ldloc(nameScopeLoc.Local) + .Brfalse(exit) + .Ldloc(nameScopeLoc.Local) .Ldloc(nameLoc.Local) .Ldloc(targetLoc.Local) .EmitCall(registerMethod) .MarkLabel(exit); } - return XamlIlNodeEmitResult.Void; + return XamlIlNodeEmitResult.Void(1); } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs index 3edc5e9d6e..7ba7b3b124 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs @@ -15,12 +15,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { if (node is XamlIlAstObjectNode on) { - foreach (var ch in on.Children) + for (var c =0; c< on.Children.Count;c++) { + var ch = on.Children[c]; if (ch is XamlIlAstXmlDirective d && d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Name") - return new XamlIlAstXamlPropertyValueNode(d, + + + on.Children[c] = new XamlIlAstXamlPropertyValueNode(d, new XamlIlAstNamePropertyReference(d, on.Type, "Name", on.Type), d.Values); } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs index 084462e31d..53047ca902 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs @@ -62,6 +62,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime else throw new ArgumentException("Attempt to apply binding to non-avalonia property " + property); } + else if (value is UnsetValueType unset) + { + if (property is AvaloniaProperty p) + ((AvaloniaObject)target).SetValue(p, unset); + //TODO: Investigate + //throw new ArgumentException("Attempt to apply UnsetValue to non-avalonia property " + property); + } else throw new ArgumentException("Don't know what to do with " + value.GetType()); } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github index 89bc4d268d..4e7544ea2d 160000 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github @@ -1 +1 @@ -Subproject commit 89bc4d268d7ee48d0907cec24175a99759d0bc4a +Subproject commit 4e7544ea2d152d22668b93c993d4965d5e9d515a diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 4921b7c9d7..ba5ffc4fa7 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -19,7 +19,7 @@ namespace Avalonia.Data /// /// Gets the collection of child bindings. /// - [Content] + [Content, AssignBinding] public IList Bindings { get; set; } = new List(); ///