From f14aac365bf6bc12b5d7133c22ce0ddd839fc0f2 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 15 Feb 2019 14:48:10 +0300 Subject: [PATCH 001/149] WIP --- .gitmodules | 3 + .../Pages/ButtonSpinnerPage.xaml.cs | 2 +- .../UsableDuringInitializationAttribute.cs | 10 ++ .../Controls/NameScopeExtensions.cs | 3 +- src/Avalonia.Visuals/Visual.cs | 2 + .../Avalonia.Markup.Xaml.csproj | 18 ++ .../AvaloniaTypeConverters.cs | 1 + .../AvaloniaXamlLoader.cs | 15 +- .../AvaloniaPropertyTypeConverter.cs | 4 +- .../Converters/BitmapTypeConverter.cs | 4 +- .../Converters/FontFamilyTypeConverter.cs | 2 +- .../Converters/IconTypeConverter.cs | 2 +- src/Markup/Avalonia.Markup.Xaml/Extensions.cs | 47 +++++ .../MarkupExtensions/BindingExtension.cs | 11 +- .../DynamicResourceExtension.cs | 16 +- .../MarkupExtensions/ResourceInclude.cs | 2 +- .../MarkupExtensions/StyleIncludeExtension.cs | 5 +- .../PortableXaml/TypeDescriptorExtensions.cs | 4 +- .../XamlIl/AvaloniaXamlIlRuntimeCompiler.cs | 160 ++++++++++++++++++ .../AvaloniaPropertyDescriptorEmitter.cs | 21 +++ .../AvaloniaXamlIlCompiler.cs | 61 +++++++ .../AvaloniaXamlIlLanguage.cs | 153 +++++++++++++++++ .../XamlIl/CompilerExtensions/README.md | 4 + .../Transformers/AddNameScopeRegistration.cs | 79 +++++++++ .../IgnoredDirectivesTransformer.cs | 27 +++ .../KnownPseudoMarkupExtensionsTransformer.cs | 26 +++ .../Transformers/XNameTransformer.cs | 33 ++++ .../IAvaloniaXamlIlParentStackProvider.cs | 9 + ...valoniaXamlIlXmlNamespaceInfoProviderV1.cs | 15 ++ .../XamlIl/Runtime/XamlIlRuntimeHelpers.cs | 121 +++++++++++++ .../Avalonia.Markup.Xaml/XamlIl/xamlil.github | 1 + 31 files changed, 827 insertions(+), 34 deletions(-) create mode 100644 src/Avalonia.Base/Metadata/UsableDuringInitializationAttribute.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Extensions.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaPropertyDescriptorEmitter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/README.md create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/KnownPseudoMarkupExtensionsTransformer.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlParentStackProvider.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs create mode 160000 src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github diff --git a/.gitmodules b/.gitmodules index 22c56307b0..22a241f120 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "nukebuild/Numerge"] path = nukebuild/Numerge url = https://github.com/kekekeks/Numerge.git +[submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"] + path = src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github + url = https://github.com/kekekeks/XamlIl.git diff --git a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs index 1f753ab3ea..c5042baccb 100644 --- a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs @@ -18,7 +18,7 @@ namespace ControlCatalog.Pages AvaloniaXamlLoader.Load(this); } - private void OnSpin(object sender, SpinEventArgs e) + public void OnSpin(object sender, SpinEventArgs e) { var spinner = (ButtonSpinner)sender; var txtBox = (TextBlock)spinner.Content; diff --git a/src/Avalonia.Base/Metadata/UsableDuringInitializationAttribute.cs b/src/Avalonia.Base/Metadata/UsableDuringInitializationAttribute.cs new file mode 100644 index 0000000000..753a96b9ce --- /dev/null +++ b/src/Avalonia.Base/Metadata/UsableDuringInitializationAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace Avalonia.Metadata +{ + [AttributeUsage(AttributeTargets.Class)] + public class UsableDuringInitializationAttribute : Attribute + { + + } +} diff --git a/src/Avalonia.Styling/Controls/NameScopeExtensions.cs b/src/Avalonia.Styling/Controls/NameScopeExtensions.cs index 491e4d71a7..991a97a614 100644 --- a/src/Avalonia.Styling/Controls/NameScopeExtensions.cs +++ b/src/Avalonia.Styling/Controls/NameScopeExtensions.cs @@ -71,10 +71,11 @@ namespace Avalonia.Controls { Contract.Requires(control != null); - return control.GetSelfAndLogicalAncestors() + var scope = control.GetSelfAndLogicalAncestors() .OfType() .Select(x => (x as INameScope) ?? NameScope.GetNameScope(x)) .FirstOrDefault(x => x != null); + return scope; } } } diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index f26c21d1b6..3360ba84c1 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -9,6 +9,7 @@ using Avalonia.Collections; using Avalonia.Data; using Avalonia.Logging; using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Rendering; using Avalonia.VisualTree; @@ -23,6 +24,7 @@ namespace Avalonia /// to render the control. To traverse the visual tree, use the /// extension methods defined in . /// + [UsableDuringInitialization] public class Visual : StyledElement, IVisual { /// diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 38d207a31d..4603d31fae 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -15,6 +15,7 @@ + @@ -50,8 +51,21 @@ + + + + + + + + + + + + + @@ -63,6 +77,10 @@ + + + + diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs index c30822aacb..2b6572e1a2 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaTypeConverters.cs @@ -29,6 +29,7 @@ namespace Avalonia.Markup.Xaml /// public static class AvaloniaTypeConverters { + // When adding item to that list make sure to modify AvaloniaXamlIlLanguage private static Dictionary _converters = new Dictionary() { { typeof(AvaloniaList<>), typeof(AvaloniaListConverter<>) }, diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index a825deeae3..dd413ee10f 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -13,6 +13,7 @@ using System.Reflection; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; +using Avalonia.Markup.Xaml.XamlIl; namespace Avalonia.Markup.Xaml { @@ -23,6 +24,8 @@ namespace Avalonia.Markup.Xaml { private readonly AvaloniaXamlSchemaContext _context = GetContext(); + public bool EnforceCompilerForRuntimeXaml { get; set; } = true; + public bool IsDesignMode { get => _context.IsDesignMode; @@ -137,13 +140,13 @@ namespace Avalonia.Markup.Xaml using (var stream = asset.stream) { var absoluteUri = uri.IsAbsoluteUri ? uri : new Uri(baseUri, uri); - try + //try { return Load(stream, asset.assembly, rootInstance, absoluteUri); } - catch (Exception e) + //catch (Exception e) { - throw new XamlLoadException("Error loading xaml at " + absoluteUri + ": " + e.Message, e); + //throw new XamlLoadException("Error loading xaml at " + absoluteUri + ": " + e.Message, e); } } } @@ -179,6 +182,12 @@ namespace Avalonia.Markup.Xaml /// The loaded object. public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null) { + if (EnforceCompilerForRuntimeXaml) + { + return AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri); + } + + var readerSettings = new XamlXmlReaderSettings() { BaseUri = uri, diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs index 8a0ba64582..18a7fe9ab6 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -28,8 +28,8 @@ namespace Avalonia.Markup.Xaml.Converters var parser = new PropertyParser(); var (ns, owner, propertyName) = parser.Parse(new CharacterReader(((string)value).AsSpan())); var ownerType = TryResolveOwnerByName(context, ns, owner); - var targetType = context.GetFirstAmbientValue()?.TargetType ?? - context.GetFirstAmbientValue + + + + + + + + + + + + + + + + + + + From 9ec7c7ce4bf09825ea0682961b1277b0c6ed5457 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 11 Apr 2019 00:15:30 +0100 Subject: [PATCH 016/149] sensible close delay. --- src/Avalonia.Controls/Notifications/NotificationManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Notifications/NotificationManager.cs b/src/Avalonia.Controls/Notifications/NotificationManager.cs index 8e6ad0a90b..236d67a35f 100644 --- a/src/Avalonia.Controls/Notifications/NotificationManager.cs +++ b/src/Avalonia.Controls/Notifications/NotificationManager.cs @@ -26,7 +26,7 @@ namespace Avalonia.Controls.Notifications } if (expirationTime == null) - expirationTime = TimeSpan.FromSeconds(25); + expirationTime = TimeSpan.FromSeconds(5); if (areaName == string.Empty && _window == null) { From 8283f3bca7c15a66fcb30bbb255a93c833b23a29 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 12 Apr 2019 00:43:14 +0800 Subject: [PATCH 017/149] Add some bubble notification animations + make IsClosing a direct property. --- .../Notifications/Notification.cs | 17 +++++++++-- .../NotificationArea.xaml | 28 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Notifications/Notification.cs b/src/Avalonia.Controls/Notifications/Notification.cs index c7cd176513..fbf28c07e5 100644 --- a/src/Avalonia.Controls/Notifications/Notification.cs +++ b/src/Avalonia.Controls/Notifications/Notification.cs @@ -2,13 +2,14 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Avalonia.Controls.Primitives; +using Avalonia.Data; using Avalonia.Interactivity; namespace Avalonia.Controls.Notifications { public class Notification : ContentControl { - private TimeSpan _closingAnimationTime = TimeSpan.Zero; + private TimeSpan _closingAnimationTime = TimeSpan.FromSeconds(0.25); static Notification() { @@ -42,7 +43,19 @@ namespace Avalonia.Controls.Notifications }); } - public bool IsClosing { get; set; } + private bool _isClosing; + + /// + /// Determines if the notification is already closing. + /// + public bool IsClosing + { + get { return _isClosing; } + private set { SetAndRaise(IsClosingProperty, ref _isClosing, value); } + } + + public static readonly DirectProperty IsClosingProperty = + AvaloniaProperty.RegisterDirect(nameof(IsClosing), o => o.IsClosing); /// /// Defines the event. diff --git a/src/Avalonia.Themes.Default/NotificationArea.xaml b/src/Avalonia.Themes.Default/NotificationArea.xaml index 3d3f4b8c20..2b2dd2a797 100644 --- a/src/Avalonia.Themes.Default/NotificationArea.xaml +++ b/src/Avalonia.Themes.Default/NotificationArea.xaml @@ -28,6 +28,34 @@ + + + + + + + + + + + + + + + + From 6fbe1c2180ef45a940e193f1b4637e64eaab80ed Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 12 Apr 2019 19:35:31 +0800 Subject: [PATCH 019/149] More animations shenanigans. --- .../LayoutTransformControl.cs | 1 + .../Notifications/Notification.cs | 32 ++++++++++++++--- .../NotificationArea.xaml | 34 ++++++++++++------- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/Avalonia.Controls/LayoutTransformControl.cs b/src/Avalonia.Controls/LayoutTransformControl.cs index 950d4f34da..482cfc5320 100644 --- a/src/Avalonia.Controls/LayoutTransformControl.cs +++ b/src/Avalonia.Controls/LayoutTransformControl.cs @@ -51,6 +51,7 @@ namespace Avalonia.Controls { if (TransformRoot == null || LayoutTransform == null) { + LayoutTransform = RenderTransform; return base.ArrangeOverride(finalSize); } diff --git a/src/Avalonia.Controls/Notifications/Notification.cs b/src/Avalonia.Controls/Notifications/Notification.cs index 54de4bcce7..c75e805892 100644 --- a/src/Avalonia.Controls/Notifications/Notification.cs +++ b/src/Avalonia.Controls/Notifications/Notification.cs @@ -9,11 +9,12 @@ namespace Avalonia.Controls.Notifications { public class Notification : ContentControl { - private TimeSpan _closingAnimationTime = TimeSpan.FromSeconds(1); + // private TimeSpan _closingAnimationTime = TimeSpan.FromSeconds(1); static Notification() { //CloseOnClickProperty.Changed.AddClassHandler //TODO Binding + [AssignBinding] public virtual IBinding Binding { get diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs index 8a237f180f..d9345738fc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleIncludeExtension.cs @@ -18,7 +18,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions { } - public override object ProvideValue(IServiceProvider serviceProvider) + public override object ProvideValue(IServiceProvider serviceProvider) => ProvideTypedValue(serviceProvider); + public IStyle ProvideTypedValue(IServiceProvider serviceProvider) { return new StyleInclude(serviceProvider.GetContextBaseUri()) { Source = Source }; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 94ebb138eb..0de9e7942b 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -24,7 +24,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions var bindingType = typeSystem.GetType("Avalonia.Data.IBinding"); var rv = new XamlIlLanguageTypeMappings(typeSystem) { - SupportInitialize = typeSystem.GetType("Avalonia.ISupportInitialize"), + SupportInitialize = typeSystem.GetType("System.ComponentModel.ISupportInitialize"), XmlnsAttributes = { typeSystem.GetType("Avalonia.Metadata.XmlnsDefinitionAttribute"), diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs index 4569accb74..1a646e50c2 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs @@ -35,12 +35,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers throw new XamlIlParseException("Selector property should be a text node", node); var selectorType = pn.Property.GetClrProperty().PropertyType; - + var initialNode = new XamlIlSelectorInitialNode(node, selectorType); XamlIlSelectorNode Create(IEnumerable syntax, Func typeResolver) { - XamlIlSelectorNode result = new XamlIlSelectorInitialNode(node, selectorType); - + XamlIlSelectorNode result = initialNode; + XamlIlOrSelectorNode results = null; foreach (var i in syntax) { switch (i) @@ -93,12 +93,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers case SelectorGrammar.NotSyntax not: result = new XamlIlNotSelector(result, Create(not.Argument, typeResolver)); break; + case SelectorGrammar.CommaSyntax comma: + if (results == null) + results = new XamlIlOrSelectorNode(node, selectorType); + results.Add(result); + result = initialNode; + break; default: throw new XamlIlParseException($"Unsupported selector grammar '{i.GetType()}'.", node); } } - return result; + return results ?? result; } IEnumerable parsed; @@ -126,7 +132,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers abstract class XamlIlSelectorNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode { - public XamlIlSelectorNode Previous { get; } + protected XamlIlSelectorNode Previous { get; } public abstract IXamlIlType TargetType { get; } public XamlIlSelectorNode(XamlIlSelectorNode previous, @@ -288,4 +294,44 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers && m.Parameters[2].Equals(context.Configuration.WellKnownTypes.Object)); } } + + class XamlIlOrSelectorNode : XamlIlSelectorNode + { + List _selectors = new List(); + public XamlIlOrSelectorNode(IXamlIlLineInfo info, IXamlIlType selectorType) : base(null, info, selectorType) + { + } + + public void Add(XamlIlSelectorNode node) + { + _selectors.Add(node); + } + + //TODO: actually find the type + public override IXamlIlType TargetType => _selectors.FirstOrDefault()?.TargetType; + protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + { + if (_selectors.Count == 0) + throw new XamlIlLoadException("Invalid selector count", this); + if (_selectors.Count == 1) + { + _selectors[0].Emit(context, codeGen); + return; + } + var listType = context.Configuration.TypeSystem.FindType("System.Collections.Generic.List`1") + .MakeGenericType(base.Type.GetClrType()); + var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType()); + codeGen + .Newobj(listType.FindConstructor()); + foreach (var s in _selectors) + { + codeGen.Dup(); + context.Emit(s, codeGen, Type.GetClrType()); + codeGen.EmitCall(add, true); + } + + EmitCall(context, codeGen, + m => m.Name == "Or" && m.Parameters.Count == 1 && m.Parameters[0].Name.StartsWith("IReadOnlyList")); + } + } } From 29746bbed1f158251f68562687541624ce249390 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Thu, 18 Apr 2019 23:57:24 +0800 Subject: [PATCH 026/149] Add "UseRenderTransform" property for LayoutTransformControl. Wire up the style animation to use that property. --- .../LayoutTransformControl.cs | 49 +++++++++++++++++++ .../NotificationArea.xaml | 38 +++++++------- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Controls/LayoutTransformControl.cs b/src/Avalonia.Controls/LayoutTransformControl.cs index 482cfc5320..07372eb714 100644 --- a/src/Avalonia.Controls/LayoutTransformControl.cs +++ b/src/Avalonia.Controls/LayoutTransformControl.cs @@ -20,6 +20,9 @@ namespace Avalonia.Controls public static readonly AvaloniaProperty LayoutTransformProperty = AvaloniaProperty.Register(nameof(LayoutTransform)); + public static readonly AvaloniaProperty UseRenderTransformProperty = + AvaloniaProperty.Register(nameof(LayoutTransform)); + static LayoutTransformControl() { ClipToBoundsProperty.OverrideDefaultValue(true); @@ -29,6 +32,7 @@ namespace Avalonia.Controls ChildProperty.Changed .AddClassHandler(x => x.OnChildChanged); + UseRenderTransformProperty.Changed.AddClassHandler(x => x.OnUseRenderTransformPropertyChanged); } /// @@ -40,6 +44,15 @@ namespace Avalonia.Controls set { SetValue(LayoutTransformProperty, value); } } + /// + /// Utilize the for layout transforms. + /// + public bool UseRenderTransform + { + get { return GetValue(UseRenderTransformProperty); } + set { SetValue(UseRenderTransformProperty, value); } + } + public IControl TransformRoot => Child; /// @@ -134,6 +147,42 @@ namespace Avalonia.Controls return transformedDesiredSize; } + IDisposable _renderTransformChangedEvent; + + private void OnUseRenderTransformPropertyChanged(AvaloniaPropertyChangedEventArgs e) + { + // HACK: In theory, this method and the UseRenderTransform shouldn't exist but + // it's hard to animate this particular control with style animations without + // PropertyPaths. + // + // So until we get that implemented, we'll stick on this not-so-good + // workaround. + + var target = e.Sender as LayoutTransformControl; + var shouldUseRenderTransform = (bool)e.NewValue; + if (target != null) + { + if (shouldUseRenderTransform) + { + _renderTransformChangedEvent = RenderTransformProperty.Changed + .Subscribe( + (x) => + { + var target2 = x.Sender as LayoutTransformControl; + if (target2 != null) + { + target2.LayoutTransform = target2.RenderTransform; + } + }); + } + else + { + _renderTransformChangedEvent?.Dispose(); + LayoutTransform = null; + } + } + } + private void OnChildChanged(AvaloniaPropertyChangedEventArgs e) { if (null != TransformRoot) diff --git a/src/Avalonia.Themes.Default/NotificationArea.xaml b/src/Avalonia.Themes.Default/NotificationArea.xaml index a6143e1a30..13adbbc0b6 100644 --- a/src/Avalonia.Themes.Default/NotificationArea.xaml +++ b/src/Avalonia.Themes.Default/NotificationArea.xaml @@ -30,20 +30,18 @@ - - - - + + + + + - + @@ -63,25 +61,27 @@ - + + "; + var xaml = ""; var loader = new AvaloniaXamlLoader(); var style = (Style)loader.Load(xaml); var setter = (Setter)(style.Setters.First()); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs index d2247e3d02..359d2521e0 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs @@ -162,6 +162,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml [Fact] public void Non_Attached_Property_With_Attached_Property_Syntax_Throws() { + // 1) It has been allowed in AvaloniaObject.SetValue for ages + // 2) There is no way to know if AddOwner was called in compile-time + if (!AvaloniaXamlLoader.UseLegacyXamlLoader) + return; var xaml = @""; From 2b7e3db469115aac3d24ab6f4f9f8e1dc8374e3a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 22 Apr 2019 15:12:44 +0100 Subject: [PATCH 054/149] correctly set notification manager properties. --- src/Avalonia.Controls/TopLevel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index f29da746ab..732363466a 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -103,7 +103,7 @@ namespace Avalonia.Controls PlatformImpl = impl; - _localNotificationManager = new NotificationManager(); + LocalNotificationManager = new NotificationManager(); dependencyResolver = dependencyResolver ?? AvaloniaLocator.Current; var styler = TryGetService(dependencyResolver); @@ -118,7 +118,7 @@ namespace Avalonia.Controls if(_systemNotificationManager == null) { - _systemNotificationManager = _localNotificationManager; + SystemNotificationManager = _localNotificationManager; } Renderer = impl.CreateRenderer(this); From c021bf717dc4d3d055857a3bf0f96d5f3895e1f5 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 22 Apr 2019 17:21:25 +0300 Subject: [PATCH 055/149] Disable Xamarin projects on CI --- dirs.proj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dirs.proj b/dirs.proj index 03fa51b3c4..b78b38d51d 100644 --- a/dirs.proj +++ b/dirs.proj @@ -8,6 +8,7 @@ + From 223e929ca37f64ffc6afee0f7ca0ba6a5e6b54b8 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 22 Apr 2019 18:04:02 +0300 Subject: [PATCH 056/149] Update dirs.proj --- dirs.proj | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dirs.proj b/dirs.proj index b78b38d51d..4939a158bb 100644 --- a/dirs.proj +++ b/dirs.proj @@ -8,16 +8,13 @@ - + - - ---> From 8a877edce01b9cf9d3e5b9419f2fce8023e3a066 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 22 Apr 2019 21:37:33 +0300 Subject: [PATCH 057/149] Why was it here in the first place? --- src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 610d489d34..35d34d83a8 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -92,8 +92,5 @@ - - - From 63b7815fc06b2d87e1951ab898cd6c224c9ca211 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 23 Apr 2019 08:16:30 +0300 Subject: [PATCH 058/149] Don't overwrite dll with pdb --- src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs index 97f7af86b9..61303dbbfe 100644 --- a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs +++ b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs @@ -41,7 +41,7 @@ namespace Avalonia.Build.Tasks { File.Copy(input, OutputPath, true); if(File.Exists(inputPdb)) - File.Copy(inputPdb, OutputPath, true); + File.Copy(inputPdb, outputPdb, true); } return true; } From d52afe7a96e732a0f12b22e64d1acf3ac2cd0eba Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 23 Apr 2019 09:48:51 +0300 Subject: [PATCH 059/149] Fixed Avalonia.Diagnostics --- build/EmbedXaml.props | 6 +++--- samples/ControlCatalog/App.xaml | 2 +- .../Avalonia.Controls.DataGrid.csproj | 2 ++ src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj | 1 + src/Avalonia.Diagnostics/DevTools.xaml | 4 +++- src/Avalonia.Diagnostics/DevTools.xaml.cs | 6 ++++++ src/Avalonia.Diagnostics/Views/EventsView.xaml | 3 ++- src/Avalonia.Diagnostics/Views/TreePageView.xaml | 4 +++- src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj | 5 +++-- 9 files changed, 24 insertions(+), 9 deletions(-) diff --git a/build/EmbedXaml.props b/build/EmbedXaml.props index 219ffb2e42..dba14521ab 100644 --- a/build/EmbedXaml.props +++ b/build/EmbedXaml.props @@ -4,8 +4,8 @@ %(Filename) - + Designer - + - \ No newline at end of file + diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index d20e0100a0..2f6d25c089 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -4,7 +4,7 @@ - + \ No newline at end of file + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml index fd93c4a468..04db8fd2dd 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml @@ -1,8 +1,9 @@ \ No newline at end of file + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlClassWithPrecompiledXaml.xaml b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlClassWithPrecompiledXaml.xaml new file mode 100644 index 0000000000..ac2f75b893 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlClassWithPrecompiledXaml.xaml @@ -0,0 +1,6 @@ + + + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/XamlIlBugTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs similarity index 66% rename from tests/Avalonia.Markup.Xaml.UnitTests/XamlIlBugTests.cs rename to tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index 839cd07755..f33054e5ce 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/XamlIlBugTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -7,7 +7,7 @@ using Xunit; namespace Avalonia.Markup.Xaml.UnitTests { - public class XamlIlBugTests + public class XamlIlTests { [Fact] public void Binding_Button_IsPressed_ShouldWork() @@ -34,7 +34,24 @@ namespace Avalonia.Markup.Xaml.UnitTests Assert.Equal(1, parsed.Transitions.Count); Assert.Equal(Visual.OpacityProperty, parsed.Transitions[0].Property); } - + + [Fact] + public void Parser_Should_Override_Precompiled_Xaml() + { + var precompiled = new XamlIlClassWithPrecompiledXaml(); + Assert.Equal(Brushes.Red, precompiled.Background); + Assert.Equal(1, precompiled.Opacity); + var loaded = (XamlIlClassWithPrecompiledXaml)AvaloniaXamlLoader.Parse(@" + + +"); + Assert.Equal(loaded.Opacity, 0); + Assert.Null(loaded.Background); + + } } @@ -50,4 +67,8 @@ namespace Avalonia.Markup.Xaml.UnitTests } } + public class XamlIlClassWithPrecompiledXaml : UserControl + { + } + } From ddbe82652f673f7b6bc720562d59d2937eaca5bc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 May 2019 20:32:15 +0100 Subject: [PATCH 080/149] allow binding of notification managers --- src/Avalonia.Controls/TopLevel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 475fc5a927..55b1dbb1f6 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -52,13 +52,13 @@ namespace Avalonia.Controls /// Defines the property. /// public static readonly DirectProperty LocalNotificationManagerProperty = - AvaloniaProperty.RegisterDirect(nameof(LocalNotificationManager), o => o.LocalNotificationManager); + AvaloniaProperty.RegisterDirect(nameof(LocalNotificationManager), o => o.LocalNotificationManager, (o, v) => o.LocalNotificationManager = v); /// /// Defines the property. /// public static readonly DirectProperty SystemNotificationManagerProperty = - AvaloniaProperty.RegisterDirect(nameof(SystemNotificationManager), o => o.SystemNotificationManager); + AvaloniaProperty.RegisterDirect(nameof(SystemNotificationManager), o => o.SystemNotificationManager, (o, v) => o.SystemNotificationManager = v); private readonly IInputManager _inputManager; private readonly IAccessKeyHandler _accessKeyHandler; From c7be61a66decdeb5cc44d8b543fcd9d03fd79025 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 May 2019 20:34:04 +0100 Subject: [PATCH 081/149] children of adorner layer that are not adorning controls can arrange with all available size. --- src/Avalonia.Controls/Primitives/AdornerLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index 8a724926e8..d198570909 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -64,7 +64,7 @@ namespace Avalonia.Controls.Primitives } else { - child.Arrange(new Rect(child.DesiredSize)); + child.Arrange(new Rect(finalSize)); } } From 147eb272aa156897483d3d74a7ffa9cf4336f8a4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 May 2019 20:34:15 +0100 Subject: [PATCH 082/149] notification area to fill window --- src/Avalonia.Controls/Notifications/NotificationArea.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Notifications/NotificationArea.cs b/src/Avalonia.Controls/Notifications/NotificationArea.cs index c641e09b02..81b3c8fd59 100644 --- a/src/Avalonia.Controls/Notifications/NotificationArea.cs +++ b/src/Avalonia.Controls/Notifications/NotificationArea.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Linq; using System.Threading.Tasks; @@ -39,6 +39,9 @@ namespace Avalonia.Controls.Notifications PseudoClass(PositionProperty, x => x == NotificationPosition.TopRight, ":topright"); PseudoClass(PositionProperty, x => x == NotificationPosition.BottomLeft, ":bottomleft"); PseudoClass(PositionProperty, x => x == NotificationPosition.BottomRight, ":bottomright"); + + HorizontalAlignmentProperty.OverrideDefaultValue(Layout.HorizontalAlignment.Stretch); + VerticalAlignmentProperty.OverrideDefaultValue(Layout.VerticalAlignment.Stretch); } protected override void OnTemplateApplied(TemplateAppliedEventArgs e) From f09228cc483d015bfc747d0efd22b6bb889dc7e6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 May 2019 20:34:36 +0100 Subject: [PATCH 083/149] simplify the usage of notification manager inside main window. --- .../ControlCatalog/ViewModels/MainWindowViewModel.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index 7a02f5a45c..f66625ea82 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; @@ -24,19 +24,19 @@ namespace ControlCatalog.ViewModels await Task.Delay(5000); - Application.Current.MainWindow.LocalNotificationManager.Show(new NotificationViewModel { Title = "Warning", Message = "Please save your work before closing." }); + NotificationManager.Show(new NotificationViewModel { Title = "Warning", Message = "Please save your work before closing." }); await Task.Delay(1500); - Application.Current.MainWindow.LocalNotificationManager.Show(new NotificationContent { Message = "Test2", Type = NotificationType.Error }); + NotificationManager.Show(new NotificationContent { Message = "Test2", Type = NotificationType.Error }); await Task.Delay(2000); - Application.Current.MainWindow.LocalNotificationManager.Show(new NotificationContent { Message = "Test3", Type = NotificationType.Warning }); + NotificationManager.Show(new NotificationContent { Message = "Test3", Type = NotificationType.Warning }); await Task.Delay(2500); - Application.Current.MainWindow.LocalNotificationManager.Show(new NotificationContent { Message = "Test4", Type = NotificationType.Success }); + NotificationManager.Show(new NotificationContent { Message = "Test4", Type = NotificationType.Success }); await Task.Delay(500); - Application.Current.MainWindow.LocalNotificationManager.Show("Test5"); + NotificationManager.Show("Test5"); }); } From f8f5610b8cec96c3ede86ffd4baeb9fe0c0d0f62 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 May 2019 21:58:24 +0100 Subject: [PATCH 084/149] polish notifications --- .../ViewModels/MainWindowViewModel.cs | 19 ++----- .../ViewModels/NotificationViewModel.cs | 15 ++++-- .../Views/NotificationView.xaml | 8 +-- .../Notifications/INotificationManager.cs | 2 + .../Notifications/Notification.cs | 10 ++-- .../Notifications/NotificationArea.cs | 9 ++-- .../Notifications/NotificationContent.cs | 6 +++ src/Avalonia.Controls/TopLevel.cs | 8 +-- .../NotificationArea.xaml | 51 ++++++++----------- 9 files changed, 64 insertions(+), 64 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs index f66625ea82..3c9cb166e8 100644 --- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs +++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs @@ -1,12 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; -using Avalonia; using Avalonia.Controls.Notifications; using Avalonia.Diagnostics.ViewModels; using Avalonia.Threading; -using ReactiveUI; namespace ControlCatalog.ViewModels { @@ -14,26 +9,20 @@ namespace ControlCatalog.ViewModels { public MainWindowViewModel() { - this.WhenAnyValue(x => x.NotificationManager).Subscribe(x => - { - - }); - Dispatcher.UIThread.InvokeAsync(async () => { await Task.Delay(5000); - - NotificationManager.Show(new NotificationViewModel { Title = "Warning", Message = "Please save your work before closing." }); + NotificationManager.Show(new NotificationViewModel (NotificationManager) { Title = "Warning", Message = "Did you know that Avalonia now supports Notifications?" }); await Task.Delay(1500); - NotificationManager.Show(new NotificationContent { Message = "Test2", Type = NotificationType.Error }); + NotificationManager.Show(new NotificationContent { Title= "Title", Message = "Test2", Type = NotificationType.Error }); await Task.Delay(2000); - NotificationManager.Show(new NotificationContent { Message = "Test3", Type = NotificationType.Warning }); + NotificationManager.Show(new NotificationContent { Title = "Title", Message = "Test3", Type = NotificationType.Warning }); await Task.Delay(2500); - NotificationManager.Show(new NotificationContent { Message = "Test4", Type = NotificationType.Success }); + NotificationManager.Show(new NotificationContent { Title = "Title", Message = "Test4", Type = NotificationType.Success }); await Task.Delay(500); NotificationManager.Show("Test5"); diff --git a/samples/ControlCatalog/ViewModels/NotificationViewModel.cs b/samples/ControlCatalog/ViewModels/NotificationViewModel.cs index 8a82a82447..9e60700e71 100644 --- a/samples/ControlCatalog/ViewModels/NotificationViewModel.cs +++ b/samples/ControlCatalog/ViewModels/NotificationViewModel.cs @@ -7,18 +7,25 @@ namespace ControlCatalog.ViewModels { public class NotificationViewModel { - public NotificationViewModel() + public NotificationViewModel(INotificationManager manager) { - OKCommand = ReactiveCommand.Create(() => + YesCommand = ReactiveCommand.Create(() => { - Application.Current.MainWindow.LocalNotificationManager.Show("Notification Accepted"); + manager.Show(new NotificationContent { Title = "Avalonia Notifications", Message = "Start adding notifications to your app today." }); + }); + + NoCommand = ReactiveCommand.Create(() => + { + manager.Show(new NotificationContent { Title = "Avalonia Notifications", Message = "Start adding notifications to your app today. To find out more visit..." }); }); } public string Title { get; set; } public string Message { get; set; } - public ReactiveCommand OKCommand { get; } + public ReactiveCommand YesCommand { get; } + + public ReactiveCommand NoCommand { get; } } } diff --git a/samples/ControlCatalog/Views/NotificationView.xaml b/samples/ControlCatalog/Views/NotificationView.xaml index be0a613c57..9ba9badd80 100644 --- a/samples/ControlCatalog/Views/NotificationView.xaml +++ b/samples/ControlCatalog/Views/NotificationView.xaml @@ -8,10 +8,10 @@ - -