浏览代码

Merge branch 'master' into DisableButtonOnNullCommandBinding

Jeremy Koritzinsky 8 年之前
父节点
当前提交
6d32e6a36c
共有 71 个文件被更改,包括 572 次插入273 次删除
  1. 5 0
      .ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject
  2. 5 0
      .ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject
  3. 5 0
      .ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject
  4. 5 0
      .ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject
  5. 5 0
      .ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject
  6. 5 0
      .ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject
  7. 5 0
      .ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject
  8. 5 0
      .ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject
  9. 5 0
      .ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject
  10. 5 0
      .ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject
  11. 5 0
      .ncrunch/Direct3DInteropSample.v3.ncrunchproject
  12. 1 0
      Avalonia.sln.DotSettings
  13. 1 0
      appveyor.yml
  14. 40 3
      build.cake
  15. 0 5
      build/SkiaSharp.Desktop.props
  16. 2 1
      build/SkiaSharp.props
  17. 1 1
      docs/guidelines/build.md
  18. 1 1
      docs/index.md
  19. 1 1
      docs/tutorial/gettingstarted.md
  20. 15 9
      packages.cake
  21. 11 3
      parameters.cake
  22. 1 1
      readme.md
  23. 2 1
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  24. 1 1
      samples/interop/Direct3DInteropSample/MainWindow.cs
  25. 1 0
      samples/interop/GtkInteropDemo/GtkInteropDemo.csproj
  26. 1 0
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  27. 1 0
      src/Android/Avalonia.Android/AndroidPlatform.cs
  28. 6 11
      src/Avalonia.Base/AvaloniaObject.cs
  29. 1 1
      src/Avalonia.Base/AvaloniaProperty.cs
  30. 9 16
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  31. 2 2
      src/Avalonia.Base/PriorityValue.cs
  32. 162 75
      src/Avalonia.Base/Utilities/TypeUtilities.cs
  33. 20 4
      src/Avalonia.Controls/AppBuilderBase.cs
  34. 1 1
      src/Avalonia.Controls/Button.cs
  35. 1 1
      src/Avalonia.Controls/Control.cs
  36. 6 6
      src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
  37. 1 1
      src/Avalonia.Controls/ItemsControl.cs
  38. 1 2
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  39. 3 4
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  40. 5 2
      src/Avalonia.Controls/TextBox.cs
  41. 19 16
      src/Avalonia.Controls/TopLevel.cs
  42. 17 11
      src/Avalonia.Controls/Window.cs
  43. 20 14
      src/Avalonia.Controls/WindowBase.cs
  44. 3 1
      src/Avalonia.DesignerSupport/DesignerAssist.cs
  45. 7 1
      src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
  46. 3 4
      src/Avalonia.Layout/Layoutable.cs
  47. 1 1
      src/Avalonia.Styling/Controls/NameScope.cs
  48. 7 0
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  49. 1 1
      src/Avalonia.Visuals/Rendering/ZIndexComparer.cs
  50. 1 1
      src/Avalonia.Visuals/VisualTree/VisualExtensions.cs
  51. 1 0
      src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs
  52. 3 3
      src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs
  53. 3 3
      src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs
  54. 1 0
      src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs
  55. 5 0
      src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs
  56. 1 0
      src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
  57. 1 0
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  58. 1 1
      src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs
  59. 2 2
      src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs
  60. 14 50
      src/Markup/Avalonia.Markup/DefaultValueConverter.cs
  61. 3 3
      src/Shared/SharedAssemblyInfo.cs
  62. 0 1
      src/Skia/Avalonia.Skia.Desktop.NetStandard/Avalonia.Skia.Desktop.NetStandard.csproj
  63. 1 1
      src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj
  64. 3 1
      src/Skia/Avalonia.Skia.Desktop/Properties/AssemblyInfo.cs
  65. 2 2
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  66. 1 1
      src/Skia/Avalonia.Skia/FormattedTextImpl.cs
  67. 3 1
      src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs
  68. 1 0
      src/iOS/Avalonia.iOS/iOSPlatform.cs
  69. 24 1
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
  70. 53 0
      tests/Avalonia.Layout.UnitTests/MeasureTests.cs
  71. 17 0
      tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs

+ 5 - 0
.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 5 - 0
.ncrunch/Direct3DInteropSample.v3.ncrunchproject

@@ -0,0 +1,5 @@
+<ProjectConfiguration>
+  <Settings>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 1 - 0
Avalonia.sln.DotSettings

@@ -1,4 +1,5 @@
 <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
 <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=3E53A01A_002DB331_002D47F3_002DB828_002D4A5717E77A24_002Fd_003Aglass/@EntryIndexedValue">ExplicitlyExcluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=6417B24E_002D49C2_002D4985_002D8DB2_002D3AB9D898EC91/@EntryIndexedValue">ExplicitlyExcluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=6417B24E_002D49C2_002D4985_002D8DB2_002D3AB9D898EC91/@EntryIndexedValue">ExplicitlyExcluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=E3A1060B_002D50D0_002D44E8_002D88B6_002DF44EF2E5BD72_002Ff_003Ahtml_002Ehtm/@EntryIndexedValue">ExplicitlyExcluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=E3A1060B_002D50D0_002D44E8_002D88B6_002DF44EF2E5BD72_002Ff_003Ahtml_002Ehtm/@EntryIndexedValue">ExplicitlyExcluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantUsingDirective/@EntryIndexedValue">HINT</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantUsingDirective/@EntryIndexedValue">HINT</s:String>

+ 1 - 0
appveyor.yml

@@ -35,6 +35,7 @@ test: off
 artifacts:
 artifacts:
   - path: artifacts\nuget\*.nupkg
   - path: artifacts\nuget\*.nupkg
   - path: artifacts\zip\*.zip
   - path: artifacts\zip\*.zip
+  - path: artifacts\inspectcode.xml
 cache:
 cache:
   - gtk-sharp-2.12.26.msi
   - gtk-sharp-2.12.26.msi
   - dotnet-1.0.1.exe
   - dotnet-1.0.1.exe

+ 40 - 3
build.cake

@@ -5,7 +5,8 @@
 #addin "nuget:?package=Polly&version=4.2.0"
 #addin "nuget:?package=Polly&version=4.2.0"
 #addin "nuget:?package=NuGet.Core&version=2.12.0"
 #addin "nuget:?package=NuGet.Core&version=2.12.0"
 #tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease"
 #tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease"
