Browse Source

Merge branch 'master' into wip-animations

Jumar Macato 7 years ago
parent
commit
2182c0718a
37 changed files with 678 additions and 302 deletions
  1. 10 2
      samples/BindingTest/MainWindow.xaml
  2. 2 2
      samples/ControlCatalog/DecoratedWindow.xaml
  3. 1 1
      samples/ControlCatalog/MainView.xaml
  4. 1 1
      samples/ControlCatalog/MainWindow.xaml
  5. 1 2
      samples/RenderTest/MainWindow.xaml
  6. 5 1
      src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
  7. 16 0
      src/Avalonia.Base/Platform/IAssetLoader.cs
  8. 8 2
      src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
  9. 5 0
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  10. 14 0
      src/Avalonia.Controls/Window.cs
  11. 5 0
      src/Avalonia.Controls/WindowBase.cs
  12. 3 1
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  13. 1 1
      src/Avalonia.DesignerSupport/DesignerAssist.cs
  14. 8 0
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  15. 8 0
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  16. 1 1
      src/Avalonia.Diagnostics/Views/TreePageView.xaml
  17. 18 13
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  18. 15 0
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  19. 2 0
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  20. 0 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  21. 232 6
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  22. 0 227
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs
  23. 0 7
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
  24. 8 6
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs
  25. 1 1
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github
  26. 6 2
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs
  27. 2 1
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs
  28. 4 0
      src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs
  29. 15 3
      src/OSX/Avalonia.MonoMac/WindowImpl.cs
  30. 21 2
      src/Shared/PlatformSupport/AssetLoader.cs
  31. 25 1
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  32. 70 14
      src/Windows/Avalonia.Win32/WindowImpl.cs
  33. 4 0
      src/iOS/Avalonia.iOS/EmbeddableImpl.cs
  34. 71 0
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs
  35. 75 4
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs
  36. 15 0
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  37. 5 0
      tests/Avalonia.UnitTests/MockAssetLoader.cs

+ 10 - 2
samples/BindingTest/MainWindow.xaml

@@ -1,11 +1,15 @@
 <Window xmlns="https://github.com/avaloniaui"
-        xmlns:vm="clr-namespace:BindingTest.ViewModels;assembly=BindingTest"
-        xmlns:local="clr-namespace:BindingTest;assembly=BindingTest">
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+        xmlns:vm="clr-namespace:BindingTest.ViewModels"
+        xmlns:local="clr-namespace:BindingTest">
   <Window.Styles>
     <Style Selector="TextBlock.h1">
       <Setter Property="FontSize" Value="18"/>
     </Style>
   </Window.Styles>
+  <Window.Resources>
+    <vm:TestItem x:Key="SharedItem" StringValue="shared" />
+  </Window.Resources>
   
   <TabControl>
     <TabItem Header="Basic">
@@ -40,6 +44,10 @@
             <TextBlock FontSize="16" Text="Binding Sources"/>
             <TextBox Watermark="Value of first TextBox" UseFloatingWatermark="True" 
                      Text="{Binding #first.Text, Mode=TwoWay}"/>
+            <TextBox Watermark="Value of SharedItem.StringValue" UseFloatingWatermark="True"
+                     Text="{Binding StringValue, Source={StaticResource SharedItem}, Mode=TwoWay}"/>
+            <TextBox Watermark="Value of SharedItem.StringValue (duplicate)" UseFloatingWatermark="True"
+                     Text="{Binding StringValue, Source={StaticResource SharedItem}, Mode=TwoWay}"/>
           </StackPanel>
           <StackPanel Margin="18" Gap="4" Width="200" HorizontalAlignment="Left">
             <TextBlock FontSize="16" Text="Scheduler"/>

+ 2 - 2
samples/ControlCatalog/DecoratedWindow.xaml

@@ -1,7 +1,7 @@
 <Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
         Title="Avalonia Control Gallery"
-        Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog"
-        xmlns:local="clr-namespace:ControlCatalog;assembly=ControlCatalog" HasSystemDecorations="False">
+        Icon="resm:ControlCatalog.Assets.test_icon.ico"
+        xmlns:local="clr-namespace:ControlCatalog" HasSystemDecorations="False">
     <Grid RowDefinitions="5,*,5" ColumnDefinitions="5,*,5">
         <DockPanel  Grid.Column="1"  Grid.Row="1" >
             <Grid Name="TitleBar" Background="LightBlue" DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto">

+ 1 - 1
samples/ControlCatalog/MainView.xaml

@@ -1,5 +1,5 @@
 <UserControl xmlns="https://github.com/avaloniaui"
