From fee5b4e594ab1c17e85ebe71cd2ebfbb70e9b92c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 24 Feb 2018 21:53:42 +0300 Subject: [PATCH 01/20] 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 bd33b3076b4eea33731dcf9a8eedf374aa2a1aef Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 17 Apr 2018 14:35:08 +0200 Subject: [PATCH 02/20] 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 03/20] 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 04/20] 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 05/20] 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 06/20] 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 07/20] 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 08/20] 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 09/20] 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 10/20] 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 11/20] 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 d9819ab0047f1b21ffd7e663f52d6d0442ad084d Mon Sep 17 00:00:00 2001 From: CommonGuy Date: Fri, 27 Apr 2018 08:17:04 +0200 Subject: [PATCH 12/20] 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 5a5fc13632ae0f6110d1b0a7243cc30cbb80468b Mon Sep 17 00:00:00 2001 From: boombuler Date: Fri, 4 May 2018 08:50:30 +0200 Subject: [PATCH 13/20] 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 fee44d59a27596efbbf829a4709efdcb427c4520 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Fri, 4 May 2018 15:32:07 +0200 Subject: [PATCH 14/20] 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 15/20] 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 16/20] 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 17/20] 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">