-#tool "nuget:?package=JetBrains.dotMemoryUnit&version=2.1.20150828.125449"
+#tool "nuget:?package=JetBrains.dotMemoryUnit&version=2.3.20160517.113140"
+#tool "JetBrains.ReSharper.CommandLineTools"
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 // TOOLS
 // TOOLS
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
@@ -104,7 +105,7 @@ Task("Restore-NuGet-Packages")
     .Does(() =>
     .Does(() =>
 {
 {
     var maxRetryCount = 5;
     var maxRetryCount = 5;
-    var toolTimeout = 1d;
+    var toolTimeout = 2d;
     Policy
     Policy
         .Handle<Exception>()
         .Handle<Exception>()
         .Retry(maxRetryCount, (exception, retryCount, context) => {
         .Retry(maxRetryCount, (exception, retryCount, context) => {
@@ -279,11 +280,15 @@ Task("Zip-Files")
     Zip(parameters.ZipSourceControlCatalogDesktopDirs, 
     Zip(parameters.ZipSourceControlCatalogDesktopDirs, 
         parameters.ZipTargetControlCatalogDesktopDirs, 
         parameters.ZipTargetControlCatalogDesktopDirs, 
         GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
         GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
+        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + 
+        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + 
+        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + 
         GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
         GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
 });
 });
 
 
 Task("Create-NuGet-Packages")
 Task("Create-NuGet-Packages")
     .IsDependentOn("Run-Unit-Tests")
     .IsDependentOn("Run-Unit-Tests")
+    .IsDependentOn("Inspect")
     .Does(() =>
     .Does(() =>
 {
 {
     foreach(var nuspec in packages.NuspecNuGetSettings)
     foreach(var nuspec in packages.NuspecNuGetSettings)
@@ -331,7 +336,6 @@ Task("Publish-NuGet")
     .WithCriteria(() => !parameters.IsLocalBuild)
     .WithCriteria(() => !parameters.IsLocalBuild)
     .WithCriteria(() => !parameters.IsPullRequest)
     .WithCriteria(() => !parameters.IsPullRequest)
     .WithCriteria(() => parameters.IsMainRepo)
     .WithCriteria(() => parameters.IsMainRepo)
-    .WithCriteria(() => parameters.IsMasterBranch)
     .WithCriteria(() => parameters.IsNuGetRelease)
     .WithCriteria(() => parameters.IsNuGetRelease)
     .Does(() =>
     .Does(() =>
 {
 {
@@ -360,6 +364,39 @@ Task("Publish-NuGet")
     Information("Publish-NuGet Task failed, but continuing with next Task...");
     Information("Publish-NuGet Task failed, but continuing with next Task...");
 });
 });
 
 
+Task("Inspect")
+    .WithCriteria(parameters.IsRunningOnWindows)
+    .IsDependentOn("Restore-NuGet-Packages")
+    .Does(() =>
+    {
+        var badIssues = new []{"PossibleNullReferenceException"};
+        var whitelist = new []{"tests", "src\\android", "src\\ios",
+            "src\\windows\\avalonia.designer", "src\\avalonia.htmlrenderer\\external"};
+        Information("Running code inspections");
+        
+        
+        StartProcess("tools\\JetBrains.ReSharper.CommandLineTools\\tools\\inspectcode.exe",
+            new ProcessSettings{ Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln" });
+        Information("Analyzing report");
+        var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml"));
+        var failBuild = false;
+        foreach(var xml in doc.Descendants("Issue"))
+        {
+            var typeId = xml.Attribute("TypeId").Value.ToString();
+            if(badIssues.Contains(typeId))
+            {
+                var file = xml.Attribute("File").Value.ToString().ToLower();
+                if(whitelist.Any(wh => file.StartsWith(wh)))
+                    continue;
+                var line = xml.Attribute("Line").Value.ToString();
+                Error(typeId + " - " + file + " on line " + line);
+                failBuild = true;
+            }
+        }
+        if(failBuild)
+            throw new Exception("Issues found");
+    });
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 // TARGETS
 // TARGETS
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////

+ 0 - 5
build/SkiaSharp.Desktop.props

@@ -1,5 +0,0 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <PackageReference Include="Avalonia.Skia.Linux.Natives" Version="1.56.1.3" />
-  </ItemGroup>
-</Project>

+ 2 - 1
build/SkiaSharp.props

@@ -1,5 +1,6 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="SkiaSharp" Version="1.56.1-beta" />
+    <PackageReference Include="SkiaSharp" Version="1.57.1" />
+    <PackageReference Condition="$(TargetFramework.Trim('.').ToLower().StartsWith('netframework'))" Include="Avalonia.Skia.Linux.Natives" Version="1.57.1.3" />
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 1 - 1
docs/guidelines/build.md

@@ -2,7 +2,7 @@
 
 
 ## Windows
 ## Windows
 
 
-Avalonia requires at least Visual Studio 2015 to build on Windows.
+Avalonia requires at least Visual Studio 2017 to build on Windows.
 
 
 ### Install GTK Sharp
 ### Install GTK Sharp
 
 

+ 1 - 1
docs/index.md

@@ -10,7 +10,7 @@ What does alpha mean? Well, it means that it's now at a stage where you can have
 
 
 ## How do I try it out
 ## How do I try it out
 
 
-The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/a4542e8a-b56c-4295-8df1-7e220178b873).
+The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio).
 
 
 This will add a Avalonia project template and a Window template to the standard Visual Studo "Add" dialog (yes, icons still to come :) ):
 This will add a Avalonia project template and a Window template to the standard Visual Studo "Add" dialog (yes, icons still to come :) ):
 
 

+ 1 - 1
docs/tutorial/gettingstarted.md

@@ -4,7 +4,7 @@
 
 
 ![](images/add-dialogs.png)
 ![](images/add-dialogs.png)
 
 
-The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/e1c6ae1f-6fd9-467d-8f62-1e28b4225213).
+The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio).
 
 
 This will add a Avalonia project template and a Window template to the standard Visual Studo “Add”
 This will add a Avalonia project template and a Window template to the standard Visual Studo “Add”
 dialog (yes, icons still to come :) ):
 dialog (yes, icons still to come :) ):

+ 15 - 9
packages.cake

@@ -7,6 +7,7 @@ public class Packages
     public FilePath[] BinFiles { get; private set; }
     public FilePath[] BinFiles { get; private set; }
     public string NugetPackagesDir {get; private set;}
     public string NugetPackagesDir {get; private set;}
     public string SkiaSharpVersion {get; private set; }
     public string SkiaSharpVersion {get; private set; }
+    public string SkiaSharpLinuxVersion {get; private set; }
     public Packages(ICakeContext context, Parameters parameters)
     public Packages(ICakeContext context, Parameters parameters)
     {
     {
         // NUGET NUSPECS
         // NUGET NUSPECS
@@ -75,6 +76,7 @@ public class Packages
         var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
         var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
         var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
         var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
         SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
         SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
+		SkiaSharpLinuxVersion = packageVersions["Avalonia.Skia.Linux.Natives"].FirstOrDefault().Item1;
         var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
         var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
         var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
         var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
         var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
         var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
@@ -85,6 +87,7 @@ public class Packages
         context.Information("Package: Sprache, version: {0}", SpracheVersion);
         context.Information("Package: Sprache, version: {0}", SpracheVersion);
         context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
         context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
         context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
         context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
+        context.Information("Package: Avalonia.Skia.Linux.Natives, version: {0}", SkiaSharpLinuxVersion);
         context.Information("Package: SharpDX, version: {0}", SharpDXVersion);
         context.Information("Package: SharpDX, version: {0}", SharpDXVersion);
         context.Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
         context.Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
         context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version);
         context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version);
@@ -425,10 +428,7 @@ public class Packages
                 {
                 {
                     new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
                     new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
                     new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion },
                     new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion },
-                    //netstandard1.3
-                    new NuSpecDependency() { Id = "Avalonia", TargetFramework = "netstandard1.3", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "SkiaSharp", TargetFramework = "netstandard1.3", Version = SkiaSharpVersion },
-                    new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netstandard1.3", Version = "1.6.0" }
+                    new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion }
                 },
                 },
                 Files = new []
                 Files = new []
                 {
                 {
@@ -446,11 +446,17 @@ public class Packages
                 Id = "Avalonia.Desktop",
                 Id = "Avalonia.Desktop",
                 Dependencies = new []
                 Dependencies = new []
                 {
                 {
-                    new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Gtk", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Cairo", Version = parameters.Version },
-                    new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = parameters.Version }
+                    //Full .NET
+                    new NuSpecDependency() { Id = "Avalonia.Direct2D1", TargetFramework="net45", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Gtk", TargetFramework="net45", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Cairo", TargetFramework="net45", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="net45", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", TargetFramework="net45", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="net45", Version = parameters.Version },
+                    //.NET Core
+                    new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp1.1", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", TargetFramework="netcoreapp1.1", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp1.1", Version = parameters.Version }
                 },
                 },
                 Files = new NuSpecContent[]
                 Files = new NuSpecContent[]
                 {
                 {

+ 11 - 3
parameters.cake

@@ -75,17 +75,25 @@ public class Parameters
         IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleasePlatform, Platform) 
         IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleasePlatform, Platform) 
                     && StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration);
                     && StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration);
         IsMyGetRelease = !IsTagged && IsReleasable;
         IsMyGetRelease = !IsTagged && IsReleasable;
-        IsNuGetRelease = IsTagged && IsReleasable;
+        
 
 
         // VERSION
         // VERSION
         Version = context.Argument("force-nuget-version", context.ParseAssemblyInfo(AssemblyInfoPath).AssemblyVersion);
         Version = context.Argument("force-nuget-version", context.ParseAssemblyInfo(AssemblyInfoPath).AssemblyVersion);
 
 
         if (IsRunningOnAppVeyor)
         if (IsRunningOnAppVeyor)
         {
         {
+            string tagVersion = null;
             if (IsTagged)
             if (IsTagged)
             {
             {
-                // Use Tag Name as version
-                Version = buildSystem.AppVeyor.Environment.Repository.Tag.Name;
+                var tag = buildSystem.AppVeyor.Environment.Repository.Tag.Name;
+                var nugetReleasePrefix = "nuget-release-";
+                IsNuGetRelease = IsTagged && IsReleasable && tag.StartsWith(nugetReleasePrefix);
+                if(IsNuGetRelease)
+                    tagVersion = tag.Substring(nugetReleasePrefix.Length);
+            }
+            if(tagVersion != null)
+            {
+                Version = tagVersion;
             }
             }
             else
             else
             {
             {

+ 1 - 1
readme.md

@@ -42,7 +42,7 @@ using Direct2D and other operating systems using Gtk & Cairo.
 
 
 Avalonia is now in alpha. What does "alpha" mean? Well, it means that it's now at a stage where you
 Avalonia is now in alpha. What does "alpha" mean? Well, it means that it's now at a stage where you
 can have a play and hopefully create simple applications. There's now a [Visual
 can have a play and hopefully create simple applications. There's now a [Visual
-Studio Extension](https://visualstudiogallery.msdn.microsoft.com/e1c6ae1f-6fd9-467d-8f62-1e28b4225213)
+Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio)
 containing project and item templates that will help you get started, and
 containing project and item templates that will help you get started, and
 there's an initial complement of controls. There's still a lot missing, and you
 there's an initial complement of controls. There's still a lot missing, and you
 *will* find bugs, and the API *will* change, but this represents the first time
 *will* find bugs, and the API *will* change, but this represents the first time

+ 2 - 1
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@@ -26,7 +26,7 @@
     <WarningLevel>4</WarningLevel>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <PlatformTarget>x86</PlatformTarget>
     <DebugType>pdbonly</DebugType>
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
     <OutputPath>bin\Release\</OutputPath>
@@ -142,6 +142,7 @@
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="..\..\build\Serilog.props" />
   <Import Project="..\..\build\Serilog.props" />
+  <Import Project="..\..\build\SkiaSharp.props" />
   <Import Project="..\..\build\Serilog.Sinks.Trace.props" />
   <Import Project="..\..\build\Serilog.Sinks.Trace.props" />
   <Import Project="$(MSBuildThisFileDirectory)..\..\src\Shared\nuget.workaround.targets" />
   <Import Project="$(MSBuildThisFileDirectory)..\..\src\Shared\nuget.workaround.targets" />
 </Project>
 </Project>

+ 1 - 1
samples/interop/Direct3DInteropSample/MainWindow.cs

@@ -58,7 +58,7 @@ namespace Direct3DInteropSample
                    new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height,
                    new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height,
                             new Rational(60, 1), Format.R8G8B8A8_UNorm),
                             new Rational(60, 1), Format.R8G8B8A8_UNorm),
                 IsWindowed = true,
                 IsWindowed = true,
-                OutputHandle = PlatformImpl.Handle.Handle,
+                OutputHandle = PlatformImpl?.Handle.Handle ?? IntPtr.Zero,
                 SampleDescription = new SampleDescription(1, 0),
                 SampleDescription = new SampleDescription(1, 0),
                 SwapEffect = SwapEffect.Discard,
                 SwapEffect = SwapEffect.Discard,
                 Usage = Usage.RenderTargetOutput
                 Usage = Usage.RenderTargetOutput

+ 1 - 0
samples/interop/GtkInteropDemo/GtkInteropDemo.csproj

@@ -149,6 +149,7 @@
       <Name>ControlCatalog</Name>
       <Name>ControlCatalog</Name>
     </ProjectReference>
     </ProjectReference>
   </ItemGroup>
   </ItemGroup>
+  <Import Project="..\..\..\build\Rx.props" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildThisFileDirectory)..\..\..\src\Shared\nuget.workaround.targets" />
   <Import Project="$(MSBuildThisFileDirectory)..\..\..\src\Shared\nuget.workaround.targets" />
 </Project>
 </Project>

+ 1 - 0
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@@ -179,6 +179,7 @@
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
     </Page>
     </Page>
   </ItemGroup>
   </ItemGroup>
+  <Import Project="..\..\..\build\Rx.props" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildThisFileDirectory)..\..\..\src\Shared\nuget.workaround.targets" />
   <Import Project="$(MSBuildThisFileDirectory)..\..\..\src\Shared\nuget.workaround.targets" />
 </Project>
 </Project>

+ 1 - 0
src/Android/Avalonia.Android/AndroidPlatform.cs