-        xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
+        xmlns:pages="clr-namespace:ControlCatalog.Pages"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <TabControl Classes="sidebar" Name="Sidebar">
     <TabControl.PageTransition>

+ 1 - 1
samples/ControlCatalog/MainWindow.xaml

@@ -1,6 +1,6 @@
 <Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
         Title="Avalonia Control Gallery"
         Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog"
-        xmlns:local="clr-namespace:ControlCatalog;assembly=ControlCatalog">
+        xmlns:local="clr-namespace:ControlCatalog">
     <local:MainView/>
 </Window>

+ 1 - 2
samples/RenderTest/MainWindow.xaml

@@ -1,7 +1,6 @@
 <Window xmlns="https://github.com/avaloniaui"
         Title="Avalonia Render Test"
-        xmlns:pages="clr-namespace:RenderTest.Pages;assembly=RenderTest" MinWidth="900" MinHeight="600"
-        >
+        xmlns:pages="clr-namespace:RenderTest.Pages;assembly=RenderTest" MinWidth="900" MinHeight="600">
   <DockPanel>
     <Menu DockPanel.Dock="Top">
       <MenuItem Header="Rendering">

+ 5 - 1
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

+ 16 - 0
src/Avalonia.Base/Platform/IAssetLoader.cs

@@ -43,5 +43,21 @@ namespace Avalonia.Platform
         /// The resource was not found.
         /// </exception>
         Stream Open(Uri uri, Uri baseUri = null);
+
+        /// <summary>
+        /// Opens the resource with the requested URI and returns the resource string and the
+        /// assembly containing the resource.
+        /// </summary>
+        /// <param name="uri">The URI.</param>
+        /// <param name="baseUri">
+        /// A base URI to use if <paramref name="uri"/> is relative.
+        /// </param>
+        /// <returns>
+        /// The stream containing the resource contents together with the assembly.
+        /// </returns>
+        /// <exception cref="FileNotFoundException">
+        /// The resource was not found.
+        /// </exception>
+        Tuple<Stream, Assembly> OpenAndGetAssembly(Uri uri, Uri baseUri = null);
     }
 }

+ 8 - 2
src/Avalonia.Controls/Platform/IWindowBaseImpl.cs

@@ -55,7 +55,7 @@ namespace Avalonia.Platform
         /// Gets the platform window handle.
         /// </summary>
         IPlatformHandle Handle { get; }
-        
+       
         /// <summary>
         /// Gets the maximum size of a window on the system.
         /// </summary>
@@ -65,7 +65,13 @@ namespace Avalonia.Platform
         /// Sets the client size of the toplevel.
         /// </summary>
         void Resize(Size clientSize);
-        
+
+        /// <summary>
+        /// Minimum width of the window.
+        /// </summary>
+        /// 
+        void SetMinMaxSize(Size minSize, Size maxSize);
+
         /// <summary>
         /// Gets platform specific display information
         /// </summary>

+ 5 - 0
src/Avalonia.Controls/Platform/IWindowImpl.cs

@@ -45,6 +45,11 @@ namespace Avalonia.Platform
         /// </summary>
         void ShowTaskbarIcon(bool value);
 
+        /// <summary>
+        /// Enables or disables resizing of the window
+        /// </summary>
+        void CanResize(bool value);
+
         /// <summary>
         /// Gets or sets a method called before the underlying implementation is destroyed.
         /// Return true to prevent the underlying implementation from closing.

+ 14 - 0
src/Avalonia.Controls/Window.cs

@@ -95,6 +95,9 @@ namespace Avalonia.Controls
                 o => o.WindowStartupLocation,
                 (o, v) => o.WindowStartupLocation = v);
 
+        public static readonly StyledProperty<bool> CanResizeProperty =
+            AvaloniaProperty.Register<Window, bool>(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<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
 
             IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
+
+            CanResizeProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue));
         }
 
         /// <summary>
@@ -208,6 +213,15 @@ namespace Avalonia.Controls
             }
         }
 
+        /// <summary>
+        /// Enables or disables resizing of the window
+        /// </summary>
+        public bool CanResize
+        {
+            get { return GetValue(CanResizeProperty); }
+            set { SetValue(CanResizeProperty, value); }
+        }
+
         /// <summary>
         /// Gets or sets the icon of the window.
         /// </summary>

+ 5 - 0
src/Avalonia.Controls/WindowBase.cs

