Browse Source

Merge branch 'master' into master

Steven Kirk 7 năm trước cách đây
mục cha
commit
f4c7430c38

+ 17 - 0
.github/PULL_REQUEST_TEMPLATE.md

@@ -0,0 +1,17 @@
+This template is not intended to be prescriptive, but to help us review pull requests it would be useful if you included as much of the following information as possible:
+
+- What does the pull request do?
+- What is the current behavior?
+- What is the updated/expected behavior with this PR?
+- How was the solution implemented (if it's not obvious)?
+
+Checklist:
+
+- [ ] Added unit tests (if possible)?
+- [ ] Added XML documentation to any related classes?
+- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Avaloniaui.net with user documentation
+
+If the pull request fixes issue(s) list them like this:
+
+Fixes #123
+Fixes #456

+ 8 - 0
samples/BindingTest/MainWindow.xaml

@@ -1,4 +1,5 @@
 <Window xmlns="https://github.com/avaloniaui"
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
         xmlns:vm="clr-namespace:BindingTest.ViewModels;assembly=BindingTest"
         xmlns:local="clr-namespace:BindingTest;assembly=BindingTest">
   <Window.Styles>
@@ -6,6 +7,9 @@
       <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"/>

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

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

@@ -97,5 +97,9 @@ namespace Avalonia.DesignerSupport.Remote
         public void ShowTaskbarIcon(bool value)
         {
         }
+
+        public void CanResize(bool value)
+        {
+        }
     }
 }

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

@@ -99,6 +99,10 @@ namespace Avalonia.DesignerSupport.Remote
         public void ShowTaskbarIcon(bool value)
         {
         }
+
+        public void CanResize(bool value)
+        {
+        }
     }
 
     class ClipboardStub : IClipboard

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

+ 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

+ 3 - 2
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();

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

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

+ 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

+ 0 - 1
src/Windows/Avalonia.Win32/DataObject.cs

@@ -7,7 +7,6 @@ using System.Text;
 using Avalonia.Input;
 using Avalonia.Win32.Interop;
 using IDataObject = Avalonia.Input.IDataObject;
-using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
 using System.IO;
 using System.Runtime.Serialization.Formatters.Binary;
 

+ 36 - 4
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
@@ -984,7 +995,7 @@ namespace Avalonia.Win32.Interop
         public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
 
         [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
-        public static extern void DoDragDrop(IDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect);
+        public static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect);
 
 
 
@@ -1376,13 +1387,13 @@ namespace Avalonia.Win32.Interop
     internal interface IDropTarget
     {
         [PreserveSig]
-        UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+        UnmanagedMethods.HRESULT DragEnter([MarshalAs(UnmanagedType.Interface)] [In] IOleDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
         [PreserveSig]
         UnmanagedMethods.HRESULT DragOver([MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
         [PreserveSig]
         UnmanagedMethods.HRESULT DragLeave();
         [PreserveSig]
-        UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
+        UnmanagedMethods.HRESULT Drop([MarshalAs(UnmanagedType.Interface)] [In] IOleDataObject pDataObj, [MarshalAs(UnmanagedType.U4)] [In] int grfKeyState, [MarshalAs(UnmanagedType.U8)] [In] long pt, [In] [Out] ref DropEffect pdwEffect);
     }
 
     [ComImport]
@@ -1397,6 +1408,27 @@ namespace Avalonia.Win32.Interop
     }
 
 
+    [ComImport]
+    [Guid("0000010E-0000-0000-C000-000000000046")]
+    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+    public interface IOleDataObject
+    {
+        void GetData([In] ref FORMATETC format, out STGMEDIUM medium);
+        void GetDataHere([In] ref FORMATETC format, ref STGMEDIUM medium);
+        [PreserveSig]
+        int QueryGetData([In] ref FORMATETC format);
+        [PreserveSig]
+        int GetCanonicalFormatEtc([In] ref FORMATETC formatIn, out FORMATETC formatOut);
+        void SetData([In] ref FORMATETC formatIn, [In] ref STGMEDIUM medium, [MarshalAs(UnmanagedType.Bool)] bool release);
+        IEnumFORMATETC EnumFormatEtc(DATADIR direction);
+        [PreserveSig]
+        int DAdvise([In] ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection);
+        void DUnadvise(int connection);
+        [PreserveSig]
+        int EnumDAdvise(out IEnumSTATDATA enumAdvise);
+    }
+
+
     [StructLayoutAttribute(LayoutKind.Sequential)]
     internal struct _DROPFILES
     {

+ 2 - 3
src/Windows/Avalonia.Win32/OleDataObject.cs

@@ -8,15 +8,14 @@ using System.Runtime.Serialization.Formatters.Binary;
 using System.Text;
 using Avalonia.Input;
 using Avalonia.Win32.Interop;
-using IDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
 
 namespace Avalonia.Win32
 {
     class OleDataObject : Avalonia.Input.IDataObject
     {
-        private IDataObject _wrapped;
+        private IOleDataObject _wrapped;
 
-        public OleDataObject(IDataObject wrapped)
+        public OleDataObject(IOleDataObject wrapped)
         {
             _wrapped = wrapped;
         }

+ 0 - 1
src/Windows/Avalonia.Win32/OleDropTarget.cs

@@ -3,7 +3,6 @@ using Avalonia.Input.Raw;
 using Avalonia.Platform;
 using Avalonia.Win32.Interop;
 using IDataObject = Avalonia.Input.IDataObject;
-using IOleDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
 
 namespace Avalonia.Win32
 {

+ 3 - 3
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -82,11 +82,11 @@ namespace Avalonia.Win32
                 .Bind<IWindowingPlatform>().ToConstant(s_instance)
                 .Bind<IPlatformIconLoader>().ToConstant(s_instance);
 
-            if (OleContext.Current != null)
-                AvaloniaLocator.CurrentMutable.Bind<IPlatformDragSource>().ToSingleton<DragSource>();
-
             UseDeferredRendering = deferredRendering;
             _uiThread = UnmanagedMethods.GetCurrentThreadId();
+
+            if (OleContext.Current != null)
+                AvaloniaLocator.CurrentMutable.Bind<IPlatformDragSource>().ToSingleton<DragSource>();
         }
 
         public bool HasMessages()

+ 36 - 11
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;
@@ -80,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))
@@ -244,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;
@@ -260,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)
             {
@@ -826,11 +833,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
@@ -841,9 +848,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;
+        }
     }
 }

+ 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()
         {