@@ -53,6 +53,7 @@ namespace Avalonia.Android
                 .Bind<IKeyboardDevice>().ToSingleton<AndroidKeyboardDevice>()
                 .Bind<IKeyboardDevice>().ToSingleton<AndroidKeyboardDevice>()
                 .Bind<IMouseDevice>().ToSingleton<AndroidMouseDevice>()
                 .Bind<IMouseDevice>().ToSingleton<AndroidMouseDevice>()
                 .Bind<IPlatformSettings>().ToConstant(Instance)
                 .Bind<IPlatformSettings>().ToConstant(Instance)
+                .Bind<IRendererFactory>().ToConstant(ImmediateRenderer.Factory)
                 .Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
                 .Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
                 .Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
                 .Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
                 .Bind<IWindowingPlatform>().ToConstant(Instance)
                 .Bind<IWindowingPlatform>().ToConstant(Instance)

+ 6 - 11
src/Avalonia.Base/AvaloniaObject.cs

@@ -578,13 +578,13 @@ namespace Avalonia
 
 
             if (notification == null)
             if (notification == null)
             {
             {
-                return TypeUtilities.CastOrDefault(value, type);
+                return TypeUtilities.ConvertImplicitOrDefault(value, type);
             }
             }
             else
             else
             {
             {
                 if (notification.HasValue)
                 if (notification.HasValue)
                 {
                 {
-                    notification.SetValue(TypeUtilities.CastOrDefault(notification.Value, type));
+                    notification.SetValue(TypeUtilities.ConvertImplicitOrDefault(notification.Value, type));
                 }
                 }
 
 
                 return notification;
                 return notification;
@@ -622,14 +622,9 @@ namespace Avalonia
         /// <returns>The default value.</returns>
         /// <returns>The default value.</returns>
         private object GetDefaultValue(AvaloniaProperty property)
         private object GetDefaultValue(AvaloniaProperty property)
         {
         {
-            if (property.Inherits && _inheritanceParent != null)
-            {
-                return (_inheritanceParent as AvaloniaObject).GetValueInternal(property);
-            }
-            else
-            {
-                return ((IStyledPropertyAccessor)property).GetDefaultValue(GetType());
-            }
+            if (property.Inherits && _inheritanceParent is AvaloniaObject aobj)
+                return aobj.GetValueInternal(property);
+            return ((IStyledPropertyAccessor) property).GetDefaultValue(GetType());
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -735,7 +730,7 @@ namespace Avalonia
                 ThrowNotRegistered(property);
                 ThrowNotRegistered(property);
             }
             }
 
 
-            if (!TypeUtilities.TryCast(property.PropertyType, value, out value))
+            if (!TypeUtilities.TryConvertImplicit(property.PropertyType, value, out value))
             {
             {
                 throw new ArgumentException(string.Format(
                 throw new ArgumentException(string.Format(
                     "Invalid value for Property '{0}': '{1}' ({2})",
                     "Invalid value for Property '{0}': '{1}' ({2})",

+ 1 - 1
src/Avalonia.Base/AvaloniaProperty.cs

@@ -476,7 +476,7 @@ namespace Avalonia
         /// <returns>True if the value is valid, otherwise false.</returns>
         /// <returns>True if the value is valid, otherwise false.</returns>
         public bool IsValidValue(object value)
         public bool IsValidValue(object value)
         {
         {
-            return TypeUtilities.TryCast(PropertyType, value, out value);
+            return TypeUtilities.TryConvertImplicit(PropertyType, value, out value);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 9 - 16
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@@ -103,11 +103,9 @@ namespace Avalonia.Collections
 
 
             _inner = new Dictionary<TKey, TValue>();
             _inner = new Dictionary<TKey, TValue>();
 
 
-            if (PropertyChanged != null)
-            {
-                PropertyChanged(this, new PropertyChangedEventArgs("Count"));
-                PropertyChanged(this, new PropertyChangedEventArgs($"Item[]"));
-            }
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[]"));
+            
 
 
             if (CollectionChanged != null)
             if (CollectionChanged != null)
             {
             {
@@ -144,12 +142,9 @@ namespace Avalonia.Collections
 
 
             if (_inner.TryGetValue(key, out value))
             if (_inner.TryGetValue(key, out value))
             {
             {
-                if (PropertyChanged != null)
-                {
-                    PropertyChanged(this, new PropertyChangedEventArgs("Count"));
-                    PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]"));
-                }
-
+                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
+                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
+                
                 if (CollectionChanged != null)
                 if (CollectionChanged != null)
                 {
                 {
                     var e = new NotifyCollectionChangedEventArgs(
                     var e = new NotifyCollectionChangedEventArgs(
@@ -199,11 +194,9 @@ namespace Avalonia.Collections
 
 
         private void NotifyAdd(TKey key, TValue value)
         private void NotifyAdd(TKey key, TValue value)
         {
         {
-            if (PropertyChanged != null)
-            {
-                PropertyChanged(this, new PropertyChangedEventArgs("Count"));
-                PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]"));
-            }
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
+            
 
 
             if (CollectionChanged != null)
             if (CollectionChanged != null)
             {
             {

+ 2 - 2
src/Avalonia.Base/PriorityValue.cs

@@ -249,7 +249,7 @@ namespace Avalonia
                 value = (notification.HasValue) ? notification.Value : null;
                 value = (notification.HasValue) ? notification.Value : null;
             }
             }
 
 
-            if (TypeUtilities.TryCast(_valueType, value, out castValue))
+            if (TypeUtilities.TryConvertImplicit(_valueType, value, out castValue))
             {
             {
                 var old = _value;
                 var old = _value;
 
 
@@ -285,7 +285,7 @@ namespace Avalonia
                     Property.Name, 
                     Property.Name, 
                     _valueType, 
                     _valueType, 
                     value,
                     value,
-                    value.GetType());
+                    value?.GetType());
             }
             }
         }
         }
     }
     }

+ 162 - 75
src/Avalonia.Base/Utilities/TypeUtilities.cs

@@ -14,17 +14,61 @@ namespace Avalonia.Utilities
     /// </summary>
     /// </summary>
     public static class TypeUtilities
     public static class TypeUtilities
     {
     {
-        private static readonly Dictionary<Type, List<Type>> Conversions = new Dictionary<Type, List<Type>>()
+        private static int[] Conversions =
         {
         {
-            { typeof(decimal), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } },
-            { typeof(double), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },
-            { typeof(float), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },
-            { typeof(ulong), new List<Type> { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } },
-            { typeof(long), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } },
-            { typeof(uint), new List<Type> { typeof(byte), typeof(ushort), typeof(char) } },
-            { typeof(int), new List<Type> { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } },
-            { typeof(ushort), new List<Type> { typeof(byte), typeof(char) } },
-            { typeof(short), new List<Type> { typeof(byte) } }
+            0b101111111111101, // Boolean
+            0b100001111111110, // Char
+            0b101111111111111, // SByte
+            0b101111111111111, // Byte
+            0b101111111111111, // Int16
+            0b101111111111111, // UInt16
+            0b101111111111111, // Int32
+            0b101111111111111, // UInt32
+            0b101111111111111, // Int64
+            0b101111111111111, // UInt64
+            0b101111111111101, // Single
+            0b101111111111101, // Double
+            0b101111111111101, // Decimal
+            0b110000000000000, // DateTime
+            0b111111111111111, // String
+        };
+
+        private static int[] ImplicitConversions =
+        {
+            0b000000000000001, // Boolean
+            0b001110111100010, // Char
+            0b001110101010100, // SByte
+            0b001111111111000, // Byte
+            0b001110101010000, // Int16
+            0b001111111100000, // UInt16
+            0b001110101000000, // Int32
+            0b001111110000000, // UInt32
+            0b001110100000000, // Int64
+            0b001111000000000, // UInt64
+            0b000110000000000, // Single
+            0b000100000000000, // Double
+            0b001000000000000, // Decimal
+            0b010000000000000, // DateTime
+            0b100000000000000, // String
+        };
+
+        private static Type[] InbuiltTypes =
+        {
+            typeof(Boolean),
+            typeof(Char),
+            typeof(SByte),
+            typeof(Byte),
+            typeof(Int16),
+            typeof(UInt16),
+            typeof(Int32),
+            typeof(UInt32),
+            typeof(Int64),
+            typeof(UInt64),
+            typeof(Single),
+            typeof(Double),
+            typeof(Decimal),
+            typeof(DateTime),
+            typeof(String),
         };
         };
 
 
         private static readonly Type[] NumericTypes = new[]
         private static readonly Type[] NumericTypes = new[]
@@ -54,49 +98,104 @@ namespace Avalonia.Utilities
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Try to cast a value to a type, using implicit conversions if possible.
+        /// Try to convert a value to a type by any means possible.
         /// </summary>
         /// </summary>
         /// <param name="to">The type to cast to.</param>
         /// <param name="to">The type to cast to.</param>
         /// <param name="value">The value to cast.</param>
         /// <param name="value">The value to cast.</param>
+        /// <param name="culture">The culture to use.</param>
         /// <param name="result">If sucessful, contains the cast value.</param>
         /// <param name="result">If sucessful, contains the cast value.</param>
         /// <returns>True if the cast was sucessful, otherwise false.</returns>
         /// <returns>True if the cast was sucessful, otherwise false.</returns>
-        public static bool TryCast(Type to, object value, out object result)
+        public static bool TryConvert(Type to, object value, CultureInfo culture, out object result)
         {
         {
-            Contract.Requires<ArgumentNullException>(to != null);
-
             if (value == null)
             if (value == null)
             {
             {
                 result = null;
                 result = null;
                 return AcceptsNull(to);
                 return AcceptsNull(to);
             }
             }
 
 
-            var from = value.GetType();
-
             if (value == AvaloniaProperty.UnsetValue)
             if (value == AvaloniaProperty.UnsetValue)
             {
             {
                 result = value;
                 result = value;
                 return true;
                 return true;
             }
             }
-            else if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo()))
+
+            var from = value.GetType();
+            var fromTypeInfo = from.GetTypeInfo();
+            var toTypeInfo = to.GetTypeInfo();
+
+            if (toTypeInfo.IsAssignableFrom(fromTypeInfo))
             {
             {
                 result = value;
                 result = value;
                 return true;
                 return true;
             }
             }
-            else if (Conversions.ContainsKey(to) && Conversions[to].Contains(from))
+
+            if (to == typeof(string))
             {
             {
-                result = Convert.ChangeType(value, to);
+                result = Convert.ToString(value);
                 return true;
                 return true;
             }
             }
-            else
+
+            if (toTypeInfo.IsEnum && from == typeof(string))
+            {
+                if (Enum.IsDefined(to, (string)value))
+                {
+                    result = Enum.Parse(to, (string)value);
+                    return true;
+                }
+            }
+
+            if (!fromTypeInfo.IsEnum && toTypeInfo.IsEnum)
             {
             {
-                var cast = from.GetRuntimeMethods()
-                    .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to);
+                result = null;
+
+                if (TryConvert(Enum.GetUnderlyingType(to), value, culture, out object enumValue))
+                {
+                    result = Enum.ToObject(to, enumValue);
+                    return true;
+                }
+            }
 
 
-                if (cast != null)
+            if (fromTypeInfo.IsEnum && IsNumeric(to))
+            {
+                try
                 {
                 {
-                    result = cast.Invoke(null, new[] { value });
+                    result = Convert.ChangeType((int)value, to, culture);
                     return true;
                     return true;
                 }
                 }
+                catch
+                {
+                    result = null;
+                    return false;
+                }
+            }
+
+            var convertableFrom = Array.IndexOf(InbuiltTypes, from);
+            var convertableTo = Array.IndexOf(InbuiltTypes, to);
+
+            if (convertableFrom != -1 && convertableTo != -1)
+            {
+                if ((Conversions[convertableFrom] & 1 << convertableTo) != 0)
+                {
+                    try
+                    {
+                        result = Convert.ChangeType(value, to, culture);
+                        return true;
+                    }
+                    catch
+                    {
+                        result = null;
+                        return false;
+                    }
+                }
+            }
+
+            var cast = from.GetRuntimeMethods()
+                .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to);
+
+            if (cast != null)
+            {
+                result = cast.Invoke(null, new[] { value });
+                return true;
             }
             }
 
 
             result = null;
             result = null;
@@ -104,15 +203,14 @@ namespace Avalonia.Utilities
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Try to convert a value to a type, using <see cref="System.Convert"/> if possible,
-        /// otherwise using <see cref="TryCast(Type, object, out object)"/>.
+        /// Try to convert a value to a type using the implicit conversions allowed by the C#
+        /// language.
         /// </summary>
         /// </summary>
         /// <param name="to">The type to cast to.</param>
         /// <param name="to">The type to cast to.</param>
         /// <param name="value">The value to cast.</param>
         /// <param name="value">The value to cast.</param>
-        /// <param name="culture">The culture to use.</param>
         /// <param name="result">If sucessful, contains the cast value.</param>
         /// <param name="result">If sucessful, contains the cast value.</param>
         /// <returns>True if the cast was sucessful, otherwise false.</returns>
         /// <returns>True if the cast was sucessful, otherwise false.</returns>
-        public static bool TryConvert(Type to, object value, CultureInfo culture, out object result)
+        public static bool TryConvertImplicit(Type to, object value, out object result)
         {
         {
             if (value == null)
             if (value == null)
             {
             {
@@ -120,54 +218,44 @@ namespace Avalonia.Utilities
                 return AcceptsNull(to);
                 return AcceptsNull(to);
             }
             }
 
 
-            var from = value.GetType();
-
             if (value == AvaloniaProperty.UnsetValue)
             if (value == AvaloniaProperty.UnsetValue)
             {
             {
                 result = value;
                 result = value;
                 return true;
                 return true;
             }
             }
 
 
-            if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo()))
-            {
-                result = value;
-                return true;
-            }
+            var from = value.GetType();
+            var fromTypeInfo = from.GetTypeInfo();
+            var toTypeInfo = to.GetTypeInfo();
 
 
-            if (to == typeof(string))
+            if (toTypeInfo.IsAssignableFrom(fromTypeInfo))
             {
             {
-                result = Convert.ToString(value);
+                result = value;
                 return true;
                 return true;
             }
             }
 
 
-            if (to.GetTypeInfo().IsEnum && from == typeof(string))
-            {
-                if (Enum.IsDefined(to, (string)value))
-                {
-                    result = Enum.Parse(to, (string)value);
-                    return true;
-                }
-            }
-
-            bool containsFrom = Conversions.ContainsKey(from);
-            bool containsTo = Conversions.ContainsKey(to);
+            var convertableFrom = Array.IndexOf(InbuiltTypes, from);
+            var convertableTo = Array.IndexOf(InbuiltTypes, to);
 
 
-            if ((containsFrom && containsTo) || (from == typeof(string) && containsTo))
+            if (convertableFrom != -1 && convertableTo != -1)
             {
             {
-                try
-                {
-                    result = Convert.ChangeType(value, to, culture);
-                    return true;
-                }
-                catch
+                if ((ImplicitConversions[convertableFrom] & 1 << convertableTo) != 0)
                 {
                 {
-                    result = null;
-                    return false;
+                    try
+                    {
+                        result = Convert.ChangeType(value, to, CultureInfo.InvariantCulture);
+                        return true;
+                    }
+                    catch
+                    {
+                        result = null;
+                        return false;
+                    }
                 }
                 }
             }
             }
 
 
             var cast = from.GetRuntimeMethods()
             var cast = from.GetRuntimeMethods()
-                .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to);
+                .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to);
 
 
             if (cast != null)
             if (cast != null)
             {
             {
@@ -180,29 +268,28 @@ namespace Avalonia.Utilities
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Casts a value to a type, returning the default for that type if the value could not be
-        /// cast.
+        /// Convert a value to a type by any means possible, returning the default for that type
+        /// if the value could not be converted.
         /// </summary>
         /// </summary>
         /// <param name="value">The value to cast.</param>
         /// <param name="value">The value to cast.</param>
         /// <param name="type">The type to cast to..</param>
         /// <param name="type">The type to cast to..</param>
+        /// <param name="culture">The culture to use.</param>
         /// <returns>A value of <paramref name="type"/>.</returns>
         /// <returns>A value of <paramref name="type"/>.</returns>
-        public static object CastOrDefault(object value, Type type)
+        public static object ConvertOrDefault(object value, Type type, CultureInfo culture)
         {
         {
-            var typeInfo = type.GetTypeInfo();
-            object result;
+            return TryConvert(type, value, culture, out object result) ? result : Default(type);
+        }
 
 
-            if (TypeUtilities.TryCast(type, value, out result))
-            {
-                return result;
-            }
-            else if (typeInfo.IsValueType)
-            {
-                return Activator.CreateInstance(type);
-            }
-            else
-            {
-                return null;
-            }
+        /// <summary>
+        /// Convert a value to a type using the implicit conversions allowed by the C# language or
+        /// return the default for the type if the value could not be converted.
+        /// </summary>
+        /// <param name="value">The value to cast.</param>
+        /// <param name="type">The type to cast to..</param>
+        /// <returns>A value of <paramref name="type"/>.</returns>
+        public static object ConvertImplicitOrDefault(object value, Type type)
+        {
+            return TryConvertImplicit(type, value, out object result) ? result : Default(type);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 20 - 4
src/Avalonia.Controls/AppBuilderBase.cs

@@ -55,8 +55,7 @@ namespace Avalonia.Controls
         public Action<TAppBuilder> AfterSetupCallback { get; private set; } = builder => { };
         public Action<TAppBuilder> AfterSetupCallback { get; private set; } = builder => { };
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets a method to call before <see cref="Start{TMainWindow}"/> is called on the
-        /// <see cref="Application"/>.
+        /// Gets or sets a method to call before Startis called on the <see cref="Application"/>.
         /// </summary>
         /// </summary>
         public Action<TAppBuilder> BeforeStartCallback { get; private set; } = builder => { };
         public Action<TAppBuilder> BeforeStartCallback { get; private set; } = builder => { };
 
 
@@ -94,8 +93,7 @@ namespace Avalonia.Controls
         protected TAppBuilder Self => (TAppBuilder) this;
         protected TAppBuilder Self => (TAppBuilder) this;
 
 
         /// <summary>
         /// <summary>
-        /// Registers a callback to call before <see cref="Start{TMainWindow}"/> is called on the
-        /// <see cref="Application"/>.
+        /// Registers a callback to call before Start is called on the <see cref="Application"/>.
         /// </summary>
         /// </summary>
         /// <param name="callback">The callback.</param>
         /// <param name="callback">The callback.</param>
         /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
         /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
@@ -129,6 +127,24 @@ namespace Avalonia.Controls
             Instance.Run(window);
             Instance.Run(window);
         }
         }
 
 
+        /// <summary>
+        /// Starts the application with the provided instance of <typeparamref name="TMainWindow"/>.
+        /// </summary>
+        /// <typeparam name="TMainWindow">The window type.</typeparam>
+        /// <param name="mainWindow">Instance of type TMainWindow to use when starting the app</param>
+        /// <param name="dataContextProvider">A delegate that will be called to create a data context for the window (optional).</param>
+        public void Start<TMainWindow>(TMainWindow mainWindow, Func<object> dataContextProvider = null)
+            where TMainWindow : Window
+        {
+            Setup();
+            BeforeStartCallback(Self);
+
+            if (dataContextProvider != null)
+                mainWindow.DataContext = dataContextProvider();
+            mainWindow.Show();
+            Instance.Run(mainWindow);
+        }
+
         /// <summary>
         /// <summary>
         /// Sets up the platform-specific services for the application, but does not run it.
         /// Sets up the platform-specific services for the application, but does not run it.
         /// </summary>
         /// </summary>

+ 1 - 1
src/Avalonia.Controls/Button.cs

@@ -291,7 +291,7 @@ namespace Avalonia.Controls
         {
         {
             var button = e.Sender as Button;
             var button = e.Sender as Button;
             var isDefault = (bool)e.NewValue;
             var isDefault = (bool)e.NewValue;
-            var inputRoot = button.VisualRoot as IInputElement;
+            var inputRoot = button?.VisualRoot as IInputElement;
 
 
             if (inputRoot != null)
             if (inputRoot != null)
             {
             {

+ 1 - 1
src/Avalonia.Controls/Control.cs

@@ -645,7 +645,7 @@ namespace Avalonia.Controls
 
 
             if (_focusAdorner != null)
             if (_focusAdorner != null)
             {
             {
-                var adornerLayer = _focusAdorner.Parent as Panel;
+                var adornerLayer = (IPanel)_focusAdorner.Parent;
                 adornerLayer.Children.Remove(_focusAdorner);
                 adornerLayer.Children.Remove(_focusAdorner);
                 _focusAdorner = null;
                 _focusAdorner = null;
             }
             }

+ 6 - 6
src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs

@@ -4,6 +4,7 @@ using Avalonia.Input;
 using Avalonia.Layout;
 using Avalonia.Layout;
 using Avalonia.Platform;
 using Avalonia.Platform;
 using Avalonia.Styling;
 using Avalonia.Styling;
+using JetBrains.Annotations;
 
 
 namespace Avalonia.Controls.Embedding
 namespace Avalonia.Controls.Embedding
 {
 {
@@ -18,6 +19,7 @@ namespace Avalonia.Controls.Embedding
         {
         {
         }
         }
 
 
+        [CanBeNull]
         public new IEmbeddableWindowImpl PlatformImpl => (IEmbeddableWindowImpl) base.PlatformImpl;
         public new IEmbeddableWindowImpl PlatformImpl => (IEmbeddableWindowImpl) base.PlatformImpl;
 
 
         public void Prepare()
         public void Prepare()
@@ -39,8 +41,9 @@ namespace Avalonia.Controls.Embedding
 
 
         protected override Size MeasureOverride(Size availableSize)
         protected override Size MeasureOverride(Size availableSize)
         {
         {
-            base.MeasureOverride(PlatformImpl.ClientSize);
-            return PlatformImpl.ClientSize;
+            var cs = PlatformImpl?.ClientSize ?? default(Size);
+            base.MeasureOverride(cs);
+            return cs;
         }
         }
 
 
         private readonly NameScope _nameScope = new NameScope();
         private readonly NameScope _nameScope = new NameScope();
@@ -63,9 +66,6 @@ namespace Avalonia.Controls.Embedding
         public void Unregister(string name) => _nameScope.Unregister(name);
         public void Unregister(string name) => _nameScope.Unregister(name);
 
 
         Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
         Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
-        public void Dispose()
-        {
-            PlatformImpl.Dispose();
-        }
+        public void Dispose() => PlatformImpl?.Dispose();
     }
     }
 }
 }

+ 1 - 1
src/Avalonia.Controls/ItemsControl.cs

@@ -354,7 +354,7 @@ namespace Avalonia.Controls
             }
             }
 
 
             var collection = sender as ICollection;
             var collection = sender as ICollection;
-            PseudoClasses.Set(":empty", collection.Count == 0);
+            PseudoClasses.Set(":empty", collection == null || collection.Count == 0);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 2
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@@ -155,8 +155,7 @@ namespace Avalonia.Controls.Presenters
                     case NotifyCollectionChangedAction.Add:
                     case NotifyCollectionChangedAction.Add:
                         CreateAndRemoveContainers();
                         CreateAndRemoveContainers();
 
 
-                        if (e.NewStartingIndex >= FirstIndex &&
-                            e.NewStartingIndex < NextIndex)
+                        if (e.NewStartingIndex < NextIndex)
                         {
                         {
                             RecycleContainers();
                             RecycleContainers();
                         }
                         }

+ 3 - 4
src/Avalonia.Controls/Primitives/PopupRoot.cs

@@ -9,6 +9,7 @@ using Avalonia.Layout;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.Platform;
 using Avalonia.Platform;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
+using JetBrains.Annotations;
 
 
 namespace Avalonia.Controls.Primitives
 namespace Avalonia.Controls.Primitives
 {
 {
@@ -49,6 +50,7 @@ namespace Avalonia.Controls.Primitives
         /// <summary>
         /// <summary>
         /// Gets the platform-specific window implementation.
         /// Gets the platform-specific window implementation.
         /// </summary>
         /// </summary>
+        [CanBeNull]
         public new IPopupImpl PlatformImpl => (IPopupImpl)base.PlatformImpl;
         public new IPopupImpl PlatformImpl => (IPopupImpl)base.PlatformImpl;
 
 
         /// <summary>
         /// <summary>
@@ -65,10 +67,7 @@ namespace Avalonia.Controls.Primitives
         IVisual IHostedVisualTreeRoot.Host => Parent;
         IVisual IHostedVisualTreeRoot.Host => Parent;
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
-        public void Dispose()
-        {
-            this.PlatformImpl.Dispose();
-        }
+        public void Dispose() => PlatformImpl?.Dispose();
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
         protected override void OnTemplateApplied(TemplateAppliedEventArgs e)

+ 5 - 2
src/Avalonia.Controls/TextBox.cs

@@ -720,7 +720,7 @@ namespace Avalonia.Controls
                         if (pos < text.Length)
                         if (pos < text.Length)
                         {
                         {
                             --pos;
                             --pos;
-                            if (pos > 0 && Text[pos - 1] == '\r' && Text[pos] == '\n')
+                            if (pos > 0 && text[pos - 1] == '\r' && text[pos] == '\n')
                             {
                             {
                                 --pos;
                                 --pos;
                             }
                             }
@@ -771,6 +771,9 @@ namespace Avalonia.Controls
 
 
         private string GetSelection()
         private string GetSelection()
         {
         {
+            var text = Text;
+            if (string.IsNullOrEmpty(text))
+                return "";
             var selectionStart = SelectionStart;
             var selectionStart = SelectionStart;
             var selectionEnd = SelectionEnd;
             var selectionEnd = SelectionEnd;
             var start = Math.Min(selectionStart, selectionEnd);
             var start = Math.Min(selectionStart, selectionEnd);
@@ -779,7 +782,7 @@ namespace Avalonia.Controls
             {
             {
                 return "";
                 return "";
             }
             }
-            return Text.Substring(start, end - start);
+            return text.Substring(start, end - start);
         }
         }
 
 
         private int GetLine(int caretIndex, IList<FormattedTextLine> lines)
         private int GetLine(int caretIndex, IList<FormattedTextLine> lines)

+ 19 - 16
src/Avalonia.Controls/TopLevel.cs

@@ -14,6 +14,7 @@ using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.Rendering;
 using Avalonia.Styling;
 using Avalonia.Styling;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
+using JetBrains.Annotations;
 
 
 namespace Avalonia.Controls
 namespace Avalonia.Controls
 {
 {
@@ -92,25 +93,25 @@ namespace Avalonia.Controls
             var rendererFactory = TryGetService<IRendererFactory>(dependencyResolver);
             var rendererFactory = TryGetService<IRendererFactory>(dependencyResolver);
             Renderer = rendererFactory?.CreateRenderer(this, renderLoop);
             Renderer = rendererFactory?.CreateRenderer(this, renderLoop);
 
 
-            PlatformImpl.SetInputRoot(this);
+            impl.SetInputRoot(this);
 
 
-            PlatformImpl.Closed = HandleClosed;
-            PlatformImpl.Input = HandleInput;
-            PlatformImpl.Paint = HandlePaint;
-            PlatformImpl.Resized = HandleResized;
-            PlatformImpl.ScalingChanged = HandleScalingChanged;
+            impl.Closed = HandleClosed;
+            impl.Input = HandleInput;
+            impl.Paint = HandlePaint;
+            impl.Resized = HandleResized;
+            impl.ScalingChanged = HandleScalingChanged;
 
 
 
 
             _keyboardNavigationHandler?.SetOwner(this);
             _keyboardNavigationHandler?.SetOwner(this);
             _accessKeyHandler?.SetOwner(this);
             _accessKeyHandler?.SetOwner(this);
             styler?.ApplyStyles(this);
             styler?.ApplyStyles(this);
 
 
-            ClientSize = PlatformImpl.ClientSize;
+            ClientSize = impl.ClientSize;
             
             
             this.GetObservable(PointerOverElementProperty)
             this.GetObservable(PointerOverElementProperty)
                 .Select(
                 .Select(
                     x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
                     x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
-                .Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor));
+                .Switch().Subscribe(cursor => PlatformImpl?.SetCursor(cursor?.PlatformCursor));
 
 
             if (_applicationLifecycle != null)
             if (_applicationLifecycle != null)
             {
             {
@@ -135,10 +136,8 @@ namespace Avalonia.Controls
         /// <summary>
         /// <summary>
         /// Gets the platform-specific window implementation.
         /// Gets the platform-specific window implementation.
         /// </summary>
         /// </summary>
-        public ITopLevelImpl PlatformImpl
-        {
-            get;
-        }
+        [CanBeNull]
+        public ITopLevelImpl PlatformImpl { get; private set; }
         
         
         /// <summary>
         /// <summary>
         /// Gets the renderer for the window.
         /// Gets the renderer for the window.
@@ -177,7 +176,7 @@ namespace Avalonia.Controls
         Size ILayoutRoot.MaxClientSize => Size.Infinity;
         Size ILayoutRoot.MaxClientSize => Size.Infinity;
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
-        double ILayoutRoot.LayoutScaling => PlatformImpl.Scaling;
+        double ILayoutRoot.LayoutScaling => PlatformImpl?.Scaling ?? 1;
 
 
         IStyleHost IStyleHost.StylingParent
         IStyleHost IStyleHost.StylingParent
         {
         {
@@ -189,25 +188,27 @@ namespace Avalonia.Controls
         /// <inheritdoc/>
         /// <inheritdoc/>
         protected virtual IRenderTarget CreateRenderTarget()
         protected virtual IRenderTarget CreateRenderTarget()
         {
         {
+            if(PlatformImpl == null)
+                throw new InvalidOperationException("Cann't create render target, PlatformImpl is null (might be already disposed)");
             return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
             return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         void IRenderRoot.Invalidate(Rect rect)
         void IRenderRoot.Invalidate(Rect rect)
         {
         {
-            PlatformImpl.Invalidate(rect);
+            PlatformImpl?.Invalidate(rect);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         Point IRenderRoot.PointToClient(Point p)
         Point IRenderRoot.PointToClient(Point p)
         {
         {
-            return PlatformImpl.PointToClient(p);
+            return PlatformImpl?.PointToClient(p) ?? default(Point);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         Point IRenderRoot.PointToScreen(Point p)
         Point IRenderRoot.PointToScreen(Point p)
         {
         {
-            return PlatformImpl.PointToScreen(p);
+            return PlatformImpl?.PointToScreen(p) ?? default(Point);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -224,6 +225,8 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         protected virtual void HandleClosed()
         protected virtual void HandleClosed()
         {
         {
+            PlatformImpl = null;
+
             Closed?.Invoke(this, EventArgs.Empty);
             Closed?.Invoke(this, EventArgs.Empty);
             Renderer?.Dispose();
             Renderer?.Dispose();
             Renderer = null;
             Renderer = null;

+ 17 - 11
src/Avalonia.Controls/Window.cs

@@ -12,6 +12,7 @@ using Avalonia.Platform;
 using Avalonia.Styling;
 using Avalonia.Styling;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
+using JetBrains.Annotations;
 
 
 namespace Avalonia.Controls
 namespace Avalonia.Controls
 {
 {
@@ -87,11 +88,11 @@ namespace Avalonia.Controls
         static Window()
         static Window()
         {
         {
             BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
             BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
-            TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue));
+            TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue));
             HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
             HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
-                (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue));
+                (s, e) => s.PlatformImpl?.SetSystemDecorations((bool) e.NewValue));
 
 
-            IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
+            IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -109,7 +110,7 @@ namespace Avalonia.Controls
         public Window(IWindowImpl impl)
         public Window(IWindowImpl impl)
             : base(impl)
             : base(impl)
         {
         {
-            _maxPlatformClientSize = this.PlatformImpl.MaxClientSize;
+            _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -129,6 +130,7 @@ namespace Avalonia.Controls
         /// <summary>
         /// <summary>
         /// Gets the platform-specific window implementation.
         /// Gets the platform-specific window implementation.
         /// </summary>
         /// </summary>
+        [CanBeNull]
         public new IWindowImpl PlatformImpl => (IWindowImpl)base.PlatformImpl;
         public new IWindowImpl PlatformImpl => (IWindowImpl)base.PlatformImpl;
 
 
         /// <summary>
         /// <summary>
@@ -164,8 +166,12 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         public WindowState WindowState
         public WindowState WindowState
         {
         {
-            get { return this.PlatformImpl.WindowState; }
-            set { this.PlatformImpl.WindowState = value; }
+            get { return PlatformImpl?.WindowState ?? WindowState.Normal; }
+            set
+            {
+                if (PlatformImpl != null)
+                    PlatformImpl.WindowState = value;
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -189,7 +195,7 @@ namespace Avalonia.Controls
         public void Close()
         public void Close()
         {
         {
             s_windows.Remove(this);
             s_windows.Remove(this);
-            PlatformImpl.Dispose();
+            PlatformImpl?.Dispose();
             IsVisible = false;
             IsVisible = false;
         }
         }
 
 
@@ -221,7 +227,7 @@ namespace Avalonia.Controls
         {
         {
             using (BeginAutoSizing())
             using (BeginAutoSizing())
             {
             {
-                PlatformImpl.Hide();
+                PlatformImpl?.Hide();
             }
             }
 
 
             IsVisible = false;
             IsVisible = false;
@@ -240,7 +246,7 @@ namespace Avalonia.Controls
 
 
             using (BeginAutoSizing())
             using (BeginAutoSizing())
             {
             {
-                PlatformImpl.Show();
+                PlatformImpl?.Show();
             }
             }
         }
         }
 
 
@@ -278,7 +284,7 @@ namespace Avalonia.Controls
                 var activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault();
                 var activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault();
                 SetIsEnabled(affectedWindows, false);
                 SetIsEnabled(affectedWindows, false);
 
 
-                var modal = PlatformImpl.ShowDialog();
+                var modal = PlatformImpl?.ShowDialog();
                 var result = new TaskCompletionSource<TResult>();
                 var result = new TaskCompletionSource<TResult>();
 
 
                 Observable.FromEventPattern<EventHandler, EventArgs>(
                 Observable.FromEventPattern<EventHandler, EventArgs>(
@@ -287,7 +293,7 @@ namespace Avalonia.Controls
                     .Take(1)
                     .Take(1)
                     .Subscribe(_ =>
                     .Subscribe(_ =>
                     {
                     {
-                        modal.Dispose();
+                        modal?.Dispose();
                         SetIsEnabled(affectedWindows, true);
                         SetIsEnabled(affectedWindows, true);
                         activated?.Activate();
                         activated?.Activate();
                         result.SetResult((TResult)_dialogResult);
                         result.SetResult((TResult)_dialogResult);

+ 20 - 14
src/Avalonia.Controls/WindowBase.cs

@@ -9,6 +9,7 @@ using Avalonia.Controls.Primitives;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Layout;
 using Avalonia.Layout;
 using Avalonia.Platform;
 using Avalonia.Platform;
+using JetBrains.Annotations;
 
 
 namespace Avalonia.Controls
 namespace Avalonia.Controls
 {
 {
@@ -43,10 +44,10 @@ namespace Avalonia.Controls
 
 
         public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver)
         public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver)
         {
         {
-            PlatformImpl.Activated = HandleActivated;
-            PlatformImpl.Deactivated = HandleDeactivated;
-            PlatformImpl.PositionChanged = HandlePositionChanged;
-            this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl.Resize(x));
+            impl.Activated = HandleActivated;
+            impl.Deactivated = HandleDeactivated;
+            impl.PositionChanged = HandlePositionChanged;
+            this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x));
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -64,6 +65,7 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         public event EventHandler<PointEventArgs> PositionChanged;
         public event EventHandler<PointEventArgs> PositionChanged;
 
 
+        [CanBeNull]
         public new IWindowBaseImpl PlatformImpl => (IWindowBaseImpl) base.PlatformImpl;
         public new IWindowBaseImpl PlatformImpl => (IWindowBaseImpl) base.PlatformImpl;
 
 
         /// <summary>
         /// <summary>
@@ -80,8 +82,12 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         public Point Position
         public Point Position
         {
         {
-            get { return PlatformImpl.Position; }
-            set { PlatformImpl.Position = value; }
+            get { return PlatformImpl?.Position ?? default(Point); }
+            set
+            {
+                if (PlatformImpl is IWindowBaseImpl impl)
+                    impl.Position = value;
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -98,7 +104,7 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         public void Activate()
         public void Activate()
         {
         {
-            PlatformImpl.Activate();
+            PlatformImpl?.Activate();
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -110,7 +116,7 @@ namespace Avalonia.Controls
 
 
             try
             try
             {
             {
-                PlatformImpl.Hide();
+                PlatformImpl?.Hide();
                 IsVisible = false;
                 IsVisible = false;
             }
             }
             finally
             finally
@@ -131,7 +137,7 @@ namespace Avalonia.Controls
                 EnsureInitialized();
                 EnsureInitialized();
                 IsVisible = true;
                 IsVisible = true;
                 LayoutManager.Instance.ExecuteInitialLayoutPass(this);
                 LayoutManager.Instance.ExecuteInitialLayoutPass(this);
-                PlatformImpl.Show();
+                PlatformImpl?.Show();
             }
             }
             finally
             finally
             {
             {
@@ -163,10 +169,10 @@ namespace Avalonia.Controls
         {
         {
             using (BeginAutoSizing())
             using (BeginAutoSizing())
             {
             {
-                PlatformImpl.Resize(finalSize);
+                PlatformImpl?.Resize(finalSize);
             }
             }
 
 
-            return base.ArrangeOverride(PlatformImpl.ClientSize);
+            return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size));
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -174,7 +180,7 @@ namespace Avalonia.Controls
         /// </summary>
         /// </summary>
         protected void EnsureInitialized()
         protected void EnsureInitialized()
         {
         {
-            if (!this.IsInitialized)
+            if (!IsInitialized)
             {
             {
                 var init = (ISupportInitialize)this;
                 var init = (ISupportInitialize)this;
                 init.BeginInit();
                 init.BeginInit();
@@ -268,12 +274,12 @@ namespace Avalonia.Controls
         /// <summary>
         /// <summary>
         /// Starts moving a window with left button being held. Should be called from left mouse button press event handler
         /// Starts moving a window with left button being held. Should be called from left mouse button press event handler
         /// </summary>
         /// </summary>
-        public void BeginMoveDrag() => PlatformImpl.BeginMoveDrag();
+        public void BeginMoveDrag() => PlatformImpl?.BeginMoveDrag();
 
 
         /// <summary>
         /// <summary>
         /// Starts resizing a window. This function is used if an application has window resizing controls. 
         /// Starts resizing a window. This function is used if an application has window resizing controls. 
         /// Should be called from left mouse button press event handler
         /// Should be called from left mouse button press event handler
         /// </summary>
         /// </summary>
-        public void BeginResizeDrag(WindowEdge edge) => PlatformImpl.BeginResizeDrag(edge);
+        public void BeginResizeDrag(WindowEdge edge) => PlatformImpl?.BeginResizeDrag(edge);
     }
     }
 }
 }

+ 3 - 1
src/Avalonia.DesignerSupport/DesignerAssist.cs

@@ -75,7 +75,7 @@ namespace Avalonia.DesignerSupport
         private static void SetScalingFactor(double factor)
         private static void SetScalingFactor(double factor)
         {
         {
             PlatformManager.SetDesignerScalingFactor(factor);
             PlatformManager.SetDesignerScalingFactor(factor);
-            s_currentWindow?.PlatformImpl.Resize(s_currentWindow.ClientSize);
+            s_currentWindow?.PlatformImpl?.Resize(s_currentWindow.ClientSize);
         }
         }
 
 
         static Window s_currentWindow;
         static Window s_currentWindow;
@@ -149,6 +149,8 @@ namespace Avalonia.DesignerSupport
             s_currentWindow = window;
             s_currentWindow = window;
             window.Show();
             window.Show();
             Design.ApplyDesignerProperties(window, control);
             Design.ApplyDesignerProperties(window, control);
+            // ReSharper disable once PossibleNullReferenceException
+            // Always not null at this point
             Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle);
             Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle);
             Api.OnResize?.Invoke();
             Api.OnResize?.Invoke();
         }
         }

+ 7 - 1
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@@ -82,7 +82,13 @@ namespace Avalonia
 
 
         private void LoadAssembliesInDirectory()
         private void LoadAssembliesInDirectory()
         {
         {
-            foreach (var file in new FileInfo(Assembly.GetEntryAssembly().Location).Directory.EnumerateFiles("*.dll"))
+            var location = Assembly.GetEntryAssembly().Location;
+            if (string.IsNullOrWhiteSpace(location))
+                return;
+            var dir = new FileInfo(location).Directory;
+            if (dir == null)
+                return;
+            foreach (var file in dir.EnumerateFiles("*.dll"))
             {
             {
                 try
                 try
                 {
                 {

+ 3 - 4
src/Avalonia.Layout/Layoutable.cs

@@ -456,10 +456,9 @@ namespace Avalonia.Layout
 
 
                 ApplyTemplate();
                 ApplyTemplate();
 
 
-                var constrained = LayoutHelper
-                    .ApplyLayoutConstraints(this, availableSize)
-                    .Deflate(margin);
-
+                var constrained = LayoutHelper.ApplyLayoutConstraints(
+                    this,
+                    availableSize.Deflate(margin));
                 var measured = MeasureOverride(constrained);
                 var measured = MeasureOverride(constrained);
 
 
                 var width = measured.Width;
                 var width = measured.Width;

+ 1 - 1
src/Avalonia.Styling/Controls/NameScope.cs

@@ -50,7 +50,7 @@ namespace Avalonia.Controls
                     return result;
                     return result;
                 }
                 }
 
 
-                visual = (visual as ILogical).LogicalParent as Visual;
+                visual = (visual as ILogical)?.LogicalParent as Visual;
             }
             }
 
 
             return null;
             return null;

+ 7 - 0
src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs

@@ -20,6 +20,11 @@ namespace Avalonia.Rendering
     /// </remarks>
     /// </remarks>
     public class ImmediateRenderer : RendererBase, IRenderer, IVisualBrushRenderer
     public class ImmediateRenderer : RendererBase, IRenderer, IVisualBrushRenderer
     {
     {
+        class ImmediateRendererFactory : IRendererFactory
+        {
+            public IRenderer CreateRenderer(IRenderRoot root, IRenderLoop renderLoop) => new ImmediateRenderer(root);
+        }
+
         private readonly IVisual _root;
         private readonly IVisual _root;
         private readonly IRenderRoot _renderRoot;
         private readonly IRenderRoot _renderRoot;
         private IRenderTarget _renderTarget;
         private IRenderTarget _renderTarget;
@@ -36,6 +41,8 @@ namespace Avalonia.Rendering
             _renderRoot = root as IRenderRoot;
             _renderRoot = root as IRenderRoot;
         }
         }
 
 
+        public static IRendererFactory Factory { get; } = new ImmediateRendererFactory();
+
         /// <inheritdoc/>
         /// <inheritdoc/>
         public bool DrawFps { get; set; }
         public bool DrawFps { get; set; }
 
 

+ 1 - 1
src/Avalonia.Visuals/Rendering/ZIndexComparer.cs

@@ -8,6 +8,6 @@ namespace Avalonia.Rendering
     {
     {
         public static readonly ZIndexComparer Instance = new ZIndexComparer();
         public static readonly ZIndexComparer Instance = new ZIndexComparer();
 
 
-        public int Compare(IVisual x, IVisual y) => x.ZIndex.CompareTo(y.ZIndex);
+        public int Compare(IVisual x, IVisual y) => (x?.ZIndex ?? 0).CompareTo(y?.ZIndex ?? 0);
     }
     }
 }
 }

+ 1 - 1
src/Avalonia.Visuals/VisualTree/VisualExtensions.cs

@@ -189,7 +189,7 @@ namespace Avalonia.VisualTree
         {
         {
             Contract.Requires<ArgumentNullException>(visual != null);
             Contract.Requires<ArgumentNullException>(visual != null);
 
 
-            return visual.VisualRoot as IRenderRoot ?? visual.VisualRoot;
+            return visual as IRenderRoot ?? visual.VisualRoot;
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 0
src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs

@@ -9,6 +9,7 @@ using Avalonia.Cairo.Media.Imaging;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.Platform;
 using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.Rendering;
+// ReSharper disable PossibleNullReferenceException
 
 
 namespace Avalonia.Cairo.Media
 namespace Avalonia.Cairo.Media
 {
 {

+ 3 - 3
src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs

@@ -40,6 +40,6 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
 
 
-[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 2, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
-[assembly: ExportRenderingSubsystem(OperatingSystemType.Linux, 1, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
-[assembly: ExportRenderingSubsystem(OperatingSystemType.OSX, 2, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 3, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.Linux, 2, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.OSX, 3, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]

+ 3 - 3
src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs

@@ -22,7 +22,7 @@ using System.Runtime.CompilerServices;
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
 [assembly: AssemblyVersion("1.0.*")]
 [assembly: AssemblyVersion("1.0.*")]
 
 
-[assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 2, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
-[assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 1, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
-[assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 2, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
+[assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 3, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
+[assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 2, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
+[assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 3, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
 
 

+ 1 - 0
src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs

@@ -39,6 +39,7 @@ namespace Avalonia.Gtk3
                 .Bind<IPlatformThreadingInterface>().ToConstant(Instance)
                 .Bind<IPlatformThreadingInterface>().ToConstant(Instance)
                 .Bind<ISystemDialogImpl>().ToSingleton<SystemDialog>()
                 .Bind<ISystemDialogImpl>().ToSingleton<SystemDialog>()
                 .Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
                 .Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
+                .Bind<IRendererFactory>().ToConstant(ImmediateRenderer.Factory)
                 .Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoader());
                 .Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoader());
 
 
         }
         }

+ 5 - 0
src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs

@@ -2,6 +2,8 @@
 using System.Reflection;
 using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
+using Avalonia.Gtk3;
+using Avalonia.Platform;
 
 
 // General Information about an assembly is controlled through the following 
 // General Information about an assembly is controlled through the following 
 // set of attributes. Change these attribute values to modify the information
 // set of attributes. Change these attribute values to modify the information
@@ -28,3 +30,6 @@ using System.Runtime.InteropServices;
 // [assembly: AssemblyVersion("1.0.*")]
 // [assembly: AssemblyVersion("1.0.*")]
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
+[assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 1, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
+[assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]

+ 1 - 0
src/Gtk/Avalonia.Gtk3/SystemDialogs.cs

@@ -28,6 +28,7 @@ namespace Avalonia.Gtk3
             List<IDisposable> disposables = null;
             List<IDisposable> disposables = null;
             Action dispose = () =>
             Action dispose = () =>
             {
             {
+                // ReSharper disable once PossibleNullReferenceException
                 foreach (var d in disposables)
                 foreach (var d in disposables)
                     d.Dispose();
                     d.Dispose();
                 disposables.Clear();
                 disposables.Clear();

+ 1 - 0
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@@ -35,6 +35,7 @@ namespace Avalonia.LinuxFramebuffer
                 .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
                 .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
                 .Bind<IMouseDevice>().ToConstant(MouseDevice)
                 .Bind<IMouseDevice>().ToConstant(MouseDevice)
                 .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
                 .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
+                .Bind<IRendererFactory>().ToConstant(ImmediateRenderer.Factory)
                 .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
                 .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
                 .Bind<IRenderLoop>().ToConstant(PlatformThreadingInterface.Instance);
                 .Bind<IRenderLoop>().ToConstant(PlatformThreadingInterface.Instance);
         }
         }

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs

@@ -68,7 +68,7 @@ namespace Avalonia.Markup.Xaml.Parsers
                 }
                 }
                 else if (property != null)
                 else if (property != null)
                 {
                 {
-                    var type = result.TargetType;
+                    var type = result?.TargetType;
 
 
                     if (type == null)
                     if (type == null)
                     {
                     {

+ 2 - 2
src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs

@@ -36,7 +36,7 @@ namespace Avalonia.Markup.Data.Plugins
 
 
             if (task != null)
             if (task != null)
             {
             {
-                var resultProperty = task.GetType().GetTypeInfo().GetDeclaredProperty("Result");
+                var resultProperty = task.GetType().GetRuntimeProperty("Result");
 
 
                 if (resultProperty != null)
                 if (resultProperty != null)
                 {
                 {
@@ -61,7 +61,7 @@ namespace Avalonia.Markup.Data.Plugins
 
 
         protected IObservable<object> HandleCompleted(Task task)
         protected IObservable<object> HandleCompleted(Task task)
         {
         {
-            var resultProperty = task.GetType().GetTypeInfo().GetDeclaredProperty("Result");
+            var resultProperty = task.GetType().GetRuntimeProperty("Result");
             
             
             if (resultProperty != null)
             if (resultProperty != null)
             {
             {

+ 14 - 50
src/Markup/Avalonia.Markup/DefaultValueConverter.cs

@@ -3,10 +3,7 @@
 
 
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
-using System.Linq;
-using System.Reflection;
 using Avalonia.Data;
 using Avalonia.Data;
-using Avalonia.Logging;
 using Avalonia.Utilities;
 using Avalonia.Utilities;
 
 
 namespace Avalonia.Markup
 namespace Avalonia.Markup
@@ -32,32 +29,28 @@ namespace Avalonia.Markup
         /// <returns>The converted value.</returns>
         /// <returns>The converted value.</returns>
         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
         {
-            object result;
-
-            if (value != null && 
-                (TypeUtilities.TryConvert(targetType, value, culture, out result) ||
-                 TryConvertEnum(value, targetType, culture, out result)))
+            if (value == null)
             {
             {
-                return result;
+                return AvaloniaProperty.UnsetValue;
             }
             }
 
 
-            if (value != null)
+            if (TypeUtilities.TryConvert(targetType, value, culture, out object result))
             {
             {
-                string message;
+                return result;
+            }
 
 
-                if (TypeUtilities.IsNumeric(targetType))
-                {
-                    message = $"'{value}' is not a valid number.";
-                }
-                else
-                {
-                    message = $"Could not convert '{value}' to '{targetType.Name}'.";
-                }
+            string message;
 
 
-                return new BindingNotification(new InvalidCastException(message), BindingErrorType.Error);
+            if (TypeUtilities.IsNumeric(targetType))
+            {
+                message = $"'{value}' is not a valid number.";
+            }
+            else
+            {
+                message = $"Could not convert '{value}' to '{targetType.Name}'.";
             }
             }
 
 
-            return AvaloniaProperty.UnsetValue;
+            return new BindingNotification(new InvalidCastException(message), BindingErrorType.Error);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -72,34 +65,5 @@ namespace Avalonia.Markup
         {
         {
             return Convert(value, targetType, parameter, culture);
             return Convert(value, targetType, parameter, culture);
         }
         }
-
-        private bool TryConvertEnum(object value, Type targetType, CultureInfo cultur, out object result)
-        {
-            var valueTypeInfo = value.GetType().GetTypeInfo();
-            var targetTypeInfo = targetType.GetTypeInfo();
-
-            if (valueTypeInfo.IsEnum && !targetTypeInfo.IsEnum)
-            {
-                var enumValue = (int)value;
-
-                if (TypeUtilities.TryCast(targetType, enumValue, out result))
-                {
-                    return true;
-                }
-            }
-            else if (!valueTypeInfo.IsEnum && targetTypeInfo.IsEnum)
-            {
-                object intValue;
-
-                if (TypeUtilities.TryCast(typeof(int), value, out intValue))
-                {
-                    result = Enum.ToObject(targetType, intValue);
-                    return true;
-                }
-            }
-
-            result = null;
-            return false;
-        }
     }
     }
 }
 }

+ 3 - 3
src/Shared/SharedAssemblyInfo.cs

@@ -13,6 +13,6 @@ using System.Resources;
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyTrademark("")]
 [assembly: NeutralResourcesLanguage("en")]
 [assembly: NeutralResourcesLanguage("en")]
 
 
-[assembly: AssemblyVersion("0.4.1")]
-[assembly: AssemblyFileVersion("0.4.1")]
-[assembly: AssemblyInformationalVersion("0.4.1")]
+[assembly: AssemblyVersion("0.5.1")]
+[assembly: AssemblyFileVersion("0.5.1")]
+[assembly: AssemblyInformationalVersion("0.5.1")]

+ 0 - 1
src/Skia/Avalonia.Skia.Desktop.NetStandard/Avalonia.Skia.Desktop.NetStandard.csproj

@@ -40,7 +40,6 @@
     <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
     <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
   </ItemGroup>
   </ItemGroup>
   <Import Project="..\..\..\build\SkiaSharp.props" />
   <Import Project="..\..\..\build\SkiaSharp.props" />
-  <Import Project="..\..\..\build\SkiaSharp.Desktop.props" />
   <Import Project="..\Avalonia.Skia\Avalonia.Skia.projitems" Label="Shared" />
   <Import Project="..\Avalonia.Skia\Avalonia.Skia.projitems" Label="Shared" />
   <Import Project="..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
   <Import Project="..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
 </Project>
 </Project>

+ 1 - 1
src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj

@@ -50,7 +50,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <Optimize>true</Optimize>
     <Optimize>true</Optimize>
     <DebugType>pdbonly</DebugType>
     <DebugType>pdbonly</DebugType>
-    <PlatformTarget>x86</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
     <ErrorReport>prompt</ErrorReport>
     <ErrorReport>prompt</ErrorReport>
     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
   </PropertyGroup>
   </PropertyGroup>

+ 3 - 1
src/Skia/Avalonia.Skia.Desktop/Properties/AssemblyInfo.cs

@@ -37,4 +37,6 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
 
 
-[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 3, "Skia", typeof(SkiaPlatform), nameof(SkiaPlatform.Initialize))]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 2, "Skia", typeof(SkiaPlatform), nameof(SkiaPlatform.Initialize))]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.OSX, 1, "Skia", typeof(SkiaPlatform), nameof(SkiaPlatform.Initialize))]
+[assembly: ExportRenderingSubsystem(OperatingSystemType.Linux, 1, "Skia", typeof(SkiaPlatform), nameof(SkiaPlatform.Initialize))]

+ 2 - 2
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@@ -285,7 +285,7 @@ namespace Avalonia.Skia
                 paint.StrokeCap = SKStrokeCap.Butt;
                 paint.StrokeCap = SKStrokeCap.Butt;
 
 
             if (pen.LineJoin == PenLineJoin.Miter)
             if (pen.LineJoin == PenLineJoin.Miter)
-                paint.StrokeJoin = SKStrokeJoin.Mitter;
+                paint.StrokeJoin = SKStrokeJoin.Miter;
             else if (pen.LineJoin == PenLineJoin.Round)
             else if (pen.LineJoin == PenLineJoin.Round)
                 paint.StrokeJoin = SKStrokeJoin.Round;
                 paint.StrokeJoin = SKStrokeJoin.Round;
             else
             else
@@ -397,7 +397,7 @@ namespace Avalonia.Skia
 
 
         public void PopOpacityMask()
         public void PopOpacityMask()
         {
         {
-            Canvas.SaveLayer(new SKPaint { XferMode = SKXferMode.DstIn });
+            Canvas.SaveLayer(new SKPaint { BlendMode = SKBlendMode.DstIn });
             using (var paintWrapper = maskStack.Pop())
             using (var paintWrapper = maskStack.Pop())
             {
             {
                 Canvas.DrawPaint(paintWrapper.Paint);
                 Canvas.DrawPaint(paintWrapper.Paint);

+ 1 - 1
src/Skia/Avalonia.Skia/FormattedTextImpl.cs

@@ -42,7 +42,7 @@ namespace Avalonia.Skia
             _paint.Typeface = skiaTypeface;
             _paint.Typeface = skiaTypeface;
             _paint.TextSize = (float)(typeface?.FontSize ?? 12);
             _paint.TextSize = (float)(typeface?.FontSize ?? 12);
             _paint.TextAlign = textAlignment.ToSKTextAlign();
             _paint.TextAlign = textAlignment.ToSKTextAlign();
-            _paint.XferMode = SKXferMode.Src;
+            _paint.BlendMode = SKBlendMode.Src;
 
 
             _wrapping = wrapping;
             _wrapping = wrapping;
             _constraint = constraint;
             _constraint = constraint;

+ 3 - 1
src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs

@@ -15,7 +15,7 @@ namespace Avalonia.Win32.Embedding
     {
     {
         private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot();
         private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot();
 
 
-        private IntPtr WindowHandle => ((WindowImpl) _root.PlatformImpl).Handle.Handle;
+        private IntPtr WindowHandle => ((WindowImpl) _root?.PlatformImpl)?.Handle?.Handle ?? IntPtr.Zero;
 
 
         public WinFormsAvaloniaControlHost()
         public WinFormsAvaloniaControlHost()
         {
         {
@@ -25,6 +25,8 @@ namespace Avalonia.Win32.Embedding
             if (_root.IsFocused)
             if (_root.IsFocused)
                 FocusManager.Instance.Focus(null);
                 FocusManager.Instance.Focus(null);
             _root.GotFocus += RootGotFocus;
             _root.GotFocus += RootGotFocus;
+            // ReSharper disable once PossibleNullReferenceException
+            // Always non-null at this point
             _root.PlatformImpl.LostFocus += PlatformImpl_LostFocus;
             _root.PlatformImpl.LostFocus += PlatformImpl_LostFocus;
             FixPosition();
             FixPosition();
         }
         }

+ 1 - 0
src/iOS/Avalonia.iOS/iOSPlatform.cs

@@ -58,6 +58,7 @@ namespace Avalonia.iOS
                 .Bind<IStandardCursorFactory>().ToTransient<CursorFactory>()
                 .Bind<IStandardCursorFactory>().ToTransient<CursorFactory>()
                 .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
                 .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
                 .Bind<IMouseDevice>().ToConstant(MouseDevice)
                 .Bind<IMouseDevice>().ToConstant(MouseDevice)
+                .Bind<IRendererFactory>().ToConstant(ImmediateRenderer.Factory)
                 .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
                 .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
                 .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
                 .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
                 .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
                 .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()

+ 24 - 1
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs

@@ -206,6 +206,30 @@ namespace Avalonia.Controls.UnitTests.Presenters
             Assert.Equal(expected, actual);
             Assert.Equal(expected, actual);
         }
         }
 
 
+        [Fact]
+        public void Inserting_Items_Before_Visibile_Containers_Should_Update_Containers()
+        {
+            var target = CreateTarget();
+
+            target.ApplyTemplate();
+            target.Measure(new Size(100, 100));
+            target.Arrange(new Rect(0, 0, 100, 100));
+
+            ((ILogicalScrollable)target).Offset = new Vector(0, 5);
+
+            var expected = Enumerable.Range(5, 10).Select(x => $"Item {x}").ToList();
+            var items = (ObservableCollection<string>)target.Items;
+            var actual = target.Panel.Children.Select(x => x.DataContext).ToList();
+
+            Assert.Equal(expected, actual);
+
+            items.Insert(0, "Inserted");
+
+            expected = Enumerable.Range(4, 10).Select(x => $"Item {x}").ToList();
+            actual = target.Panel.Children.Select(x => x.DataContext).ToList();
+            Assert.Equal(expected, actual);
+        }
+
         [Fact]
         [Fact]
         public void Removing_First_Materialized_Item_Should_Update_Containers()
         public void Removing_First_Materialized_Item_Should_Update_Containers()
         {
         {
@@ -477,7 +501,6 @@ namespace Avalonia.Controls.UnitTests.Presenters
             target.Arrange(new Rect(0, 0, 100, 100));
             target.Arrange(new Rect(0, 0, 100, 100));
 
 
             var expected = Enumerable.Range(0, 6).Select(x => $"Item {x}").ToList();
             var expected = Enumerable.Range(0, 6).Select(x => $"Item {x}").ToList();
-            var items = (ObservableCollection<string>)target.Items;
             var actual = target.Panel.Children.Select(x => x.DataContext).ToList();
             var actual = target.Panel.Children.Select(x => x.DataContext).ToList();
 
 
             Assert.Equal(expected, actual);
             Assert.Equal(expected, actual);

+ 53 - 0
tests/Avalonia.Layout.UnitTests/MeasureTests.cs

@@ -100,5 +100,58 @@ namespace Avalonia.Layout.UnitTests
 
 
             Assert.Equal(0, target.DesiredSize.Height);
             Assert.Equal(0, target.DesiredSize.Height);
         }
         }
+
+        [Fact]
+        public void Margin_Should_Affect_AvailableSize()
+        {
+            MeasureTest target;
+
+            var outer = new Decorator
+            {
+                Width = 100,
+                Height = 100,
+                Child = target = new MeasureTest
+                {
+                    Margin = new Thickness(10),
+                }
+            };
+
+            outer.Measure(Size.Infinity);
+
+            Assert.Equal(new Size(80, 80), target.AvailableSize);
+        }
+
+        [Fact]
+        public void Margin_Should_Be_Applied_Before_Width_Height()
+        {
+            MeasureTest target;
+
+            var outer = new Decorator
+            {
+                Width = 100,
+                Height = 100,
+                Child = target = new MeasureTest
+                {
+                    Width = 80,
+                    Height = 80,
+                    Margin = new Thickness(10),
+                }
+            };
+
+            outer.Measure(Size.Infinity);
+
+            Assert.Equal(new Size(80, 80), target.AvailableSize);
+        }
+
+        class MeasureTest : Control
+        {
+            public Size? AvailableSize { get; private set; }
+
+            protected override Size MeasureOverride(Size availableSize)
+            {
+                AvailableSize = availableSize;
+                return availableSize;
+            }
+        }
     }
     }
 }
 }

+ 17 - 0
tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs

@@ -0,0 +1,17 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.Parsers;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Parsers
+{
+    public class SelectorParserTests
+    {
+        [Fact]
+        public void Parses_Boolean_Property_Selector()
+        {
+            var target = new SelectorParser((type, ns) => typeof(TextBlock));
+            var result = target.Parse("TextBlock[IsPointerOver=True]");
+        }
+    }
+}