@@ -47,6 +47,11 @@ namespace Avalonia.Controls
         {
             IsVisibleProperty.OverrideDefaultValue<WindowBase>(false);
             IsVisibleProperty.Changed.AddClassHandler<WindowBase>(x => x.IsVisibleChanged);
+
+            MinWidthProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight)));
+            MinHeightProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight)));
+            MaxWidthProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight)));
+            MaxHeightProperty.Changed.AddClassHandler<WindowBase>((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)

+ 3 - 1
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(Path.GetFullPath(assemblyPath)) : null;
+                var loaded = loader.Load(stream, localAsm, null, baseUri);
                 var styles = loaded as Styles;
                 if (styles != null)
                 {

+ 1 - 1
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);
             }
         }

+ 8 - 0
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@@ -67,6 +67,10 @@ namespace Avalonia.DesignerSupport.Remote
             RenderIfNeeded();
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public IScreenImpl Screen { get; } = new ScreenStub();
 
         public void Activate()
@@ -93,5 +97,9 @@ namespace Avalonia.DesignerSupport.Remote
         public void ShowTaskbarIcon(bool value)
         {
         }
+
+        public void CanResize(bool value)
+        {
+        }
     }
 }

+ 8 - 0
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@@ -78,6 +78,10 @@ namespace Avalonia.DesignerSupport.Remote
 
         public IScreenImpl Screen { get; } = new ScreenStub();
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public void SetTitle(string title)
         {
         }
@@ -95,6 +99,10 @@ namespace Avalonia.DesignerSupport.Remote
         public void ShowTaskbarIcon(bool value)
         {
         }
+
+        public void CanResize(bool value)
+        {
+        }
     }
 
     class ClipboardStub : IClipboard

+ 1 - 1
src/Avalonia.Diagnostics/Views/TreePageView.xaml

@@ -1,5 +1,5 @@
 <UserControl xmlns="https://github.com/avaloniaui"
-             xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels;assembly=Avalonia.Diagnostics">
+             xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels">
   <Grid ColumnDefinitions="*,4,3*">    
     <TreeView Name="tree" Items="{Binding Nodes}" SelectedItem="{Binding SelectedNode, Mode=TwoWay}">
       <TreeView.DataTemplates>

+ 18 - 13
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);
@@ -263,7 +265,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)]
@@ -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;
@@ -421,6 +424,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;
@@ -502,6 +506,7 @@ 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 const int G_TYPE_OBJECT = 80;
     }
 
@@ -739,19 +744,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

+ 15 - 0
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@@ -341,6 +341,20 @@ namespace Avalonia.Gtk3
             }
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+            if (GtkWidget.IsClosed)
+                return;
+
+            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;
+
+            Native.GtkWindowSetGeometryHints(GtkWidget, IntPtr.Zero, ref geometry, GdkWindowHints.GDK_HINT_MIN_SIZE | GdkWindowHints.GDK_HINT_MAX_SIZE);
+        } 
+
         public IMouseDevice MouseDevice => Gtk3Platform.Mouse;
 
         public double Scaling => LastKnownScaleFactor = (int) (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1);
