From fee5b4e594ab1c17e85ebe71cd2ebfbb70e9b92c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 24 Feb 2018 21:53:42 +0300 Subject: [PATCH 001/101] Support default clr-namespace when loading XAML from Uri or previewer --- samples/ControlCatalog/MainWindow.xaml | 2 +- src/Avalonia.Base/Platform/IAssetLoader.cs | 2 ++ .../DesignWindowLoader.cs | 4 ++- .../DesignerAssist.cs | 2 +- .../Avalonia.Markup.Xaml.csproj | 1 - .../AvaloniaXamlLoader.cs | 11 -------- .../AvaloniaXamlLoaderPortableXaml.cs | 27 ++++++++++++------- src/Shared/PlatformSupport/AssetLoader.cs | 20 ++++++++++++-- tests/Avalonia.UnitTests/MockAssetLoader.cs | 5 ++++ 9 files changed, 48 insertions(+), 26 deletions(-) delete mode 100644 src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index f39beced1a..7029273a84 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -1,6 +1,6 @@  + xmlns:local="clr-namespace:ControlCatalog"> \ No newline at end of file diff --git a/src/Avalonia.Base/Platform/IAssetLoader.cs b/src/Avalonia.Base/Platform/IAssetLoader.cs index eae8db5a14..32008ffd07 100644 --- a/src/Avalonia.Base/Platform/IAssetLoader.cs +++ b/src/Avalonia.Base/Platform/IAssetLoader.cs @@ -43,5 +43,7 @@ namespace Avalonia.Platform /// The resource was not found. /// Stream Open(Uri uri, Uri baseUri = null); + + Tuple OpenWithAssembly(Uri uri, Uri baseUri = null); } } diff --git a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs index 9ad2a216b4..d9cac47bf3 100644 --- a/src/Avalonia.DesignerSupport/DesignWindowLoader.cs +++ b/src/Avalonia.DesignerSupport/DesignWindowLoader.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using Avalonia.Controls; using Avalonia.Controls.Platform; @@ -30,7 +31,8 @@ namespace Avalonia.DesignerSupport new Uri("resm:Fake.xaml?assembly=" + Path.GetFileNameWithoutExtension(assemblyPath)); } - var loaded = loader.Load(stream, null, baseUri); + var localAsm = assemblyPath != null ? Assembly.LoadFile(assemblyPath) : null; + var loaded = loader.Load(stream, localAsm, null, baseUri); var styles = loaded as Styles; if (styles != null) { diff --git a/src/Avalonia.DesignerSupport/DesignerAssist.cs b/src/Avalonia.DesignerSupport/DesignerAssist.cs index 65c4c14d83..f6f704b838 100644 --- a/src/Avalonia.DesignerSupport/DesignerAssist.cs +++ b/src/Avalonia.DesignerSupport/DesignerAssist.cs @@ -24,7 +24,7 @@ namespace Avalonia.DesignerSupport var loader = new AvaloniaXamlLoader(); var baseLight = (IStyle)loader.Load( - new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")); + new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"), null); Styles.Add(baseLight); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 0ce2a1a992..62c23543fd 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -30,7 +30,6 @@ Properties\SharedAssemblyInfo.cs - diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs deleted file mode 100644 index 3142d954ff..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Avalonia.Markup.Xaml -{ - public class AvaloniaXamlLoader : AvaloniaXamlLoaderPortableXaml - { - public static object Parse(string xaml) - => new AvaloniaXamlLoader().Load(xaml); - - public static T Parse(string xaml) - => (T)Parse(xaml); - } -} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs index de2a79c54e..e057aa3b53 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml /// /// Loads XAML for a avalonia application. /// - public class AvaloniaXamlLoaderPortableXaml + public class AvaloniaXamlLoader { private readonly AvaloniaXamlSchemaContext _context = GetContext(); @@ -40,7 +40,7 @@ namespace Avalonia.Markup.Xaml /// /// Initializes a new instance of the class. /// - public AvaloniaXamlLoaderPortableXaml() + public AvaloniaXamlLoader() { } @@ -89,7 +89,7 @@ namespace Avalonia.Markup.Xaml initialize?.BeginInit(); try { - return Load(stream, rootInstance, uri); + return Load(stream, type.Assembly, rootInstance, uri); } finally { @@ -125,11 +125,12 @@ namespace Avalonia.Markup.Xaml "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); } - using (var stream = assetLocator.Open(uri, baseUri)) + var asset = assetLocator.OpenWithAssembly(uri, baseUri); + using (var stream = asset.Item2) { try { - return Load(stream, rootInstance, uri); + return Load(stream, asset.Item1, rootInstance, uri); } catch (Exception e) { @@ -147,17 +148,18 @@ namespace Avalonia.Markup.Xaml /// Loads XAML from a string. /// /// The string containing the XAML. + /// Default assembly for clr-namespace: /// /// The optional instance into which the XAML should be loaded. /// /// The loaded object. - public object Load(string xaml, object rootInstance = null) + public object Load(string xaml, Assembly localAssembly, object rootInstance = null) { Contract.Requires(xaml != null); using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml))) { - return Load(stream, rootInstance); + return Load(stream, localAssembly, rootInstance); } } @@ -165,17 +167,18 @@ namespace Avalonia.Markup.Xaml /// Loads XAML from a stream. /// /// The stream containing the XAML. + /// Default assembly for clr-namespace /// /// The optional instance into which the XAML should be loaded. /// /// The URI of the XAML /// The loaded object. - public object Load(Stream stream, object rootInstance = null, Uri uri = null) + public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null) { var readerSettings = new XamlXmlReaderSettings() { BaseUri = uri, - LocalAssembly = rootInstance?.GetType().GetTypeInfo().Assembly + LocalAssembly = localAssembly }; var reader = new XamlXmlReader(stream, _context, readerSettings); @@ -223,5 +226,11 @@ namespace Avalonia.Markup.Xaml yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); } + + public static object Parse(string xaml, Assembly localAssembly = null) + => new AvaloniaXamlLoader().Load(xaml, localAssembly); + + public static T Parse(string xaml, Assembly localAssembly) + => (T)Parse(xaml, localAssembly); } } \ No newline at end of file diff --git a/src/Shared/PlatformSupport/AssetLoader.cs b/src/Shared/PlatformSupport/AssetLoader.cs index 4287fd0b9e..eb9b04fe54 100644 --- a/src/Shared/PlatformSupport/AssetLoader.cs +++ b/src/Shared/PlatformSupport/AssetLoader.cs @@ -67,7 +67,20 @@ namespace Avalonia.Shared.PlatformSupport /// /// The resource was not found. /// - public Stream Open(Uri uri, Uri baseUri = null) + public Stream Open(Uri uri, Uri baseUri = null) => OpenWithAssembly(uri, baseUri).Item2; + + /// + /// Opens the resource with the requested URI. + /// + /// The URI. + /// + /// A base URI to use if is relative. + /// + /// An assembly (optional) and a stream containing the resource contents. + /// + /// The resource was not found. + /// + public Tuple OpenWithAssembly(Uri uri, Uri baseUri = null) { var asset = GetAsset(uri, baseUri); @@ -76,7 +89,7 @@ namespace Avalonia.Shared.PlatformSupport throw new FileNotFoundException($"The resource {uri} could not be found."); } - return asset.GetStream(); + return Tuple.Create(asset.Assembly, asset.GetStream()); } private IAssetDescriptor GetAsset(Uri uri, Uri baseUri) @@ -162,6 +175,7 @@ namespace Avalonia.Shared.PlatformSupport private interface IAssetDescriptor { Stream GetStream(); + Assembly Assembly { get; } } private class AssemblyResourceDescriptor : IAssetDescriptor @@ -179,6 +193,8 @@ namespace Avalonia.Shared.PlatformSupport { return _asm.GetManifestResourceStream(_name); } + + public Assembly Assembly => _asm; } private class AssemblyDescriptor diff --git a/tests/Avalonia.UnitTests/MockAssetLoader.cs b/tests/Avalonia.UnitTests/MockAssetLoader.cs index 5cff20c6a1..3cf7370f1f 100644 --- a/tests/Avalonia.UnitTests/MockAssetLoader.cs +++ b/tests/Avalonia.UnitTests/MockAssetLoader.cs @@ -27,6 +27,11 @@ namespace Avalonia.UnitTests { return new MemoryStream(Encoding.UTF8.GetBytes(_assets[uri])); } + + public Tuple OpenWithAssembly(Uri uri, Uri baseUri = null) + { + return Tuple.Create((Assembly) null, Open(uri, baseUri)); + } public void SetDefaultAssembly(Assembly asm) { From 7b4cd4f96d1d5afad14a7eddbb79069bada4dbc7 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 24 Mar 2018 15:59:44 +0100 Subject: [PATCH 002/101] Modify/add tests for non-registered properties. We should change to the behavior of other XAML frameworks where non-registered `AvaloniaProperty`s can be set on `AvaloniaObject`s via code. --- .../AvaloniaObjectTests_Binding.cs | 9 ++- .../AvaloniaObjectTests_GetValue.cs | 4 +- .../AvaloniaObjectTests_SetValue.cs | 39 +++++++++-- .../Xaml/AttachedPropertyOwner.cs | 14 ++++ .../Xaml/BasicTests.cs | 19 ++++++ .../Xaml/BindingTests.cs | 66 +++++++++++++++++++ .../Xaml/TestControl.cs | 17 +++++ 7 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/AttachedPropertyOwner.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TestControl.cs diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs index c75150ca6d..80cd52d529 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs @@ -92,14 +92,13 @@ namespace Avalonia.Base.UnitTests } [Fact] - public void Bind_Throws_Exception_For_Unregistered_Property() + public void Bind_Does_Not_Throw_Exception_For_Unregistered_Property() { Class1 target = new Class1(); - Assert.Throws(() => - { - target.Bind(Class2.BarProperty, Observable.Return("foo")); - }); + target.Bind(Class2.BarProperty, Observable.Never().StartWith("foo")); + + Assert.Equal("foo", target.GetValue(Class2.BarProperty)); } [Fact] diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetValue.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetValue.cs index 98f7289228..740023fd37 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetValue.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetValue.cs @@ -46,11 +46,11 @@ namespace Avalonia.Base.UnitTests } [Fact] - public void GetValue_Throws_Exception_For_Unregistered_Property() + public void GetValue_Doesnt_Throw_Exception_For_Unregistered_Property() { var target = new Class3(); - Assert.Throws(() => target.GetValue(Class1.FooProperty)); + Assert.Equal("foodefault", target.GetValue(Class1.FooProperty)); } private class Class1 : AvaloniaObject diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs index 1f9c47f8ae..a56cd717b9 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs @@ -30,6 +30,16 @@ namespace Avalonia.Base.UnitTests Assert.Equal("newvalue", target.GetValue(Class1.FooProperty)); } + [Fact] + public void SetValue_Sets_Attached_Value() + { + Class2 target = new Class2(); + + target.SetValue(AttachedOwner.AttachedProperty, "newvalue"); + + Assert.Equal("newvalue", target.GetValue(AttachedOwner.AttachedProperty)); + } + [Fact] public void SetValue_Raises_PropertyChanged() { @@ -84,14 +94,27 @@ namespace Avalonia.Base.UnitTests } [Fact] - public void SetValue_Throws_Exception_For_Unregistered_Property() + public void SetValue_Allows_Setting_Unregistered_Property() { Class1 target = new Class1(); - Assert.Throws(() => - { - target.SetValue(Class2.BarProperty, "invalid"); - }); + Assert.False(AvaloniaPropertyRegistry.Instance.IsRegistered(target, Class2.BarProperty)); + + target.SetValue(Class2.BarProperty, "bar"); + + Assert.Equal("bar", target.GetValue(Class2.BarProperty)); + } + + [Fact] + public void SetValue_Allows_Setting_Unregistered_Attached_Property() + { + Class1 target = new Class1(); + + Assert.False(AvaloniaPropertyRegistry.Instance.IsRegistered(target, AttachedOwner.AttachedProperty)); + + target.SetValue(AttachedOwner.AttachedProperty, "bar"); + + Assert.Equal("bar", target.GetValue(AttachedOwner.AttachedProperty)); } [Fact] @@ -189,6 +212,12 @@ namespace Avalonia.Base.UnitTests } } + private class AttachedOwner + { + public static readonly AttachedProperty AttachedProperty = + AvaloniaProperty.RegisterAttached("Attached"); + } + private class ImplictDouble { public ImplictDouble(double value) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/AttachedPropertyOwner.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/AttachedPropertyOwner.cs new file mode 100644 index 0000000000..aac5b01f96 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/AttachedPropertyOwner.cs @@ -0,0 +1,14 @@ +using System; +using Avalonia.Controls; + +namespace Avalonia.Markup.Xaml.UnitTests.Xaml +{ + public class AttachedPropertyOwner + { + public static readonly AttachedProperty DoubleProperty = + AvaloniaProperty.RegisterAttached("Double"); + + public static double GetDouble(Control control) => control.GetValue(DoubleProperty); + public static void SetDouble(Control control, double value) => control.SetValue(DoubleProperty, value); + } +} diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs index fb432c30d4..9bee92cd7a 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs @@ -10,6 +10,7 @@ using Avalonia.Markup.Xaml.Templates; using Avalonia.Media; using Avalonia.Styling; using Avalonia.UnitTests; +using Portable.Xaml; using System.Collections; using System.ComponentModel; using System.Linq; @@ -124,6 +125,24 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml Assert.Equal("Foo", ToolTip.GetTip(target)); } + [Fact] + public void NonExistent_Property_Throws() + { + var xaml = + @""; + + Assert.Throws(() => AvaloniaXamlLoader.Parse(xaml)); + } + + [Fact] + public void Non_Attached_Property_With_Attached_Property_Syntax_Throws() + { + var xaml = + @""; + + Assert.Throws(() => AvaloniaXamlLoader.Parse(xaml)); + } + [Fact] public void ContentControl_ContentTemplate_Is_Functional() { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs index a44d09dee7..568c6482f5 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs @@ -215,5 +215,71 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml Assert.Equal("bar", textBlock.Text); } } + + [Fact] + public void Binding_To_Namespaced_Attached_Property_Works() + { + using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) + { + var xaml = @" + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBlock = (TextBlock)window.Content; + + window.DataContext = 5.6; + window.ApplyTemplate(); + + Assert.Equal(5.6, AttachedPropertyOwner.GetDouble(textBlock)); + } + } + + [Fact] + public void Binding_To_AddOwnered_Attached_Property_Works() + { + using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) + { + var xaml = @" + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var testControl = (TestControl)window.Content; + + window.DataContext = 5.6; + window.ApplyTemplate(); + + Assert.Equal(5.6, testControl.Double); + } + } + + [Fact] + public void Binding_To_Attached_Property_Using_AddOwnered_Type_Works() + { + using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) + { + var xaml = @" + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBlock = (TextBlock)window.Content; + + window.DataContext = 5.6; + window.ApplyTemplate(); + + Assert.Equal(5.6, AttachedPropertyOwner.GetDouble(textBlock)); + } + } } } \ No newline at end of file diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TestControl.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TestControl.cs new file mode 100644 index 0000000000..d0591e5ee6 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TestControl.cs @@ -0,0 +1,17 @@ +using System; +using Avalonia.Controls; + +namespace Avalonia.Markup.Xaml.UnitTests.Xaml +{ + public class TestControl : Control + { + public static readonly StyledProperty DoubleProperty = + AttachedPropertyOwner.DoubleProperty.AddOwner(); + + public double Double + { + get => GetValue(DoubleProperty); + set => SetValue(DoubleProperty, value); + } + } +} From f8791ecad784022ff5fc30dbbd34261f0653104d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 14 Apr 2018 16:19:05 +0200 Subject: [PATCH 003/101] Make attached property accessors static. --- src/Avalonia.Controls/Primitives/TemplatedControl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index 77735f3f12..1a805a3822 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -207,7 +207,7 @@ namespace Avalonia.Controls.Primitives /// The control. /// The property value. /// - public bool GetIsTemplateFocusTarget(Control control) + public static bool GetIsTemplateFocusTarget(Control control) { return control.GetValue(IsTemplateFocusTargetProperty); } @@ -223,7 +223,7 @@ namespace Avalonia.Controls.Primitives /// attached property is set to true on an element in the control template, then the focus /// adorner will be shown around that control instead. /// - public void SetIsTemplateFocusTarget(Control control, bool value) + public static void SetIsTemplateFocusTarget(Control control, bool value) { control.SetValue(IsTemplateFocusTargetProperty, value); } From 44cfcfb04d49f46c3b2a5f5c075907e8872c6f8d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 14 Apr 2018 18:09:53 +0200 Subject: [PATCH 004/101] Allow any property to be registered anywhere. Makes Avalonia more like other XAML frameworks, in that any avalonia property can now be set anywhere. The XAML parser however will only allow you to set registered properties. --- src/Avalonia.Base/AttachedProperty.cs | 9 +- src/Avalonia.Base/AvaloniaObject.cs | 50 ++-- src/Avalonia.Base/AvaloniaProperty.cs | 8 +- src/Avalonia.Base/AvaloniaPropertyRegistry.cs | 283 ++++++++---------- src/Avalonia.Base/DirectProperty.cs | 3 + src/Avalonia.Base/IDirectPropertyAccessor.cs | 7 + .../AvaloniaPropertyTypeConverter.cs | 5 +- .../PortableXaml/AvaloniaXamlSchemaContext.cs | 3 +- .../PortableXaml/AvaloniaXamlType.cs | 22 +- .../Plugins/AvaloniaPropertyAccessorPlugin.cs | 55 +++- .../AvaloniaObjectTests_AddOwner.cs | 52 ++++ .../AvaloniaObjectTests_Attached.cs | 52 ++++ .../AvaloniaPropertyRegistryTests.cs | 108 +++---- 13 files changed, 386 insertions(+), 271 deletions(-) create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_AddOwner.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs index 9d4d40bfef..fdb04b6dfc 100644 --- a/src/Avalonia.Base/AttachedProperty.cs +++ b/src/Avalonia.Base/AttachedProperty.cs @@ -9,7 +9,7 @@ namespace Avalonia /// An attached avalonia property. /// /// The type of the property's value. - public class AttachedProperty : StyledPropertyBase + public class AttachedProperty : StyledProperty { /// /// Initializes a new instance of the class. @@ -35,11 +35,10 @@ namespace Avalonia /// /// The owner type. /// The property. - public StyledProperty AddOwner() where TOwner : IAvaloniaObject + public new AttachedProperty AddOwner() where TOwner : IAvaloniaObject { - var result = new StyledProperty(this, typeof(TOwner)); - AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result); - return result; + AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this); + return this; } } } diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index a46d567d28..4ab813333d 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -12,7 +12,6 @@ using Avalonia.Diagnostics; using Avalonia.Logging; using Avalonia.Threading; using Avalonia.Utilities; -using System.Reactive.Concurrency; namespace Avalonia { @@ -218,11 +217,6 @@ namespace Avalonia } else { - if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property)) - { - ThrowNotRegistered(property); - } - return GetValueInternal(property); } } @@ -377,11 +371,6 @@ namespace Avalonia { PriorityValue v; - if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property)) - { - ThrowNotRegistered(property); - } - if (!_values.TryGetValue(property, out v)) { v = CreatePriorityValue(property); @@ -804,11 +793,6 @@ namespace Avalonia var originalValue = value; - if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property)) - { - ThrowNotRegistered(property); - } - if (!TypeUtilities.TryConvertImplicit(property.PropertyType, value, out value)) { throw new ArgumentException(string.Format( @@ -836,18 +820,32 @@ namespace Avalonia } /// - /// Given a returns a registered avalonia property that is - /// equal or throws if not found. + /// Given a direct property, returns a registered avalonia property that is equivalent or + /// throws if not found. /// /// The property. /// The registered property. - public AvaloniaProperty GetRegistered(AvaloniaProperty property) + private AvaloniaProperty GetRegistered(AvaloniaProperty property) { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(this, property); + var direct = property as IDirectPropertyAccessor; + + if (direct == null) + { + throw new AvaloniaInternalException( + "AvaloniaObject.GetRegistered should only be called for direct properties"); + } + + if (property.OwnerType.IsAssignableFrom(GetType())) + { + return property; + } + + var result = AvaloniaPropertyRegistry.Instance.GetRegistered(this) + .FirstOrDefault(x => x == property); if (result == null) { - ThrowNotRegistered(property); + throw new ArgumentException($"Property '{property.Name} not registered on '{this.GetType()}"); } return result; @@ -898,15 +896,5 @@ namespace Avalonia value, priority); } - - /// - /// Throws an exception indicating that the specified property is not registered on this - /// object. - /// - /// The property - private void ThrowNotRegistered(AvaloniaProperty p) - { - throw new ArgumentException($"Property '{p.Name} not registered on '{this.GetType()}"); - } } } diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index fb78e3b2a0..f7dabd3a43 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -311,7 +311,9 @@ namespace Avalonia defaultBindingMode: defaultBindingMode); var result = new AttachedProperty(name, typeof(TOwner), metadata, inherits); - AvaloniaPropertyRegistry.Instance.Register(typeof(THost), result); + var registry = AvaloniaPropertyRegistry.Instance; + registry.Register(typeof(TOwner), result); + registry.RegisterAttached(typeof(THost), result); return result; } @@ -344,7 +346,9 @@ namespace Avalonia defaultBindingMode: defaultBindingMode); var result = new AttachedProperty(name, ownerType, metadata, inherits); - AvaloniaPropertyRegistry.Instance.Register(typeof(THost), result); + var registry = AvaloniaPropertyRegistry.Instance; + registry.Register(ownerType, result); + registry.RegisterAttached(typeof(THost), result); return result; } diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs index ec1643427b..c0a4ace6ed 100644 --- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs +++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Runtime.CompilerServices; namespace Avalonia @@ -14,23 +13,14 @@ namespace Avalonia /// public class AvaloniaPropertyRegistry { - /// - /// The registered properties by type. - /// private readonly Dictionary> _registered = new Dictionary>(); - - /// - /// The registered properties by type cached values to increase performance. - /// - private readonly Dictionary> _registeredCache = - new Dictionary>(); - - /// - /// The registered attached properties by owner type. - /// private readonly Dictionary> _attached = new Dictionary>(); + private readonly Dictionary> _registeredCache = + new Dictionary>(); + private readonly Dictionary> _attachedCache = + new Dictionary>(); /// /// Gets the instance @@ -39,51 +29,68 @@ namespace Avalonia = new AvaloniaPropertyRegistry(); /// - /// Gets all attached s registered by an owner. + /// Gets all non-attached s registered on a type. /// - /// The owner type. + /// The type. /// A collection of definitions. - public IEnumerable GetAttached(Type ownerType) + public IEnumerable GetRegistered(Type type) { - Dictionary inner; + Contract.Requires(type != null); + + if (_registeredCache.TryGetValue(type, out var result)) + { + return result; + } - // Ensure the type's static ctor has been run. - RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle); + var t = type; + result = new List(); - if (_attached.TryGetValue(ownerType, out inner)) + while (t != null) { - return inner.Values; + // Ensure the type's static ctor has been run. + RuntimeHelpers.RunClassConstructor(t.TypeHandle); + + if (_registered.TryGetValue(t, out var registered)) + { + result.AddRange(registered.Values); + } + + t = t.BaseType; } - return Enumerable.Empty(); + _registeredCache.Add(type, result); + return result; } /// - /// Gets all s registered on a type. + /// Gets all attached s registered on a type. /// /// The type. /// A collection of definitions. - public IEnumerable GetRegistered(Type type) + public IEnumerable GetRegisteredAttached(Type type) { Contract.Requires(type != null); - while (type != null) + if (_attachedCache.TryGetValue(type, out var result)) { - // Ensure the type's static ctor has been run. - RuntimeHelpers.RunClassConstructor(type.TypeHandle); + return result; + } - Dictionary inner; + var t = type; + result = new List(); - if (_registered.TryGetValue(type, out inner)) + while (t != null) + { + if (_attached.TryGetValue(t, out var attached)) { - foreach (var p in inner) - { - yield return p.Value; - } + result.AddRange(attached.Values); } - type = type.GetTypeInfo().BaseType; + t = t.BaseType; } + + _attachedCache.Add(type, result); + return result; } /// @@ -99,142 +106,92 @@ namespace Avalonia } /// - /// Finds a registered on a type. + /// Finds a registered non-attached property on a type by name. /// /// The type. - /// The property. - /// The registered property or null if not found. - /// - /// Calling AddOwner on a AvaloniaProperty creates a new AvaloniaProperty that is a - /// different object but is equal according to . - /// - public AvaloniaProperty FindRegistered(Type type, AvaloniaProperty property) + /// The property name. + /// + /// The registered property or null if no matching property found. + /// + /// + /// The property name contains a '.'. + /// + public AvaloniaProperty FindRegistered(Type type, string name) { - Type currentType = type; - Dictionary cache; - AvaloniaProperty result; + Contract.Requires(type != null); + Contract.Requires(name != null); - if (_registeredCache.TryGetValue(type, out cache)) + if (name.Contains('.')) { - if (cache.TryGetValue(property.Id, out result)) - { - return result; - } + throw new InvalidOperationException("Attached properties not supported."); } - while (currentType != null) - { - Dictionary inner; - - if (_registered.TryGetValue(currentType, out inner)) - { - if (inner.TryGetValue(property.Id, out result)) - { - if (cache == null) - { - _registeredCache[type] = cache = new Dictionary(); - } - - cache[property.Id] = result; - - return result; - } - } - - currentType = currentType.GetTypeInfo().BaseType; - } - - return null; + return GetRegistered(type).FirstOrDefault(x => x.Name == name); } /// - /// Finds registered on an object. + /// Finds a registered non-attached property on a type by name. /// /// The object. - /// The property. - /// The registered property or null if not found. - /// - /// Calling AddOwner on a AvaloniaProperty creates a new AvaloniaProperty that is a - /// different object but is equal according to . - /// - public AvaloniaProperty FindRegistered(object o, AvaloniaProperty property) + /// The property name. + /// + /// The registered property or null if no matching property found. + /// + /// + /// The property name contains a '.'. + /// + public AvaloniaProperty FindRegistered(AvaloniaObject o, string name) { - return FindRegistered(o.GetType(), property); + Contract.Requires(o != null); + Contract.Requires(name != null); + + return FindRegistered(o.GetType(), name); } /// - /// Finds a registered property on a type by name. + /// Finds a registered attached property on a type by name. /// /// The type. - /// - /// The property name. If an attached property it should be in the form - /// "OwnerType.PropertyName". - /// + /// The owner type. + /// The property name. /// /// The registered property or null if no matching property found. /// - public AvaloniaProperty FindRegistered(Type type, string name) + /// + /// The property name contains a '.'. + /// + public AvaloniaProperty FindRegisteredAttached(Type type, Type ownerType, string name) { Contract.Requires(type != null); + Contract.Requires(ownerType != null); Contract.Requires(name != null); - var parts = name.Split('.'); - var types = GetImplementedTypes(type).ToList(); - - if (parts.Length < 1 || parts.Length > 2) + if (name.Contains('.')) { - throw new ArgumentException("Invalid property name."); + throw new InvalidOperationException("Attached properties not supported."); } - string propertyName; - var results = GetRegistered(type); - - if (parts.Length == 1) - { - propertyName = parts[0]; - results = results.Where(x => !x.IsAttached || types.Contains(x.OwnerType.Name)); - } - else - { - if (!types.Contains(parts[0])) - { - results = results.Where(x => x.OwnerType.Name == parts[0]); - } - - propertyName = parts[1]; - } - - return results.FirstOrDefault(x => x.Name == propertyName); + return GetRegisteredAttached(type).FirstOrDefault(x => x.Name == name); } /// - /// Finds a registered property on an object by name. + /// Finds a registered non-attached property on a type by name. /// /// The object. - /// - /// The property name. If an attached property it should be in the form - /// "OwnerType.PropertyName". - /// + /// The owner type. + /// The property name. /// /// The registered property or null if no matching property found. /// - public AvaloniaProperty FindRegistered(AvaloniaObject o, string name) + /// + /// The property name contains a '.'. + /// + public AvaloniaProperty FindRegisteredAttached(AvaloniaObject o, Type ownerType, string name) { - return FindRegistered(o.GetType(), name); - } + Contract.Requires(o != null); + Contract.Requires(name != null); - /// - /// Returns a type and all its base types. - /// - /// The type. - /// The type and all its base types. - private IEnumerable GetImplementedTypes(Type type) - { - while (type != null) - { - yield return type.Name; - type = type.GetTypeInfo().BaseType; - } + return FindRegisteredAttached(o.GetType(), ownerType, name); } /// @@ -245,7 +202,11 @@ namespace Avalonia /// True if the property is registered, otherwise false. public bool IsRegistered(Type type, AvaloniaProperty property) { - return FindRegistered(type, property) != null; + Contract.Requires(type != null); + Contract.Requires(property != null); + + return Instance.GetRegistered(type).Any(x => x == property) || + Instance.GetRegisteredAttached(type).Any(x => x == property); } /// @@ -256,6 +217,9 @@ namespace Avalonia /// True if the property is registered, otherwise false. public bool IsRegistered(object o, AvaloniaProperty property) { + Contract.Requires(o != null); + Contract.Requires(property != null); + return IsRegistered(o.GetType(), property); } @@ -274,34 +238,53 @@ namespace Avalonia Contract.Requires(type != null); Contract.Requires(property != null); - Dictionary inner; - - if (!_registered.TryGetValue(type, out inner)) + if (!_registered.TryGetValue(type, out var inner)) { inner = new Dictionary(); + inner.Add(property.Id, property); _registered.Add(type, inner); } - - if (!inner.ContainsKey(property.Id)) + else if (!inner.ContainsKey(property.Id)) { inner.Add(property.Id, property); } + + _registeredCache.Clear(); + } - if (property.IsAttached) + /// + /// Registers an attached on a type. + /// + /// The type. + /// The property. + /// + /// You won't usually want to call this method directly, instead use the + /// + /// method. + /// + public void RegisterAttached(Type type, AvaloniaProperty property) + { + Contract.Requires(type != null); + Contract.Requires(property != null); + + if (!property.IsAttached) { - if (!_attached.TryGetValue(property.OwnerType, out inner)) - { - inner = new Dictionary(); - _attached.Add(property.OwnerType, inner); - } + throw new InvalidOperationException( + "Cannot register a non-attached property as attached."); + } - if (!inner.ContainsKey(property.Id)) - { - inner.Add(property.Id, property); - } + if (!_attached.TryGetValue(type, out var inner)) + { + inner = new Dictionary(); + inner.Add(property.Id, property); + _attached.Add(type, inner); + } + else + { + inner.Add(property.Id, property); } - _registeredCache.Clear(); + _attachedCache.Clear(); } } } \ No newline at end of file diff --git a/src/Avalonia.Base/DirectProperty.cs b/src/Avalonia.Base/DirectProperty.cs index 8352528285..1ce73c20ba 100644 --- a/src/Avalonia.Base/DirectProperty.cs +++ b/src/Avalonia.Base/DirectProperty.cs @@ -75,6 +75,9 @@ namespace Avalonia /// public Action Setter { get; } + /// + Type IDirectPropertyAccessor.Owner => typeof(TOwner); + /// /// Registers the direct property on another type. /// diff --git a/src/Avalonia.Base/IDirectPropertyAccessor.cs b/src/Avalonia.Base/IDirectPropertyAccessor.cs index 62aeef73c7..4f46652693 100644 --- a/src/Avalonia.Base/IDirectPropertyAccessor.cs +++ b/src/Avalonia.Base/IDirectPropertyAccessor.cs @@ -1,6 +1,8 @@ // 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; + namespace Avalonia { /// @@ -14,6 +16,11 @@ namespace Avalonia /// bool IsReadOnly { get; } + /// + /// Gets the class that registered the property. + /// + Type Owner { get; } + /// /// Gets the value of the property on the instance. /// diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs index a34ccaa413..bc3caff3b9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -53,10 +53,7 @@ namespace Avalonia.Markup.Xaml.Converters } } - // First look for non-attached property on the type and then look for an attached property. - var property = AvaloniaPropertyRegistry.Instance.FindRegistered(type, s) ?? - AvaloniaPropertyRegistry.Instance.GetAttached(type) - .FirstOrDefault(x => x.Name == propertyName); + AvaloniaProperty property = AvaloniaPropertyRegistry.Instance.FindRegistered(type, propertyName); if (property == null) { diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs index bdb21abd77..fda5da902a 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs @@ -200,8 +200,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml var type = (getter ?? setter).DeclaringType; - var prop = AvaloniaPropertyRegistry.Instance.GetAttached(type) - .FirstOrDefault(v => v.Name == attachablePropertyName); + var prop = AvaloniaPropertyRegistry.Instance.FindRegistered(type, attachablePropertyName); if (prop != null) { diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs index 7de96ea220..59dbba7084 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs @@ -19,16 +19,36 @@ namespace Avalonia.Markup.Xaml.PortableXaml public class AvaloniaXamlType : XamlType { + static readonly AvaloniaPropertyTypeConverter propertyTypeConverter = new AvaloniaPropertyTypeConverter(); + public AvaloniaXamlType(Type underlyingType, XamlSchemaContext schemaContext) : base(underlyingType, schemaContext) { } + protected override XamlMember LookupAttachableMember(string name) + { + var m = base.LookupAttachableMember(name); + + if (m == null) + { + // Might be an AddOwnered attached property. + var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(UnderlyingType, name); + + if (avProp?.IsAttached == true) + { + return new AvaloniaPropertyXamlMember(avProp, this); + } + } + + return m; + } + protected override XamlMember LookupMember(string name, bool skipReadOnlyCheck) { var m = base.LookupMember(name, skipReadOnlyCheck); - if (m == null) + if (m == null && !name.Contains(".")) { //so far Portable.xaml haven't found the member/property //but what if we have AvaloniaProperty diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs index 90eabc69fb..ac64459dd7 100644 --- a/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs +++ b/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Linq; using System.Reactive.Linq; using Avalonia.Data; @@ -15,9 +16,9 @@ namespace Avalonia.Markup.Data.Plugins /// public bool Match(object obj, string propertyName) { - if (obj is AvaloniaObject a) + if (obj is AvaloniaObject o) { - return AvaloniaPropertyRegistry.Instance.FindRegistered(a, propertyName) != null; + return LookupProperty(o, propertyName) != null; } return false; @@ -39,7 +40,7 @@ namespace Avalonia.Markup.Data.Plugins var instance = reference.Target; var o = (AvaloniaObject)instance; - var p = AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName); + var p = LookupProperty(o, propertyName); if (p != null) { @@ -57,6 +58,54 @@ namespace Avalonia.Markup.Data.Plugins } } + private static AvaloniaProperty LookupProperty(AvaloniaObject o, string propertyName) + { + if (!propertyName.Contains(".")) + { + return AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName); + } + else + { + var split = propertyName.Split('.'); + + if (split.Length == 2) + { + // HACK: We need a way to resolve types here using something like IXamlTypeResolver. + // We don't currently have that so we have to make our best guess. + var type = split[0]; + var name = split[1]; + var registry = AvaloniaPropertyRegistry.Instance; + var registered = registry.GetRegisteredAttached(o.GetType()) + .Concat(registry.GetRegistered(o.GetType())); + + foreach (var p in registered) + { + if (p.Name == name && IsOfType(p.OwnerType, type)) + { + return p; + } + } + } + } + + return null; + } + + private static bool IsOfType(Type type, string typeName) + { + while (type != null) + { + if (type.Name == typeName) + { + return true; + } + + type = type.BaseType; + } + + return false; + } + private class Accessor : PropertyAccessorBase { private readonly WeakReference _reference; diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_AddOwner.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_AddOwner.cs new file mode 100644 index 0000000000..4e033be3fb --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_AddOwner.cs @@ -0,0 +1,52 @@ +// 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 Xunit; + +namespace Avalonia.Base.UnitTests +{ + public class AvaloniaObjectTests_AddOwner + { + [Fact] + public void AddOwnered_Property_Retains_Default_Value() + { + var target = new Class2(); + + Assert.Equal("foodefault", target.GetValue(Class2.FooProperty)); + } + + [Fact] + public void AddOwnered_Property_Does_Not_Retain_Validation() + { + var target = new Class2(); + + target.SetValue(Class2.FooProperty, "throw"); + } + + private class Class1 : AvaloniaObject + { + public static readonly StyledProperty FooProperty = + AvaloniaProperty.Register( + "Foo", + "foodefault", + validate: ValidateFoo); + + private static string ValidateFoo(AvaloniaObject arg1, string arg2) + { + if (arg2 == "throw") + { + throw new IndexOutOfRangeException(); + } + + return arg2; + } + } + + private class Class2 : AvaloniaObject + { + public static readonly StyledProperty FooProperty = + Class1.FooProperty.AddOwner(); + } + } +} diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs new file mode 100644 index 0000000000..acaabc73df --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs @@ -0,0 +1,52 @@ +// 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 Xunit; + +namespace Avalonia.Base.UnitTests +{ + public class AvaloniaObjectTests_Attached + { + [Fact] + public void AddOwnered_Property_Retains_Default_Value() + { + var target = new Class2(); + + Assert.Equal("foodefault", target.GetValue(Class2.FooProperty)); + } + + [Fact] + public void AddOwnered_Property_Retains_Validation() + { + var target = new Class2(); + + Assert.Throws(() => target.SetValue(Class2.FooProperty, "throw")); + } + + private class Class1 : AvaloniaObject + { + public static readonly AttachedProperty FooProperty = + AvaloniaProperty.RegisterAttached( + "Foo", + "foodefault", + validate: ValidateFoo); + + private static string ValidateFoo(AvaloniaObject arg1, string arg2) + { + if (arg2 == "throw") + { + throw new IndexOutOfRangeException(); + } + + return arg2; + } + } + + private class Class2 : AvaloniaObject + { + public static readonly AttachedProperty FooProperty = + Class1.FooProperty.AddOwner(); + } + } +} diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs index da0b0252a3..c030657034 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs @@ -4,12 +4,15 @@ using System.Linq; using System.Reactive.Linq; using Xunit; +using Xunit.Abstractions; namespace Avalonia.Base.UnitTests { public class AvaloniaPropertyRegistryTests { - public AvaloniaPropertyRegistryTests() + ITestOutputHelper s; + + public AvaloniaPropertyRegistryTests(ITestOutputHelper s) { // Ensure properties are registered. AvaloniaProperty p; @@ -25,7 +28,7 @@ namespace Avalonia.Base.UnitTests .Select(x => x.Name) .ToArray(); - Assert.Equal(new[] { "Foo", "Baz", "Qux", "Attached" }, names); + Assert.Equal(new[] { "Foo", "Baz", "Qux" }, names); } [Fact] @@ -35,61 +38,41 @@ namespace Avalonia.Base.UnitTests .Select(x => x.Name) .ToArray(); - Assert.Equal(new[] { "Bar", "Flob", "Fred", "Foo", "Baz", "Qux", "Attached" }, names); + Assert.Equal(new[] { "Bar", "Flob", "Fred", "Foo", "Baz", "Qux" }, names); } [Fact] - public void GetAttached_Returns_Registered_Properties_For_Base_Types() + public void GetRegisteredAttached_Returns_Registered_Properties() { - string[] names = AvaloniaPropertyRegistry.Instance.GetAttached(typeof(AttachedOwner)).Select(x => x.Name).ToArray(); + string[] names = AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(typeof(Class1)) + .Select(x => x.Name) + .ToArray(); Assert.Equal(new[] { "Attached" }, names); } [Fact] - public void FindRegistered_Finds_Untyped_Property() + public void GetRegisteredAttached_Returns_Registered_Properties_For_Base_Types() { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class1), "Foo"); + string[] names = AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(typeof(Class2)) + .Select(x => x.Name) + .ToArray(); - Assert.Equal(Class1.FooProperty, result); + Assert.Equal(new[] { "Attached" }, names); } [Fact] - public void FindRegistered_Finds_Typed_Property() + public void FindRegistered_Finds_Property() { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class1), "Class1.Foo"); + var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class1), "Foo"); Assert.Equal(Class1.FooProperty, result); } [Fact] - public void FindRegistered_Finds_Typed_Inherited_Property() - { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class2), "Class1.Foo"); - - Assert.Equal(Class2.FooProperty, result); - } - - [Fact] - public void FindRegistered_Finds_Inherited_Property_With_Derived_Type_Name() - { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class2), "Class2.Foo"); - - Assert.Equal(Class2.FooProperty, result); - } - - [Fact] - public void FindRegistered_Finds_Attached_Property() - { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class2), "AttachedOwner.Attached"); - - Assert.Equal(AttachedOwner.AttachedProperty, result); - } - - [Fact] - public void FindRegistered_Doesnt_Finds_Unqualified_Attached_Property() + public void FindRegistered_Doesnt_Find_Nonregistered_Property() { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class2), "Attached"); + var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class1), "Bar"); Assert.Null(result); } @@ -99,55 +82,34 @@ namespace Avalonia.Base.UnitTests { var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(AttachedOwner), "Attached"); - Assert.True(AttachedOwner.AttachedProperty == result); + Assert.Same(AttachedOwner.AttachedProperty, result); } [Fact] - public void FindRegistered_Finds_AddOwnered_Untyped_Attached_Property() + public void FindRegistered_Finds_AddOwnered_Attached_Property() { var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class3), "Attached"); - Assert.True(AttachedOwner.AttachedProperty == result); + Assert.Same(AttachedOwner.AttachedProperty, result); } [Fact] - public void FindRegistered_Finds_AddOwnered_Typed_Attached_Property() + public void FindRegistered_Doesnt_Find_Non_AddOwnered_Attached_Property() { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class3), "Class3.Attached"); - - Assert.True(AttachedOwner.AttachedProperty == result); - } - - [Fact] - public void FindRegistered_Finds_AddOwnered_AttachedTyped_Attached_Property() - { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class3), "AttachedOwner.Attached"); - - Assert.True(AttachedOwner.AttachedProperty == result); - } - - [Fact] - public void FindRegistered_Finds_AddOwnered_BaseTyped_Attached_Property() - { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class3), "Class1.Attached"); - - Assert.True(AttachedOwner.AttachedProperty == result); - } - - [Fact] - public void FindRegistered_Doesnt_Find_Nonregistered_Property() - { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class1), "Bar"); + var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class2), "Attached"); Assert.Null(result); } [Fact] - public void FindRegistered_Doesnt_Find_Nonregistered_Attached_Property() + public void FindRegisteredAttached_Finds_Property() { - var result = AvaloniaPropertyRegistry.Instance.FindRegistered(typeof(Class4), "AttachedOwner.Attached"); + var result = AvaloniaPropertyRegistry.Instance.FindRegisteredAttached( + typeof(Class1), + typeof(AttachedOwner), + "Attached"); - Assert.Null(result); + Assert.Equal(AttachedOwner.AttachedProperty, result); } private class Class1 : AvaloniaObject @@ -176,18 +138,18 @@ namespace Avalonia.Base.UnitTests private class Class3 : Class1 { - public static readonly StyledProperty AttachedProperty = + public static readonly AttachedProperty AttachedProperty = AttachedOwner.AttachedProperty.AddOwner(); } - public class Class4 : AvaloniaObject - { - } - private class AttachedOwner : Class1 { public static readonly AttachedProperty AttachedProperty = AvaloniaProperty.RegisterAttached("Attached"); } + + private class AttachedOwner2 : AttachedOwner + { + } } } From f0d0429644c3488050389618e1ae0c9d6ee92418 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 14 Apr 2018 23:21:34 +0200 Subject: [PATCH 005/101] Remove unused member. --- tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs index c030657034..8b2e500d37 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs @@ -10,8 +10,6 @@ namespace Avalonia.Base.UnitTests { public class AvaloniaPropertyRegistryTests { - ITestOutputHelper s; - public AvaloniaPropertyRegistryTests(ITestOutputHelper s) { // Ensure properties are registered. From b02ad2be485451127e197bd285c3854cf6c59390 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 14 Apr 2018 23:22:04 +0200 Subject: [PATCH 006/101] Fix failing tests. This class was registering a global attached property which affected other tests. --- tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs index acaabc73df..ab2a2d899d 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Attached.cs @@ -27,7 +27,7 @@ namespace Avalonia.Base.UnitTests private class Class1 : AvaloniaObject { public static readonly AttachedProperty FooProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "Foo", "foodefault", validate: ValidateFoo); From bd33b3076b4eea33731dcf9a8eedf374aa2a1aef Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 17 Apr 2018 14:35:08 +0200 Subject: [PATCH 007/101] Fix Win32 window size constraints fixes + revert testing changes --- .../Platform/IWindowBaseImpl.cs | 24 +++++++++++++-- src/Avalonia.Controls/WindowBase.cs | 9 +++++- .../Remote/PreviewerWindowImpl.cs | 8 +++++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 8 +++++ src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs | 8 +++++ src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs | 8 +++++ .../Interop/UnmanagedMethods.cs | 10 +++++++ src/Windows/Avalonia.Win32/WindowImpl.cs | 29 ++++++++++++++++++- 8 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index 0a01cf3df4..f043371e9d 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -55,7 +55,7 @@ namespace Avalonia.Platform /// Gets the platform window handle. /// IPlatformHandle Handle { get; } - + /// /// Gets the maximum size of a window on the system. /// @@ -65,7 +65,27 @@ namespace Avalonia.Platform /// Sets the client size of the toplevel. /// void Resize(Size clientSize); - + + /// + /// Minimum width of the window. + /// + double MinWidth { get; set; } + + /// + /// Maximum width of the window. + /// + double MaxWidth { get; set; } + + /// + /// Minimum height of the window. + /// + double MinHeight { get; set; } + + /// + /// Maximum height of the window. + /// + double MaxHeight { get; set; } + /// /// Gets platform specific display information /// diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 50068d280d..16fc8117d5 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -197,7 +197,14 @@ namespace Avalonia.Controls { using (BeginAutoSizing()) { - PlatformImpl?.Resize(finalSize); + if (PlatformImpl != null) + { + PlatformImpl.MinHeight = MinHeight; + PlatformImpl.MaxHeight = MaxHeight; + PlatformImpl.MinWidth = MinWidth; + PlatformImpl.MaxWidth = MaxWidth; + PlatformImpl.Resize(finalSize); + } } return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size)); diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index fc9541abb7..703f5ec5c8 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -67,6 +67,14 @@ namespace Avalonia.DesignerSupport.Remote RenderIfNeeded(); } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IScreenImpl Screen { get; } = new ScreenStub(); public void Activate() diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 560425286e..6dd207178d 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -78,6 +78,14 @@ namespace Avalonia.DesignerSupport.Remote public IScreenImpl Screen { get; } = new ScreenStub(); + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public void SetTitle(string title) { } diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index a42c8a19b9..768b1500af 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -341,6 +341,14 @@ namespace Avalonia.Gtk3 } } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IMouseDevice MouseDevice => Gtk3Platform.Mouse; public double Scaling => LastKnownScaleFactor = (int) (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1); diff --git a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs index e5ba285f4f..0b64aae36b 100644 --- a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs +++ b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs @@ -161,6 +161,14 @@ namespace Avalonia.MonoMac Position = pos; } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IScreenImpl Screen { get; diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index aa86ab0f8d..b679d746f3 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -615,6 +615,16 @@ namespace Avalonia.Win32.Interop public uint[] cols; } + [StructLayout(LayoutKind.Sequential)] + public struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + } + public const int SizeOf_BITMAPINFOHEADER = 40; [DllImport("user32.dll")] diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bb3c4cf6e6..73d8228bab 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -102,6 +102,14 @@ namespace Avalonia.Win32 } } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IScreenImpl Screen { get; @@ -611,7 +619,26 @@ namespace Avalonia.Win32 case UnmanagedMethods.WindowsMessage.WM_MOVE: PositionChanged?.Invoke(new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16))); return IntPtr.Zero; - + + case UnmanagedMethods.WindowsMessage.WM_GETMINMAXINFO: + + MINMAXINFO mmi = Marshal.PtrToStructure(lParam); + + if (MinWidth > 0) + mmi.ptMinTrackSize.X = (int)((MinWidth * Scaling) + BorderThickness.Left + BorderThickness.Right); + + if (MinHeight > 0) + mmi.ptMinTrackSize.Y = (int)((MinHeight * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + + if (!Double.IsInfinity(MaxWidth) && MaxWidth > 0) + mmi.ptMaxTrackSize.X = (int)((MaxWidth * Scaling) + BorderThickness.Left + BorderThickness.Right); + + if (!Double.IsInfinity(MaxHeight) && MaxHeight > 0) + mmi.ptMaxTrackSize.Y = (int)((MaxHeight * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + + Marshal.StructureToPtr(mmi, lParam, true); + return IntPtr.Zero; + case UnmanagedMethods.WindowsMessage.WM_DISPLAYCHANGE: (Screen as ScreenImpl)?.InvalidateScreensCache(); return IntPtr.Zero; From 3f87b9d02d1171a0078bd9c9a17db9cee1a58302 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Fri, 20 Apr 2018 15:24:09 +0200 Subject: [PATCH 008/101] Support StaticResource in Bindings inside DataTemplate --- .../AvaloniaXamlLoaderPortableXaml.cs | 5 +-- .../PortableXaml/AvaloniaXamlObjectWriter.cs | 26 ++++++++++++-- .../PortableXaml/portable.xaml.github | 2 +- .../Templates/TemplateContent.cs | 8 +++-- .../Templates/TemplateLoader.cs | 3 +- .../StaticResourceExtensionTests.cs | 36 ++++++++++++++++++- 6 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs index de2a79c54e..539fbeb680 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs @@ -194,11 +194,12 @@ namespace Avalonia.Markup.Xaml return result; } - internal static object LoadFromReader(XamlReader reader, AvaloniaXamlContext context = null) + internal static object LoadFromReader(XamlReader reader, AvaloniaXamlContext context = null, IAmbientProvider parentAmbientProvider = null) { var writer = AvaloniaXamlObjectWriter.Create( reader.SchemaContext, - context); + context, + parentAmbientProvider); XamlServices.Transform(reader, writer); writer.ApplyAllDelayedProperties(); diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs index e0e2553f46..509c52503b 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs @@ -27,6 +27,26 @@ namespace Avalonia.Markup.Xaml.PortableXaml nameScope); } + public static AvaloniaXamlObjectWriter Create( + XamlSchemaContext schemaContext, + AvaloniaXamlContext context, + IAmbientProvider parentAmbientProvider) + { + var nameScope = new AvaloniaNameScope { Instance = context?.RootInstance }; + + var writerSettings = new XamlObjectWriterSettings() + { + ExternalNameScope = nameScope, + RegisterNamesOnExternalNamescope = true, + RootObjectInstance = context?.RootInstance + }; + + return new AvaloniaXamlObjectWriter(schemaContext, + writerSettings.WithContext(context), + nameScope, + parentAmbientProvider); + } + private readonly DelayedValuesHelper _delayedValuesHelper = new DelayedValuesHelper(); private AvaloniaNameScope _nameScope; @@ -34,9 +54,9 @@ namespace Avalonia.Markup.Xaml.PortableXaml private AvaloniaXamlObjectWriter( XamlSchemaContext schemaContext, XamlObjectWriterSettings settings, - AvaloniaNameScope nameScope - ) - : base(schemaContext, settings) + AvaloniaNameScope nameScope, + IAmbientProvider parentAmbientProvider = null) + : base(schemaContext, settings, parentAmbientProvider) { _nameScope = nameScope; } diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github index c066401445..e7077fa7df 160000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github @@ -1 +1 @@ -Subproject commit c0664014455392ac221a765e66f9837704339b6f +Subproject commit e7077fa7df836af53f220f845f59971208c3e408 diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs index 1d4dafc413..63fb9f193c 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs @@ -10,8 +10,10 @@ namespace Avalonia.Markup.Xaml.Templates public class TemplateContent { - public TemplateContent(IEnumerable namespaces, XamlReader reader) + public TemplateContent(IEnumerable namespaces, XamlReader reader, + IAmbientProvider ambientProvider) { + ParentAmbientProvider = ambientProvider; List = new XamlNodeList(reader.SchemaContext); //we need to rpeserve all namespace and prefixes to writer @@ -26,9 +28,11 @@ namespace Avalonia.Markup.Xaml.Templates public XamlNodeList List { get; } + private IAmbientProvider ParentAmbientProvider { get; } + public IControl Load() { - return (IControl)AvaloniaXamlLoader.LoadFromReader(List.GetReader()); + return (IControl)AvaloniaXamlLoader.LoadFromReader(List.GetReader(), parentAmbientProvider: ParentAmbientProvider); } public static IControl Load(object templateContent) diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs index 1085131230..e29485ddb0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs @@ -14,7 +14,8 @@ namespace Avalonia.Markup.Xaml.Templates { var tdc = (ITypeDescriptorContext)serviceProvider; var ns = tdc.GetService(); - return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader); + var ambientProvider = tdc.GetService(); + return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader, ambientProvider); } public override XamlReader Save(object value, IServiceProvider serviceProvider) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs index 862ce2b3c0..57293d5d16 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs @@ -323,7 +323,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions Assert.Equal(0xff506070, brush.Color.ToUint32()); } - [Fact(Skip = "Not yet supported by Portable.Xaml")] + [Fact(/*Skip = "Not yet supported by Portable.Xaml"*/)] public void StaticResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File() { var styleXaml = @" @@ -417,6 +417,40 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } + [Fact] + public void StaticResource_Can_Be_Assigned_To_Converter_In_DataTemplate() + { + using (StyledWindow()) + { + var xaml = @" + + + + + + + + + +"; + + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + + window.DataContext = "foo"; + var presenter = window.FindControl("presenter"); + + window.Show(); + + var textBlock = (TextBlock)presenter.GetVisualChildren().Single(); + + Assert.NotNull(textBlock); + Assert.Equal("foobar", textBlock.Text); + } + } + [Fact] public void Control_Property_Is_Not_Updated_When_Parent_Is_Changed() { From b89b72f0ba24283b2605293f7c4160764e3dccf9 Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 17 Apr 2018 14:35:08 +0200 Subject: [PATCH 009/101] Fix Win32 window size constraints fixes + revert testing changes --- .../Platform/IWindowBaseImpl.cs | 24 +++++++++++++-- src/Avalonia.Controls/WindowBase.cs | 9 +++++- .../Remote/PreviewerWindowImpl.cs | 8 +++++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 8 +++++ src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs | 8 +++++ src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs | 8 +++++ .../Interop/UnmanagedMethods.cs | 10 +++++++ src/Windows/Avalonia.Win32/WindowImpl.cs | 29 ++++++++++++++++++- 8 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index 0a01cf3df4..f043371e9d 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -55,7 +55,7 @@ namespace Avalonia.Platform /// Gets the platform window handle. /// IPlatformHandle Handle { get; } - + /// /// Gets the maximum size of a window on the system. /// @@ -65,7 +65,27 @@ namespace Avalonia.Platform /// Sets the client size of the toplevel. /// void Resize(Size clientSize); - + + /// + /// Minimum width of the window. + /// + double MinWidth { get; set; } + + /// + /// Maximum width of the window. + /// + double MaxWidth { get; set; } + + /// + /// Minimum height of the window. + /// + double MinHeight { get; set; } + + /// + /// Maximum height of the window. + /// + double MaxHeight { get; set; } + /// /// Gets platform specific display information /// diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 50068d280d..16fc8117d5 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -197,7 +197,14 @@ namespace Avalonia.Controls { using (BeginAutoSizing()) { - PlatformImpl?.Resize(finalSize); + if (PlatformImpl != null) + { + PlatformImpl.MinHeight = MinHeight; + PlatformImpl.MaxHeight = MaxHeight; + PlatformImpl.MinWidth = MinWidth; + PlatformImpl.MaxWidth = MaxWidth; + PlatformImpl.Resize(finalSize); + } } return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size)); diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index fc9541abb7..703f5ec5c8 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -67,6 +67,14 @@ namespace Avalonia.DesignerSupport.Remote RenderIfNeeded(); } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IScreenImpl Screen { get; } = new ScreenStub(); public void Activate() diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 560425286e..6dd207178d 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -78,6 +78,14 @@ namespace Avalonia.DesignerSupport.Remote public IScreenImpl Screen { get; } = new ScreenStub(); + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public void SetTitle(string title) { } diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index a42c8a19b9..768b1500af 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -341,6 +341,14 @@ namespace Avalonia.Gtk3 } } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IMouseDevice MouseDevice => Gtk3Platform.Mouse; public double Scaling => LastKnownScaleFactor = (int) (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1); diff --git a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs index e5ba285f4f..0b64aae36b 100644 --- a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs +++ b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs @@ -161,6 +161,14 @@ namespace Avalonia.MonoMac Position = pos; } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IScreenImpl Screen { get; diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index aa86ab0f8d..b679d746f3 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -615,6 +615,16 @@ namespace Avalonia.Win32.Interop public uint[] cols; } + [StructLayout(LayoutKind.Sequential)] + public struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + } + public const int SizeOf_BITMAPINFOHEADER = 40; [DllImport("user32.dll")] diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bb3c4cf6e6..73d8228bab 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -102,6 +102,14 @@ namespace Avalonia.Win32 } } + public double MinWidth { get; set; } + + public double MaxWidth { get; set; } + + public double MinHeight { get; set; } + + public double MaxHeight { get; set; } + public IScreenImpl Screen { get; @@ -611,7 +619,26 @@ namespace Avalonia.Win32 case UnmanagedMethods.WindowsMessage.WM_MOVE: PositionChanged?.Invoke(new Point((short)(ToInt32(lParam) & 0xffff), (short)(ToInt32(lParam) >> 16))); return IntPtr.Zero; - + + case UnmanagedMethods.WindowsMessage.WM_GETMINMAXINFO: + + MINMAXINFO mmi = Marshal.PtrToStructure(lParam); + + if (MinWidth > 0) + mmi.ptMinTrackSize.X = (int)((MinWidth * Scaling) + BorderThickness.Left + BorderThickness.Right); + + if (MinHeight > 0) + mmi.ptMinTrackSize.Y = (int)((MinHeight * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + + if (!Double.IsInfinity(MaxWidth) && MaxWidth > 0) + mmi.ptMaxTrackSize.X = (int)((MaxWidth * Scaling) + BorderThickness.Left + BorderThickness.Right); + + if (!Double.IsInfinity(MaxHeight) && MaxHeight > 0) + mmi.ptMaxTrackSize.Y = (int)((MaxHeight * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + + Marshal.StructureToPtr(mmi, lParam, true); + return IntPtr.Zero; + case UnmanagedMethods.WindowsMessage.WM_DISPLAYCHANGE: (Screen as ScreenImpl)?.InvalidateScreensCache(); return IntPtr.Zero; From 3f75825f46903deb399fe9f2222422c511440fc4 Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Mon, 23 Apr 2018 15:31:17 +0200 Subject: [PATCH 010/101] Fix GTK --- src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 28 +++++++++++++------------ src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs | 9 ++++++++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index d4618e7bc1..7cf0a0b256 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -263,7 +263,7 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_window_close(GtkWindow window); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] @@ -502,6 +502,8 @@ namespace Avalonia.Gtk3.Interop public static D.cairo_set_font_size CairoSetFontSize; public static D.cairo_move_to CairoMoveTo; public static D.cairo_destroy CairoDestroy; + + public static D.gtk_window_set_geometry_hints GtkWindowSetGeometryHints; public const int G_TYPE_OBJECT = 80; } @@ -739,19 +741,19 @@ namespace Avalonia.Gtk3.Interop } [StructLayout(LayoutKind.Sequential)] - struct GdkGeometry + public struct GdkGeometry { - gint min_width; - gint min_height; - gint max_width; - gint max_height; - gint base_width; - gint base_height; - gint width_inc; - gint height_inc; - gdouble min_aspect; - gdouble max_aspect; - gint win_gravity; + public gint min_width; + public gint min_height; + public gint max_width; + public gint max_height; + public gint base_width; + public gint base_height; + public gint width_inc; + public gint height_inc; + public gdouble min_aspect; + public gdouble max_aspect; + public gint win_gravity; } enum GdkWindowHints diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index 768b1500af..7e55892570 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -439,6 +439,15 @@ namespace Avalonia.Gtk3 { if (GtkWidget.IsClosed) return; + + GdkGeometry geometry = new GdkGeometry(); + geometry.min_width = MinWidth > 0 ? (int)MinWidth : -1; + geometry.min_height = MinHeight > 0 ? (int)MinHeight : -1; + geometry.max_width = !Double.IsInfinity(MaxWidth) && MaxWidth > 0 ? (int)MaxWidth : 999999; + geometry.max_height = !Double.IsInfinity(MaxHeight) && MaxHeight > 0 ? (int)MaxHeight : 999999; + + Native.GtkWindowSetGeometryHints(GtkWidget, IntPtr.Zero, ref geometry, GdkWindowHints.GDK_HINT_MIN_SIZE | GdkWindowHints.GDK_HINT_MAX_SIZE); + Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height); if (OverrideRedirect) { From 586e8654f304f4099504cf02f5b377d41fea9f11 Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 24 Apr 2018 10:19:01 +0200 Subject: [PATCH 011/101] replace Min Max properties with function --- .../Platform/IWindowBaseImpl.cs | 18 ++--------- src/Avalonia.Controls/WindowBase.cs | 14 ++++----- .../Remote/PreviewerWindowImpl.cs | 10 ++---- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 10 ++---- src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 2 +- src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs | 26 +++++++--------- src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs | 10 ++---- src/Windows/Avalonia.Win32/WindowImpl.cs | 31 ++++++++++--------- 8 files changed, 46 insertions(+), 75 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index f043371e9d..4f7ac82df7 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -69,22 +69,8 @@ namespace Avalonia.Platform /// /// Minimum width of the window. /// - double MinWidth { get; set; } - - /// - /// Maximum width of the window. - /// - double MaxWidth { get; set; } - - /// - /// Minimum height of the window. - /// - double MinHeight { get; set; } - - /// - /// Maximum height of the window. - /// - double MaxHeight { get; set; } + /// + void SetMinMaxSize(Size minSize, Size maxSize); /// /// Gets platform specific display information diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 16fc8117d5..c427df1c26 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -47,6 +47,11 @@ namespace Avalonia.Controls { IsVisibleProperty.OverrideDefaultValue(false); IsVisibleProperty.Changed.AddClassHandler(x => x.IsVisibleChanged); + + MinWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight))); + MinHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight))); + MaxWidthProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight))); + MaxHeightProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue))); } public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current) @@ -197,14 +202,7 @@ namespace Avalonia.Controls { using (BeginAutoSizing()) { - if (PlatformImpl != null) - { - PlatformImpl.MinHeight = MinHeight; - PlatformImpl.MaxHeight = MaxHeight; - PlatformImpl.MinWidth = MinWidth; - PlatformImpl.MaxWidth = MaxWidth; - PlatformImpl.Resize(finalSize); - } + PlatformImpl?.Resize(finalSize); } return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size)); diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 703f5ec5c8..f2676925a3 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -67,13 +67,9 @@ namespace Avalonia.DesignerSupport.Remote RenderIfNeeded(); } - public double MinWidth { get; set; } - - public double MaxWidth { get; set; } - - public double MinHeight { get; set; } - - public double MaxHeight { get; set; } + public void SetMinMaxSize(Size minSize, Size maxSize) + { + } public IScreenImpl Screen { get; } = new ScreenStub(); diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 6dd207178d..08c2c77ad1 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -78,13 +78,9 @@ namespace Avalonia.DesignerSupport.Remote public IScreenImpl Screen { get; } = new ScreenStub(); - public double MinWidth { get; set; } - - public double MaxWidth { get; set; } - - public double MinHeight { get; set; } - - public double MaxHeight { get; set; } + public void SetMinMaxSize(Size minSize, Size maxSize) + { + } public void SetTitle(string title) { diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index 7cf0a0b256..0240e15a19 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -421,6 +421,7 @@ namespace Avalonia.Gtk3.Interop public static D.gdk_window_set_override_redirect GdkWindowSetOverrideRedirect; public static D.gtk_widget_set_size_request GtkWindowSetSizeRequest; public static D.gtk_window_set_default_size GtkWindowSetDefaultSize; + public static D.gtk_window_set_geometry_hints GtkWindowSetGeometryHints; public static D.gtk_window_get_position GtkWindowGetPosition; public static D.gtk_window_move GtkWindowMove; public static D.gtk_file_chooser_dialog_new GtkFileChooserDialogNew; @@ -503,7 +504,6 @@ namespace Avalonia.Gtk3.Interop public static D.cairo_move_to CairoMoveTo; public static D.cairo_destroy CairoDestroy; - public static D.gtk_window_set_geometry_hints GtkWindowSetGeometryHints; public const int G_TYPE_OBJECT = 80; } diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index 7e55892570..0ebfea998a 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -341,13 +341,19 @@ namespace Avalonia.Gtk3 } } - public double MinWidth { get; set; } - - public double MaxWidth { get; set; } + public void SetMinMaxSize(Size minSize, Size maxSize) + { + if (GtkWidget.IsClosed) + return; - public double MinHeight { get; set; } + GdkGeometry geometry = new GdkGeometry(); + geometry.min_width = minSize.Width > 0 ? (int)minSize.Width : -1; + geometry.min_height = minSize.Height > 0 ? (int)minSize.Height : -1; + geometry.max_width = !Double.IsInfinity(maxSize.Width) && maxSize.Width > 0 ? (int)maxSize.Width : 999999; + geometry.max_height = !Double.IsInfinity(maxSize.Height) && maxSize.Height > 0 ? (int)maxSize.Height : 999999; - public double MaxHeight { get; set; } + Native.GtkWindowSetGeometryHints(GtkWidget, IntPtr.Zero, ref geometry, GdkWindowHints.GDK_HINT_MIN_SIZE | GdkWindowHints.GDK_HINT_MAX_SIZE); + } public IMouseDevice MouseDevice => Gtk3Platform.Mouse; @@ -439,15 +445,7 @@ namespace Avalonia.Gtk3 { if (GtkWidget.IsClosed) return; - - GdkGeometry geometry = new GdkGeometry(); - geometry.min_width = MinWidth > 0 ? (int)MinWidth : -1; - geometry.min_height = MinHeight > 0 ? (int)MinHeight : -1; - geometry.max_width = !Double.IsInfinity(MaxWidth) && MaxWidth > 0 ? (int)MaxWidth : 999999; - geometry.max_height = !Double.IsInfinity(MaxHeight) && MaxHeight > 0 ? (int)MaxHeight : 999999; - - Native.GtkWindowSetGeometryHints(GtkWidget, IntPtr.Zero, ref geometry, GdkWindowHints.GDK_HINT_MIN_SIZE | GdkWindowHints.GDK_HINT_MAX_SIZE); - + Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height); if (OverrideRedirect) { diff --git a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs index 0b64aae36b..8cbc6cbdd8 100644 --- a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs +++ b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs @@ -161,13 +161,9 @@ namespace Avalonia.MonoMac Position = pos; } - public double MinWidth { get; set; } - - public double MaxWidth { get; set; } - - public double MinHeight { get; set; } - - public double MaxHeight { get; set; } + public void SetMinMaxSize(Size minSize, Size maxSize) + { + } public IScreenImpl Screen { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 73d8228bab..d9d4e4520c 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -35,6 +35,9 @@ namespace Avalonia.Win32 private WindowState _showWindowState; private FramebufferManager _framebuffer; private OleDropTarget _dropTarget; + private Size _minSize; + private Size _maxSize; + #if USE_MANAGED_DRAG private readonly ManagedWindowResizeDragHelper _managedDrag; #endif @@ -102,13 +105,11 @@ namespace Avalonia.Win32 } } - public double MinWidth { get; set; } - - public double MaxWidth { get; set; } - - public double MinHeight { get; set; } - - public double MaxHeight { get; set; } + public void SetMinMaxSize(Size minSize, Size maxSize) + { + _minSize = minSize; + _maxSize = maxSize; + } public IScreenImpl Screen { @@ -624,17 +625,17 @@ namespace Avalonia.Win32 MINMAXINFO mmi = Marshal.PtrToStructure(lParam); - if (MinWidth > 0) - mmi.ptMinTrackSize.X = (int)((MinWidth * Scaling) + BorderThickness.Left + BorderThickness.Right); + if (_minSize.Width > 0) + mmi.ptMinTrackSize.X = (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); - if (MinHeight > 0) - mmi.ptMinTrackSize.Y = (int)((MinHeight * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + if (_minSize.Height > 0) + mmi.ptMinTrackSize.Y = (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); - if (!Double.IsInfinity(MaxWidth) && MaxWidth > 0) - mmi.ptMaxTrackSize.X = (int)((MaxWidth * Scaling) + BorderThickness.Left + BorderThickness.Right); + if (!Double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0) + mmi.ptMaxTrackSize.X = (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right); - if (!Double.IsInfinity(MaxHeight) && MaxHeight > 0) - mmi.ptMaxTrackSize.Y = (int)((MaxHeight * Scaling) + BorderThickness.Top + BorderThickness.Bottom); + if (!Double.IsInfinity(_maxSize.Height) && _maxSize.Height > 0) + mmi.ptMaxTrackSize.Y = (int)((_maxSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom); Marshal.StructureToPtr(mmi, lParam, true); return IntPtr.Zero; From 69e4a5220cf91071f2cb4e371754b6af63b3f513 Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 24 Apr 2018 11:03:21 +0200 Subject: [PATCH 012/101] Stubs for Android and iOS --- .../Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs | 6 +++++- src/iOS/Avalonia.iOS/EmbeddableImpl.cs | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs index 0b683239fb..78f744cea0 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs @@ -36,7 +36,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform _clientSize = value; UpdateParams(); } - + + public void SetMinMaxSize(Size minSize, Size maxSize) + { + } + public IScreenImpl Screen { get; } public Point Position diff --git a/src/iOS/Avalonia.iOS/EmbeddableImpl.cs b/src/iOS/Avalonia.iOS/EmbeddableImpl.cs index 50a3cd9ec0..3d8bafeca9 100644 --- a/src/iOS/Avalonia.iOS/EmbeddableImpl.cs +++ b/src/iOS/Avalonia.iOS/EmbeddableImpl.cs @@ -14,6 +14,10 @@ namespace Avalonia.iOS } + public void SetMinMaxSize(Size minSize, Size maxSize) + { + } + public IDisposable ShowDialog() { return Disposable.Empty; From ccd62038afeb5e75afc516c0bd5c404bba9216bf Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Wed, 25 Apr 2018 21:40:54 +0200 Subject: [PATCH 013/101] Update Portable.Xaml to https://github.com/AvaloniaUI/Portable.Xaml/pull/1 --- .../Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github index e7077fa7df..faa952f3a0 160000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github @@ -1 +1 @@ -Subproject commit e7077fa7df836af53f220f845f59971208c3e408 +Subproject commit faa952f3a05b4bdf2986d686f4154b1ab084508a From 8d11d7a5fa0557397fd4de749f8b68d709558538 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Thu, 26 Apr 2018 02:42:21 +0200 Subject: [PATCH 014/101] BindingExtension Source tests and sample #1521 --- samples/BindingTest/MainWindow.xaml | 8 +++ .../MarkupExtensions/BindingExtensionTests.cs | 71 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs diff --git a/samples/BindingTest/MainWindow.xaml b/samples/BindingTest/MainWindow.xaml index 3547e33181..21e3af0d22 100644 --- a/samples/BindingTest/MainWindow.xaml +++ b/samples/BindingTest/MainWindow.xaml @@ -1,4 +1,5 @@ @@ -6,6 +7,9 @@ + + + @@ -40,6 +44,10 @@ + + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs new file mode 100644 index 0000000000..4b0bee00f3 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Avalonia.Controls; +using Avalonia.Controls.Presenters; +using Avalonia.Controls.Templates; +using Avalonia.Styling; +using Avalonia.UnitTests; +using Xunit; + +namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions +{ + public class BindingExtensionTests + { + + [Fact] + public void BindingExtension_Binds_To_Source() + { + using (StyledWindow()) + { + var xaml = @" + + + foobar + + + +"; + + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBlock = window.FindControl("textBlock"); + + window.Show(); + + Assert.Equal("foobar", textBlock.Text); + } + } + + private IDisposable StyledWindow(params (string, string)[] assets) + { + var services = TestServices.StyledWindow.With( + assetLoader: new MockAssetLoader(assets), + theme: () => new Styles + { + WindowStyle(), + }); + + return UnitTestApplication.Start(services); + } + + private Style WindowStyle() + { + return new Style(x => x.OfType()) + { + Setters = + { + new Setter( + Window.TemplateProperty, + new FuncControlTemplate(x => + new ContentPresenter + { + Name = "PART_ContentPresenter", + [!ContentPresenter.ContentProperty] = x[!Window.ContentProperty], + })) + } + }; + } + } +} From 5dabc067edb222cdc3d3c55f295c4aab0e8572ec Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Thu, 26 Apr 2018 02:19:26 +0200 Subject: [PATCH 015/101] Added StaticResource tests for bindings within DataTemplate --- .../StaticResourceExtensionTests.cs | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs index 57293d5d16..e6116ed563 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs @@ -323,7 +323,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions Assert.Equal(0xff506070, brush.Color.ToUint32()); } - [Fact(/*Skip = "Not yet supported by Portable.Xaml"*/)] + [Fact] public void StaticResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File() { var styleXaml = @" @@ -418,7 +418,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } [Fact] - public void StaticResource_Can_Be_Assigned_To_Converter_In_DataTemplate() + public void StaticResource_Can_Be_Assigned_To_Binding_Converter_In_DataTemplate() { using (StyledWindow()) { @@ -429,7 +429,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions - + @@ -451,6 +451,45 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } + [Fact] + public void StaticResource_Is_Correctly_Chosen_From_Within_DataTemplate() + { + // this tests if IAmbientProviders in DataTemplate contexts are in correct order + // if they wouldn't be, Purple brush would be bound to + using (StyledWindow()) + { + var xaml = @" + + + + + + + + + + + + + + + +"; + + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + + window.Show(); + + var textBlock = window.GetVisualDescendants().OfType().Single(); + + Assert.NotNull(textBlock); + Assert.Equal("White-bar", textBlock.Text); + } + } + [Fact] public void Control_Property_Is_Not_Updated_When_Parent_Is_Changed() { From a50a8a33148ac476363e94097ce12cbeb601364e Mon Sep 17 00:00:00 2001 From: CommonGuy Date: Thu, 26 Apr 2018 10:35:52 +0200 Subject: [PATCH 016/101] Add CanResize to Window --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 5 +++ src/Avalonia.Controls/Window.cs | 14 ++++++++ .../Remote/PreviewerWindowImpl.cs | 4 +++ src/Avalonia.DesignerSupport/Remote/Stubs.cs | 4 +++ src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 3 ++ src/Gtk/Avalonia.Gtk3/WindowImpl.cs | 2 ++ src/OSX/Avalonia.MonoMac/WindowImpl.cs | 18 ++++++++-- src/Windows/Avalonia.Win32/WindowImpl.cs | 35 ++++++++++++++++--- 8 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 1f84574318..3f2c977718 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -45,6 +45,11 @@ namespace Avalonia.Platform /// void ShowTaskbarIcon(bool value); + /// + /// Enables or disables resizing of the window + /// + void CanResize(bool value); + /// /// Gets or sets a method called before the underlying implementation is destroyed. /// Return true to prevent the underlying implementation from closing. diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index c66209d3c6..16ee3a46b3 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -95,6 +95,9 @@ namespace Avalonia.Controls o => o.WindowStartupLocation, (o, v) => o.WindowStartupLocation = v); + public static readonly StyledProperty CanResizeProperty = + AvaloniaProperty.Register(nameof(CanResize), true); + private readonly NameScope _nameScope = new NameScope(); private object _dialogResult; private readonly Size _maxPlatformClientSize; @@ -113,6 +116,8 @@ namespace Avalonia.Controls ShowInTaskbarProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue)); IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); + + CanResizeProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue)); } /// @@ -208,6 +213,15 @@ namespace Avalonia.Controls } } + /// + /// Enables or disables resizing of the window + /// + public bool CanResize + { + get { return GetValue(CanResizeProperty); } + set { SetValue(CanResizeProperty, value); } + } + /// /// Gets or sets the icon of the window. /// diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index fc9541abb7..f949d05171 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -93,5 +93,9 @@ namespace Avalonia.DesignerSupport.Remote public void ShowTaskbarIcon(bool value) { } + + public void CanResize(bool value) + { + } } } \ No newline at end of file diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 560425286e..01c3065486 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -95,6 +95,10 @@ namespace Avalonia.DesignerSupport.Remote public void ShowTaskbarIcon(bool value) { } + + public void CanResize(bool value) + { + } } class ClipboardStub : IClipboard diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index d4618e7bc1..f33623dd91 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -115,6 +115,8 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_window_set_title(GtkWindow gtkWindow, Utf8Buffer title); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_set_resizable(GtkWindow gtkWindow, bool resizable); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] public delegate void gtk_window_set_decorated(GtkWindow gtkWindow, bool decorated); @@ -395,6 +397,7 @@ namespace Avalonia.Gtk3.Interop public static D.gdk_screen_get_monitor_geometry GdkScreenGetMonitorGeometry; public static D.gdk_screen_get_monitor_workarea GdkScreenGetMonitorWorkarea; public static D.gtk_window_set_decorated GtkWindowSetDecorated; + public static D.gtk_window_set_resizable GtkWindowSetResizable; public static D.gtk_window_set_skip_taskbar_hint GtkWindowSetSkipTaskbarHint; public static D.gtk_window_get_skip_taskbar_hint GtkWindowGetSkipTaskbarHint; public static D.gtk_window_set_skip_pager_hint GtkWindowSetSkipPagerHint; diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs index c586661a7a..2d309e19d4 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs @@ -61,6 +61,8 @@ namespace Avalonia.Gtk3 } public void ShowTaskbarIcon(bool value) => Native.GtkWindowSetSkipTaskbarHint(GtkWidget, !value); + + public void CanResize(bool value) => Native.GtkWindowSetResizable(GtkWidget, value); class EmptyDisposable : IDisposable diff --git a/src/OSX/Avalonia.MonoMac/WindowImpl.cs b/src/OSX/Avalonia.MonoMac/WindowImpl.cs index 6825fce82e..d01cbd6ae3 100644 --- a/src/OSX/Avalonia.MonoMac/WindowImpl.cs +++ b/src/OSX/Avalonia.MonoMac/WindowImpl.cs @@ -9,6 +9,7 @@ namespace Avalonia.MonoMac class WindowImpl : WindowBaseImpl, IWindowImpl { public bool IsDecorated = true; + public bool IsResizable = true; public CGRect? UndecoratedLastUnmaximizedFrame; public WindowImpl() @@ -76,10 +77,15 @@ namespace Avalonia.MonoMac protected override NSWindowStyle GetStyle() { + var windowStyle = NSWindowStyle.Borderless; + if (IsDecorated) - return NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Miniaturizable | - NSWindowStyle.Titled; - return NSWindowStyle.Borderless; + windowStyle |= NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Titled; + + if (IsResizable) + windowStyle |= NSWindowStyle.Resizable; + + return windowStyle; } public void SetSystemDecorations(bool enabled) @@ -88,6 +94,12 @@ namespace Avalonia.MonoMac UpdateStyle(); } + public void CanResize(bool value) + { + IsResizable = value; + UpdateStyle(); + } + public void SetTitle(string title) => Window.Title = title; class ModalDisposable : IDisposable diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bb3c4cf6e6..9014f1fb85 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -31,6 +31,7 @@ namespace Avalonia.Win32 private IInputRoot _owner; private bool _trackingMouse; private bool _decorated = true; + private bool _resizable = true; private double _scaling = 1; private WindowState _showWindowState; private FramebufferManager _framebuffer; @@ -237,11 +238,17 @@ namespace Avalonia.Win32 var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16); - style |= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + var systemDecorationStyles = UnmanagedMethods.WindowStyles.WS_OVERLAPPED + | UnmanagedMethods.WindowStyles.WS_CAPTION + | UnmanagedMethods.WindowStyles.WS_SYSMENU + | UnmanagedMethods.WindowStyles.WS_MINIMIZEBOX + | UnmanagedMethods.WindowStyles.WS_MAXIMIZEBOX; + + style |= systemDecorationStyles; if (!value) { - style ^= UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW; + style ^= systemDecorationStyles; } UnmanagedMethods.RECT windowRect; @@ -799,10 +806,10 @@ namespace Avalonia.Win32 public void ShowTaskbarIcon(bool value) { var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -20); - - style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE); - style |= UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW; + style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE); + + style |= UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW; if (value) style |= UnmanagedMethods.WindowStyles.WS_EX_APPWINDOW; else @@ -817,5 +824,23 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(_hwnd, windowPlacement.ShowCmd); } } + + public void CanResize(bool value) + { + if (value == _resizable) + { + return; + } + + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16); + + if (value) + style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; + else + style &= ~(UnmanagedMethods.WindowStyles.WS_SIZEFRAME); + + UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint)style); + _resizable = value; + } } } From 73ca7334ee880714926fea387f2e32c1814c806a Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 26 Apr 2018 18:39:28 +0200 Subject: [PATCH 017/101] Initial --- .../Data/BindingExpressionTests.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs index f5c0c6ec15..f42e0daf2a 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs @@ -58,7 +58,7 @@ namespace Avalonia.Markup.UnitTests.Data [Fact] public async Task Should_Convert_Get_String_To_Double() { - var data = new Class1 { StringValue = "5.6" }; + var data = new Class1 { StringValue = $"{5.6}" }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double)); var result = await target.Take(1); @@ -94,12 +94,12 @@ namespace Avalonia.Markup.UnitTests.Data [Fact] public void Should_Convert_Set_String_To_Double() { - var data = new Class1 { StringValue = (5.6).ToString() }; + var data = new Class1 { StringValue = $"{5.6}" }; var target = new BindingExpression(new ExpressionObserver(data, "StringValue"), typeof(double)); target.OnNext(6.7); - Assert.Equal((6.7).ToString(), data.StringValue); + Assert.Equal($"{6.7}", data.StringValue); GC.KeepAlive(data); } @@ -111,7 +111,7 @@ namespace Avalonia.Markup.UnitTests.Data var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string)); var result = await target.Take(1); - Assert.Equal((5.6).ToString(), result); + Assert.Equal($"{5.6}", result); GC.KeepAlive(data); } @@ -122,7 +122,7 @@ namespace Avalonia.Markup.UnitTests.Data var data = new Class1 { DoubleValue = 5.6 }; var target = new BindingExpression(new ExpressionObserver(data, "DoubleValue"), typeof(string)); - target.OnNext("6.7"); + target.OnNext($"{6.7}"); Assert.Equal(6.7, data.DoubleValue); @@ -318,15 +318,15 @@ namespace Avalonia.Markup.UnitTests.Data target.Subscribe(x => result.Add(x)); target.OnNext(1.2); - target.OnNext("3.4"); + target.OnNext($"{3.4}"); target.OnNext("bar"); Assert.Equal( new[] { - new BindingNotification("5.6"), - new BindingNotification("1.2"), - new BindingNotification("3.4"), + new BindingNotification($"{5.6}"), + new BindingNotification($"{1.2}"), + new BindingNotification($"{3.4}"), new BindingNotification( new InvalidCastException("'bar' is not a valid number."), BindingErrorType.Error) From d9819ab0047f1b21ffd7e663f52d6d0442ad084d Mon Sep 17 00:00:00 2001 From: CommonGuy Date: Fri, 27 Apr 2018 08:17:04 +0200 Subject: [PATCH 018/101] Extract WindowLong parameter into enum --- .../Avalonia.Win32/Interop/UnmanagedMethods.cs | 13 ++++++++++++- src/Windows/Avalonia.Win32/WindowImpl.cs | 16 ++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index aa86ab0f8d..c98b6d0a70 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -558,7 +558,18 @@ namespace Avalonia.Win32.Interop { DIB_RGB_COLORS = 0, /* color table in RGBs */ DIB_PAL_COLORS /* color table in palette indices */ - }; + } + + public enum WindowLongParam + { + GWL_WNDPROC = -4, + GWL_HINSTANCE = -6, + GWL_HWNDPARENT = -8, + GWL_ID = -12, + GWL_STYLE = -16, + GWL_EXSTYLE = -20, + GWL_USERDATA = -21 + } [StructLayout(LayoutKind.Sequential)] public struct RGBQUAD diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9014f1fb85..ce1eaed13c 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -78,8 +78,8 @@ namespace Avalonia.Win32 { get { - var style = UnmanagedMethods.GetWindowLong(_hwnd, -16); - var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, -20); + var style = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); + var exStyle = UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); var padding = new UnmanagedMethods.RECT(); if (UnmanagedMethods.AdjustWindowRectEx(ref padding, style, false, exStyle)) @@ -236,7 +236,7 @@ namespace Avalonia.Win32 return; } - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16); + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); var systemDecorationStyles = UnmanagedMethods.WindowStyles.WS_OVERLAPPED | UnmanagedMethods.WindowStyles.WS_CAPTION @@ -258,7 +258,7 @@ namespace Avalonia.Win32 Rect newRect; var oldThickness = BorderThickness; - UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint)style); + UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); if (value) { @@ -805,7 +805,7 @@ namespace Avalonia.Win32 public void ShowTaskbarIcon(bool value) { - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -20); + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE); style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE); @@ -820,7 +820,7 @@ namespace Avalonia.Win32 { //Toggle to make the styles stick UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide); - UnmanagedMethods.SetWindowLong(_hwnd, -20, (uint)style); + UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE, (uint)style); UnmanagedMethods.ShowWindow(_hwnd, windowPlacement.ShowCmd); } } @@ -832,14 +832,14 @@ namespace Avalonia.Win32 return; } - var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16); + var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE); if (value) style |= UnmanagedMethods.WindowStyles.WS_SIZEFRAME; else style &= ~(UnmanagedMethods.WindowStyles.WS_SIZEFRAME); - UnmanagedMethods.SetWindowLong(_hwnd, -16, (uint)style); + UnmanagedMethods.SetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style); _resizable = value; } } From 3bc303c4e8fc3a1906616e12782ef5c420eed0f0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 27 Apr 2018 13:12:28 +0100 Subject: [PATCH 019/101] implement menus and submenus obey screen extremities. --- src/Avalonia.Controls/ContextMenu.cs | 7 +++--- src/Avalonia.Controls/Primitives/Popup.cs | 18 +++++++++++++- src/Avalonia.Controls/Primitives/PopupRoot.cs | 24 +++++++++++++++++++ src/Avalonia.Themes.Default/MenuItem.xaml | 6 +++-- 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index fdb04f4ade..78dc994df7 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -19,7 +19,7 @@ namespace Avalonia.Controls { ContextMenuProperty.Changed.Subscribe(ContextMenuChanged); - MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true); + MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true); } /// @@ -75,13 +75,14 @@ namespace Avalonia.Controls { if (control != null) { - if(_popup == null) + if (_popup == null) { _popup = new Popup() { PlacementMode = PlacementMode.Pointer, PlacementTarget = control, - StaysOpen = false + StaysOpen = false, + ObeyScreenEdges = true }; _popup.Closed += PopupClosed; diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index b8817d28f3..d34e467133 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -40,6 +40,9 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty PlacementModeProperty = AvaloniaProperty.Register(nameof(PlacementMode), defaultValue: PlacementMode.Bottom); + public static readonly StyledProperty ObeyScreenEdgesProperty = + AvaloniaProperty.Register(nameof(ObeyScreenEdges)); + /// /// Defines the property. /// @@ -136,6 +139,12 @@ namespace Avalonia.Controls.Primitives set { SetValue(PlacementModeProperty, value); } } + public bool ObeyScreenEdges + { + get => GetValue(ObeyScreenEdgesProperty); + set => SetValue(ObeyScreenEdgesProperty, value); + } + /// /// Gets or sets the Horizontal offset of the popup in relation to the /// @@ -234,6 +243,11 @@ namespace Avalonia.Controls.Primitives _popupRoot.Show(); + if (ObeyScreenEdges) + { + _popupRoot.SnapInsideScreenEdges(); + } + _ignoreIsOpenChanged = true; IsOpen = true; _ignoreIsOpenChanged = false; @@ -346,8 +360,10 @@ namespace Avalonia.Controls.Primitives /// The popup's position in screen coordinates. protected virtual Point GetPosition() { - return GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot, + var result = GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot, HorizontalOffset, VerticalOffset); + + return result; } internal static Point GetPosition(Control target, PlacementMode placement, PopupRoot popupRoot, double horizontalOffset, double verticalOffset) diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs index 507a085fed..d0279200b6 100644 --- a/src/Avalonia.Controls/Primitives/PopupRoot.cs +++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Linq; using Avalonia.Controls.Platform; using Avalonia.Controls.Presenters; using Avalonia.Interactivity; @@ -75,6 +76,29 @@ namespace Avalonia.Controls.Primitives /// public void Dispose() => PlatformImpl?.Dispose(); + /// + /// Moves the Popups position so that it doesnt overlap screen edges. + /// This method can be called immediately after Show has been called. + /// + public void SnapInsideScreenEdges() + { + var mainWindow = Window.OpenWindows.First(); + var screen = mainWindow.Screens.ScreenFromPoint(Position); + + var screenX = Position.X + Bounds.Width - screen.Bounds.X; + var screenY = Position.Y + Bounds.Height - screen.Bounds.Y; + + if (screenX > screen.Bounds.Width) + { + Position = Position.WithX(Position.X - (screenX - screen.Bounds.Width)); + } + + if (screenY > screen.Bounds.Height) + { + Position = Position.WithY(Position.Y - (screenY - screen.Bounds.Height)); + } + } + /// protected override void OnTemplateApplied(TemplateAppliedEventArgs e) { diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index 66f226d2f6..efb31175fa 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -45,7 +45,8 @@ + IsOpen="{TemplateBinding Path=IsSubMenuOpen, Mode=TwoWay}" + ObeyScreenEdges="True"> @@ -92,7 +93,8 @@ + StaysOpen="True" + ObeyScreenEdges="True"> From 89767c8b78d122056d9a6827a6384be795a4e1ea Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 28 Apr 2018 09:43:03 +0100 Subject: [PATCH 020/101] add comments to new properties. --- src/Avalonia.Controls/Primitives/Popup.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index d34e467133..5483815522 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -39,7 +39,10 @@ namespace Avalonia.Controls.Primitives /// public static readonly StyledProperty PlacementModeProperty = AvaloniaProperty.Register(nameof(PlacementMode), defaultValue: PlacementMode.Bottom); - + + /// + /// Degines the property. + /// public static readonly StyledProperty ObeyScreenEdgesProperty = AvaloniaProperty.Register(nameof(ObeyScreenEdges)); @@ -139,6 +142,10 @@ namespace Avalonia.Controls.Primitives set { SetValue(PlacementModeProperty, value); } } + /// + /// Gets or sets a value indicating whether the popup positions itself within the nearest screen boundary + /// when its opened at a position where it would otherwise overlap the screen edge. + /// public bool ObeyScreenEdges { get => GetValue(ObeyScreenEdgesProperty); From 240bb40be4075aee7efa68a829bcd8852517c573 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 28 Apr 2018 09:45:08 +0100 Subject: [PATCH 021/101] whitespace fixes. --- src/Avalonia.Controls/Primitives/Popup.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 5483815522..56e09b7db6 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -39,7 +39,7 @@ namespace Avalonia.Controls.Primitives /// public static readonly StyledProperty PlacementModeProperty = AvaloniaProperty.Register(nameof(PlacementMode), defaultValue: PlacementMode.Bottom); - + /// /// Degines the property. /// @@ -232,12 +232,12 @@ namespace Avalonia.Controls.Primitives var window = _topLevel as Window; if (window != null) { - window.Deactivated += WindowDeactivated; + window.Deactivated += WindowDeactivated; } else { var parentPopuproot = _topLevel as PopupRoot; - if(parentPopuproot != null && parentPopuproot.Parent!=null) + if (parentPopuproot != null && parentPopuproot.Parent != null) { ((Popup)(parentPopuproot.Parent)).Closed += ParentClosed; } @@ -261,7 +261,7 @@ namespace Avalonia.Controls.Primitives Opened?.Invoke(this, EventArgs.Empty); } - + /// /// Closes the popup. /// @@ -367,7 +367,7 @@ namespace Avalonia.Controls.Primitives /// The popup's position in screen coordinates. protected virtual Point GetPosition() { - var result = GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot, + var result = GetPosition(PlacementTarget ?? this.GetVisualParent(), PlacementMode, PopupRoot, HorizontalOffset, VerticalOffset); return result; @@ -422,8 +422,8 @@ namespace Avalonia.Controls.Primitives { if (!StaysOpen) { - if(!IsChildOrThis((IVisual)e.Source)) - { + if (!IsChildOrThis((IVisual)e.Source)) + { Close(); e.Handled = true; } @@ -435,12 +435,12 @@ namespace Avalonia.Controls.Primitives IVisual root = child.GetVisualRoot(); while (root is PopupRoot) { - if (root == PopupRoot) return true; + if (root == PopupRoot) return true; root = ((PopupRoot)root).Parent.GetVisualRoot(); } return false; } - + private void WindowDeactivated(object sender, EventArgs e) { if (!StaysOpen) From 35b4913c0bfe712045a6ef340daebea721f8aa14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Sat, 28 Apr 2018 18:13:44 +0100 Subject: [PATCH 022/101] Removed AvaloniaWin32Exception usings. --- src/Windows/Avalonia.Win32/ScreenImpl.cs | 7 ------- src/Windows/Avalonia.Win32/Win32Platform.cs | 18 +++++++----------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs index 113b2811dc..e1df24151d 100644 --- a/src/Windows/Avalonia.Win32/ScreenImpl.cs +++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs @@ -2,16 +2,9 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using System.Linq; -using Avalonia.Controls; using Avalonia.Platform; -using Avalonia.Utilities; using static Avalonia.Win32.Interop.UnmanagedMethods; -#if NETSTANDARD -using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception; -#endif - namespace Avalonia.Win32 { public class ScreenImpl : IScreenImpl diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 902abaf65b..95077f82a1 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -1,27 +1,23 @@ // 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 Avalonia.Input.Platform; using System; using System.Collections.Generic; -using System.Reactive.Disposables; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Reactive.Disposables; using System.Runtime.InteropServices; using System.Threading; +using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.Platform; -using Avalonia.Win32.Input; -using Avalonia.Win32.Interop; -using Avalonia.Controls; using Avalonia.Rendering; using Avalonia.Threading; -using System.IO; -#if NETSTANDARD -using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception; -#else -using System.ComponentModel; -#endif +using Avalonia.Win32.Input; +using Avalonia.Win32.Interop; namespace Avalonia { From c1d6fe66864e797f486e7f4b1609438b270b0330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Sat, 28 Apr 2018 22:45:11 +0100 Subject: [PATCH 023/101] Fixed possible NullReferenceException in DefaultRenderLoop. --- src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs b/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs index 5dff3715b3..9cf849f59b 100644 --- a/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs +++ b/src/Avalonia.Visuals/Rendering/DefaultRenderLoop.cs @@ -41,12 +41,12 @@ namespace Avalonia.Rendering { add { + _tick += value; + if (_subscriberCount++ == 0) { Start(); } - - _tick += value; } remove From 6bb25bea93a20657c441ed6b2b0e3a53a01115c7 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 30 Apr 2018 10:22:43 +0100 Subject: [PATCH 024/101] fix typo. --- src/Avalonia.Controls/Primitives/Popup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 56e09b7db6..656f3890cd 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -41,7 +41,7 @@ namespace Avalonia.Controls.Primitives AvaloniaProperty.Register(nameof(PlacementMode), defaultValue: PlacementMode.Bottom); /// - /// Degines the property. + /// Defines the property. /// public static readonly StyledProperty ObeyScreenEdgesProperty = AvaloniaProperty.Register(nameof(ObeyScreenEdges)); From 247365714878d8b880889447065b94bdf1613645 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 30 Apr 2018 21:41:24 +0800 Subject: [PATCH 025/101] Fix 1533 Avoid throwing exception in TryReadDouble --- src/Avalonia.Base/Utilities/StringTokenizer.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Utilities/StringTokenizer.cs b/src/Avalonia.Base/Utilities/StringTokenizer.cs index 2559e52932..f4e9eee960 100644 --- a/src/Avalonia.Base/Utilities/StringTokenizer.cs +++ b/src/Avalonia.Base/Utilities/StringTokenizer.cs @@ -70,8 +70,15 @@ namespace Avalonia.Utilities public bool TryReadDouble(out double result, char? separator = null) { var success = TryReadString(out var stringResult, separator); - result = success ? double.Parse(stringResult, _formatProvider) : 0; - return success; + + if (success) + { + success = double.TryParse(stringResult, NumberStyles.Float, _formatProvider, out result); + return success; + } + + result = default(double); + return false; } public double ReadDouble(char? separator = null) From fd8e1ecba7e52abfe72cfa37af8d2921d72763c4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 30 Apr 2018 20:26:10 +0100 Subject: [PATCH 026/101] walk tree to find window. --- src/Avalonia.Controls/Primitives/PopupRoot.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs index d0279200b6..457a7bd4b4 100644 --- a/src/Avalonia.Controls/Primitives/PopupRoot.cs +++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs @@ -7,6 +7,7 @@ using Avalonia.Controls.Platform; using Avalonia.Controls.Presenters; using Avalonia.Interactivity; using Avalonia.Layout; +using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Styling; @@ -82,8 +83,9 @@ namespace Avalonia.Controls.Primitives /// public void SnapInsideScreenEdges() { - var mainWindow = Window.OpenWindows.First(); - var screen = mainWindow.Screens.ScreenFromPoint(Position); + var window = this.GetSelfAndLogicalAncestors().OfType().First(); + + var screen = window.Screens.ScreenFromPoint(Position); var screenX = Position.X + Bounds.Width - screen.Bounds.X; var screenY = Position.Y + Bounds.Height - screen.Bounds.Y; From eb273c0fcbe3a4b6e396b280afd3f6c568a0167a Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 2 May 2018 16:49:57 +0200 Subject: [PATCH 027/101] Inital --- src/Avalonia.Controls/ColumnDefinitions.cs | 2 +- src/Avalonia.Controls/GridLength.cs | 13 +++--- src/Avalonia.Controls/RowDefinitions.cs | 2 +- src/Avalonia.Visuals/CornerRadius.cs | 40 +++++++++---------- src/Avalonia.Visuals/Matrix.cs | 4 +- src/Avalonia.Visuals/Point.cs | 5 +-- src/Avalonia.Visuals/Rect.cs | 5 +-- src/Avalonia.Visuals/RelativePoint.cs | 9 ++--- src/Avalonia.Visuals/RelativeRect.cs | 12 +++--- src/Avalonia.Visuals/Size.cs | 5 +-- src/Avalonia.Visuals/Thickness.cs | 24 ++++++----- .../Converters/CornerRadiusTypeConverter.cs | 2 +- .../Converters/GridLengthTypeConverter.cs | 2 +- .../Converters/MatrixTypeConverter.cs | 2 +- .../Converters/PointTypeConverter.cs | 2 +- .../Converters/PointsListTypeConverter.cs | 2 +- .../Converters/RectTypeConverter.cs | 2 +- .../Converters/RelativePointTypeConverter.cs | 2 +- .../Converters/RelativeRectTypeConverter.cs | 2 +- .../Converters/SizeTypeConverter.cs | 2 +- .../Converters/ThicknessTypeConverter.cs | 2 +- .../GridLengthTests.cs | 18 ++++----- .../CornerRadiusTests.cs | 8 ++-- .../Media/MatrixTests.cs | 2 +- .../Media/RectTests.cs | 2 +- .../RelativePointTests.cs | 4 +- .../RelativeRectTests.cs | 6 +-- .../ThicknessTests.cs | 8 ++-- 28 files changed, 91 insertions(+), 98 deletions(-) diff --git a/src/Avalonia.Controls/ColumnDefinitions.cs b/src/Avalonia.Controls/ColumnDefinitions.cs index 32fe5a6034..972655262a 100644 --- a/src/Avalonia.Controls/ColumnDefinitions.cs +++ b/src/Avalonia.Controls/ColumnDefinitions.cs @@ -27,7 +27,7 @@ namespace Avalonia.Controls public ColumnDefinitions(string s) : this() { - AddRange(GridLength.ParseLengths(s, CultureInfo.InvariantCulture).Select(x => new ColumnDefinition(x))); + AddRange(GridLength.ParseLengths(s).Select(x => new ColumnDefinition(x))); } } } \ No newline at end of file diff --git a/src/Avalonia.Controls/GridLength.cs b/src/Avalonia.Controls/GridLength.cs index 789953a249..8a079b9837 100644 --- a/src/Avalonia.Controls/GridLength.cs +++ b/src/Avalonia.Controls/GridLength.cs @@ -180,9 +180,8 @@ namespace Avalonia.Controls /// Parses a string to return a . /// /// The string. - /// The current culture. /// The . - public static GridLength Parse(string s, CultureInfo culture) + public static GridLength Parse(string s) { s = s.ToUpperInvariant(); @@ -193,12 +192,12 @@ namespace Avalonia.Controls else if (s.EndsWith("*")) { var valueString = s.Substring(0, s.Length - 1).Trim(); - var value = valueString.Length > 0 ? double.Parse(valueString, culture) : 1; + var value = valueString.Length > 0 ? double.Parse(valueString, CultureInfo.InvariantCulture) : 1; return new GridLength(value, GridUnitType.Star); } else { - var value = double.Parse(s, culture); + var value = double.Parse(s, CultureInfo.InvariantCulture); return new GridLength(value, GridUnitType.Pixel); } } @@ -209,13 +208,13 @@ namespace Avalonia.Controls /// The string. /// The current culture. /// The . - public static IEnumerable ParseLengths(string s, CultureInfo culture) + public static IEnumerable ParseLengths(string s) { - using (var tokenizer = new StringTokenizer(s, culture)) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture)) { while (tokenizer.TryReadString(out var item)) { - yield return Parse(item, culture); + yield return Parse(item); } } } diff --git a/src/Avalonia.Controls/RowDefinitions.cs b/src/Avalonia.Controls/RowDefinitions.cs index e677492580..2dfad7111a 100644 --- a/src/Avalonia.Controls/RowDefinitions.cs +++ b/src/Avalonia.Controls/RowDefinitions.cs @@ -27,7 +27,7 @@ namespace Avalonia.Controls public RowDefinitions(string s) : this() { - AddRange(GridLength.ParseLengths(s, CultureInfo.InvariantCulture).Select(x => new RowDefinition(x))); + AddRange(GridLength.ParseLengths(s).Select(x => new RowDefinition(x))); } } } \ No newline at end of file diff --git a/src/Avalonia.Visuals/CornerRadius.cs b/src/Avalonia.Visuals/CornerRadius.cs index db0ac97d49..33a553d477 100644 --- a/src/Avalonia.Visuals/CornerRadius.cs +++ b/src/Avalonia.Visuals/CornerRadius.cs @@ -4,6 +4,7 @@ using System; using System.Globalization; using System.Linq; +using Avalonia.Utilities; namespace Avalonia { @@ -53,31 +54,26 @@ namespace Avalonia return $"{TopLeft},{TopRight},{BottomRight},{BottomLeft}"; } - public static CornerRadius Parse(string s, CultureInfo culture) + public static CornerRadius Parse(string s) { - var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Trim()) - .ToList(); - - switch (parts.Count) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Thickness")) { - case 1: - var uniform = double.Parse(parts[0], culture); - return new CornerRadius(uniform); - case 2: - var top = double.Parse(parts[0], culture); - var bottom = double.Parse(parts[1], culture); - return new CornerRadius(top, bottom); - case 4: - var topLeft = double.Parse(parts[0], culture); - var topRight = double.Parse(parts[1], culture); - var bottomRight = double.Parse(parts[2], culture); - var bottomLeft = double.Parse(parts[3], culture); - return new CornerRadius(topLeft, topRight, bottomRight, bottomLeft); - default: + if (tokenizer.TryReadDouble(out var a)) + { + if (tokenizer.TryReadDouble(out var b)) { - throw new FormatException("Invalid CornerRadius."); + if (tokenizer.TryReadDouble(out var c)) + { + return new CornerRadius(a, b, c, tokenizer.ReadDouble()); + } + + return new CornerRadius(a, b); } + + return new CornerRadius(a); + } + + throw new FormatException("Invalid CornerRadius."); } } @@ -85,7 +81,7 @@ namespace Avalonia { return cr1.TopLeft.Equals(cr2.TopLeft) && cr1.TopRight.Equals(cr2.TopRight) - && cr1.BottomRight.Equals(cr2.BottomRight) + && cr1.BottomRight.Equals(cr2.BottomRight) && cr1.BottomLeft.Equals(cr2.BottomLeft); } diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 70804ee04f..4336d24de8 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -316,9 +316,9 @@ namespace Avalonia /// The string. /// The current culture. /// The . - public static Matrix Parse(string s, CultureInfo culture) + public static Matrix Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Matrix")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Matrix")) { return new Matrix( tokenizer.ReadDouble(), diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs index d0c3edfeb2..62be3bf276 100644 --- a/src/Avalonia.Visuals/Point.cs +++ b/src/Avalonia.Visuals/Point.cs @@ -170,11 +170,10 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The . - public static Point Parse(string s, CultureInfo culture) + public static Point Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Point")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point")) { return new Point( tokenizer.ReadDouble(), diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 748928ada3..73021ca29a 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -487,11 +487,10 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The parsed . - public static Rect Parse(string s, CultureInfo culture) + public static Rect Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Rect")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Rect")) { return new Rect( tokenizer.ReadDouble(), diff --git a/src/Avalonia.Visuals/RelativePoint.cs b/src/Avalonia.Visuals/RelativePoint.cs index a2ef0e6725..e4d7ea05cb 100644 --- a/src/Avalonia.Visuals/RelativePoint.cs +++ b/src/Avalonia.Visuals/RelativePoint.cs @@ -154,11 +154,10 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The parsed . - public static RelativePoint Parse(string s, CultureInfo culture) + public static RelativePoint Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid RelativePoint")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid RelativePoint")) { var x = tokenizer.ReadString(); var y = tokenizer.ReadString(); @@ -180,8 +179,8 @@ namespace Avalonia } return new RelativePoint( - double.Parse(x, culture) * scale, - double.Parse(y, culture) * scale, + double.Parse(x, CultureInfo.InvariantCulture) * scale, + double.Parse(y, CultureInfo.InvariantCulture) * scale, unit); } } diff --git a/src/Avalonia.Visuals/RelativeRect.cs b/src/Avalonia.Visuals/RelativeRect.cs index c13c3282db..6929a8f71e 100644 --- a/src/Avalonia.Visuals/RelativeRect.cs +++ b/src/Avalonia.Visuals/RelativeRect.cs @@ -169,9 +169,9 @@ namespace Avalonia /// The string. /// The current culture. /// The parsed . - public static RelativeRect Parse(string s, CultureInfo culture) + public static RelativeRect Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid RelativeRect")) + using (var tokenizer = new StringTokenizer(s, exceptionMessage: "Invalid RelativeRect")) { var x = tokenizer.ReadString(); var y = tokenizer.ReadString(); @@ -202,10 +202,10 @@ namespace Avalonia } return new RelativeRect( - double.Parse(x, culture) * scale, - double.Parse(y, culture) * scale, - double.Parse(width, culture) * scale, - double.Parse(height, culture) * scale, + double.Parse(x, CultureInfo.InvariantCulture) * scale, + double.Parse(y, CultureInfo.InvariantCulture) * scale, + double.Parse(width, CultureInfo.InvariantCulture) * scale, + double.Parse(height, CultureInfo.InvariantCulture) * scale, unit); } } diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs index c5eaa33b41..b6889af6f0 100644 --- a/src/Avalonia.Visuals/Size.cs +++ b/src/Avalonia.Visuals/Size.cs @@ -150,11 +150,10 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The . - public static Size Parse(string s, CultureInfo culture) + public static Size Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Size")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Size")) { return new Size( tokenizer.ReadDouble(), diff --git a/src/Avalonia.Visuals/Thickness.cs b/src/Avalonia.Visuals/Thickness.cs index a5ca0a04a8..43a5fed9e7 100644 --- a/src/Avalonia.Visuals/Thickness.cs +++ b/src/Avalonia.Visuals/Thickness.cs @@ -165,25 +165,27 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The . - public static Thickness Parse(string s, CultureInfo culture) + public static Thickness Parse(string s) { - using (var tokenizer = new StringTokenizer(s, culture, exceptionMessage: "Invalid Thickness")) + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Thickness")) { - var a = tokenizer.ReadDouble(); - - if (tokenizer.TryReadDouble(out var b)) + if(tokenizer.TryReadDouble(out var a)) { - if (tokenizer.TryReadDouble(out var c)) + if (tokenizer.TryReadDouble(out var b)) { - return new Thickness(a, b, c, tokenizer.ReadDouble()); + if (tokenizer.TryReadDouble(out var c)) + { + return new Thickness(a, b, c, tokenizer.ReadDouble()); + } + + return new Thickness(a, b); } - return new Thickness(a, b); + return new Thickness(a); } - - return new Thickness(a); + + throw new FormatException("Invalid Thickness."); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/CornerRadiusTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/CornerRadiusTypeConverter.cs index 5da0efae1b..d8c1ecd4eb 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/CornerRadiusTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/CornerRadiusTypeConverter.cs @@ -13,7 +13,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return CornerRadius.Parse((string)value, culture); + return CornerRadius.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs index 1f72ca325c..05f3bed04d 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs @@ -18,7 +18,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return GridLength.Parse((string)value, culture); + return GridLength.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs index c477ff5637..fec6e31771 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return Matrix.Parse((string)value, culture); + return Matrix.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs index 1381fe7a75..9ca7212c68 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return Point.Parse((string)value, culture); + return Point.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs index b6c6da3055..29c7dbfd39 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs @@ -23,7 +23,7 @@ namespace Avalonia.Markup.Xaml.Converters var result = new List(pointStrs.Length); foreach (var pointStr in pointStrs) { - result.Add(Point.Parse(pointStr, culture)); + result.Add(Point.Parse(pointStr)); } return result; diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs index c9c6462f89..0946f95938 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return Rect.Parse((string)value, culture); + return Rect.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs index f68b8d66e6..b3178f1496 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return RelativePoint.Parse((string)value, culture); + return RelativePoint.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs index 64e39e224a..38c2833815 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return RelativeRect.Parse((string)value, culture); + return RelativeRect.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs index 73fef9ab1f..535e7948d5 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return Size.Parse((string)value, culture); + return Size.Parse((string)value); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs index 6ca5ec2f66..3a7652a153 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs @@ -17,7 +17,7 @@ namespace Avalonia.Markup.Xaml.Converters public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return Thickness.Parse((string)value, culture); + return Thickness.Parse((string)value); } } } \ No newline at end of file diff --git a/tests/Avalonia.Controls.UnitTests/GridLengthTests.cs b/tests/Avalonia.Controls.UnitTests/GridLengthTests.cs index 0a811333d4..ab4da0ca7e 100644 --- a/tests/Avalonia.Controls.UnitTests/GridLengthTests.cs +++ b/tests/Avalonia.Controls.UnitTests/GridLengthTests.cs @@ -13,7 +13,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Parse_Should_Parse_Auto() { - var result = GridLength.Parse("Auto", CultureInfo.InvariantCulture); + var result = GridLength.Parse("Auto"); Assert.Equal(GridLength.Auto, result); } @@ -21,7 +21,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Parse_Should_Parse_Auto_Lowercase() { - var result = GridLength.Parse("auto", CultureInfo.InvariantCulture); + var result = GridLength.Parse("auto"); Assert.Equal(GridLength.Auto, result); } @@ -29,7 +29,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Parse_Should_Parse_Star() { - var result = GridLength.Parse("*", CultureInfo.InvariantCulture); + var result = GridLength.Parse("*"); Assert.Equal(new GridLength(1, GridUnitType.Star), result); } @@ -37,7 +37,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Parse_Should_Parse_Star_Value() { - var result = GridLength.Parse("2*", CultureInfo.InvariantCulture); + var result = GridLength.Parse("2*"); Assert.Equal(new GridLength(2, GridUnitType.Star), result); } @@ -45,7 +45,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Parse_Should_Parse_Pixel_Value() { - var result = GridLength.Parse("2", CultureInfo.InvariantCulture); + var result = GridLength.Parse("2"); Assert.Equal(new GridLength(2, GridUnitType.Pixel), result); } @@ -53,13 +53,13 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Parse_Should_Throw_FormatException_For_Invalid_String() { - Assert.Throws(() => GridLength.Parse("2x", CultureInfo.InvariantCulture)); + Assert.Throws(() => GridLength.Parse("2x")); } [Fact] public void ParseLengths_Accepts_Comma_Separators() { - var result = GridLength.ParseLengths("*,Auto,2*,4", CultureInfo.InvariantCulture).ToList(); + var result = GridLength.ParseLengths("*,Auto,2*,4").ToList(); Assert.Equal( new[] @@ -75,7 +75,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void ParseLengths_Accepts_Space_Separators() { - var result = GridLength.ParseLengths("* Auto 2* 4", CultureInfo.InvariantCulture).ToList(); + var result = GridLength.ParseLengths("* Auto 2* 4").ToList(); Assert.Equal( new[] @@ -91,7 +91,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void ParseLengths_Accepts_Comma_Separators_With_Spaces() { - var result = GridLength.ParseLengths("*, Auto, 2* ,4", CultureInfo.InvariantCulture).ToList(); + var result = GridLength.ParseLengths("*, Auto, 2* ,4").ToList(); Assert.Equal( new[] diff --git a/tests/Avalonia.Visuals.UnitTests/CornerRadiusTests.cs b/tests/Avalonia.Visuals.UnitTests/CornerRadiusTests.cs index bc0bbdc867..56f9907409 100644 --- a/tests/Avalonia.Visuals.UnitTests/CornerRadiusTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/CornerRadiusTests.cs @@ -11,7 +11,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Parses_Single_Uniform_Radius() { - var result = CornerRadius.Parse("3.4", CultureInfo.InvariantCulture); + var result = CornerRadius.Parse("3.4"); Assert.Equal(new CornerRadius(3.4), result); } @@ -19,7 +19,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Parses_Top_Bottom() { - var result = CornerRadius.Parse("1.1,2.2", CultureInfo.InvariantCulture); + var result = CornerRadius.Parse("1.1,2.2"); Assert.Equal(new CornerRadius(1.1, 2.2), result); } @@ -27,7 +27,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Parses_TopLeft_TopRight_BottomRight_BottomLeft() { - var result = CornerRadius.Parse("1.1,2.2,3.3,4.4", CultureInfo.InvariantCulture); + var result = CornerRadius.Parse("1.1,2.2,3.3,4.4"); Assert.Equal(new CornerRadius(1.1, 2.2, 3.3, 4.4), result); } @@ -35,7 +35,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Accepts_Spaces() { - var result = CornerRadius.Parse("1.1 2.2 3.3 4.4", CultureInfo.InvariantCulture); + var result = CornerRadius.Parse("1.1 2.2 3.3 4.4"); Assert.Equal(new CornerRadius(1.1, 2.2, 3.3, 4.4), result); } diff --git a/tests/Avalonia.Visuals.UnitTests/Media/MatrixTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/MatrixTests.cs index 4c1e361952..ff1d17164e 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/MatrixTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/MatrixTests.cs @@ -8,7 +8,7 @@ namespace Avalonia.Visuals.UnitTests.Media [Fact] public void Parse_Parses() { - var matrix = Matrix.Parse("1,2,3,-4,5 6", CultureInfo.CurrentCulture); + var matrix = Matrix.Parse("1,2,3,-4,5 6"); var expected = new Matrix(1, 2, 3, -4, 5, 6); Assert.Equal(expected, matrix); } diff --git a/tests/Avalonia.Visuals.UnitTests/Media/RectTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/RectTests.cs index 12070bfed3..cd0c7e1ace 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/RectTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/RectTests.cs @@ -8,7 +8,7 @@ namespace Avalonia.Visuals.UnitTests.Media [Fact] public void Parse_Parses() { - var rect = Rect.Parse("1,2 3,-4", CultureInfo.CurrentCulture); + var rect = Rect.Parse("1,2 3,-4"); var expected = new Rect(1, 2, 3, -4); Assert.Equal(expected, rect); } diff --git a/tests/Avalonia.Visuals.UnitTests/RelativePointTests.cs b/tests/Avalonia.Visuals.UnitTests/RelativePointTests.cs index f4a21fb6b4..b9eecc809f 100644 --- a/tests/Avalonia.Visuals.UnitTests/RelativePointTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/RelativePointTests.cs @@ -11,7 +11,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Should_Accept_Absolute_Value() { - var result = RelativePoint.Parse("4,5", CultureInfo.InvariantCulture); + var result = RelativePoint.Parse("4,5"); Assert.Equal(new RelativePoint(4, 5, RelativeUnit.Absolute), result); } @@ -19,7 +19,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Should_Accept_Relative_Value() { - var result = RelativePoint.Parse("25%, 50%", CultureInfo.InvariantCulture); + var result = RelativePoint.Parse("25%, 50%"); Assert.Equal(new RelativePoint(0.25, 0.5, RelativeUnit.Relative), result); } diff --git a/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs b/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs index 9f25dcd413..68a0df2d9b 100644 --- a/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/RelativeRectTests.cs @@ -14,7 +14,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Should_Accept_Absolute_Value() { - var result = RelativeRect.Parse("4,5,50,60", CultureInfo.InvariantCulture); + var result = RelativeRect.Parse("4,5,50,60"); Assert.Equal(new RelativeRect(4, 5, 50, 60, RelativeUnit.Absolute), result, Compare); } @@ -22,7 +22,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Should_Accept_Relative_Value() { - var result = RelativeRect.Parse("10%, 20%, 40%, 70%", CultureInfo.InvariantCulture); + var result = RelativeRect.Parse("10%, 20%, 40%, 70%"); Assert.Equal(new RelativeRect(0.1, 0.2, 0.4, 0.7, RelativeUnit.Relative), result, Compare); } @@ -31,7 +31,7 @@ namespace Avalonia.Visuals.UnitTests public void Parse_Should_Throw_Mixed_Values() { Assert.Throws(() => - RelativeRect.Parse("10%, 20%, 40, 70%", CultureInfo.InvariantCulture)); + RelativeRect.Parse("10%, 20%, 40, 70%")); } } } diff --git a/tests/Avalonia.Visuals.UnitTests/ThicknessTests.cs b/tests/Avalonia.Visuals.UnitTests/ThicknessTests.cs index 03bf395d1e..ac4c6bc781 100644 --- a/tests/Avalonia.Visuals.UnitTests/ThicknessTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/ThicknessTests.cs @@ -11,7 +11,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Parses_Single_Uniform_Size() { - var result = Thickness.Parse("1.2", CultureInfo.InvariantCulture); + var result = Thickness.Parse("1.2"); Assert.Equal(new Thickness(1.2), result); } @@ -19,7 +19,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Parses_Horizontal_Vertical() { - var result = Thickness.Parse("1.2,3.4", CultureInfo.InvariantCulture); + var result = Thickness.Parse("1.2,3.4"); Assert.Equal(new Thickness(1.2, 3.4), result); } @@ -27,7 +27,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Parses_Left_Top_Right_Bottom() { - var result = Thickness.Parse("1.2, 3.4, 5, 6", CultureInfo.InvariantCulture); + var result = Thickness.Parse("1.2, 3.4, 5, 6"); Assert.Equal(new Thickness(1.2, 3.4, 5, 6), result); } @@ -35,7 +35,7 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Parse_Accepts_Spaces() { - var result = Thickness.Parse("1.2 3.4 5 6", CultureInfo.InvariantCulture); + var result = Thickness.Parse("1.2 3.4 5 6"); Assert.Equal(new Thickness(1.2, 3.4, 5, 6), result); } From 4e4c49b1e32db6b74dae1cf93a45d3e33888db47 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 2 May 2018 16:53:12 +0200 Subject: [PATCH 028/101] fix comments --- src/Avalonia.Visuals/Matrix.cs | 1 - src/Avalonia.Visuals/RelativeRect.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 4336d24de8..b09ea2b68c 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -314,7 +314,6 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The . public static Matrix Parse(string s) { diff --git a/src/Avalonia.Visuals/RelativeRect.cs b/src/Avalonia.Visuals/RelativeRect.cs index 6929a8f71e..ad42e30057 100644 --- a/src/Avalonia.Visuals/RelativeRect.cs +++ b/src/Avalonia.Visuals/RelativeRect.cs @@ -167,7 +167,6 @@ namespace Avalonia /// Parses a string. /// /// The string. - /// The current culture. /// The parsed . public static RelativeRect Parse(string s) { From f2e01704b2c48406dfadd9f1eea132375e2081b1 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 2 May 2018 19:35:38 +0200 Subject: [PATCH 029/101] comment removed --- src/Avalonia.Controls/GridLength.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Avalonia.Controls/GridLength.cs b/src/Avalonia.Controls/GridLength.cs index 8a079b9837..608879812c 100644 --- a/src/Avalonia.Controls/GridLength.cs +++ b/src/Avalonia.Controls/GridLength.cs @@ -206,7 +206,6 @@ namespace Avalonia.Controls /// Parses a string to return a collection of s. /// /// The string. - /// The current culture. /// The . public static IEnumerable ParseLengths(string s) { From 35141713383d0395b005f48df8ef247cdcd210e8 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 3 May 2018 23:00:10 +0200 Subject: [PATCH 030/101] Added PR template. --- .github/PULL_REQUEST_TEMPLATE.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..9a0da4aa9b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +This template is not intended to be prescriptive, but to help us review pull requests it would be useful if you included as much of the following information as possible: + +- What does the pull request do? +- What is the current behavior? +- What is the updated/expected behavior with this PR? +- How was the solution implemented (if it's not obvious)? + +Checklist: + +- [ ] Added unit tests (if possible)? +- [ ] Added XML documentation to any related classes? +- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Avaloniaui.net with user documentation + +If the pull request fixes issue(s) list them like this: + +Fixes #123 +Fixes #456 \ No newline at end of file From 1f4d21244a3c4cd50ed16ca5990ddb3ec4983530 Mon Sep 17 00:00:00 2001 From: boombuler Date: Fri, 4 May 2018 07:35:34 +0200 Subject: [PATCH 031/101] register `DragSource` after the UI thread has set due to the fact that the UI-Thread is unknown, there is no OLEContext available and the platform specific DragSource will never be used. --- src/Windows/Avalonia.Win32/Win32Platform.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 902abaf65b..f06f951d74 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -86,11 +86,11 @@ namespace Avalonia.Win32 .Bind().ToConstant(s_instance) .Bind().ToConstant(s_instance); - if (OleContext.Current != null) - AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); - UseDeferredRendering = deferredRendering; _uiThread = UnmanagedMethods.GetCurrentThreadId(); + + if (OleContext.Current != null) + AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); } public bool HasMessages() From 1e2e5b5efce4be41f5364bc07a7800db2e0c2d83 Mon Sep 17 00:00:00 2001 From: boombuler Date: Fri, 4 May 2018 07:57:40 +0200 Subject: [PATCH 032/101] fixes #1537 since the `System.Runtime.InteropServices.ComTypes.IDataObject` of .net core is missing the GUID, any OLE-Calls with this type will fail. --- src/Windows/Avalonia.Win32/DataObject.cs | 1 - .../Interop/UnmanagedMethods.cs | 27 ++++++++++++++++--- src/Windows/Avalonia.Win32/OleDataObject.cs | 5 ++-- src/Windows/Avalonia.Win32/OleDropTarget.cs | 1 - 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/Windows/Avalonia.Win32/DataObject.cs b/src/Windows/Avalonia.Win32/DataObject.cs index 34867765e5..13d5f662c2 100644 --- a/src/Windows/Avalonia.Win32/DataObject.cs +++ b/src/Windows/Avalonia.Win32/DataObject.cs @@ -7,7 +7,6 @@ using System.Text; using Avalonia.Input; using Avalonia.Win32.Interop; using IDataObject = Avalonia.Input.IDataObject; -using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; using System.IO; using System.Runtime.Serialization.Formatters.Binary; diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index aa86ab0f8d..c5ef006b84 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -974,7 +974,7 @@ namespace Avalonia.Win32.Interop public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch); [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)] - public static extern void DoDragDrop(IDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect); + public static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect); @@ -1366,13 +1366,13 @@ namespace Avalonia.Win32.Interop internal interface IDropTarget { [PreserveSig] - UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect); + UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IOleDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect); [PreserveSig] UnmanagedMethods.HRESULT DragOver([MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect); [PreserveSig] UnmanagedMethods.HRESULT DragLeave(); [PreserveSig] - UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect); + UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IOleDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect); } [ComImport] @@ -1387,6 +1387,27 @@ namespace Avalonia.Win32.Interop } + [ComImport] + [Guid("0000010E-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IOleDataObject + { + void GetData([In] ref FORMATETC format, out STGMEDIUM medium); + void GetDataHere([In] ref FORMATETC format, ref STGMEDIUM medium); + [PreserveSig] + int QueryGetData([In] ref FORMATETC format); + [PreserveSig] + int GetCanonicalFormatEtc([In] ref FORMATETC formatIn, out FORMATETC formatOut); + void SetData([In] ref FORMATETC formatIn, [In] ref STGMEDIUM medium, [MarshalAs(UnmanagedType.Bool)] bool release); + IEnumFORMATETC EnumFormatEtc(DATADIR direction); + [PreserveSig] + int DAdvise([In] ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection); + void DUnadvise(int connection); + [PreserveSig] + int EnumDAdvise(out IEnumSTATDATA enumAdvise); + } + + [StructLayoutAttribute(LayoutKind.Sequential)] internal struct _DROPFILES { diff --git a/src/Windows/Avalonia.Win32/OleDataObject.cs b/src/Windows/Avalonia.Win32/OleDataObject.cs index 85d1daadeb..d7b663e7bf 100644 --- a/src/Windows/Avalonia.Win32/OleDataObject.cs +++ b/src/Windows/Avalonia.Win32/OleDataObject.cs @@ -8,15 +8,14 @@ using System.Runtime.Serialization.Formatters.Binary; using System.Text; using Avalonia.Input; using Avalonia.Win32.Interop; -using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; namespace Avalonia.Win32 { class OleDataObject : Avalonia.Input.IDataObject { - private IDataObject _wrapped; + private IOleDataObject _wrapped; - public OleDataObject(IDataObject wrapped) + public OleDataObject(IOleDataObject wrapped) { _wrapped = wrapped; } diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index 500c03e317..973564a3d1 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -3,7 +3,6 @@ using Avalonia.Input.Raw; using Avalonia.Platform; using Avalonia.Win32.Interop; using IDataObject = Avalonia.Input.IDataObject; -using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; namespace Avalonia.Win32 { From 5a5fc13632ae0f6110d1b0a7243cc30cbb80468b Mon Sep 17 00:00:00 2001 From: boombuler Date: Fri, 4 May 2018 08:50:30 +0200 Subject: [PATCH 033/101] force mousecursor if the mouse is over the window without the call of SetCursor the cursor will only be updated once the mouse is moved. this fixes #1536 --- src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs | 3 +++ src/Windows/Avalonia.Win32/WindowImpl.cs | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index aa86ab0f8d..9b344f1bb4 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -849,6 +849,9 @@ namespace Avalonia.Win32.Interop return SetClassLong64(hWnd, nIndex, dwNewLong); } + [DllImport("user32.dll", EntryPoint = "SetCursor")] + internal static extern IntPtr SetCursor(IntPtr hCursor); + [DllImport("ole32.dll", PreserveSig = true)] internal static extern int CoCreateInstance(ref Guid clsid, IntPtr ignore1, int ignore2, ref Guid iid, [MarshalAs(UnmanagedType.IUnknown), Out] out object pUnkOuter); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index bb3c4cf6e6..c3fab0e6b9 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -383,8 +383,11 @@ namespace Avalonia.Win32 public void SetCursor(IPlatformHandle cursor) { - UnmanagedMethods.SetClassLong(_hwnd, UnmanagedMethods.ClassLongIndex.GCL_HCURSOR, - cursor?.Handle ?? DefaultCursor); + var hCursor = cursor?.Handle ?? DefaultCursor; + UnmanagedMethods.SetClassLong(_hwnd, UnmanagedMethods.ClassLongIndex.GCL_HCURSOR, hCursor); + + if (_owner.IsPointerOver) + UnmanagedMethods.SetCursor(hCursor); } protected virtual IntPtr CreateWindowOverride(ushort atom) From 7ae90eb7c502df24ce25932991420be757ef3b3b Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 4 May 2018 20:07:53 +0800 Subject: [PATCH 034/101] Cleanup all the csproj's that can be cleaned. Ported RenderTest and VirtualizationTest samples to .NET Core. --- build/Base.props | 2 +- samples/RenderTest/Properties/AssemblyInfo.cs | 36 ---- samples/RenderTest/RenderTest.csproj | 201 ++---------------- .../Properties/AssemblyInfo.cs | 36 ---- .../VirtualizationTest.csproj | 166 ++------------- .../Avalonia.Animation.csproj | 29 +-- .../Properties/AssemblyInfo.cs | 6 - .../{Properties => }/AssemblyInfo.cs | 1 - src/Avalonia.Base/Avalonia.Base.csproj | 30 +-- .../{Properties => }/AssemblyInfo.cs | 1 - .../Avalonia.Controls.csproj | 30 +-- .../Properties/AssemblyInfo.cs | 8 - .../Avalonia.Diagnostics.csproj | 37 +--- .../Properties/AssemblyInfo.cs | 6 - .../Avalonia.DotNetCoreRuntime.csproj | 6 +- .../Properties/AssemblyInfo.cs | 6 - .../Avalonia.DotNetFrameworkRuntime.csproj | 6 +- .../Avalonia.HtmlRenderer.csproj | 115 +--------- .../{Properties => }/AssemblyInfo.cs | 1 - src/Avalonia.Input/Avalonia.Input.csproj | 30 +-- .../Avalonia.Interactivity.csproj | 34 +-- .../Properties/AssemblyInfo.cs | 6 - src/Avalonia.Layout/Avalonia.Layout.csproj | 30 +-- .../Properties/AssemblyInfo.cs | 6 - .../Avalonia.Logging.Serilog.csproj | 26 +-- .../Properties/AssemblyInfo.cs | 3 - .../Avalonia.ReactiveUI.csproj | 4 +- .../Properties/AssemblyInfo.cs | 6 - .../{Properties => }/AssemblyInfo.cs | 1 - src/Avalonia.Styling/Avalonia.Styling.csproj | 30 +-- .../Avalonia.Themes.Default.csproj | 34 +-- .../Properties/AssemblyInfo.cs | 6 - .../{Properties => }/AssemblyInfo.cs | 1 - src/Avalonia.Visuals/Avalonia.Visuals.csproj | 29 +-- .../{Properties => }/AssemblyInfo.cs | 2 - src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj | 24 +-- .../Avalonia.LinuxFramebuffer.csproj | 1 + .../Avalonia.MonoMac/Avalonia.MonoMac.csproj | 2 +- src/Shared/CompileXaml.props | 11 + src/Shared/Shared.props | 11 + src/Skia/Avalonia.Skia/Avalonia.Skia.csproj | 10 +- 41 files changed, 105 insertions(+), 925 deletions(-) delete mode 100644 samples/RenderTest/Properties/AssemblyInfo.cs delete mode 100644 samples/VirtualizationTest/Properties/AssemblyInfo.cs delete mode 100644 src/Avalonia.Animation/Properties/AssemblyInfo.cs rename src/Avalonia.Base/{Properties => }/AssemblyInfo.cs (77%) rename src/Avalonia.Controls/{Properties => }/AssemblyInfo.cs (92%) delete mode 100644 src/Avalonia.DesignerSupport/Properties/AssemblyInfo.cs delete mode 100644 src/Avalonia.Diagnostics/Properties/AssemblyInfo.cs delete mode 100644 src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs rename src/Avalonia.Input/{Properties => }/AssemblyInfo.cs (87%) delete mode 100644 src/Avalonia.Interactivity/Properties/AssemblyInfo.cs delete mode 100644 src/Avalonia.Layout/Properties/AssemblyInfo.cs delete mode 100644 src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs delete mode 100644 src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs rename src/Avalonia.Styling/{Properties => }/AssemblyInfo.cs (82%) delete mode 100644 src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs rename src/Avalonia.Visuals/{Properties => }/AssemblyInfo.cs (85%) rename src/Gtk/Avalonia.Gtk3/{Properties => }/AssemblyInfo.cs (84%) create mode 100644 src/Shared/CompileXaml.props create mode 100644 src/Shared/Shared.props diff --git a/build/Base.props b/build/Base.props index 6689465338..78930156e7 100644 --- a/build/Base.props +++ b/build/Base.props @@ -2,4 +2,4 @@ - + \ No newline at end of file diff --git a/samples/RenderTest/Properties/AssemblyInfo.cs b/samples/RenderTest/Properties/AssemblyInfo.cs deleted file mode 100644 index f66c158075..0000000000 --- a/samples/RenderTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("RenderTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("RenderTest")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f1fdc5b0-4654-416f-ae69-e3e9bbd87801")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/RenderTest/RenderTest.csproj b/samples/RenderTest/RenderTest.csproj index b33d5d3c70..4373e4715a 100644 --- a/samples/RenderTest/RenderTest.csproj +++ b/samples/RenderTest/RenderTest.csproj @@ -1,184 +1,29 @@ - - - + - Debug - AnyCPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801} - WinExe - Properties - RenderTest - RenderTest - v4.7 - 512 - true - + Exe + netcoreapp2.0 - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - App.xaml - - - DrawingPage.xaml - - - ClippingPage.xaml - - - AnimationsPage.xaml - - - - - MainWindow.xaml - - - - - - - - - Designer - - - - {d211e587-d8bc-45b9-95a4-f297c8fa5200} - Avalonia.Animation - - - {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Avalonia.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Avalonia.Controls - - - {799a7bb5-3c2c-48b6-85a7-406a12c420da} - Avalonia.DesignerSupport - - - {7062ae20-5dcc-4442-9645-8195bdece63e} - Avalonia.Diagnostics - - - {4a1abb09-9047-4bd5-a4ad-a055e52c5ee0} - Avalonia.DotNetFrameworkRuntime - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Avalonia.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Avalonia.Interactivity - - - {42472427-4774-4c81-8aff-9f27b8e31721} - Avalonia.Layout - - - {b61b66a3-b82d-4875-8001-89d3394fe0c9} - Avalonia.Logging.Serilog - - - {6417b24e-49c2-4985-8db2-3ab9d898ec91} - Avalonia.ReactiveUI - - - {eb582467-6abb-43a1-b052-e981ba910e3a} - Avalonia.Visuals - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Avalonia.Styling - - - {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f} - Avalonia.Themes.Default - - - {3e53a01a-b331-47f3-b828-4a5717e77a24} - Avalonia.Markup.Xaml - - - {6417e941-21bc-467b-a771-0de389353ce6} - Avalonia.Markup - - - {7d2d3083-71dd-4cc9-8907-39a0d86fb322} - Avalonia.Skia - - - {3e908f67-5543-4879-a1dc-08eace79b3cd} - Avalonia.Direct2D1 - - - {811a76cf-1cf6-440f-963b-bbe31bd72a82} - Avalonia.Win32 - - - - - Designer - - - - - Designer - - - - - Designer - - - - - Designer - - - - - Designer - - - + + + + + + + + + + + + + + + + + + + + diff --git a/samples/VirtualizationTest/Properties/AssemblyInfo.cs b/samples/VirtualizationTest/Properties/AssemblyInfo.cs deleted file mode 100644 index e6af64555b..0000000000 --- a/samples/VirtualizationTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("VirtualizationTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("VirtualizationTest")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("fbcaf3d0-2808-4934-8e96-3f607594517b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/VirtualizationTest/VirtualizationTest.csproj b/samples/VirtualizationTest/VirtualizationTest.csproj index 0d498d827f..180c8dd48d 100644 --- a/samples/VirtualizationTest/VirtualizationTest.csproj +++ b/samples/VirtualizationTest/VirtualizationTest.csproj @@ -1,151 +1,29 @@ - - - + - Debug - AnyCPU - {FBCAF3D0-2808-4934-8E96-3F607594517B} - WinExe - Properties - VirtualizationTest - VirtualizationTest - v4.7 - 512 - true - + Exe + netcoreapp2.0 - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - App.xaml - - - MainWindow.xaml - - - - - - - - - - - - {d211e587-d8bc-45b9-95a4-f297c8fa5200} - Avalonia.Animation - - - {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Avalonia.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Avalonia.Controls - - - {799a7bb5-3c2c-48b6-85a7-406a12c420da} - Avalonia.DesignerSupport - - - {7062ae20-5dcc-4442-9645-8195bdece63e} - Avalonia.Diagnostics - - - {4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0} - Avalonia.DotNetFrameworkRuntime - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Avalonia.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Avalonia.Interactivity - - - {42472427-4774-4c81-8aff-9f27b8e31721} - Avalonia.Layout - - - {B61B66A3-B82D-4875-8001-89D3394FE0C9} - Avalonia.Logging.Serilog - - - {6417b24e-49c2-4985-8db2-3ab9d898ec91} - Avalonia.ReactiveUI - - - {eb582467-6abb-43a1-b052-e981ba910e3a} - Avalonia.Visuals - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Avalonia.Styling - - - {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f} - Avalonia.Themes.Default - - - {3e53a01a-b331-47f3-b828-4a5717e77a24} - Avalonia.Markup.Xaml - - - {6417e941-21bc-467b-a771-0de389353ce6} - Avalonia.Markup - - - {3e908f67-5543-4879-a1dc-08eace79b3cd} - Avalonia.Direct2D1 - - - {811a76cf-1cf6-440f-963b-bbe31bd72a82} - Avalonia.Win32 - - - - - Designer - - - - Designer - + + + + + + + + + + + + + + + + + - + + diff --git a/src/Avalonia.Animation/Avalonia.Animation.csproj b/src/Avalonia.Animation/Avalonia.Animation.csproj index 2101c5669d..6627fdf952 100644 --- a/src/Avalonia.Animation/Avalonia.Animation.csproj +++ b/src/Avalonia.Animation/Avalonia.Animation.csproj @@ -1,37 +1,10 @@  netstandard2.0 - false - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Animation.xml - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Animation.xml - CS1591 - true - - - - Properties\SharedAssemblyInfo.cs - - + \ No newline at end of file diff --git a/src/Avalonia.Animation/Properties/AssemblyInfo.cs b/src/Avalonia.Animation/Properties/AssemblyInfo.cs deleted file mode 100644 index a41edcc7b1..0000000000 --- a/src/Avalonia.Animation/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.Animation")] diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/AssemblyInfo.cs similarity index 77% rename from src/Avalonia.Base/Properties/AssemblyInfo.cs rename to src/Avalonia.Base/AssemblyInfo.cs index 2ee7378413..0a276aa2aa 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/AssemblyInfo.cs @@ -4,7 +4,6 @@ using System.Reflection; using System.Runtime.CompilerServices; -[assembly: AssemblyTitle("Avalonia.Base")] [assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.UnitTests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] \ No newline at end of file diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 54537841a9..599374f75a 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -1,36 +1,10 @@  netstandard2.0 - false + Avalonia.Base Avalonia - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Base.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Base.xml - CS1591 - true - - - - Properties\SharedAssemblyInfo.cs - - + diff --git a/src/Avalonia.Controls/Properties/AssemblyInfo.cs b/src/Avalonia.Controls/AssemblyInfo.cs similarity index 92% rename from src/Avalonia.Controls/Properties/AssemblyInfo.cs rename to src/Avalonia.Controls/AssemblyInfo.cs index ae8c88f7e8..3466119411 100644 --- a/src/Avalonia.Controls/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls/AssemblyInfo.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using Avalonia.Metadata; -[assembly: AssemblyTitle("Avalonia.Controls")] [assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.DesignerSupport")] diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 997e15050f..e50625a4c4 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -1,35 +1,8 @@  netstandard2.0 - false + Avalonia.Controls - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Controls.xml - CS1591;CS0067 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Controls.xml - CS1591 - true - - - - Properties\SharedAssemblyInfo.cs - - @@ -40,6 +13,7 @@ + \ No newline at end of file diff --git a/src/Avalonia.DesignerSupport/Properties/AssemblyInfo.cs b/src/Avalonia.DesignerSupport/Properties/AssemblyInfo.cs deleted file mode 100644 index 1c43bc6d1f..0000000000 --- a/src/Avalonia.DesignerSupport/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -// 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.Reflection; -using Avalonia.Metadata; - -[assembly: AssemblyTitle("Avalonia.Application")] -[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")] diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index 5f8e25269b..59ed1685f4 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -1,29 +1,7 @@  netstandard2.0 - false - - - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - bin\Debug\Avalonia.Diagnostics.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Diagnostics.xml - CS1591 - true + Avalonia.Diagnostics @@ -38,16 +16,7 @@ - - - Properties\SharedAssemblyInfo.cs - - - %(Filename) - - - Designer - - + + \ No newline at end of file diff --git a/src/Avalonia.Diagnostics/Properties/AssemblyInfo.cs b/src/Avalonia.Diagnostics/Properties/AssemblyInfo.cs deleted file mode 100644 index f4100ef48b..0000000000 --- a/src/Avalonia.Diagnostics/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.Diagnostics")] diff --git a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj index a7586ac7ac..3df25cca49 100644 --- a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj +++ b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj @@ -7,11 +7,6 @@ bin\$(Configuration)\Avalonia.DotNetCoreRuntime.xml - - - Properties\SharedAssemblyInfo.cs - - @@ -21,6 +16,7 @@ + \ No newline at end of file diff --git a/src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs b/src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs deleted file mode 100644 index 51ec3975c9..0000000000 --- a/src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.DotNetCoreRuntime")] diff --git a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj index dc4a06d2a7..1c30fe1795 100644 --- a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj +++ b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj @@ -7,15 +7,13 @@ true - - Properties\SharedAssemblyInfo.cs - + - + \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj index fde486fa12..a5d9bae468 100644 --- a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj +++ b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj @@ -6,124 +6,10 @@ false CS0436 - - true - full - false - bin\Debug\ - TRACE;DEBUG;PCL - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE;PCL - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -134,5 +20,6 @@ + \ No newline at end of file diff --git a/src/Avalonia.Input/Properties/AssemblyInfo.cs b/src/Avalonia.Input/AssemblyInfo.cs similarity index 87% rename from src/Avalonia.Input/Properties/AssemblyInfo.cs rename to src/Avalonia.Input/AssemblyInfo.cs index 64b8e8f1a3..7025965f83 100644 --- a/src/Avalonia.Input/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Input/AssemblyInfo.cs @@ -4,5 +4,4 @@ using System.Reflection; using Avalonia.Metadata; -[assembly: AssemblyTitle("Avalonia.Input")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input")] diff --git a/src/Avalonia.Input/Avalonia.Input.csproj b/src/Avalonia.Input/Avalonia.Input.csproj index c82601ac2c..59e413670e 100644 --- a/src/Avalonia.Input/Avalonia.Input.csproj +++ b/src/Avalonia.Input/Avalonia.Input.csproj @@ -1,29 +1,7 @@  netstandard2.0 - false - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Input.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Input.xml - CS1591 - true + Avalonia.Input @@ -32,10 +10,6 @@ - - - Properties\SharedAssemblyInfo.cs - - + \ No newline at end of file diff --git a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj index 4f6f9ad6fe..6178ad954e 100644 --- a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj +++ b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj @@ -1,29 +1,7 @@  netstandard2.0 - false - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Interactivity.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Interactivity.xml - CS1591 - true + Avalonia.Interactive @@ -31,10 +9,8 @@ - - - Properties\SharedAssemblyInfo.cs - - + - \ No newline at end of file + + + diff --git a/src/Avalonia.Interactivity/Properties/AssemblyInfo.cs b/src/Avalonia.Interactivity/Properties/AssemblyInfo.cs deleted file mode 100644 index 27c8765239..0000000000 --- a/src/Avalonia.Interactivity/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.Interactive")] diff --git a/src/Avalonia.Layout/Avalonia.Layout.csproj b/src/Avalonia.Layout/Avalonia.Layout.csproj index 58c18921f5..39dc37478c 100644 --- a/src/Avalonia.Layout/Avalonia.Layout.csproj +++ b/src/Avalonia.Layout/Avalonia.Layout.csproj @@ -1,39 +1,13 @@  netstandard2.0 - false - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Layout.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Layout.xml - CS1591 - true + Avalonia.Layout - - - Properties\SharedAssemblyInfo.cs - - + \ No newline at end of file diff --git a/src/Avalonia.Layout/Properties/AssemblyInfo.cs b/src/Avalonia.Layout/Properties/AssemblyInfo.cs deleted file mode 100644 index 126893e189..0000000000 --- a/src/Avalonia.Layout/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.Layout")] diff --git a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj index 4d9d141d0d..5116d196b5 100644 --- a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj +++ b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj @@ -1,34 +1,12 @@  netstandard2.0 - false + Avalonia.Serilog - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Logging.Serilog.xml - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Logging.Serilog.xml - true - - - - + \ No newline at end of file diff --git a/src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs b/src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs deleted file mode 100644 index 35b2e48f70..0000000000 --- a/src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Avalonia.Serilog")] diff --git a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj index b7ad36f8b2..aee428c247 100644 --- a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj +++ b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj @@ -1,10 +1,9 @@  netstandard2.0 - false + Avalonia.ReactiveUI - @@ -14,6 +13,7 @@ + \ No newline at end of file diff --git a/src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs b/src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs deleted file mode 100644 index c9ead6f6e6..0000000000 --- a/src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.ReactiveUI")] diff --git a/src/Avalonia.Styling/Properties/AssemblyInfo.cs b/src/Avalonia.Styling/AssemblyInfo.cs similarity index 82% rename from src/Avalonia.Styling/Properties/AssemblyInfo.cs rename to src/Avalonia.Styling/AssemblyInfo.cs index 0a639139f7..9f1794c700 100644 --- a/src/Avalonia.Styling/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Styling/AssemblyInfo.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using Avalonia.Metadata; -[assembly: AssemblyTitle("Avalonia.Styling")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.LogicalTree")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj index b8083b52db..d614747c7b 100644 --- a/src/Avalonia.Styling/Avalonia.Styling.csproj +++ b/src/Avalonia.Styling/Avalonia.Styling.csproj @@ -1,40 +1,14 @@  netstandard2.0 - false + Avalonia.Styling Avalonia - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Styling.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Styling.xml - CS1591 - true - - - - Properties\SharedAssemblyInfo.cs - - + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj index d8260226e9..1cc31d57c7 100644 --- a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj +++ b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj @@ -1,27 +1,6 @@  netstandard2.0 - false - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Themes.Default.xml - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Themes.Default.xml - true @@ -34,16 +13,7 @@ - - - Properties\SharedAssemblyInfo.cs - - - %(Filename) - - - Designer - - + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs b/src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs deleted file mode 100644 index 3657673618..0000000000 --- a/src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// 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.Reflection; - -[assembly: AssemblyTitle("Avalonia.Themes.Default")] diff --git a/src/Avalonia.Visuals/Properties/AssemblyInfo.cs b/src/Avalonia.Visuals/AssemblyInfo.cs similarity index 85% rename from src/Avalonia.Visuals/Properties/AssemblyInfo.cs rename to src/Avalonia.Visuals/AssemblyInfo.cs index 900746d05a..05c3d7e62a 100644 --- a/src/Avalonia.Visuals/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Visuals/AssemblyInfo.cs @@ -5,7 +5,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using Avalonia.Metadata; -[assembly: AssemblyTitle("Avalonia.Visuals")] [assembly: InternalsVisibleTo("Avalonia.Visuals.UnitTests")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media")] diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index fe18b0e446..0e2cde2c97 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -1,39 +1,12 @@  netstandard2.0 - false Avalonia - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Avalonia.Visuals.xml - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Avalonia.Visuals.xml - CS1591 - true - - - - Properties\SharedAssemblyInfo.cs - - + \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs b/src/Gtk/Avalonia.Gtk3/AssemblyInfo.cs similarity index 84% rename from src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs rename to src/Gtk/Avalonia.Gtk3/AssemblyInfo.cs index 034b73f699..a27d631ee0 100644 --- a/src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs +++ b/src/Gtk/Avalonia.Gtk3/AssemblyInfo.cs @@ -5,8 +5,6 @@ using Avalonia.Platform; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Avalonia.Gtk3")] - [assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))] [assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 1, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))] [assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))] \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj index f1b990f349..7ac43e98bf 100644 --- a/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj +++ b/src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj @@ -1,30 +1,9 @@  netstandard2.0 - false - - - true - full - false - bin\Debug\ - TRACE;DEBUG;GTK3_PINVOKE - prompt - 4 - true - - - pdbonly - true - bin\Release\ - TRACE;GTK3_PINVOKE - prompt - 4 true + $(DefineConstants);GTK3_PINVOKE - - - @@ -32,4 +11,5 @@ + \ No newline at end of file diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj b/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj index 466b47f7a0..fc34ecf9e9 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj +++ b/src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj @@ -11,4 +11,5 @@ + \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj index c31c131ea9..e7c1154110 100644 --- a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj +++ b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj @@ -5,7 +5,6 @@ false - @@ -18,5 +17,6 @@ + \ No newline at end of file diff --git a/src/Shared/CompileXaml.props b/src/Shared/CompileXaml.props new file mode 100644 index 0000000000..219ffb2e42 --- /dev/null +++ b/src/Shared/CompileXaml.props @@ -0,0 +1,11 @@ + + + + %(Filename) + + + Designer + + + \ No newline at end of file diff --git a/src/Shared/Shared.props b/src/Shared/Shared.props new file mode 100644 index 0000000000..1602d7d617 --- /dev/null +++ b/src/Shared/Shared.props @@ -0,0 +1,11 @@ + + + Avalonia + 0.6.2 + Copyright 2016 © AvaloniaUI + https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md + https://github.com/AvaloniaUI/Avalonia/ + https://github.com/AvaloniaUI/Avalonia/ + + \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj index f5ed89d154..19ab0dffde 100644 --- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj +++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj @@ -5,13 +5,8 @@ Avalonia.Skia Avalonia.Skia true - true + true - - - Properties\SharedAssemblyInfo.cs - - @@ -21,6 +16,7 @@ + - + \ No newline at end of file From fee44d59a27596efbbf829a4709efdcb427c4520 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Fri, 4 May 2018 15:32:07 +0200 Subject: [PATCH 035/101] Cleanup AvaloniaXamlObjectWriter factory methods --- .../PortableXaml/AvaloniaXamlObjectWriter.cs | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs index 509c52503b..240ca291a8 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs @@ -9,28 +9,10 @@ namespace Avalonia.Markup.Xaml.PortableXaml { public class AvaloniaXamlObjectWriter : XamlObjectWriter { - public static AvaloniaXamlObjectWriter Create( - XamlSchemaContext schemaContext, - AvaloniaXamlContext context) - { - var nameScope = new AvaloniaNameScope { Instance = context?.RootInstance }; - - var writerSettings = new XamlObjectWriterSettings() - { - ExternalNameScope = nameScope, - RegisterNamesOnExternalNamescope = true, - RootObjectInstance = context?.RootInstance - }; - - return new AvaloniaXamlObjectWriter(schemaContext, - writerSettings.WithContext(context), - nameScope); - } - public static AvaloniaXamlObjectWriter Create( XamlSchemaContext schemaContext, AvaloniaXamlContext context, - IAmbientProvider parentAmbientProvider) + IAmbientProvider parentAmbientProvider = null) { var nameScope = new AvaloniaNameScope { Instance = context?.RootInstance }; @@ -55,7 +37,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml XamlSchemaContext schemaContext, XamlObjectWriterSettings settings, AvaloniaNameScope nameScope, - IAmbientProvider parentAmbientProvider = null) + IAmbientProvider parentAmbientProvider) : base(schemaContext, settings, parentAmbientProvider) { _nameScope = nameScope; From c7f7640ae711bcda44bc536ac5f52d26ab38c8a3 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Fri, 4 May 2018 15:51:44 +0200 Subject: [PATCH 036/101] Removed comments about not working parent ambient providers --- .../MarkupExtensions/StaticResourceExtension.cs | 7 ------- .../MarkupExtensions/StaticResourceExtensionTests.cs | 4 +--- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index 9089a13656..8e71c5f81b 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -36,13 +36,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions // Look upwards though the ambient context for IResourceProviders which might be able // to give us the resource. - // - // TODO: If we're in a template then only the ambient values since the root of the - // template wil be included here. We need some way to get hold of the parent ambient - // context and search that. See the test: - // - // StaticResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File - // foreach (var ambientValue in ambientValues) { // We override XamlType.CanAssignTo in BindingXamlType so the results we get back diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs index e6116ed563..8615efd967 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs @@ -361,9 +361,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions var border = (Border)button.GetVisualChildren().Single(); var brush = (SolidColorBrush)border.Background; - - // To make this work we somehow need to be able to get hold of the parent ambient - // context from Portable.Xaml. See TODO in StaticResourceExtension. + Assert.Equal(0xff506070, brush.Color.ToUint32()); } } From 1ee4fa47f925016e9325e48906cbfa88492a69dc Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 4 May 2018 22:46:37 +0200 Subject: [PATCH 037/101] Tweak IAssetLoader API and fix tests. --- src/Avalonia.Base/Platform/IAssetLoader.cs | 16 +++++++++++++++- .../Avalonia.Markup.Xaml.csproj | 2 +- ...aderPortableXaml.cs => AvaloniaXamlLoader.cs} | 10 +++++----- src/Shared/PlatformSupport/AssetLoader.cs | 13 ++++++++----- tests/Avalonia.UnitTests/MockAssetLoader.cs | 4 ++-- 5 files changed, 31 insertions(+), 14 deletions(-) rename src/Markup/Avalonia.Markup.Xaml/{AvaloniaXamlLoaderPortableXaml.cs => AvaloniaXamlLoader.cs} (96%) diff --git a/src/Avalonia.Base/Platform/IAssetLoader.cs b/src/Avalonia.Base/Platform/IAssetLoader.cs index 32008ffd07..ba30af60bf 100644 --- a/src/Avalonia.Base/Platform/IAssetLoader.cs +++ b/src/Avalonia.Base/Platform/IAssetLoader.cs @@ -44,6 +44,20 @@ namespace Avalonia.Platform /// Stream Open(Uri uri, Uri baseUri = null); - Tuple OpenWithAssembly(Uri uri, Uri baseUri = null); + /// + /// Opens the resource with the requested URI and returns the resource string and the + /// assembly containing the resource. + /// + /// The URI. + /// + /// A base URI to use if is relative. + /// + /// + /// The stream containing the resource contents together with the assembly. + /// + /// + /// The resource was not found. + /// + Tuple OpenAndGetAssembly(Uri uri, Uri baseUri = null); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 62c23543fd..2e8771082c 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -29,7 +29,7 @@ Properties\SharedAssemblyInfo.cs - + diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs similarity index 96% rename from src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs rename to src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index e057aa3b53..5047ce5e61 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -125,12 +125,12 @@ namespace Avalonia.Markup.Xaml "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); } - var asset = assetLocator.OpenWithAssembly(uri, baseUri); - using (var stream = asset.Item2) + var asset = assetLocator.OpenAndGetAssembly(uri, baseUri); + using (var stream = asset.Item1) { try { - return Load(stream, asset.Item1, rootInstance, uri); + return Load(stream, asset.Item2, rootInstance, uri); } catch (Exception e) { @@ -153,7 +153,7 @@ namespace Avalonia.Markup.Xaml /// The optional instance into which the XAML should be loaded. /// /// The loaded object. - public object Load(string xaml, Assembly localAssembly, object rootInstance = null) + public object Load(string xaml, Assembly localAssembly = null, object rootInstance = null) { Contract.Requires(xaml != null); @@ -230,7 +230,7 @@ namespace Avalonia.Markup.Xaml public static object Parse(string xaml, Assembly localAssembly = null) => new AvaloniaXamlLoader().Load(xaml, localAssembly); - public static T Parse(string xaml, Assembly localAssembly) + public static T Parse(string xaml, Assembly localAssembly = null) => (T)Parse(xaml, localAssembly); } } \ No newline at end of file diff --git a/src/Shared/PlatformSupport/AssetLoader.cs b/src/Shared/PlatformSupport/AssetLoader.cs index eb9b04fe54..fa11edb57b 100644 --- a/src/Shared/PlatformSupport/AssetLoader.cs +++ b/src/Shared/PlatformSupport/AssetLoader.cs @@ -67,20 +67,23 @@ namespace Avalonia.Shared.PlatformSupport /// /// The resource was not found. /// - public Stream Open(Uri uri, Uri baseUri = null) => OpenWithAssembly(uri, baseUri).Item2; + public Stream Open(Uri uri, Uri baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1; /// - /// Opens the resource with the requested URI. + /// Opens the resource with the requested URI and returns the resource string and the + /// assembly containing the resource. /// /// The URI. /// /// A base URI to use if is relative. /// - /// An assembly (optional) and a stream containing the resource contents. + /// + /// The stream containing the resource contents together with the assembly. + /// /// /// The resource was not found. /// - public Tuple OpenWithAssembly(Uri uri, Uri baseUri = null) + public Tuple OpenAndGetAssembly(Uri uri, Uri baseUri = null) { var asset = GetAsset(uri, baseUri); @@ -89,7 +92,7 @@ namespace Avalonia.Shared.PlatformSupport throw new FileNotFoundException($"The resource {uri} could not be found."); } - return Tuple.Create(asset.Assembly, asset.GetStream()); + return Tuple.Create(asset.GetStream(), asset.Assembly); } private IAssetDescriptor GetAsset(Uri uri, Uri baseUri) diff --git a/tests/Avalonia.UnitTests/MockAssetLoader.cs b/tests/Avalonia.UnitTests/MockAssetLoader.cs index 3cf7370f1f..d6b70aee16 100644 --- a/tests/Avalonia.UnitTests/MockAssetLoader.cs +++ b/tests/Avalonia.UnitTests/MockAssetLoader.cs @@ -28,9 +28,9 @@ namespace Avalonia.UnitTests return new MemoryStream(Encoding.UTF8.GetBytes(_assets[uri])); } - public Tuple OpenWithAssembly(Uri uri, Uri baseUri = null) + public Tuple OpenAndGetAssembly(Uri uri, Uri baseUri = null) { - return Tuple.Create((Assembly) null, Open(uri, baseUri)); + return Tuple.Create(Open(uri, baseUri), (Assembly)null); } public void SetDefaultAssembly(Assembly asm) From 9b24d244b53ece6b2b18730fd5de3c0a8b492bbb Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 4 May 2018 23:06:37 +0200 Subject: [PATCH 038/101] Remove now-unneeded assembly references. --- samples/BindingTest/MainWindow.xaml | 4 ++-- samples/ControlCatalog/DecoratedWindow.xaml | 4 ++-- samples/ControlCatalog/MainView.xaml | 2 +- samples/RenderTest/MainWindow.xaml | 2 +- src/Avalonia.Diagnostics/Views/TreePageView.xaml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/samples/BindingTest/MainWindow.xaml b/samples/BindingTest/MainWindow.xaml index 3547e33181..b0a4a5b7ed 100644 --- a/samples/BindingTest/MainWindow.xaml +++ b/samples/BindingTest/MainWindow.xaml @@ -1,6 +1,6 @@ + xmlns:vm="clr-namespace:BindingTest.ViewModels" + xmlns:local="clr-namespace:BindingTest">