@@ -431,6 +445,7 @@ namespace Avalonia.Gtk3
         {
             if (GtkWidget.IsClosed)
                 return;
+         
             Native.GtkWindowResize(GtkWidget, (int)value.Width, (int)value.Height);
             if (OverrideRedirect)
             {

+ 2 - 0
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

+ 0 - 1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -29,7 +29,6 @@
         <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
             <Link>Properties\SharedAssemblyInfo.cs</Link>
         </Compile>
-        <Compile Include="AvaloniaXamlLoaderPortableXaml.cs" />
         <Compile Include="AvaloniaXamlLoader.cs" />
         <Compile Include="Converters\CornerRadiusTypeConverter.cs" />
         <Compile Include="Converters\MatrixTypeConverter.cs" />

+ 232 - 6
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@@ -1,11 +1,237 @@
-namespace Avalonia.Markup.Xaml
+// 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.Controls;
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.Markup.Xaml.PortableXaml;
+using Avalonia.Platform;
+using Portable.Xaml;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace Avalonia.Markup.Xaml
 {
-    public class AvaloniaXamlLoader : AvaloniaXamlLoaderPortableXaml
+    /// <summary>
+    /// Loads XAML for a avalonia application.
+    /// </summary>
+    public class AvaloniaXamlLoader
     {
-        public static object Parse(string xaml)
-                => new AvaloniaXamlLoader().Load(xaml);
+        private readonly AvaloniaXamlSchemaContext _context = GetContext();
+
+        private static AvaloniaXamlSchemaContext GetContext()
+        {
+            var result = AvaloniaLocator.Current.GetService<AvaloniaXamlSchemaContext>();
+
+            if (result == null)
+            {
+                result = AvaloniaXamlSchemaContext.Create();
+
+                AvaloniaLocator.CurrentMutable
+                    .Bind<AvaloniaXamlSchemaContext>()
+                    .ToConstant(result);
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
+        /// </summary>
+        public AvaloniaXamlLoader()
+        {
+        }
+
+        /// <summary>
+        /// Loads the XAML into a Avalonia component.
+        /// </summary>
+        /// <param name="obj">The object to load the XAML into.</param>
+        public static void Load(object obj)
+        {
+            Contract.Requires<ArgumentNullException>(obj != null);
+
+            var loader = new AvaloniaXamlLoader();
+            loader.Load(obj.GetType(), obj);
+        }
+
+        /// <summary>
+        /// Loads the XAML for a type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Type type, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(type != null);
+
+            // HACK: Currently Visual Studio is forcing us to change the extension of xaml files
+            // in certain situations, so we try to load .xaml and if that's not found we try .xaml.
+            // Ideally we'd be able to use .xaml everywhere
+            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+            if (assetLocator == null)
+            {
+                throw new InvalidOperationException(
+                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
+            }
+
+            foreach (var uri in GetUrisFor(type))
+            {
+                if (assetLocator.Exists(uri))
+                {
+                    using (var stream = assetLocator.Open(uri))
+                    {
+                        var initialize = rootInstance as ISupportInitialize;
+                        initialize?.BeginInit();
+                        try
+                        {
+                            return Load(stream, type.Assembly, rootInstance, uri);
+                        }
+                        finally
+                        {
+                            initialize?.EndInit();
+                        }
+                    }
+                }
+            }
+
+            throw new FileNotFoundException("Unable to find view for " + type.FullName);
+        }
+
+        /// <summary>
+        /// Loads XAML from a URI.
+        /// </summary>
+        /// <param name="uri">The URI of the XAML file.</param>
+        /// <param name="baseUri">
+        /// A base URI to use if <paramref name="uri"/> is relative.
+        /// </param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Uri uri, Uri baseUri = null, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(uri != null);
+
+            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
+
+            if (assetLocator == null)
+            {
+                throw new InvalidOperationException(
+                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
+            }
+
+            var asset = assetLocator.OpenAndGetAssembly(uri, baseUri);
+            using (var stream = asset.Item1)
+            {
+                try
+                {
+                    return Load(stream, asset.Item2, rootInstance, uri);
+                }
+                catch (Exception e)
+                {
+                    var uriString = uri.ToString();
+                    if (!uri.IsAbsoluteUri)
+                    {
+                        uriString = new Uri(baseUri, uri).AbsoluteUri;
+                    }
+                    throw new XamlLoadException("Error loading xaml at " + uriString, e);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Loads XAML from a string.
+        /// </summary>
+        /// <param name="xaml">The string containing the XAML.</param>
+        /// <param name="localAssembly">Default assembly for clr-namespace:</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <returns>The loaded object.</returns>
+        public object Load(string xaml, Assembly localAssembly = null, object rootInstance = null)
+        {
+            Contract.Requires<ArgumentNullException>(xaml != null);
+
+            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
+            {
+                return Load(stream, localAssembly, rootInstance);
+            }
+        }
+
+        /// <summary>
+        /// Loads XAML from a stream.
+        /// </summary>
+        /// <param name="stream">The stream containing the XAML.</param>
+        /// <param name="localAssembly">Default assembly for clr-namespace</param>
+        /// <param name="rootInstance">
+        /// The optional instance into which the XAML should be loaded.
+        /// </param>
+        /// <param name="uri">The URI of the XAML</param>
+        /// <returns>The loaded object.</returns>
+        public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null)
+        {
+            var readerSettings = new XamlXmlReaderSettings()
+            {
+                BaseUri = uri,
+                LocalAssembly = localAssembly
+            };
+
+            var reader = new XamlXmlReader(stream, _context, readerSettings);
+
+            object result = LoadFromReader(
+                reader,
+                AvaloniaXamlContext.For(readerSettings, rootInstance));
+
+            var topLevel = result as TopLevel;
+
+            if (topLevel != null)
+            {
+                DelayedBinding.ApplyBindings(topLevel);
+            }
+
+            return result;
+        }
+
+        internal static object LoadFromReader(XamlReader reader, AvaloniaXamlContext context = null, IAmbientProvider parentAmbientProvider = null)
+        {
+            var writer = AvaloniaXamlObjectWriter.Create(
+                                    reader.SchemaContext,
+                                    context,
+                                    parentAmbientProvider);
+
+            XamlServices.Transform(reader, writer);
+            writer.ApplyAllDelayedProperties();
+            return writer.Result;
+        }
+
+        internal static object LoadFromReader(XamlReader reader)
+        {
+            //return XamlServices.Load(reader);
+            return LoadFromReader(reader, null);
+        }
+
+        /// <summary>
+        /// Gets the URI for a type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>The URI.</returns>
+        private static IEnumerable<Uri> GetUrisFor(Type type)
+        {
+            var asm = type.GetTypeInfo().Assembly.GetName().Name;
+            var typeName = type.FullName;
+            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<T>(string xaml)
-                     => (T)Parse(xaml);
+        public static T Parse<T>(string xaml, Assembly localAssembly = null)
+            => (T)Parse(xaml, localAssembly);
     }
 }

+ 0 - 227
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs

@@ -1,227 +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 Avalonia.Controls;
-using Avalonia.Markup.Xaml.Data;
-using Avalonia.Markup.Xaml.PortableXaml;
-using Avalonia.Platform;
-using Portable.Xaml;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Text;
-
-namespace Avalonia.Markup.Xaml
-{
-    /// <summary>
-    /// Loads XAML for a avalonia application.
-    /// </summary>
-    public class AvaloniaXamlLoaderPortableXaml
-    {
-        private readonly AvaloniaXamlSchemaContext _context = GetContext();
-
-        private static AvaloniaXamlSchemaContext GetContext()
-        {
-            var result = AvaloniaLocator.Current.GetService<AvaloniaXamlSchemaContext>();
-
-            if (result == null)
-            {
-                result = AvaloniaXamlSchemaContext.Create();
-
-                AvaloniaLocator.CurrentMutable
-                    .Bind<AvaloniaXamlSchemaContext>()
-                    .ToConstant(result);
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
-        /// </summary>
-        public AvaloniaXamlLoaderPortableXaml()
-        {
-        }
-
-        /// <summary>
-        /// Loads the XAML into a Avalonia component.
-        /// </summary>
-        /// <param name="obj">The object to load the XAML into.</param>
-        public static void Load(object obj)
-        {
-            Contract.Requires<ArgumentNullException>(obj != null);
-
-            var loader = new AvaloniaXamlLoader();
-            loader.Load(obj.GetType(), obj);
-        }
-
-        /// <summary>
-        /// Loads the XAML for a type.
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <returns>The loaded object.</returns>
-        public object Load(Type type, object rootInstance = null)
-        {
-            Contract.Requires<ArgumentNullException>(type != null);
-
-            // HACK: Currently Visual Studio is forcing us to change the extension of xaml files
-            // in certain situations, so we try to load .xaml and if that's not found we try .xaml.
-            // Ideally we'd be able to use .xaml everywhere
-            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
-            if (assetLocator == null)
-            {
-                throw new InvalidOperationException(
-                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
-            }
-
-            foreach (var uri in GetUrisFor(type))
-            {
-                if (assetLocator.Exists(uri))
-                {
-                    using (var stream = assetLocator.Open(uri))
-                    {
-                        var initialize = rootInstance as ISupportInitialize;
-                        initialize?.BeginInit();
-                        try
-                        {
-                            return Load(stream, rootInstance, uri);
-                        }
-                        finally
-                        {
-                            initialize?.EndInit();
-                        }
-                    }
-                }
-            }
-
-            throw new FileNotFoundException("Unable to find view for " + type.FullName);
-        }
-
-        /// <summary>
-        /// Loads XAML from a URI.
-        /// </summary>
-        /// <param name="uri">The URI of the XAML file.</param>
-        /// <param name="baseUri">
-        /// A base URI to use if <paramref name="uri"/> is relative.
-        /// </param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <returns>The loaded object.</returns>
-        public object Load(Uri uri, Uri baseUri = null, object rootInstance = null)
-        {
-            Contract.Requires<ArgumentNullException>(uri != null);
-
-            var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>();
-
-            if (assetLocator == null)
-            {
-                throw new InvalidOperationException(
-                    "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?");
-            }
-
-            using (var stream = assetLocator.Open(uri, baseUri))
-            {
-                try
-                {
-                    return Load(stream, rootInstance, uri);
-                }
-                catch (Exception e)
-                {
-                    var uriString = uri.ToString();
-                    if (!uri.IsAbsoluteUri)
-                    {
-                        uriString = new Uri(baseUri, uri).AbsoluteUri;
-                    }
-                    throw new XamlLoadException("Error loading xaml at " + uriString, e);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Loads XAML from a string.
-        /// </summary>
-        /// <param name="xaml">The string containing the XAML.</param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <returns>The loaded object.</returns>
-        public object Load(string xaml, object rootInstance = null)
-        {
-            Contract.Requires<ArgumentNullException>(xaml != null);
-
-            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
-            {
-                return Load(stream, rootInstance);
-            }
-        }
-
-        /// <summary>
-        /// Loads XAML from a stream.
-        /// </summary>
-        /// <param name="stream">The stream containing the XAML.</param>
-        /// <param name="rootInstance">
-        /// The optional instance into which the XAML should be loaded.
-        /// </param>
-        /// <param name="uri">The URI of the XAML</param>
-        /// <returns>The loaded object.</returns>
-        public object Load(Stream stream, object rootInstance = null, Uri uri = null)
-        {
-            var readerSettings = new XamlXmlReaderSettings()
-            {
-                BaseUri = uri,
-                LocalAssembly = rootInstance?.GetType().GetTypeInfo().Assembly
-            };
-
-            var reader = new XamlXmlReader(stream, _context, readerSettings);
-
-            object result = LoadFromReader(
-                reader,
-                AvaloniaXamlContext.For(readerSettings, rootInstance));
-
-            var topLevel = result as TopLevel;
-
-            if (topLevel != null)
-            {
-                DelayedBinding.ApplyBindings(topLevel);
-            }
-
-            return result;
-        }
-
-        internal static object LoadFromReader(XamlReader reader, AvaloniaXamlContext context = null)
-        {
-            var writer = AvaloniaXamlObjectWriter.Create(
-                                    reader.SchemaContext,
-                                    context);
-
-            XamlServices.Transform(reader, writer);
-            writer.ApplyAllDelayedProperties();
-            return writer.Result;
-        }
-
-        internal static object LoadFromReader(XamlReader reader)
-        {
-            //return XamlServices.Load(reader);
-            return LoadFromReader(reader, null);
-        }
-
-        /// <summary>
-        /// Gets the URI for a type.
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <returns>The URI.</returns>
-        private static IEnumerable<Uri> GetUrisFor(Type type)
-        {
-            var asm = type.GetTypeInfo().Assembly.GetName().Name;
-            var typeName = type.FullName;
-            yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm);
-            yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm);
-        }
-    }
-}

+ 0 - 7
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

+ 8 - 6
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs

@@ -11,7 +11,8 @@ namespace Avalonia.Markup.Xaml.PortableXaml
     {
         public static AvaloniaXamlObjectWriter Create(
             XamlSchemaContext schemaContext,
-            AvaloniaXamlContext context)
+            AvaloniaXamlContext context,
+            IAmbientProvider parentAmbientProvider = null)
         {
             var nameScope = new AvaloniaNameScope { Instance = context?.RootInstance };
 
@@ -23,8 +24,9 @@ namespace Avalonia.Markup.Xaml.PortableXaml
             };
 
             return new AvaloniaXamlObjectWriter(schemaContext,
-                                                writerSettings.WithContext(context),
-                                                nameScope);
+                writerSettings.WithContext(context),
+                nameScope,
+                parentAmbientProvider);
         }
 
         private readonly DelayedValuesHelper _delayedValuesHelper = new DelayedValuesHelper();
@@ -34,9 +36,9 @@ namespace Avalonia.Markup.Xaml.PortableXaml
         private AvaloniaXamlObjectWriter(
             XamlSchemaContext schemaContext,
             XamlObjectWriterSettings settings,
-            AvaloniaNameScope nameScope
-            )
-            : base(schemaContext, settings)
+            AvaloniaNameScope nameScope,
+            IAmbientProvider parentAmbientProvider)
+            : base(schemaContext, settings, parentAmbientProvider)
         {
             _nameScope = nameScope;
         }

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github

@@ -1 +1 @@
-Subproject commit c0664014455392ac221a765e66f9837704339b6f
+Subproject commit cdf46d7892def8a6ba29f12a9339147377f7cf5c

+ 6 - 2
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs

@@ -10,8 +10,10 @@ namespace Avalonia.Markup.Xaml.Templates
 
     public class TemplateContent
     {
-        public TemplateContent(IEnumerable<NamespaceDeclaration> namespaces, XamlReader reader)
+        public TemplateContent(IEnumerable<NamespaceDeclaration> 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)

+ 2 - 1
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<IXamlNamespaceResolver>();
-            return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader);
+            var ambientProvider = tdc.GetService<IAmbientProvider>();
+            return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader, ambientProvider);
         }
 
         public override XamlReader Save(object value, IServiceProvider serviceProvider)

+ 4 - 0
src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs

@@ -161,6 +161,10 @@ namespace Avalonia.MonoMac
             Position = pos;
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+        }
+
         public IScreenImpl Screen
         {
             get;

+ 15 - 3
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

+ 21 - 2
src/Shared/PlatformSupport/AssetLoader.cs

@@ -67,7 +67,23 @@ namespace Avalonia.Shared.PlatformSupport
         /// <exception cref="FileNotFoundException">
         /// The resource was not found.
         /// </exception>
-        public Stream Open(Uri uri, Uri baseUri = null)
+        public Stream Open(Uri uri, Uri baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1;
+        
+        /// <summary>
+        /// Opens the resource with the requested URI and returns the resource string and the
+        /// assembly containing the resource.
+        /// </summary>
+        /// <param name="uri">The URI.</param>
+        /// <param name="baseUri">
+        /// A base URI to use if <paramref name="uri"/> is relative.
+        /// </param>
+        /// <returns>
+        /// The stream containing the resource contents together with the assembly.
+        /// </returns>
+        /// <exception cref="FileNotFoundException">
+        /// The resource was not found.
+        /// </exception>
+        public Tuple<Stream, Assembly> OpenAndGetAssembly(Uri uri, Uri baseUri = null)
         {
             var asset = GetAsset(uri, baseUri);
 
@@ -76,7 +92,7 @@ namespace Avalonia.Shared.PlatformSupport
                 throw new FileNotFoundException($"The resource {uri} could not be found.");
             }
 
-            return asset.GetStream();
+            return Tuple.Create(asset.GetStream(), asset.Assembly);
         }
 
         private IAssetDescriptor GetAsset(Uri uri, Uri baseUri)
@@ -162,6 +178,7 @@ namespace Avalonia.Shared.PlatformSupport
         private interface IAssetDescriptor
         {
             Stream GetStream();
+            Assembly Assembly { get; }
         }
 
         private class AssemblyResourceDescriptor : IAssetDescriptor
@@ -179,6 +196,8 @@ namespace Avalonia.Shared.PlatformSupport
             {
                 return _asm.GetManifestResourceStream(_name);
             }
+
+            public Assembly Assembly => _asm;
         }
 
         private class AssemblyDescriptor

+ 25 - 1
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
@@ -615,6 +626,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")]
@@ -849,6 +870,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);

+ 70 - 14
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -31,10 +31,14 @@ 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;
         private OleDropTarget _dropTarget;
+        private Size _minSize;
+        private Size _maxSize;
+
 #if USE_MANAGED_DRAG
         private readonly ManagedWindowResizeDragHelper _managedDrag;
 #endif
@@ -77,8 +81,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))
@@ -102,6 +106,12 @@ namespace Avalonia.Win32
             }
         }
 
+        public void SetMinMaxSize(Size minSize, Size maxSize)
+        {
+            _minSize = minSize;
+            _maxSize = maxSize;
+        }
+
         public IScreenImpl Screen
         {
             get;
@@ -235,13 +245,19 @@ namespace Avalonia.Win32
                 return;
             }
 
-            var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -16);
+            var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE);
 
-            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;
@@ -251,7 +267,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)
             {
@@ -383,8 +399,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)
@@ -611,7 +630,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<UnmanagedMethods.MINMAXINFO>(lParam);
+
+                    if  (_minSize.Width > 0)
+                        mmi.ptMinTrackSize.X = (int)((_minSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right);
+
+                    if (_minSize.Height > 0)
+                        mmi.ptMinTrackSize.Y = (int)((_minSize.Height * Scaling) + BorderThickness.Top + BorderThickness.Bottom);
+
+                    if (!Double.IsInfinity(_maxSize.Width) && _maxSize.Width > 0)
+                        mmi.ptMaxTrackSize.X = (int)((_maxSize.Width * Scaling) + BorderThickness.Left + BorderThickness.Right);
+
+                    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;
+
                 case UnmanagedMethods.WindowsMessage.WM_DISPLAYCHANGE:
                     (Screen as ScreenImpl)?.InvalidateScreensCache();
                     return IntPtr.Zero;
@@ -798,11 +836,11 @@ namespace Avalonia.Win32
 
         public void ShowTaskbarIcon(bool value)
         {
-            var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, -20);
-            
-            style &= ~(UnmanagedMethods.WindowStyles.WS_VISIBLE);   
+            var style = (UnmanagedMethods.WindowStyles)UnmanagedMethods.GetWindowLong(_hwnd, (int)UnmanagedMethods.WindowLongParam.GWL_EXSTYLE);
 
-            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
@@ -813,9 +851,27 @@ 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);
             }
         }
+
+        public void CanResize(bool value)
+        {
+            if (value == _resizable)
+            {
+                return;
+            }
+
+            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, (int)UnmanagedMethods.WindowLongParam.GWL_STYLE, (uint)style);
+            _resizable = value;
+        }
     }
 }

+ 4 - 0
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;

+ 71 - 0
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 = @"
+<Window xmlns='https://github.com/avaloniaui'
+             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
+    <Window.Resources>
+        <x:String x:Key='text'>foobar</x:String>
+    </Window.Resources>
+
+    <TextBlock Name='textBlock' Text='{Binding Source={StaticResource text}}'/>
+</Window>";
+
+                var loader = new AvaloniaXamlLoader();
+                var window = (Window)loader.Load(xaml);
+                var textBlock = window.FindControl<TextBlock>("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<Window>())
+            {
+                Setters =
+                {
+                    new Setter(
+                        Window.TemplateProperty,
+                        new FuncControlTemplate<Window>(x =>
+                            new ContentPresenter
+                            {
+                                Name = "PART_ContentPresenter",
+                                [!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
+                            }))
+                }
+            };
+        }
+    }
+}

+ 75 - 4
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 = @"
@@ -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());
             }
         }
@@ -417,6 +415,79 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
             }
         }
 
+        [Fact]
+        public void StaticResource_Can_Be_Assigned_To_Binding_Converter_In_DataTemplate()
+        {
+            using (StyledWindow())
+            {
+                var xaml = @"
+<Window xmlns='https://github.com/avaloniaui'
+             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+             xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
+    <Window.Resources>
+        <local:TestValueConverter x:Key='converter' Append='bar'/>
+        <DataTemplate x:Key='PurpleData'>
+          <TextBlock Name='textBlock' Text='{Binding Converter={StaticResource converter}}'/>
+        </DataTemplate>
+    </Window.Resources>
+
+    <ContentPresenter Name='presenter' Content='foo' ContentTemplate='{StaticResource PurpleData}'/>
+</Window>";
+
+                var loader = new AvaloniaXamlLoader();
+                var window = (Window)loader.Load(xaml);
+
+                window.DataContext = "foo";
+                var presenter = window.FindControl<ContentPresenter>("presenter");
+
+                window.Show();
+
+                var textBlock = (TextBlock)presenter.GetVisualChildren().Single();
+
+                Assert.NotNull(textBlock);
+                Assert.Equal("foobar", textBlock.Text);
+            }
+        }
+
+        [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 = @"
+<Window xmlns='https://github.com/avaloniaui'
+             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+             xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
+    <Window.Resources>
+        <local:TestValueConverter x:Key='converter' Append='-bar'/>
+        <SolidColorBrush x:Key='brush' Color='Purple'/>
+        <DataTemplate x:Key='WhiteData'>
+          <Border>
+            <Border.Resources>
+              <SolidColorBrush x:Key='brush' Color='White'/>
+            </Border.Resources>
+            <TextBlock Name='textBlock' Text='{Binding Color, Source={StaticResource brush}, Converter={StaticResource converter}}' Foreground='{StaticResource brush}' />
+          </Border>
+        </DataTemplate>
+    </Window.Resources>
+
+    <ContentPresenter Content='foo' ContentTemplate='{StaticResource WhiteData}'/>
+</Window>";
+
+                var loader = new AvaloniaXamlLoader();
+                var window = (Window)loader.Load(xaml);
+
+                window.Show();
+
+                var textBlock = window.GetVisualDescendants().OfType<TextBlock>().Single();
+
+                Assert.NotNull(textBlock);
+                Assert.Equal("White-bar", textBlock.Text);
+            }
+        }
+
         [Fact]
         public void Control_Property_Is_Not_Updated_When_Parent_Is_Changed()
         {

+ 15 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@@ -81,6 +81,21 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
             Assert.Equal(21.0, TextBlock.GetFontSize(target));
         }
 
+        [Fact]
+        public void Attached_Property_Is_Set_On_Control_Outside_Avalonia_Namspace()
+        {
+            // Test for issue #1548
+            var xaml =
+@"<UserControl xmlns='https://github.com/avaloniaui'
+    xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
+  <local:TestControl Grid.Column='2' />
+</UserControl>";
+
+            var target = AvaloniaXamlLoader.Parse<UserControl>(xaml);
+
+            Assert.Equal(2, Grid.GetColumn((TestControl)target.Content));
+        }
+
         [Fact]
         public void Attached_Property_With_Namespace_Is_Set()
         {

+ 5 - 0
tests/Avalonia.UnitTests/MockAssetLoader.cs

@@ -27,6 +27,11 @@ namespace Avalonia.UnitTests
         {
             return new MemoryStream(Encoding.UTF8.GetBytes(_assets[uri]));
         }
+        
+        public Tuple<Stream, Assembly> OpenAndGetAssembly(Uri uri, Uri baseUri = null)
+        {
+            return Tuple.Create(Open(uri, baseUri), (Assembly)null);
+        }
 
         public void SetDefaultAssembly(Assembly asm)
         {