Browse Source

Merge branch 'master' into render-loop

 Conflicts:
	src/Android/Avalonia.Android/AndroidPlatform.cs
	src/Avalonia.Controls/TopLevel.cs
Steven Kirk 9 years ago
parent
commit
b602e8caba
100 changed files with 1507 additions and 470 deletions
  1. 68 11
      Avalonia.sln
  2. 10 15
      build.cake
  3. 156 0
      docs/spec/binding-from-code.md
  4. 99 0
      docs/spec/binding-from-xaml.md
  5. 4 0
      docs/spec/toc.yml
  6. 2 0
      docs/spec/working-with-properties.md
  7. 2 18
      docs/tutorial/from-wpf.md
  8. 19 0
      samples/ControlCatalog.Android/Assets/AboutAssets.txt
  9. 169 0
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  10. 26 0
      samples/ControlCatalog.Android/ControlCatalog.Android.v2.ncrunchproject
  11. 4 0
      samples/ControlCatalog.Android/GettingStarted.Xamarin
  12. 46 0
      samples/ControlCatalog.Android/MainActivity.cs
  13. 5 0
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  14. 30 0
      samples/ControlCatalog.Android/Properties/AssemblyInfo.cs
  15. 44 0
      samples/ControlCatalog.Android/Resources/AboutResources.txt
  16. 114 0
      samples/ControlCatalog.Android/Resources/Resource.Designer.cs
  17. BIN
      samples/ControlCatalog.Android/Resources/drawable/Icon.png
  18. 13 0
      samples/ControlCatalog.Android/Resources/layout/Main.axml
  19. 5 0
      samples/ControlCatalog.Android/Resources/values/Strings.xml
  20. 21 8
      src/Android/Avalonia.Android/AndroidPlatform.cs
  21. 1 1
      src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs
  22. 5 8
      src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
  23. 70 12
      src/Android/Avalonia.AndroidTestApplication/MainActivity.cs
  24. 2 0
      src/Avalonia.Animation/Avalonia.Animation.csproj
  25. 2 1
      src/Avalonia.Base/Avalonia.Base.csproj
  26. 0 2
      src/Avalonia.Base/AvaloniaObject.cs
  27. 7 1
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  28. 2 3
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  29. 0 1
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  30. 0 2
      src/Avalonia.Base/Collections/AvaloniaList.cs
  31. 25 32
      src/Avalonia.Base/Data/BindingChainException.cs
  32. 1 1
      src/Avalonia.Base/Data/InstancedBinding.cs
  33. 0 3
      src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
  34. 0 1
      src/Avalonia.Base/PriorityBindingEntry.cs
  35. 4 2
      src/Avalonia.Controls/AppBuilderBase.cs
  36. 1 0
      src/Avalonia.Controls/Avalonia.Controls.csproj
  37. 4 4
      src/Avalonia.Controls/Canvas.cs
  38. 0 1
      src/Avalonia.Controls/Classes.cs
  39. 0 5
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  40. 2 1
      src/Avalonia.Controls/HotkeyManager.cs
  41. 0 2
      src/Avalonia.Controls/Platform/PlatformManager.cs
  42. 3 2
      src/Avalonia.Controls/Presenters/CarouselPresenter.cs
  43. 61 6
      src/Avalonia.Controls/Presenters/ItemVirtualizer.cs
  44. 50 3
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  45. 6 15
      src/Avalonia.Controls/Presenters/ItemsPresenter.cs
  46. 1 1
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  47. 1 1
      src/Avalonia.Controls/ScrollViewer.cs
  48. 60 19
      src/Avalonia.Controls/TextBox.cs
  49. 0 1
      src/Avalonia.Controls/TopLevel.cs
  50. 24 94
      src/Avalonia.Controls/Utils/StringUtils.cs
  51. 31 28
      src/Avalonia.Controls/Utils/UndoRedoHelper.cs
  52. 1 0
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  53. 0 3
      src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
  54. 4 4
      src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
  55. 17 5
      src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
  56. 1 0
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  57. 25 0
      src/Avalonia.Input/AccessKeyHandler.cs
  58. 1 0
      src/Avalonia.Input/Avalonia.Input.csproj
  59. 0 1
      src/Avalonia.Input/Navigation/DirectionalNavigation.cs
  60. 1 0
      src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
  61. 1 0
      src/Avalonia.Layout/Avalonia.Layout.csproj
  62. 1 1
      src/Avalonia.Layout/LayoutManager.cs
  63. 2 1
      src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
  64. 12 0
      src/Avalonia.Logging.Serilog/SerilogLogger.cs
  65. 1 0
      src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj
  66. 21 3
      src/Avalonia.SceneGraph/Media/DrawingContext.cs
  67. 10 1
      src/Avalonia.SceneGraph/Media/FormattedText.cs
  68. 1 0
      src/Avalonia.SceneGraph/Media/Imaging/RenderTargetBitmap.cs
  69. 1 0
      src/Avalonia.SceneGraph/Media/MatrixTransform.cs
  70. 2 6
      src/Avalonia.SceneGraph/Media/PathMarkupParser.cs
  71. 1 0
      src/Avalonia.SceneGraph/Media/RotateTransform.cs
  72. 1 0
      src/Avalonia.SceneGraph/Media/ScaleTransform.cs
  73. 1 1
      src/Avalonia.SceneGraph/Media/StreamGeometry.cs
  74. 1 0
      src/Avalonia.SceneGraph/Media/Transform.cs
  75. 1 0
      src/Avalonia.SceneGraph/Media/TranslateTransform.cs
  76. 1 0
      src/Avalonia.Styling/Avalonia.Styling.csproj
  77. 3 3
      src/Avalonia.Styling/Styling/SelectorMatch.cs
  78. 0 1
      src/Avalonia.Styling/Styling/Style.cs
  79. 1 0
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  80. 4 1
      src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs
  81. 2 0
      src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs
  82. 3 1
      src/Gtk/Avalonia.Gtk/WindowImplBase.cs
  83. 6 6
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  84. 1 1
      src/Markup/Avalonia.Markup.Xaml/OmniXAML
  85. 6 4
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  86. 14 43
      src/Markup/Avalonia.Markup/Data/ExpressionNode.cs
  87. 7 7
      src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs
  88. 42 0
      src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs
  89. 0 33
      src/Markup/Avalonia.Markup/Data/MarkupBindingChainNullException.cs
  90. 10 0
      src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs
  91. 2 2
      src/Markup/Avalonia.Markup/Data/Plugins/IStreamPlugin.cs
  92. 3 15
      src/Markup/Avalonia.Markup/Data/Plugins/ObservableStreamPlugin.cs
  93. 2 2
      src/Markup/Avalonia.Markup/Data/Plugins/TaskStreamPlugin.cs
  94. 31 0
      src/Markup/Avalonia.Markup/Data/StreamNode.cs
  95. 10 2
      src/Shared/PlatformSupport/AssetLoader.cs
  96. 7 0
      src/Skia/Avalonia.Skia.Android.TestApp/App.cs
  97. 24 8
      src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj
  98. 16 9
      src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs
  99. 2 0
      src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs
  100. 3 1
      src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj

+ 68 - 11
Avalonia.sln

@@ -172,6 +172,7 @@ EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DotNetFrameworkRuntime", "src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj", "{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\RenderTest\RenderTest.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Android", "samples\ControlCatalog.Android\ControlCatalog.Android.csproj", "{29132311-1848-4FD6-AE0C-4FF841151BD3}"
 EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
@@ -196,7 +197,6 @@ Global
 		samples\TestApplicationShared\TestApplicationShared.projitems*{e3a1060b-50d0-44e8-88b6-f44ef2e5bd72}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4
-		samples\TestApplicationShared\TestApplicationShared.projitems*{ff69b927-c545-49ae-8e16-3d14d621aa12}*SharedItemsImports = 4
 	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -2120,24 +2120,24 @@ Global
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|Mono.ActiveCfg = Debug|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|x86.ActiveCfg = Release|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|x86.Build.0 = Release|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.ActiveCfg = Debug|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.Build.0 = Debug|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.ActiveCfg = Debug|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.Build.0 = Debug|x86
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Mono.ActiveCfg = Debug|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.Build.0 = Debug|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.ActiveCfg = Debug|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.Build.0 = Debug|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.ActiveCfg = Release|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.Build.0 = Release|x86
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhone.ActiveCfg = Release|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhone.Build.0 = Release|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Mono.ActiveCfg = Release|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.ActiveCfg = Release|Any CPU
-		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.Build.0 = Release|Any CPU
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.ActiveCfg = Release|x86
+		{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.Build.0 = Release|x86
 		{52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -2404,6 +2404,62 @@ Global
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|Mono.Build.0 = Release|Any CPU
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|x86.ActiveCfg = Release|Any CPU
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|x86.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Mono.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|x86.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|x86.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Any CPU.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhone.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhone.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Mono.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Mono.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Mono.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|x86.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|x86.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|x86.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhone.Deploy.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|x86.Build.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|x86.Deploy.0 = Debug|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhone.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhone.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Mono.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.ActiveCfg = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.Build.0 = Release|Any CPU
+		{29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|x86.Deploy.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2460,5 +2516,6 @@ Global
 		{C7A69145-60B6-4882-97D6-A3921DD43978} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 		{BD7F352C-6DC1-4740-BAF2-2D34A038728C} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 		{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+		{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 	EndGlobalSection
 EndGlobal

+ 10 - 15
build.cake

@@ -635,21 +635,19 @@ Task("Run-Unit-Tests")
     .WithCriteria(() => !skipTests)
     .Does(() =>
 {
-    var pattern = "./tests/Avalonia.*.UnitTests/bin/" + dirSuffix + "/Avalonia.*.UnitTests.dll";
-
-    Func<IFileSystemInfo, bool> ExcludeWindowsTests = i => {
-        return !(i.Path.FullPath.IndexOf("Direct2D", StringComparison.OrdinalIgnoreCase) >= 0);
-    };
-
-    var unitTests = isRunningOnWindows ? GetFiles(pattern) : GetFiles(pattern, ExcludeWindowsTests);
+    var unitTests = GetDirectories("./tests/Avalonia.*.UnitTests")
+        .Select(dir => System.IO.Path.GetFileName(dir.FullPath))
+        .Where(name => isRunningOnWindows ? true : !(name.IndexOf("Direct2D", StringComparison.OrdinalIgnoreCase) >= 0))
+        .Select(name => MakeAbsolute(File("./tests/" + name + "/bin/" + dirSuffix + "/" + name + ".dll")))
+        .ToList();
 
     if (isRunningOnWindows)
     {
-        var windowsTests = GetFiles("./tests/Avalonia.DesignerSupport.Tests/bin/" + dirSuffix + "/*Tests.dll") + 
-                           GetFiles("./tests/Avalonia.LeakTests/bin/" + dirSuffix + "/*Tests.dll") + 
-                           GetFiles("./tests/Avalonia.RenderTests/bin/" + dirSuffix + "/*Tests.dll");
+        var windowsTests = GetFiles("./tests/Avalonia.DesignerSupport.Tests/bin/" + dirSuffix + "/*.Tests.dll") + 
+                           GetFiles("./tests/Avalonia.LeakTests/bin/" + dirSuffix + "/*.LeakTests.dll") + 
+                           GetFiles("./tests/Avalonia.RenderTests/bin/" + dirSuffix + "/*.RenderTests.dll");
 
-        unitTests += windowsTests;
+        unitTests.AddRange(windowsTests);
     }
 
     var toolPath = (isPlatformAnyCPU || isPlatformX86) ? 
@@ -662,10 +660,7 @@ Task("Run-Unit-Tests")
         Parallelism = ParallelismOption.None 
     };
 
-    if (isRunningOnWindows)
-    {
-        settings.NoAppDomain = false;
-    }
+    settings.NoAppDomain = !isRunningOnWindows;
 
     foreach (var file in unitTests)
     {

+ 156 - 0
docs/spec/binding-from-code.md

@@ -0,0 +1,156 @@
+# Binding from Code
+
+Avalonia binding from code works somewhat differently to WPF/UWP. At the low level, Avalonia's
+binding system is based on Reactive Extensions' `IObservable` which is then built upon by XAML
+bindings (which can also be instantiated in code).
+
+## Binding to an observable
+
+You can bind a property to an observable using the `AvaloniaObject.Bind` method:
+
+```csharp
+// We use an Rx Subject here so we can push new values using OnNext
+var source = new Subject<string>();
+var textBlock = new TextBlock();
+
+// Bind TextBlock.Text to source
+textBlock.Bind(TextBlock.TextProperty, source);
+
+// Set textBlock.Text to "hello"
+source.OnNext("hello");
+// Set textBlock.Text to "world!"
+source.OnNext("world!");
+```
+
+## Binding priorities
+
+You can also pass a priority to a binding. *Note: Priorities only apply to styled properties: they*
+*are ignored for direct properties.*
+
+The priority is passed using the `BindingPriority` enum, which looks like this:
+
+```csharp
+/// <summary>
+/// The priority of a binding.
+/// </summary>
+public enum BindingPriority
+{
+    /// <summary>
+    /// A value that comes from an animation.
+    /// </summary>
+    Animation = -1,
+
+    /// <summary>
+    /// A local value: this is the default.
+    /// </summary>
+    LocalValue = 0,
+
+    /// <summary>
+    /// A triggered style binding.
+    /// </summary>
+    /// <remarks>
+    /// A style trigger is a selector such as .class which overrides a
+    /// <see cref="TemplatedParent"/> binding. In this way, a basic control can have
+    /// for example a Background from the templated parent which changes when the
+    /// control has the :pointerover class.
+    /// </remarks>
+    StyleTrigger,
+
+    /// <summary>
+    /// A binding to a property on the templated parent.
+    /// </summary>
+    TemplatedParent,
+
+    /// <summary>
+    /// A style binding.
+    /// </summary>
+    Style,
+
+    /// <summary>
+    /// The binding is uninitialized.
+    /// </summary>
+    Unset = int.MaxValue,
+}
+```
+
+Bindings with a priority with a smaller number take precedence over bindings with a higher value
+priority, and bindings added more recently take precedence over other bindings with the same
+priority. Whenever the binding produces `AvaloniaProperty.UnsetValue` then the next binding in the
+priority order is selected.
+
+## Setting a binding in an object initializer
+
+It is often useful to set up bindings in object initializers. You can do this using the indexer:
+
+```csharp
+var source = new Subject<string>();
+var textBlock = new TextBlock
+{
+    Foreground = Brushes.Red,
+    MaxWidth = 200,
+    [!TextBlock.TextProperty] = source.ToBinding(),
+};
+```
+
+Using this method you can also easily bind a property on one control to a property on another:
+
+```csharp
+var textBlock1 = new TextBlock();
+var textBlock2 = new TextBlock
+{
+    Foreground = Brushes.Red,
+    MaxWidth = 200,
+    [!TextBlock.TextProperty] = textBlock1[!TextBlock.TextProperty],
+};
+```
+
+Of course the indexer can be used outside object initializers too:
+
+```csharp
+textBlock2[!TextBlock.TextProperty] = textBlock1[!TextBlock.TextProperty];
+```
+
+# Transforming binding values
+
+Because we're working with observables, we can easily transform the values we're binding!
+
+```csharp
+var source = new Subject<string>();
+var textBlock = new TextBlock
+{
+    Foreground = Brushes.Red,
+    MaxWidth = 200,
+    [!TextBlock.TextProperty] = source.Select(x => "Hello " + x).ToBinding(),
+};
+```
+
+# Using XAML bindings from code
+
+Sometimes when you want the additional features that XAML bindings provide, it's easier to use XAML bindings from code. For example, using only observables you could bind to a property on `DataContext` like this:
+
+```csharp
+var textBlock = new TextBlock();
+var viewModelProperty = textBlock.GetObservable(TextBlock.DataContext)
+    .OfType<MyViewModel>()
+    .Select(x => x?.Name);
+textBlock.Bind(TextBlock, viewModelProperty);
+```
+
+However, it might be preferable to use a XAML binding in this case:
+
+```csharp
+var textBlock = new TextBlock
+{
+    [!TextBlock.TextProperty] = new Binding("Name")
+};
+```
+
+By using XAML binding objects, you get access to binding to named controls and [all the other features that XAML bindings bring](binding-from.xaml.md):
+
+```csharp
+var textBlock = new TextBlock
+{
+    [!TextBlock.TextProperty] = new Binding("Text") { ElementName = "other" }
+};
+```
+

+ 99 - 0
docs/spec/binding-from-xaml.md

@@ -0,0 +1,99 @@
+# Binding from XAML
+
+Binding from XAML works on the whole the same as in other XAML frameworks: you use the `{Binding}`
+markup extension. Avalonia does have some extra syntacic niceties however. Here's an overview of
+what you can currently do in Avalonia:
+
+## Binding to a property on the DataContext
+
+By default a binding binds to a property on the `DataContext`, e.g.:
+
+```xml
+<!-- Binds to the tb.DataContext.Name property -->
+<TextBlock Name="tb" Text="{Binding Name}"/>
+<!-- Which is the same as ('Path' is optional) -->
+<TextBlock Name="tb" Text="{Binding Path=Name}"/>
+```
+
+An empty binding binds to DataContext itself
+
+```xml
+<!-- Binds to the tb.DataContext property -->
+<TextBlock Name="tb" Text="{Binding}"/>
+<!-- Which is the same as -->
+<TextBlock Name="tb" Text="{Binding .}"/>
+```
+
+This usage is identical to WPF/UWP etc.
+
+## Two way bindings and more
+
+You can also specify a binding `Mode`:
+
+```xml
+<!-- Bind two-way to the property (although this is actually the default binding mode for
+     TextBox.Text) so strictly speaking it's unnecessary here) -->
+<TextBox Name="tb" Text="{Binding Name, Mode=TwoWay}"/>
+```
+
+This usage is identical to WPF/UWP etc.
+
+## Binding to a property on the templated parent
+
+When you're creating a control template and you want to bind to the templated parent you can use:
+
+```xml
+<TextBlock Name="tb" Text="{TemplateBinding Caption}"/>
+<!-- Which is short for -->
+<TextBlock Name="tb" Text="{Binding Caption, RelativeSource={RelativeSource TemplatedParent}}"/>
+```
+
+This usage is identical to WPF/UWP etc.
+
+## Binding to a named control
+
+If you want to bind to a property on another (named) control, you can use `ElementName` as in
+WPF/UWP:
+
+```xml
+<!-- Binds to the Tag property of a control named "other" -->
+<TextBlock Text="{Binding Tag, ElementName=other}"/>
+```
+
+However Avalonia also introduces a shorthand syntax for this:
+
+```xml
+<TextBlock Text="{Binding #other.Tag}"/>
+```
+
+## Negating bindings
+
+You can also negate the value of a binding using the `!` operator:
+
+```xml
+<TextBox IsEnabled="{Binding !HasErrors}"/>
+```
+
+Here, the `TextBox` will only be enabled when the view model signals that it has no errors. Behind
+the scenes, Avalonia tries to convert the incoming value to a boolean, and if it can be converted
+it negates the value. If the incoming value cannot be converted to a boolean then no value will be
+pushed to the binding target.
+
+This syntax is specific to Avalonia.
+
+## Binding to tasks and observables
+
+You can subscribe to the result of a task or an observable by using the `^` stream binding operator.
+
+```xml
+<!-- If DataContext.Name is an IObservable<string> then this will bind to the length of each
+     string produced by the observable as each value is produced -->
+<TextBlock Text="{Binding Name^.Length}"/>
+```
+
+This syntax is specific to Avalonia.
+
+*Note: the stream operator is actually extensible, see
+[here](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Markup/Avalonia.Markup/Data/Plugins/IStreamPlugin.cs)
+for the interface to implement and [here](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs#L47)
+for the registration.*

+ 4 - 0
docs/spec/toc.yml

@@ -8,3 +8,7 @@
   href: working-with-properties.md
 - name: Logging
   href: logging.md
+- name: Binding from XAML
+  href: binding-from-xaml.md
+- name: Binding from Code
+  href: binding-from-code.md

+ 2 - 0
docs/spec/working-with-properties.md

@@ -71,6 +71,8 @@ property to the first:
   Console.WriteLine(textBlock2.Text);
 ```
 
+To read more about creating bindings from code, see [Binding from Code](binding-from-code.md).
+
 # Subscribing to a Property on Any Object
 
 The `GetObservable` method returns an observable that tracks changes to a

+ 2 - 18
docs/tutorial/from-wpf.md

@@ -40,17 +40,6 @@ placed in a `DataTemplates` collection on each control (and on `Application`):
         <ContentControl Content="{Binding Foo}"/>
     <UserControl>    
 
-`ItemsControl`s don't currently have an `ItemTemplate` property: instead just
-place the template for your items into the control's `DataTemplates`, e.g.
-
-    <ListBox Items="ItemsSource">
-        <ListBox.DataTemplates>
-            <DataTemplate>
-                <TextBlock Text="{Binding Caption}"/>
-            </DataTemplate>
-        </ListBox.DataTemplates>
-    </ListBox>
-
 Data templates in Avalonia can also target interfaces and derived classes (which
 cannot be done in WPF) and so the order of `DataTemplate`s can be important:
 `DataTemplate`s  within the same collection are evaluated in declaration order
@@ -92,13 +81,8 @@ referred to using the `{StyleResource}` markup extension both inside and outside
 styles.
 
 For non-style-related resources, we suggest defining them in code and referring
-to them in markup using the `{Static}` markup extension. There are [various
-reasons](http://www.codemag.com/article/1501091) for this, but briefly:
-
-- Resources have to be parsed
-- The tree has to be traversed to find them
-- XAML doesn't handle immutable objects
-- XAML syntax can be long-winded compared to C#
+to them in markup using the `{Static}` markup extension. To read more about the reasoning for this,
+see [this issue comment](https://github.com/AvaloniaUI/Avalonia/issues/462#issuecomment-191849723).
 
 ## Grid
 

+ 19 - 0
samples/ControlCatalog.Android/Assets/AboutAssets.txt

@@ -0,0 +1,19 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories) and given a Build Action of "AndroidAsset".
+
+These files will be deployed with you package and will be accessible using Android's
+AssetManager, like this:
+
+public class ReadAsset : Activity
+{
+	protected override void OnCreate (Bundle bundle)
+	{
+		base.OnCreate (bundle);
+
+		InputStream input = Assets.Open ("my_asset.txt");
+	}
+}
+
+Additionally, some Android functions will automatically load asset files:
+
+Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

+ 169 - 0
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{29132311-1848-4FD6-AE0C-4FF841151BD3}</ProjectGuid>
+    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ControlCatalog.Android</RootNamespace>
+    <AssemblyName>ControlCatalog.Android</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <AndroidApplication>true</AndroidApplication>
+    <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
+    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+    <AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
+    <TargetFrameworkVersion>v4.4</TargetFrameworkVersion>
+    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>True</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
+    <AndroidLinkMode>None</AndroidLinkMode>
+    <EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
+    <BundleAssemblies>False</BundleAssemblies>
+    <AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
+    <AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
+    <Debugger>Xamarin</Debugger>
+    <AndroidEnableMultiDex>False</AndroidEnableMultiDex>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
+    <AndroidLinkMode>Full</AndroidLinkMode>
+    <EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
+    <BundleAssemblies>False</BundleAssemblies>
+    <AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
+    <AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
+    <Debugger>Xamarin</Debugger>
+    <AotAssemblies>False</AotAssemblies>
+    <EnableLLVM>False</EnableLLVM>
+    <AndroidEnableMultiDex>False</AndroidEnableMultiDex>
+    <EnableProguard>False</EnableProguard>
+    <DebugSymbols>False</DebugSymbols>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Mono.Android" />
+    <Reference Include="mscorlib" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MainActivity.cs" />
+    <Compile Include="Resources\Resource.Designer.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="GettingStarted.Xamarin" />
+    <None Include="Resources\AboutResources.txt" />
+    <None Include="Assets\AboutAssets.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidResource Include="Resources\layout\Main.axml">
+      <SubType>Designer</SubType>
+    </AndroidResource>
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidResource Include="Resources\values\Strings.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidResource Include="Resources\drawable\Icon.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Properties\AndroidManifest.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj">
+      <Project>{7B92AF71-6287-4693-9DCB-BD5B6E927E23}</Project>
+      <Name>Avalonia.Android</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
+      <Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
+      <Name>Avalonia.Animation</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj">
+      <Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
+      <Name>Avalonia.Base</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
+      <Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
+      <Name>Avalonia.Controls</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
+      <Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
+      <Name>Avalonia.Diagnostics</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
+      <Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project>
+      <Name>Avalonia.DotNetFrameworkRuntime</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.HtmlRenderer\Avalonia.HtmlRenderer.csproj">
+      <Project>{5fb2b005-0a7f-4dad-add4-3ed01444e63d}</Project>
+      <Name>Avalonia.HtmlRenderer</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj">
+      <Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
+      <Name>Avalonia.Input</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
+      <Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
+      <Name>Avalonia.Interactivity</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
+      <Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
+      <Name>Avalonia.Layout</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj">
+      <Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
+      <Name>Avalonia.SceneGraph</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
+      <Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
+      <Name>Avalonia.Styling</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
+      <Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
+      <Name>Avalonia.Themes.Default</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
+      <Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
+      <Name>Avalonia.Markup.Xaml</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
+      <Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
+      <Name>Avalonia.Markup</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\src\Skia\Avalonia.Skia.Android\Avalonia.Skia.Android.csproj">
+      <Project>{bd43f7c0-396b-4aa1-bad9-dfde54d51298}</Project>
+      <Name>Avalonia.Skia.Android</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj">
+      <Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
+      <Name>ControlCatalog</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+     Other similar extension points exist, see Microsoft.Common.targets.
+		<Target Name="BeforeBuild">
+		</Target>
+		<Target Name="AfterBuild">
+		</Target>
+ -->
+</Project>

+ 26 - 0
samples/ControlCatalog.Android/ControlCatalog.Android.v2.ncrunchproject

@@ -0,0 +1,26 @@
+<ProjectConfiguration>
+  <AutoDetectNugetBuildDependencies>true</AutoDetectNugetBuildDependencies>
+  <BuildPriority>1000</BuildPriority>
+  <CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
+  <ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
+  <PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
+  <AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
+  <AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
+  <AllowCodeAnalysis>false</AllowCodeAnalysis>
+  <IgnoreThisComponentCompletely>true</IgnoreThisComponentCompletely>
+  <RunPreBuildEvents>false</RunPreBuildEvents>
+  <RunPostBuildEvents>false</RunPostBuildEvents>
+  <PreviouslyBuiltSuccessfully>false</PreviouslyBuiltSuccessfully>
+  <InstrumentAssembly>true</InstrumentAssembly>
+  <PreventSigningOfAssembly>false</PreventSigningOfAssembly>
+  <AnalyseExecutionTimes>true</AnalyseExecutionTimes>
+  <DetectStackOverflow>true</DetectStackOverflow>
+  <IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
+  <DefaultTestTimeout>60000</DefaultTestTimeout>
+  <UseBuildConfiguration />
+  <UseBuildPlatform />
+  <ProxyProcessPath />
+  <UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
+  <MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
+  <BuildProcessArchitecture>x86</BuildProcessArchitecture>
+</ProjectConfiguration>

+ 4 - 0
samples/ControlCatalog.Android/GettingStarted.Xamarin

@@ -0,0 +1,4 @@
+<GettingStarted>
+	<LocalContent>GS\Android\CS\AndroidApp\GettingStarted.html</LocalContent>
+	<EmbeddedNavigation>false</EmbeddedNavigation>
+</GettingStarted>

+ 46 - 0
samples/ControlCatalog.Android/MainActivity.cs

@@ -0,0 +1,46 @@
+using System;
+using Android.App;
+
+using Android.OS;
+using Android.Content.PM;
+using Avalonia.Android.Platform.Specific;
+using Avalonia.Controls;
+using Avalonia.Controls.Templates;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using Avalonia.Styling;
+using Avalonia.Themes.Default;
+using Avalonia;
+
+namespace ControlCatalog.Android
+{
+    [Activity(Label = "ControlCatalog.Android", MainLauncher = true, Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)]
+    public class MainActivity : AvaloniaActivity
+    {
+        public MainActivity() : base(typeof (App))
+        {
+
+        }
+
+        protected override void OnCreate(Bundle savedInstanceState)
+        {
+            base.OnCreate(savedInstanceState);
+
+            App app;
+            if (Avalonia.Application.Current != null)
+                app = (App)Avalonia.Application.Current;
+            else
+            {
+                app = new App();
+                AppBuilder.Configure(app)
+                    .UseAndroid()
+                    .UseSkia()
+                    .SetupWithoutStarting();
+            }
+
+            var mainWindow = new MainWindow();
+            app.Run(mainWindow);
+        }
+    }
+}
+

+ 5 - 0
samples/ControlCatalog.Android/Properties/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ControlCatalog.Android" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
+	<uses-sdk />
+	<application android:label="ControlCatalog.Android"></application>
+</manifest>

+ 30 - 0
samples/ControlCatalog.Android/Properties/AssemblyInfo.cs

@@ -0,0 +1,30 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ControlCatalog.Android")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ControlCatalog.Android")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 44 - 0
samples/ControlCatalog.Android/Resources/AboutResources.txt

@@ -0,0 +1,44 @@
+Images, layout descriptions, binary blobs and string dictionaries can be included 
+in your application as resource files.  Various Android APIs are designed to 
+operate on the resource IDs instead of dealing with images, strings or binary blobs 
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+    drawable/
+        icon.png
+
+    layout/
+        main.axml
+
+    values/
+        strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource".  The native Android APIs do not operate directly with filenames, but 
+instead operate on resource IDs.  When you compile an Android application that uses resources, 
+the build system will package the resources for distribution and generate a class called "R" 
+(this is an Android convention) that contains the tokens for each one of the resources 
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+    public class drawable {
+        public const int icon = 0x123;
+    }
+
+    public class layout {
+        public const int main = 0x456;
+    }
+
+    public class strings {
+        public const int first_string = 0xabc;
+        public const int second_string = 0xbcd;
+    }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main 
+to reference the layout/main.axml file, or R.strings.first_string to reference the first 
+string in the dictionary file values/strings.xml.

+ 114 - 0
samples/ControlCatalog.Android/Resources/Resource.Designer.cs

@@ -0,0 +1,114 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+[assembly: global::Android.Runtime.ResourceDesignerAttribute("ControlCatalog.Android.Resource", IsApplication=true)]
+
+namespace ControlCatalog.Android
+{
+	
+	
+	[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+	public partial class Resource
+	{
+		
+		static Resource()
+		{
+			global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+		}
+		
+		public static void UpdateIdValues()
+		{
+			global::Avalonia.Android.Resource.String.ApplicationName = global::ControlCatalog.Android.Resource.String.ApplicationName;
+			global::Avalonia.Android.Resource.String.Hello = global::ControlCatalog.Android.Resource.String.Hello;
+		}
+		
+		public partial class Attribute
+		{
+			
+			static Attribute()
+			{
+				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+			}
+			
+			private Attribute()
+			{
+			}
+		}
+		
+		public partial class Drawable
+		{
+			
+			// aapt resource value: 0x7f020000
+			public const int Icon = 2130837504;
+			
+			static Drawable()
+			{
+				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+			}
+			
+			private Drawable()
+			{
+			}
+		}
+		
+		public partial class Id
+		{
+			
+			// aapt resource value: 0x7f050000
+			public const int MyButton = 2131034112;
+			
+			static Id()
+			{
+				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+			}
+			
+			private Id()
+			{
+			}
+		}
+		
+		public partial class Layout
+		{
+			
+			// aapt resource value: 0x7f030000
+			public const int Main = 2130903040;
+			
+			static Layout()
+			{
+				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+			}
+			
+			private Layout()
+			{
+			}
+		}
+		
+		public partial class String
+		{
+			
+			// aapt resource value: 0x7f040001
+			public const int ApplicationName = 2130968577;
+			
+			// aapt resource value: 0x7f040000
+			public const int Hello = 2130968576;
+			
+			static String()
+			{
+				global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+			}
+			
+			private String()
+			{
+			}
+		}
+	}
+}
+#pragma warning restore 1591

BIN
samples/ControlCatalog.Android/Resources/drawable/Icon.png


+ 13 - 0
samples/ControlCatalog.Android/Resources/layout/Main.axml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+<Button  
+    android:id="@+id/MyButton"
+    android:layout_width="match_parent" 
+    android:layout_height="wrap_content" 
+    android:text="@string/Hello"
+    />
+</LinearLayout>

+ 5 - 0
samples/ControlCatalog.Android/Resources/values/Strings.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="Hello">Hello World, Click Me!</string>
+    <string name="ApplicationName">ControlCatalog.Android</string>
+</resources>

+ 21 - 8
src/Android/Avalonia.Android/AndroidPlatform.cs

@@ -1,16 +1,24 @@
 using Avalonia.Android.Platform;
 using Avalonia.Android.Platform.Input;
-using Avalonia.Android.Platform.Specific;
+using Avalonia.Android.Platform.SkiaPlatform;
+using Avalonia.Controls;
 using Avalonia.Controls.Platform;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
 using Avalonia.Platform;
 using Avalonia.Shared.PlatformSupport;
-using Avalonia.Skia;
-using System;
-using System.Collections.Generic;
-using Avalonia.Android.Platform.SkiaPlatform;
-using System.IO;
+
+namespace Avalonia
+{
+    public static class AndroidApplicationExtensions
+    {
+        public static T UseAndroid<T>(this T builder) where T : AppBuilderBase<T>, new()
+        {
+            builder.UseWindowingSubsystem(Android.AndroidPlatform.Initialize, "Android");
+            return builder;
+        }
+    }
+}
 
 namespace Avalonia.Android
 {
@@ -24,14 +32,19 @@ namespace Avalonia.Android
 
         private readonly double _scalingFactor = 1;
 
-        AndroidPlatform()
+        public AndroidPlatform()
+        {
+            _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
+        }
+
+        public static void Initialize()
         {
             AvaloniaLocator.CurrentMutable
                 .Bind<IClipboard>().ToTransient<ClipboardImpl>()
                 .Bind<IStandardCursorFactory>().ToTransient<CursorFactory>()
                 .Bind<IKeyboardDevice>().ToSingleton<AndroidKeyboardDevice>()
                 .Bind<IMouseDevice>().ToSingleton<AndroidMouseDevice>()
-                .Bind<IPlatformSettings>().ToConstant(this)
+                .Bind<IPlatformSettings>().ToConstant(Instance)
                 .Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
                 .Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
                 .Bind<IWindowingPlatform>().ToConstant(this);

+ 1 - 1
src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs

@@ -14,7 +14,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         {
         }
 
-        public WindowState WindowState
+        public new WindowState WindowState
         {
             get { return WindowState.Normal; }
             set { }

+ 5 - 8
src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj

@@ -10,7 +10,7 @@
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>Avalonia.AndroidTestApplication</RootNamespace>
-    <AssemblyName>Avalonia Test Application</AssemblyName>
+    <AssemblyName>Avalonia.AndroidTestApplication</AssemblyName>
     <FileAlignment>512</FileAlignment>
     <AndroidApplication>true</AndroidApplication>
     <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
@@ -77,11 +77,7 @@
       <Private>True</Private>
     </Reference>
     <Reference Include="System" />
-    <Reference Include="System.Collections" />
     <Reference Include="System.Core" />
-    <Reference Include="System.IO" />
-    <Reference Include="System.Linq.Expressions" />
-    <Reference Include="System.ObjectModel" />
     <Reference Include="System.Reactive.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
       <HintPath>..\..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.3\System.Reactive.Core.dll</HintPath>
       <Private>True</Private>
@@ -98,8 +94,6 @@
       <HintPath>..\..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.3\System.Reactive.PlatformServices.dll</HintPath>
       <Private>True</Private>
     </Reference>
-    <Reference Include="System.Runtime" />
-    <Reference Include="System.Runtime.Extensions" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Xml" />
   </ItemGroup>
@@ -178,6 +172,10 @@
       <Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
       <Name>Avalonia.Themes.Default</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
+      <Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project>
+      <Name>Avalonia.DotNetFrameworkRuntime</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\Avalonia.HtmlRenderer\Avalonia.HtmlRenderer.csproj">
       <Project>{5fb2b005-0a7f-4dad-add4-3ed01444e63d}</Project>
       <Name>Avalonia.HtmlRenderer</Name>
@@ -187,7 +185,6 @@
       <Name>Avalonia.Skia.Android</Name>
     </ProjectReference>
   </ItemGroup>
-  <Import Project="..\..\..\samples\TestApplicationShared\TestApplicationShared.projitems" Label="Shared" />
   <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
      Other similar extension points exist, see Microsoft.Common.targets.

+ 70 - 12
src/Android/Avalonia.AndroidTestApplication/MainActivity.cs

@@ -1,12 +1,14 @@
+using System;
 using Android.App;
 using Android.Content.PM;
 using Android.OS;
-using Avalonia.Android;
 using Avalonia.Android.Platform.Specific;
-using Avalonia.Android.Platform.Specific.Helpers;
-using Avalonia.Controls.Platform;
-using Avalonia.Platform;
-using TestApplication;
+using Avalonia.Controls;
+using Avalonia.Controls.Templates;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using Avalonia.Styling;
+using Avalonia.Themes.Default;
 
 namespace Avalonia.AndroidTestApplication
 {
@@ -30,15 +32,71 @@ namespace Avalonia.AndroidTestApplication
             if (Avalonia.Application.Current != null)
                 app = (App)Avalonia.Application.Current;
             else
+            {
                 app = new App();
-           
+                AppBuilder.Configure(app)
+                    .UseAndroid()
+                    .UseSkia()
+                    .SetupWithoutStarting();
+            }
 
-            MainWindow.RootNamespace = "Avalonia.AndroidTestApplication";
-            var window = MainWindow.Create();
+            app.Run();
+        }
+    }
+
+    public class App : Application
+    {
+        public void Run()
+        {
+            Styles.Add(new DefaultTheme());
+
+            var loader = new AvaloniaXamlLoader();
+            var baseLight = (IStyle)loader.Load(
+                new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"));
+            Styles.Add(baseLight);
+
+            var wnd = App.CreateSimpleWindow();
+            wnd.AttachDevTools();
+
+            Run(wnd);
+        }
+
+        // This provides a simple UI tree for testing input handling, drawing, etc
+        public static Window CreateSimpleWindow()
+        {
+            Window window = new Window
+            {
+                Title = "Avalonia Test Application",
+                Background = Brushes.Red,
+                Content = new StackPanel
+                {
+                    Margin = new Thickness(30),
+                    Background = Brushes.Yellow,
+                    Children = new Avalonia.Controls.Controls
+                    {
+                        new TextBlock
+                        {
+                            Text = "TEXT BLOCK",
+                            Width = 300,
+                            Height = 40,
+                            Background = Brushes.White,
+                            Foreground = Brushes.Black
+                        },
+
+                        new Button
+                        {
+                            Content = "BUTTON",
+                            Width = 150,
+                            Height = 40,
+                            Background = Brushes.LightGreen,
+                            Foreground = Brushes.Black
+                        }
+
+                    }
+                }
+            };
 
-            window.Show();
-            app.Run(window);
+            return window;
         }
-        
     }
-}
+}

+ 2 - 0
src/Avalonia.Animation/Avalonia.Animation.csproj

@@ -25,6 +25,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Debug\Avalonia.Animation.XML</DocumentationFile>
+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -35,6 +36,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Animation.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

+ 2 - 1
src/Avalonia.Base/Avalonia.Base.csproj

@@ -38,12 +38,13 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Base.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\Shared\SharedAssemblyInfo.cs">
       <Link>Properties\SharedAssemblyInfo.cs</Link>
     </Compile>
-    <Compile Include="Data\BindingChainNullException.cs" />
+    <Compile Include="Data\BindingChainException.cs" />
     <Compile Include="Data\BindingNotification.cs" />
     <Compile Include="Data\IndexerBinding.cs" />
     <Compile Include="Diagnostics\INotifyCollectionChangedDebug.cs" />

+ 0 - 2
src/Avalonia.Base/AvaloniaObject.cs

@@ -164,9 +164,7 @@ namespace Avalonia
 
             set
             {
-                var metadata = binding.Property.GetMetadata(GetType());
                 var sourceBinding = value as IBinding;
-
                 this.Bind(binding.Property, sourceBinding);
             }
         }

+ 7 - 1
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@@ -16,7 +16,13 @@ namespace Avalonia
     /// </summary>
     public static class AvaloniaObjectExtensions
     {
-        public static IBinding AsBinding<T>(this IObservable<T> source)
+        /// <summary>
+        /// Converts an <see cref="IObservable{T}"/> to an <see cref="IBinding"/>.
+        /// </summary>
+        /// <typeparam name="T">The type produced by the observable.</typeparam>
+        /// <param name="source">The observable</param>
+        /// <returns>An <see cref="IBinding"/>.</returns>
+        public static IBinding ToBinding<T>(this IObservable<T> source)
         {
             return new BindingAdaptor(source.Select(x => (object)x));
         }

+ 2 - 3
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@@ -64,8 +64,6 @@ namespace Avalonia
         {
             Contract.Requires<ArgumentNullException>(type != null);
 
-            var i = type.GetTypeInfo();
-
             while (type != null)
             {
                 // Ensure the type's static ctor has been run.
@@ -265,7 +263,8 @@ namespace Avalonia
         /// <param name="property">The property.</param>
         /// <remarks>
         /// You won't usually want to call this method directly, instead use the
-        /// <see cref="AvaloniaProperty.Register"/> method.
+        /// <see cref="AvaloniaProperty.Register{TOwner, TValue}(string, TValue, bool, Data.BindingMode, Func{TOwner, TValue, TValue}, Action{IAvaloniaObject, bool})"/>
+        /// method.
         /// </remarks>
         public void Register(Type type, AvaloniaProperty property)
         {

+ 0 - 1
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@@ -207,7 +207,6 @@ namespace Avalonia.Collections
 
             if (CollectionChanged != null)
             {
-                var val = new KeyValuePair<TKey, TValue>(key, value);
                 var e = new NotifyCollectionChangedEventArgs(
                     NotifyCollectionChangedAction.Add,
                     new[] { new KeyValuePair<TKey, TValue>(key, value) },

+ 0 - 2
src/Avalonia.Base/Collections/AvaloniaList.cs

@@ -397,8 +397,6 @@ namespace Avalonia.Collections
         {
             Contract.Requires<ArgumentNullException>(items != null);
 
-            var list = (items as IList) ?? items.ToList();
-
             foreach (var i in items)
             {
                 // TODO: Optimize to only send as many notifications as necessary.

+ 25 - 32
src/Avalonia.Base/Data/BindingChainNullException.cs → src/Avalonia.Base/Data/BindingChainException.cs

@@ -10,36 +10,39 @@ namespace Avalonia.Data
     /// requested binding expression could not be evaluated because of a null in one of the links
     /// of the binding chain.
     /// </summary>
-    public class BindingChainNullException : Exception
+    public class BindingChainException : Exception
     {
         private string _message;
 
         /// <summary>
-        /// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
+        /// Initalizes a new instance of the <see cref="BindingChainException"/> class.
         /// </summary>
-        public BindingChainNullException()
+        public BindingChainException()
         {
         }
 
         /// <summary>
-        /// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
+        /// Initalizes a new instance of the <see cref="BindingChainException"/> class.
         /// </summary>
-        public BindingChainNullException(string message)
+        /// <param name="message">The error message.</param>
+        public BindingChainException(string message)
         {
             _message = message;
         }
 
         /// <summary>
-        /// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
+        /// Initalizes a new instance of the <see cref="BindingChainException"/> class.
         /// </summary>
+        /// <param name="message">The error message.</param>
         /// <param name="expression">The expression.</param>
-        /// <param name="expressionNullPoint">
-        /// The point in the expression at which the null was encountered.
+        /// <param name="errorPoint">
+        /// The point in the expression at which the error was encountered.
         /// </param>
-        public BindingChainNullException(string expression, string expressionNullPoint)
+        public BindingChainException(string message, string expression, string errorPoint)
         {
+            _message = message;
             Expression = expression;
-            ExpressionNullPoint = expressionNullPoint;
+            ExpressionErrorPoint = errorPoint;
         }
 
         /// <summary>
@@ -48,37 +51,27 @@ namespace Avalonia.Data
         public string Expression { get; protected set; }
 
         /// <summary>
-        /// Gets the point in the expression at which the null was encountered.
+        /// Gets the point in the expression at which the error occured.
         /// </summary>
-        public string ExpressionNullPoint { get; protected set; }
+        public string ExpressionErrorPoint { get; protected set; }
 
         /// <inheritdoc/>
         public override string Message
         {
             get
             {
-                if (_message == null)
+                if (Expression != null && ExpressionErrorPoint != null)
                 {
-                    _message = BuildMessage();
+                    return $"{_message} in expression '{Expression}' at '{ExpressionErrorPoint}'.";
+                }
+                else if (ExpressionErrorPoint != null)
+                {
+                    return $"{_message} in expression '{ExpressionErrorPoint}'.";
+                }
+                else
+                {
+                    return $"{_message} in expression.";
                 }
-
-                return _message;
-            }
-        }
-
-        private string BuildMessage()
-        {
-            if (Expression != null && ExpressionNullPoint != null)
-            {
-                return $"'{ExpressionNullPoint}' is null in expression '{Expression}'.";
-            }
-            else if (ExpressionNullPoint != null)
-            {
-                return $"'{ExpressionNullPoint}' is null in expression.";
-            }
-            else
-            {
-                return "Null encountered in binding expression.";
             }
         }
     }

+ 1 - 1
src/Avalonia.Base/Data/InstancedBinding.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Data
     /// <remarks>
     /// Whereas an <see cref="IBinding"/> holds a description of a binding such as "Bind to the X
     /// property on a control's DataContext"; this class represents a binding that has been 
-    /// *instanced* by calling <see cref="IBinding.Initiate(IAvaloniaObject, AvaloniaProperty, object)"/>
+    /// *instanced* by calling <see cref="IBinding.Initiate(IAvaloniaObject, AvaloniaProperty, object, bool)"/>
     /// on a target object.
     /// 
     /// When a binding is initiated, it can return one of 3 possible sources for the binding:

+ 0 - 3
src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs

@@ -21,9 +21,6 @@ namespace Avalonia.Platform
         /// <returns>An <see cref="IDisposable"/> used to stop the timer.</returns>
         IDisposable StartTimer(TimeSpan interval, Action tick);
 
-        /// <summary>
-        /// Sends a message that causes <see cref="ProcessMessage"/> to exit.
-        /// </summary>
         void Signal();
 
         bool CurrentThreadIsLoopThread { get; }

+ 0 - 1
src/Avalonia.Base/PriorityBindingEntry.cs

@@ -21,7 +21,6 @@ namespace Avalonia
         /// <param name="index">
         /// The binding index. Later bindings should have higher indexes.
         /// </param>
-        /// <param name="validation">The validation settings for the binding.</param>
         public PriorityBindingEntry(PriorityLevel owner, int index)
         {
             _owner = owner;

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

@@ -9,9 +9,9 @@ using Avalonia.Platform;
 namespace Avalonia.Controls
 {
     /// <summary>
-    /// Initializes up platform-specific services for an <see cref="Application"/>.
+    /// Base class for initializing platform-specific services for an <see cref="Application"/>.
     /// </summary>
-    /// <typeparam name="TAppBuilder"></typeparam>
+    /// <typeparam name="TAppBuilder">The type of the AppBuilder class itself.</typeparam>
     public abstract class AppBuilderBase<TAppBuilder> where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
     {
         /// <summary>
@@ -140,6 +140,7 @@ namespace Avalonia.Controls
         /// Specifies a windowing subsystem to use.
         /// </summary>
         /// <param name="initializer">The method to call to initialize the windowing subsystem.</param>
+        /// <param name="name">The name of the windowing subsystem.</param>
         /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
         public TAppBuilder UseWindowingSubsystem(Action initializer, string name = "")
         {
@@ -159,6 +160,7 @@ namespace Avalonia.Controls
         /// Specifies a rendering subsystem to use.
         /// </summary>
         /// <param name="initializer">The method to call to initialize the rendering subsystem.</param>
+        /// <param name="name">The name of the rendering subsystem.</param>
         /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
         public TAppBuilder UseRenderingSubsystem(Action initializer, string name = "")
         {

+ 1 - 0
src/Avalonia.Controls/Avalonia.Controls.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Controls.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\Shared\SharedAssemblyInfo.cs">

+ 4 - 4
src/Avalonia.Controls/Canvas.cs

@@ -22,25 +22,25 @@ namespace Avalonia.Controls
         /// Defines the Left attached property.
         /// </summary>
         public static readonly AttachedProperty<double> LeftProperty =
-            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Left");
+            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Left", double.NaN);
 
         /// <summary>
         /// Defines the Top attached property.
         /// </summary>
         public static readonly AttachedProperty<double> TopProperty =
-            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Top");
+            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Top", double.NaN);
 
         /// <summary>
         /// Defines the Right attached property.
         /// </summary>
         public static readonly AttachedProperty<double> RightProperty =
-            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Right");
+            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Right", double.NaN);
 
         /// <summary>
         /// Defines the Bottom attached property.
         /// </summary>
         public static readonly AttachedProperty<double> BottomProperty =
-            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Bottom");
+            AvaloniaProperty.RegisterAttached<Canvas, Control, double>("Bottom", double.NaN);
 
         /// <summary>
         /// Initializes static members of the <see cref="Canvas"/> class.

+ 0 - 1
src/Avalonia.Controls/Classes.cs

@@ -197,7 +197,6 @@ namespace Avalonia.Controls
         /// <param name="count">The number of items to remove.</param>
         public override void RemoveRange(int index, int count)
         {
-            var names = GetRange(index, count);
             base.RemoveRange(index, count);
         }
 

+ 0 - 5
src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs

@@ -124,11 +124,6 @@ namespace Avalonia.Controls.Generators
             return false;
         }
 
-        /// <summary>
-        /// Gets the data template for the specified item.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>The template.</returns>
         private ITreeDataTemplate GetTreeDataTemplate(object item, IDataTemplate primary)
         {
             var template = Owner.FindDataTemplate(item, primary) ?? FuncDataTemplate.Default;

+ 2 - 1
src/Avalonia.Controls/HotkeyManager.cs

@@ -30,8 +30,9 @@ namespace Avalonia.Controls
 
             public void Execute(object parameter) => GetCommand()?.Execute(parameter);
 
-            //Implementation isn't needed in this case
+#pragma warning disable 67 // Event not used
             public event EventHandler CanExecuteChanged;
+#pragma warning restore 67
         }
 
 

+ 0 - 2
src/Avalonia.Controls/Platform/PlatformManager.cs

@@ -11,7 +11,6 @@ namespace Avalonia.Controls.Platform
             => AvaloniaLocator.Current.GetService<IPlatformSettings>();
 
         static bool s_designerMode;
-        private static double _designerScalingFactor = 1;
 
         public static IDisposable DesignerMode()
         {
@@ -21,7 +20,6 @@ namespace Avalonia.Controls.Platform
 
         public static void SetDesignerScalingFactor(double factor)
         {
-            _designerScalingFactor = factor;
         }
 
         public static IWindowImpl CreateWindow()

+ 3 - 2
src/Avalonia.Controls/Presenters/CarouselPresenter.cs

@@ -97,7 +97,9 @@ namespace Avalonia.Controls.Presenters
         /// <inheritdoc/>
         protected override void PanelCreated(IPanel panel)
         {
-            var task = MoveToPage(-1, SelectedIndex);
+#pragma warning disable 4014
+            MoveToPage(-1, SelectedIndex);
+#pragma warning restore 4014
         }
 
         /// <inheritdoc/>
@@ -139,7 +141,6 @@ namespace Avalonia.Controls.Presenters
 
                 if (toIndex != -1)
                 {
-                    var item = Items.Cast<object>().ElementAt(toIndex);
                     to = GetOrCreateContainer(toIndex);
                 }
 

+ 61 - 6
src/Avalonia.Controls/Presenters/ItemVirtualizer.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Controls.Presenters
     /// </summary>
     internal abstract class ItemVirtualizer : IVirtualizingController, IDisposable
     {
-        private bool disposedValue;
+        private double _crossAxisOffset;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ItemVirtualizer"/> class.
@@ -62,7 +62,7 @@ namespace Avalonia.Controls.Presenters
         /// <summary>
         /// Gets a value indicating whether the items should be scroll horizontally or vertically.
         /// </summary>
-        public bool Vertical => VirtualizingPanel.ScrollDirection == Orientation.Vertical;
+        public bool Vertical => VirtualizingPanel?.ScrollDirection == Orientation.Vertical;
 
         /// <summary>
         /// Gets a value indicating whether logical scrolling is enabled.
@@ -87,12 +87,28 @@ namespace Avalonia.Controls.Presenters
         /// <summary>
         /// Gets the <see cref="ExtentValue"/> as a <see cref="Size"/>.
         /// </summary>
-        public Size Extent => Vertical ? new Size(0, ExtentValue) : new Size(ExtentValue, 0);
+        public Size Extent
+        {
+            get
+            {
+                return Vertical ?
+                    new Size(Owner.Panel.DesiredSize.Width, ExtentValue) :
+                    new Size(ExtentValue, Owner.Panel.DesiredSize.Height);
+            }
+        }
 
         /// <summary>
         /// Gets the <see cref="ViewportValue"/> as a <see cref="Size"/>.
         /// </summary>
-        public Size Viewport => Vertical ? new Size(0, ViewportValue) : new Size(ViewportValue, 0);
+        public Size Viewport
+        {
+            get
+            {
+                return Vertical ? 
+                    new Size(Owner.Panel.Bounds.Width, ViewportValue) :
+                    new Size(ViewportValue, Owner.Panel.Bounds.Height);
+            }
+        }
 
         /// <summary>
         /// Gets or sets the <see cref="OffsetValue"/> as a <see cref="Vector"/>.
@@ -101,12 +117,28 @@ namespace Avalonia.Controls.Presenters
         {
             get
             {
-                return Vertical ? new Vector(0, OffsetValue) : new Vector(OffsetValue, 0);
+                return Vertical ? new Vector(_crossAxisOffset, OffsetValue) : new Vector(OffsetValue, _crossAxisOffset);
             }
 
             set
             {
-                OffsetValue = Vertical ? value.Y : value.X;
+                var oldCrossAxisOffset = _crossAxisOffset;
+
+                if (Vertical)
+                {
+                    OffsetValue = value.Y;
+                    _crossAxisOffset = value.X;
+                }
+                else
+                {
+                    OffsetValue = value.X;
+                    _crossAxisOffset = value.Y;
+                }
+
+                if (_crossAxisOffset != oldCrossAxisOffset)
+                {
+                    Owner.InvalidateArrange();
+                }
             }
         }
         
@@ -145,6 +177,29 @@ namespace Avalonia.Controls.Presenters
             return result;
         }
 
+        /// <summary>
+        /// Carries out a measure for the related <see cref="ItemsPresenter"/>.
+        /// </summary>
+        /// <param name="availableSize">The size available to the control.</param>
+        /// <returns>The desired size for the control.</returns>
+        public virtual Size MeasureOverride(Size availableSize)
+        {
+            Owner.Panel.Measure(availableSize);
+            return Owner.Panel.DesiredSize;
+        }
+
+        /// <summary>
+        /// Carries out an arrange for the related <see cref="ItemsPresenter"/>.
+        /// </summary>
+        /// <param name="finalSize">The size available to the control.</param>
+        /// <returns>The actual size used.</returns>
+        public virtual Size ArrangeOverride(Size finalSize)
+        {
+            var origin = Vertical ? new Point(-_crossAxisOffset, 0) : new Point(0, _crossAxisOffset);
+            Owner.Panel.Arrange(new Rect(origin, finalSize));
+            return finalSize;
+        }
+
         /// <inheritdoc/>
         public virtual void UpdateControls()
         {

+ 50 - 3
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@@ -94,6 +94,44 @@ namespace Avalonia.Controls.Presenters
             }
         }
 
+        /// <inheritdoc/>
+        public override Size MeasureOverride(Size availableSize)
+        {
+            var window = Owner.GetVisualRoot() as TopLevel;
+
+            // If infinity is passed as the available size and we're virtualized then we need to
+            // fill the available space, but to do that we *don't* want to materialize all our
+            // items! Take a look at the root of the tree for a MaxClientSize and use that as
+            // the available size.
+            if (VirtualizingPanel.ScrollDirection == Orientation.Vertical)
+            {
+                if (availableSize.Height == double.PositiveInfinity)
+                {
+                    if (window != null)
+                    {
+                        availableSize = availableSize.WithHeight(window.PlatformImpl.MaxClientSize.Height);
+                    }
+                }
+
+                availableSize = availableSize.WithWidth(double.PositiveInfinity);
+            }
+            else
+            {
+                if (availableSize.Width == double.PositiveInfinity)
+                {
+                    if (window != null)
+                    {
+                        availableSize = availableSize.WithWidth(window.PlatformImpl.MaxClientSize.Width);
+                    }
+                }
+
+                availableSize = availableSize.WithHeight(double.PositiveInfinity);
+            }
+
+            Owner.Panel.Measure(availableSize);
+            return Owner.Panel.DesiredSize;
+        }
+
         /// <inheritdoc/>
         public override void UpdateControls()
         {
@@ -359,7 +397,6 @@ namespace Avalonia.Controls.Presenters
             var count = Math.Min(Math.Abs(delta), panel.Children.Count);
             var move = count < panel.Children.Count;
             var first = delta < 0 && move ? panel.Children.Count + delta : 0;
-            var containers = panel.Children.GetRange(first, count).ToList();
 
             for (var i = 0; i < count; ++i)
             {
@@ -482,9 +519,19 @@ namespace Avalonia.Controls.Presenters
                 {
                     layoutManager.ExecuteLayoutPass();
 
-                    if (!new Rect(panel.Bounds.Size).Contains(container.Bounds))
+                    if (panel.ScrollDirection == Orientation.Vertical)
                     {
-                        OffsetValue += 1;
+                        if (container.Bounds.Y < panel.Bounds.Y || container.Bounds.Bottom > panel.Bounds.Bottom)
+                        {
+                            OffsetValue += 1;
+                        }
+                    }
+                    else
+                    {
+                        if (container.Bounds.X < panel.Bounds.X || container.Bounds.Right > panel.Bounds.Right)
+                        {
+                            OffsetValue += 1;
+                        }
                     }
                 }
 

+ 6 - 15
src/Avalonia.Controls/Presenters/ItemsPresenter.cs

@@ -91,24 +91,15 @@ namespace Avalonia.Controls.Presenters
             _virtualizer?.ScrollIntoView(item);
         }
 
+        /// <inheritdoc/>
         protected override Size MeasureOverride(Size availableSize)
         {
-            // If infinity is passed as the available size and we're virtualized then we need to
-            // fill the available space, but to do that we *don't* want to materialize all our
-            // items! Take a look at the root of the tree for a MaxClientSize and use that as
-            // the available size.
-            if (availableSize == Size.Infinity && VirtualizationMode != ItemVirtualizationMode.None)
-            {
-                var window = VisualRoot as TopLevel;
-
-                if (window != null)
-                {
-                    availableSize = window.PlatformImpl.MaxClientSize;
-                }
-            }
+            return _virtualizer?.MeasureOverride(availableSize) ?? Size.Empty;
+        }
 
-            Panel.Measure(availableSize);
-            return Panel.DesiredSize;
+        protected override Size ArrangeOverride(Size finalSize)
+        {
+            return _virtualizer?.ArrangeOverride(finalSize) ?? Size.Empty;
         }
 
         /// <inheritdoc/>

+ 1 - 1
src/Avalonia.Controls/Presenters/TextPresenter.cs

@@ -219,7 +219,7 @@ namespace Avalonia.Controls.Presenters
         {
             var text = Text;
 
-            if (!string.IsNullOrWhiteSpace(text))
+            if (!string.IsNullOrEmpty(text))
             {
                 return base.MeasureOverride(availableSize);
             }

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

@@ -157,7 +157,7 @@ namespace Avalonia.Controls
         /// </summary>
         public ScrollViewer()
         {
-            var extentAndViewport = Observable.CombineLatest(
+            Observable.CombineLatest(
                 this.GetObservable(ExtentProperty),
                 this.GetObservable(ViewportProperty))
                 .Select(x => new { Extent = x[0], Viewport = x[1] });

+ 60 - 19
src/Avalonia.Controls/TextBox.cs

@@ -105,7 +105,7 @@ namespace Avalonia.Controls
 
         public TextBox()
         {
-            var canScrollHorizontally = this.GetObservable(TextWrappingProperty)
+            this.GetObservable(TextWrappingProperty)
                 .Select(x => x == TextWrapping.NoWrap)
                 .Subscribe(x => CanScrollHorizontally = x);
 
@@ -148,7 +148,8 @@ namespace Avalonia.Controls
             {
                 value = CoerceCaretIndex(value);
                 SetAndRaise(CaretIndexProperty, ref _caretIndex, value);
-                if (_undoRedoHelper.IsLastState && _undoRedoHelper.LastState.Text == Text)
+                UndoRedoState state;
+                if (_undoRedoHelper.TryGetLastState(out state) && state.Text == Text)
                     _undoRedoHelper.UpdateLastState();
             }
         }
@@ -239,7 +240,21 @@ namespace Avalonia.Controls
         protected override void OnGotFocus(GotFocusEventArgs e)
         {
             base.OnGotFocus(e);
-            _presenter.ShowCaret();
+
+            // when navigating to a textbox via the tab key, select all text if
+            //   1) this textbox is *not* a multiline textbox
+            //   2) this textbox has any text to select
+            if (e.NavigationMethod == NavigationMethod.Tab &&
+                !AcceptsReturn &&
+                Text?.Length > 0)
+            {
+                SelectionStart = 0;
+                SelectionEnd = Text.Length;
+            }
+            else
+            {
+                _presenter.ShowCaret();
+            }
         }
 
         protected override void OnLostFocus(RoutedEventArgs e)
@@ -379,8 +394,20 @@ namespace Avalonia.Controls
 
                     if (!DeleteSelection() && CaretIndex > 0)
                     {
-                        SetTextInternal(text.Substring(0, caretIndex - 1) + text.Substring(caretIndex));
-                        --CaretIndex;
+                        var removedCharacters = 1;
+                        // handle deleting /r/n
+                        // you don't ever want to leave a dangling /r around. So, if deleting /n, check to see if 
+                        // a /r should also be deleted.
+                        if (CaretIndex > 1 &&
+                            text[CaretIndex - 1] == '\n' &&
+                            text[CaretIndex - 2] == '\r')
+                        {
+                            removedCharacters = 2;
+                        }
+
+                        SetTextInternal(text.Substring(0, caretIndex - removedCharacters) + text.Substring(caretIndex));
+                        CaretIndex -= removedCharacters;
+                        SelectionStart = SelectionEnd = CaretIndex;
                     }
 
                     break;
@@ -393,7 +420,18 @@ namespace Avalonia.Controls
 
                     if (!DeleteSelection() && caretIndex < text.Length)
                     {
-                        SetTextInternal(text.Substring(0, caretIndex) + text.Substring(caretIndex + 1));
+                        var removedCharacters = 1;
+                        // handle deleting /r/n
+                        // you don't ever want to leave a dangling /r around. So, if deleting /n, check to see if 
+                        // a /r should also be deleted.
+                        if (CaretIndex < text.Length - 1 &&
+                            text[caretIndex + 1] == '\n' &&
+                            text[caretIndex] == '\r')
+                        {
+                            removedCharacters = 2;
+                        }
+
+                        SetTextInternal(text.Substring(0, caretIndex) + text.Substring(caretIndex + removedCharacters));
                     }
 
                     break;
@@ -457,10 +495,10 @@ namespace Avalonia.Controls
                         case 2:
                             if (!StringUtils.IsStartOfWord(text, index))
                             {
-                                SelectionStart = StringUtils.PreviousWord(text, index, false);
+                                SelectionStart = StringUtils.PreviousWord(text, index);
                             }
 
-                            SelectionEnd = StringUtils.NextWord(text, index, false);
+                            SelectionEnd = StringUtils.NextWord(text, index);
                             break;
                         case 3:
                             SelectionStart = 0;
@@ -509,7 +547,7 @@ namespace Avalonia.Controls
                 var exceptions = aggregate == null ?
                     (IEnumerable<Exception>)new[] { exception } :
                     aggregate.InnerExceptions;
-                var filtered = exceptions.Where(x => !(x is BindingChainNullException)).ToList();
+                var filtered = exceptions.Where(x => !(x is BindingChainException)).ToList();
 
                 if (filtered.Count > 0)
                 {
@@ -575,8 +613,13 @@ namespace Avalonia.Controls
             {
                 var index = caretIndex + direction;
 
-                if (index < 0 || index >= text.Length)
+                if (index < 0 || index > text.Length)
+                {
+                    return;
+                }
+                else if (index == text.Length)
                 {
+                    CaretIndex = index;
                     return;
                 }
 
@@ -595,11 +638,11 @@ namespace Avalonia.Controls
             {
                 if (direction > 0)
                 {
-                    CaretIndex += StringUtils.NextWord(text, caretIndex, false) - caretIndex;
+                    CaretIndex += StringUtils.NextWord(text, caretIndex) - caretIndex;
                 }
                 else
                 {
-                    CaretIndex += StringUtils.PreviousWord(text, caretIndex, false) - caretIndex;
+                    CaretIndex += StringUtils.PreviousWord(text, caretIndex) - caretIndex;
                 }
             }
         }
@@ -675,6 +718,10 @@ namespace Avalonia.Controls
                         if (pos < text.Length)
                         {
                             --pos;
+                            if (pos > 0 && Text[pos - 1] == '\r' && Text[pos] == '\n')
+                            {
+                                --pos;
+                            }
                         }
 
                         break;
@@ -690,7 +737,7 @@ namespace Avalonia.Controls
         private void SelectAll()
         {
             SelectionStart = 0;
-            SelectionEnd = Text.Length;
+            SelectionEnd = Text?.Length ?? 0;
         }
 
         private bool DeleteSelection()
@@ -777,12 +824,6 @@ namespace Avalonia.Controls
             SelectionStart = CaretIndex;
             MoveHorizontal(1, modifiers);
             SelectionEnd = CaretIndex;
-
-            string selection = GetSelection();
-            if (selection != " " && selection.EndsWith(" "))
-            {
-                SelectionEnd = CaretIndex - 1;
-            }
         }
 
         UndoRedoState UndoRedoHelper<UndoRedoState>.IUndoRedoHost.UndoRedoState

+ 0 - 1
src/Avalonia.Controls/TopLevel.cs

@@ -87,7 +87,6 @@ namespace Avalonia.Controls
 
             PlatformImpl = impl;
             dependencyResolver = dependencyResolver ?? AvaloniaLocator.Current;
-
             var styler = TryGetService<IStyler>(dependencyResolver);
 
             _accessKeyHandler = TryGetService<IAccessKeyHandler>(dependencyResolver);

+ 24 - 94
src/Avalonia.Controls/Utils/StringUtils.cs

@@ -57,7 +57,7 @@ namespace Avalonia.Controls.Utils
             }
         }
 
-        public static int PreviousWord(string text, int cursor, bool gtkMode)
+        public static int PreviousWord(string text, int cursor)
         {
             int begin;
             int i;
@@ -81,60 +81,21 @@ namespace Avalonia.Controls.Utils
                 return (cr > 0) ? cr : 0;
             }
 
-            if (gtkMode)
-            {
-                CharClass cc = GetCharClass(text[cursor - 1]);
-                begin = lf + 1;
-                i = cursor;
-
-                // skip over the word, punctuation, or run of whitespace
-                while (i > begin && GetCharClass(text[i - 1]) == cc)
-                {
-                    i--;
-                }
+            CharClass cc = GetCharClass(text[cursor - 1]);
+            begin = lf + 1;
+            i = cursor;
 
-                // if the cursor was at whitespace, skip back a word too
-                if (cc == CharClass.CharClassWhitespace && i > begin)
-                {
-                    cc = GetCharClass(text[i - 1]);
-                    while (i > begin && GetCharClass(text[i - 1]) == cc)
-                    {
-                        i--;
-                    }
-                }
-            }
-            else
+            // skip over the word, punctuation, or run of whitespace
+            while (i > begin && GetCharClass(text[i - 1]) == cc)
             {
-                begin = lf + 1;
-                i = cursor;
-
-                if (cursor < text.Length)
-                {
-                    // skip to the beginning of this word
-                    while (i > begin && !char.IsWhiteSpace(text[i - 1]))
-                    {
-                        i--;
-                    }
-
-                    if (i < cursor && IsStartOfWord(text, i))
-                    {
-                        return i;
-                    }
-                }
-
-                // skip to the start of the lwsp
-                while (i > begin && char.IsWhiteSpace(text[i - 1]))
-                {
-                    i--;
-                }
-
-                if (i > begin)
-                {
-                    i--;
-                }
+                i--;
+            }
 
-                // skip to the beginning of the word
-                while (i > begin && !IsStartOfWord(text, i))
+            // if the cursor was at whitespace, skip back a word too
+            if (cc == CharClass.CharClassWhitespace && i > begin)
+            {
+                cc = GetCharClass(text[i - 1]);
+                while (i > begin && GetCharClass(text[i - 1]) == cc)
                 {
                     i--;
                 }
@@ -143,7 +104,7 @@ namespace Avalonia.Controls.Utils
             return i;
         }
 
-        public static int NextWord(string text, int cursor, bool gtkMode)
+        public static int NextWord(string text, int cursor)
         {
             int i, lf, cr;
 
@@ -169,50 +130,19 @@ namespace Avalonia.Controls.Utils
                 return cursor;
             }
 
-            if (gtkMode)
-            {
-                CharClass cc = GetCharClass(text[cursor]);
-                i = cursor;
-
-                // skip over the word, punctuation, or run of whitespace
-                while (i < cr && GetCharClass(text[i]) == cc)
-                {
-                    i++;
-                }
+            CharClass cc = GetCharClass(text[cursor]);
+            i = cursor;
 
-                // skip any whitespace after the word/punct
-                while (i < cr && char.IsWhiteSpace(text[i]))
-                {
-                    i++;
-                }
-            }
-            else
+            // skip over the word, punctuation, or run of whitespace
+            while (i < cr && GetCharClass(text[i]) == cc)
             {
-                i = cursor;
-
-                // skip any whitespace before the word
-                while (i < cr && char.IsWhiteSpace(text[i]))
-                {
-                    i++;
-                }
-
-                // skip to the end of the current word
-                while (i < cr && !char.IsWhiteSpace(text[i]))
-                {
-                    i++;
-                }
-
-                // skip any whitespace after the word
-                while (i < cr && char.IsWhiteSpace(text[i]))
-                {
-                    i++;
-                }
+                i++;
+            }
 
-                // find the start of the next word
-                while (i < cr && !IsStartOfWord(text, i))
-                {
-                    i++;
-                }
+            // skip any whitespace after the word/punct
+            while (i < cr && char.IsWhiteSpace(text[i]))
+            {
+                i++;
             }
 
             return i;

+ 31 - 28
src/Avalonia.Controls/Utils/UndoRedoHelper.cs

@@ -8,20 +8,19 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Controls.Utils
 {
-    class UndoRedoHelper<TState> : WeakTimer.IWeakTimerSubscriber where TState : IEquatable<TState>
+    class UndoRedoHelper<TState> : WeakTimer.IWeakTimerSubscriber where TState : struct, IEquatable<TState>
     {
         private readonly IUndoRedoHost _host;
 
         public interface IUndoRedoHost
         {
-             TState UndoRedoState { get; set; }
+            TState UndoRedoState { get; set; }
         }
-        
+
 
 
         private readonly LinkedList<TState> _states = new LinkedList<TState>();
 
-        [NotNull]
         private LinkedListNode<TState> _currentNode;
 
         public int Limit { get; set; } = 10;
@@ -29,24 +28,31 @@ namespace Avalonia.Controls.Utils
         public UndoRedoHelper(IUndoRedoHost host)
         {
             _host = host;
-            _states.AddFirst(_host.UndoRedoState);
-            _currentNode = _states.First;
-            WeakTimer.StartWeakTimer(this, new TimeSpan(0, 0, 1));
-
+            WeakTimer.StartWeakTimer(this, TimeSpan.FromSeconds(1));
         }
 
         public void Undo()
         {
-			if (_currentNode?.Previous != null)  
-			{
-				_currentNode = _currentNode.Previous;
-			}
-
-			_host.UndoRedoState = _currentNode.Value;            
+            if (_currentNode?.Previous != null)
+            {
+                _currentNode = _currentNode.Previous;
+                _host.UndoRedoState = _currentNode.Value;
+            }
         }
 
-        public bool IsLastState => _currentNode.Next == null;
+        public bool IsLastState => _currentNode != null && _currentNode.Next == null;
+
+        public bool TryGetLastState(out TState _state)
+        {
+            _state = default(TState);
+            if (!IsLastState)
+                return false;
 
+            _state = _currentNode.Value;
+            return true;
+        }
+
+        public bool HasState => _currentNode != null;
         public void UpdateLastState(TState state)
         {
             _states.Last.Value = state;
@@ -57,34 +63,31 @@ namespace Avalonia.Controls.Utils
             _states.Last.Value = _host.UndoRedoState;
         }
 
-        public TState LastState => _currentNode.Value;
-
         public void DiscardRedo()
         {
-            //Linked list sucks, so we are doing this
-            while (_currentNode.Next != null)
+            while (_currentNode?.Next != null)
                 _states.Remove(_currentNode.Next);
         }
 
         public void Redo()
-        {            
-			if (_currentNode?.Next != null) {
-				_currentNode = _currentNode.Next;
-			}
-
-			_host.UndoRedoState = _currentNode.Value;
+        {
+            if (_currentNode?.Next != null)
+            {
+                _currentNode = _currentNode.Next;
+                _host.UndoRedoState = _currentNode.Value;
+            }
         }
 
         public void Snapshot()
         {
             var current = _host.UndoRedoState;
-            if (!_currentNode.Value.Equals(current))
+            if (_currentNode == null || !_currentNode.Value.Equals(current))
             {
-                if(_currentNode.Next != null)
+                if (_currentNode?.Next != null)
                     DiscardRedo();
                 _states.AddLast(current);
                 _currentNode = _states.Last;
-                if(_states.Count > Limit)
+                if (_states.Count > Limit)
                     _states.RemoveFirst();
             }
         }

+ 1 - 0
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Diagnostics.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

+ 0 - 3
src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs

@@ -11,8 +11,6 @@ namespace Avalonia.Diagnostics.ViewModels
 {
     internal class DevToolsViewModel : ReactiveObject
     {
-        private IControl _root;
-
         private ReactiveObject _content;
 
         private int _selectedTab;
@@ -27,7 +25,6 @@ namespace Avalonia.Diagnostics.ViewModels
 
         public DevToolsViewModel(IControl root)
         {
-            _root = root;
             _logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root));
             _visualTree = new TreePageViewModel(VisualTreeNode.Create(root));
 

+ 4 - 4
src/Avalonia.Diagnostics/Views/ControlDetailsView.cs

@@ -49,7 +49,7 @@ namespace Avalonia.Diagnostics.Views
                         },
                     },
                     [GridRepeater.TemplateProperty] = pt,
-                    [!GridRepeater.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Properties).AsBinding(),
+                    [!GridRepeater.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Properties).ToBinding(),
                 }
             };
         }
@@ -64,7 +64,7 @@ namespace Avalonia.Diagnostics.Views
                 TextWrapping = TextWrapping.NoWrap,
                 [!ToolTip.TipProperty] = property
                     .WhenAnyValue(x => x.Diagnostic)
-                    .AsBinding(),
+                    .ToBinding(),
             };
 
             yield return new TextBlock
@@ -73,13 +73,13 @@ namespace Avalonia.Diagnostics.Views
                 [!TextBlock.TextProperty] = property
                     .WhenAnyValue(v => v.Value)
                     .Select(v => v?.ToString())
-                    .AsBinding(),
+                    .ToBinding(),
             };
 
             yield return new TextBlock
             {
                 TextWrapping = TextWrapping.NoWrap,
-                [!TextBlock.TextProperty] = property.WhenAnyValue(x => x.Priority).AsBinding(),
+                [!TextBlock.TextProperty] = property.WhenAnyValue(x => x.Priority).ToBinding(),
             };
         }
     }

+ 17 - 5
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@@ -1,27 +1,39 @@
 using System;
-using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Platform;
 using Avalonia.Shared.PlatformSupport;
-using System.IO;
 
 namespace Avalonia
 {
+    /// <summary>
+    /// Initializes platform-specific services for an <see cref="Application"/>.
+    /// </summary>
     public sealed class AppBuilder : AppBuilderBase<AppBuilder>
     {
-        public AppBuilder() : base(new StandardRuntimePlatform(), () => StandardRuntimePlatformServices.Register())
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppBuilder"/> class.
+        /// </summary>
+        public AppBuilder()
+            : base(new StandardRuntimePlatform(), () => StandardRuntimePlatformServices.Register())
         {
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AppBuilder"/> class.
+        /// </summary>
+        /// <param name="app">The <see cref="Application"/> instance.</param>
         public AppBuilder(Application app) : this()
         {
             Instance = app;
         }
 
+        /// <summary>
+        /// Instructs the <see cref="AppBuilder"/> to use the best settings for the platform.
+        /// </summary>
+        /// <returns>An <see cref="AppBuilder"/> instance.</returns>
         public AppBuilder UsePlatformDetect()
         {
             var os = RuntimePlatform.GetRuntimeInfo().OperatingSystem;

+ 1 - 0
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@@ -31,6 +31,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />

+ 25 - 0
src/Avalonia.Input/AccessKeyHandler.cs

@@ -43,6 +43,16 @@ namespace Avalonia.Input
         /// </summary>
         private bool _ignoreAltUp;
 
+        /// <summary>
+        /// Whether the AltKey is down.
+        /// </summary>
+        private bool _altIsDown;
+
+        /// <summary>
+        /// Element to restore folowing AltKey taking focus.
+        /// </summary>
+        private IInputElement _restoreFocusElement;
+
         /// <summary>
         /// Gets or sets the window's main menu.
         /// </summary>
@@ -110,8 +120,14 @@ namespace Avalonia.Input
         {
             if (e.Key == Key.LeftAlt)
             {
+                _altIsDown = true;
+
                 if (MainMenu == null || !MainMenu.IsOpen)
                 {
+                    // TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
+                    // Save currently focused input element.
+                    _restoreFocusElement = FocusManager.Instance.Current;                    
+
                     // When Alt is pressed without a main menu, or with a closed main menu, show
                     // access key markers in the window (i.e. "_File").
                     _owner.ShowAccessKeys = _showingAccessKeys = true;
@@ -121,11 +137,18 @@ namespace Avalonia.Input
                     // If the Alt key is pressed and the main menu is open, close the main menu.
                     CloseMenu();
                     _ignoreAltUp = true;
+
+                    _restoreFocusElement?.Focus();
+                    _restoreFocusElement = null;
                 }
 
                 // We always handle the Alt key.
                 e.Handled = true;
             }
+            else if (_altIsDown)
+            {
+                _ignoreAltUp = true;
+            }
         }
 
         /// <summary>
@@ -179,6 +202,8 @@ namespace Avalonia.Input
             switch (e.Key)
             {
                 case Key.LeftAlt:
+                    _altIsDown = false;
+
                     if (_ignoreAltUp)
                     {
                         _ignoreAltUp = false;

+ 1 - 0
src/Avalonia.Input/Avalonia.Input.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Input.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

+ 0 - 1
src/Avalonia.Input/Navigation/DirectionalNavigation.cs

@@ -90,7 +90,6 @@ namespace Avalonia.Input.Navigation
         /// <returns>The element's focusable descendents.</returns>
         private static IEnumerable<IInputElement> GetFocusableDescendents(IInputElement element)
         {
-            var mode = KeyboardNavigation.GetDirectionalNavigation((InputElement)element);
             var children = element.GetVisualChildren().OfType<IInputElement>();
 
             foreach (var child in children)

+ 1 - 0
src/Avalonia.Interactivity/Avalonia.Interactivity.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Interactivity.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

+ 1 - 0
src/Avalonia.Layout/Avalonia.Layout.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Layout.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

+ 1 - 1
src/Avalonia.Layout/LayoutManager.cs

@@ -168,7 +168,7 @@ namespace Avalonia.Layout
 
         private void QueueLayoutPass()
         {
-            if (!_queued)
+            if (!_queued && !_running)
             {
                 Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Render);
                 _queued = true;

+ 2 - 1
src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
@@ -34,6 +34,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Logging.Serilog.XML</DocumentationFile>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="SerilogLogger.cs" />

+ 12 - 0
src/Avalonia.Logging.Serilog/SerilogLogger.cs

@@ -8,21 +8,33 @@ using SerilogLogEventLevel = Serilog.Events.LogEventLevel;
 
 namespace Avalonia.Logging.Serilog
 {
+    /// <summary>
+    /// Sends log output to serilog.
+    /// </summary>
     public class SerilogLogger : ILogSink
     {
         private readonly ILogger _output;
         private readonly Dictionary<string, ILogger> _areas = new Dictionary<string, ILogger>();
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SerilogLogger"/> class.
+        /// </summary>
+        /// <param name="output">The serilog logger to use.</param>
         public SerilogLogger(ILogger output)
         {
             _output = output;
         }
 
+        /// <summary>
+        /// Initializes the Avalonia logging with a new instance of a <see cref="SerilogLogger"/>.
+        /// </summary>
+        /// <param name="output">The serilog logger to use.</param>
         public static void Initialize(ILogger output)
         {
             Logger.Sink = new SerilogLogger(output);
         }
 
+        /// <inheritdoc/>
         public void Log(
             AvaloniaLogEventLevel level, 
             string area, 

+ 1 - 0
src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.SceneGraph.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

+ 21 - 3
src/Avalonia.SceneGraph/Media/DrawingContext.cs

@@ -208,6 +208,9 @@ namespace Avalonia.Media
         /// Pushes an opacity mask.
         /// </summary>
         /// <param name="mask">The opacity mask.</param>
+        /// <param name="bounds">
+        /// The size of the brush's target area. TODO: Are we sure this is needed?
+        /// </param>
         /// <returns>A disposable to undo the opacity mask.</returns>
         public PushedState PushOpacityMask(IBrush mask, Rect bounds)
         {
@@ -216,15 +219,24 @@ namespace Avalonia.Media
         }
 
         /// <summary>
-        /// Pushes a matrix transformation.
+        /// Pushes a matrix post-transformation.
         /// </summary>
         /// <param name="matrix">The matrix</param>
         /// <returns>A disposable used to undo the transformation.</returns>
         public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform*matrix);
 
+        /// <summary>
+        /// Pushes a matrix pre-transformation.
+        /// </summary>
+        /// <param name="matrix">The matrix</param>
+        /// <returns>A disposable used to undo the transformation.</returns>
         public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix*CurrentTransform);
-        
 
+        /// <summary>
+        /// Sets the current matrix transformation.
+        /// </summary>
+        /// <param name="matrix">The matrix</param>
+        /// <returns>A disposable used to undo the transformation.</returns>
         PushedState PushSetTransform(Matrix matrix)
         {
             var oldMatrix = CurrentTransform;
@@ -233,7 +245,10 @@ namespace Avalonia.Media
             return new PushedState(this, PushedState.PushedStateType.Matrix, oldMatrix);
         }
 
-
+        /// <summary>
+        /// Pushes a new transform context.
+        /// </summary>
+        /// <returns>A disposable used to undo the transformation.</returns>
         public PushedState PushTransformContainer()
         {
             _transformContainers.Push(new TransformContainer(CurrentTransform, _currentContainerTransform));
@@ -242,6 +257,9 @@ namespace Avalonia.Media
             return new PushedState(this, PushedState.PushedStateType.MatrixContainer);
         }
 
+        /// <summary>
+        /// Disposes of any resources held by the <see cref="DrawingContext"/>.
+        /// </summary>
         public void Dispose()
         {
             while (_states.Count != 0)

+ 10 - 1
src/Avalonia.SceneGraph/Media/FormattedText.cs

@@ -33,7 +33,16 @@ namespace Avalonia.Media
         {
             Contract.Requires<ArgumentNullException>(text != null);
             Contract.Requires<ArgumentNullException>(fontFamilyName != null);
-            Contract.Requires<ArgumentException>(fontSize > 0);
+
+            if (fontSize <= 0)
+            {
+                throw new ArgumentException("FontSize must be greater than 0");
+            }
+
+            if (fontWeight <= 0)
+            {
+                throw new ArgumentException("FontWeight must be greater than 0");
+            }
 
             Text = text;
             FontFamilyName = fontFamilyName;

+ 1 - 0
src/Avalonia.SceneGraph/Media/Imaging/RenderTargetBitmap.cs

@@ -4,6 +4,7 @@
 using System;
 using Avalonia.Platform;
 using Avalonia.Rendering;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Media.Imaging
 {

+ 1 - 0
src/Avalonia.SceneGraph/Media/MatrixTransform.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Media
 {

+ 2 - 6
src/Avalonia.SceneGraph/Media/PathMarkupParser.cs

@@ -32,18 +32,14 @@ namespace Avalonia.Media
             {'1', FillRule.NonZero }
         };
 
-        private StreamGeometry _geometry;
-
         private readonly StreamGeometryContext _context;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PathMarkupParser"/> class.
         /// </summary>
-        /// <param name="geometry">The geometry in which the path should be stored.</param>
-        /// <param name="context">The context for <paramref name="geometry"/>.</param>
-        public PathMarkupParser(StreamGeometry geometry, StreamGeometryContext context)
+        /// <param name="context">The context for the geometry.</param>
+        public PathMarkupParser(StreamGeometryContext context)
         {
-            _geometry = geometry;
             _context = context;
         }
 

+ 1 - 0
src/Avalonia.SceneGraph/Media/RotateTransform.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Media
 {

+ 1 - 0
src/Avalonia.SceneGraph/Media/ScaleTransform.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Media
 {

+ 1 - 1
src/Avalonia.SceneGraph/Media/StreamGeometry.cs

@@ -39,7 +39,7 @@ namespace Avalonia.Media
 
             using (StreamGeometryContext ctx = result.Open())
             {
-                PathMarkupParser parser = new PathMarkupParser(result, ctx);
+                PathMarkupParser parser = new PathMarkupParser(ctx);
                 parser.Parse(s);
                 return result;
             }

+ 1 - 0
src/Avalonia.SceneGraph/Media/Transform.cs

@@ -3,6 +3,7 @@
 
 using System;
 using Avalonia.Animation;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Media
 {

+ 1 - 0
src/Avalonia.SceneGraph/Media/TranslateTransform.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using Avalonia.VisualTree;
 
 namespace Avalonia.Media
 {

+ 1 - 0
src/Avalonia.Styling/Avalonia.Styling.csproj

@@ -38,6 +38,7 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Styling.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\Shared\SharedAssemblyInfo.cs">

+ 3 - 3
src/Avalonia.Styling/Styling/SelectorMatch.cs

@@ -6,12 +6,12 @@ using System;
 namespace Avalonia.Styling
 {
     /// <summary>
-    /// Holds the result of a <see cref="FuncSelector"/> match.
+    /// Holds the result of a <see cref="Selector"/> match.
     /// </summary>
     /// <remarks>
     /// There are two types of selectors - ones whose match can never change for a particular
-    /// control (such as <see cref="Selectors.OfType{T}(FuncSelector)"/>) and ones whose result can
-    /// change over time (such as <see cref="Selectors.Class(FuncSelector, string)"/>. For the first
+    /// control (such as <see cref="Selectors.OfType(Selector, Type)"/>) and ones whose result can
+    /// change over time (such as <see cref="Selectors.Class(Selector, string)"/>. For the first
     /// category of selectors, the value of <see cref="ImmediateResult"/> will be set but for the
     /// second, <see cref="ImmediateResult"/> will be null and <see cref="ObservableResult"/> will
     /// hold an observable which tracks the match.

+ 0 - 1
src/Avalonia.Styling/Styling/Style.cs

@@ -82,7 +82,6 @@ namespace Avalonia.Styling
         {
             if (Selector != null)
             {
-                var description = "Style " + Selector.ToString();
                 var match = Selector.Match(control);
 
                 if (match.ImmediateResult != false)

+ 1 - 0
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@@ -36,6 +36,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Themes.Default.XML</DocumentationFile>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <!-- A reference to the entire .NET Framework is automatically included -->

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

@@ -372,7 +372,10 @@ namespace Avalonia.Cairo.Media
         public void PopOpacityMask()
         {
             _context.PopGroupToSource();
-            _context.Mask(_maskStack.Pop().PlatformBrush);
+			var brushImpl = _maskStack.Pop ();
+
+            _context.Mask(brushImpl.PlatformBrush);
+			brushImpl.Dispose ();
         }
     }
 }

+ 2 - 0
src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs

@@ -14,7 +14,9 @@ namespace Avalonia.Gtk
 {
     class EmbeddableImpl : WindowImplBase, IEmbeddableWindowImpl
     {
+#pragma warning disable CS0067 // Method not used
         public event Action LostFocus;
+#pragma warning restore CS0067
 
         public EmbeddableImpl(DrawingArea area) : base(area)
         {

+ 3 - 1
src/Gtk/Avalonia.Gtk/WindowImplBase.cs

@@ -134,7 +134,7 @@ namespace Avalonia.Gtk
 
         public void Invalidate(Rect rect)
         {
-            if (_window.GdkWindow != null)
+            if (_window?.GdkWindow != null)
                 _window.GdkWindow.InvalidateRect(
                     new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true);
         }
@@ -306,7 +306,9 @@ namespace Avalonia.Gtk
 
         public void Dispose()
         {
+            _window.Hide();
             _window.Dispose();
+            _window = null;
         }
     }
 }

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

@@ -8,14 +8,14 @@ using System.Reflection;
 using System.Text;
 using OmniXaml;
 using Avalonia.Platform;
+using Avalonia.Markup.Xaml.Context;
+using Avalonia.Markup.Xaml.Styling;
+using OmniXaml.ObjectAssembler;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml.Data;
 
 namespace Avalonia.Markup.Xaml
 {
-    using Context;
-    using Controls;
-    using Data;
-    using OmniXaml.ObjectAssembler;
-    using System.Linq;
     /// <summary>
     /// Loads XAML for a avalonia application.
     /// </summary>
@@ -47,7 +47,7 @@ namespace Avalonia.Markup.Xaml
         /// </summary>
         /// <remarks>
         /// TODO: Making this internal for now as I'm not sure that this is the correct
-        /// thing to do, but its needd by <see cref="StyleInclude"/> to get the URL of
+        /// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
         /// the currently loading XAML file, as we can't use the OmniXAML parsing context
         /// there. Maybe we need a way to inject OmniXAML context into the objects its
         /// constructing?

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/OmniXAML

@@ -1 +1 @@
-Subproject commit b122549406107170bbe6e67c0d6a1a4252beef77
+Subproject commit 544af79d218127b4174da4be19896c5ca78eaa5d

+ 6 - 4
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@@ -36,12 +36,14 @@
     <WarningLevel>4</WarningLevel>
     <DocumentationFile>bin\Release\Avalonia.Markup.XML</DocumentationFile>
     <NoWarn>CS1591</NoWarn>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
       <Link>Properties\SharedAssemblyInfo.cs</Link>
     </Compile>
-    <Compile Include="Data\MarkupBindingChainNullException.cs" />
+    <Compile Include="Data\StreamNode.cs" />
+    <Compile Include="Data\MarkupBindingChainException.cs" />
     <Compile Include="Data\CommonPropertyNames.cs" />
     <Compile Include="Data\EmptyExpressionNode.cs" />
     <Compile Include="Data\ExpressionNodeBuilder.cs" />
@@ -62,9 +64,9 @@
     <Compile Include="Data\Parsers\IdentifierParser.cs" />
     <Compile Include="Data\Parsers\ExpressionParser.cs" />
     <Compile Include="Data\Parsers\Reader.cs" />
-    <Compile Include="Data\Plugins\ObservableValuePlugin.cs" />
-    <Compile Include="Data\Plugins\TaskValuePlugin.cs" />
-    <Compile Include="Data\Plugins\IValuePlugin.cs" />
+    <Compile Include="Data\Plugins\ObservableStreamPlugin.cs" />
+    <Compile Include="Data\Plugins\TaskStreamPlugin.cs" />
+    <Compile Include="Data\Plugins\IStreamPlugin.cs" />
     <Compile Include="Data\Plugins\PropertyAccessorBase.cs" />
     <Compile Include="Data\Plugins\PropertyError.cs" />
     <Compile Include="Data\Plugins\DataValidatiorBase.cs" />

+ 14 - 43
src/Markup/Avalonia.Markup/Data/ExpressionNode.cs

@@ -17,7 +17,6 @@ namespace Avalonia.Markup.Data
         private WeakReference _target = UnsetReference;
         private IDisposable _valueSubscription;
         private IObserver<object> _observer;
-        private IDisposable _valuePluginSubscription;
 
         public abstract string Description { get; }
         public ExpressionNode Next { get; set; }
@@ -37,7 +36,6 @@ namespace Avalonia.Markup.Data
                 {
                     _valueSubscription?.Dispose();
                     _valueSubscription = null;
-                    _valuePluginSubscription?.Dispose();
                     _target = value;
 
                     if (running)
@@ -63,8 +61,6 @@ namespace Avalonia.Markup.Data
             {
                 _valueSubscription?.Dispose();
                 _valueSubscription = null;
-                _valuePluginSubscription?.Dispose();
-                _valuePluginSubscription = null;
                 nextSubscription?.Dispose();
                 _observer = null;
             });
@@ -92,7 +88,7 @@ namespace Avalonia.Markup.Data
 
         protected virtual void NextValueChanged(object value)
         {
-            var bindingBroken = BindingNotification.ExtractError(value) as MarkupBindingChainNullException;
+            var bindingBroken = BindingNotification.ExtractError(value) as MarkupBindingChainException;
             bindingBroken?.AddNode(Description);
             _observer.OnNext(value);
         }
@@ -115,25 +111,22 @@ namespace Avalonia.Markup.Data
                 source = StartListeningCore(_target);
             }
 
-            return source.Subscribe(TargetValueChanged);
+            return source.Subscribe(ValueChanged);
         }
 
-        private void TargetValueChanged(object value)
+        private void ValueChanged(object value)
         {
             var notification = value as BindingNotification;
 
             if (notification == null)
             {
-                if (!HandleSpecialValue(value))
+                if (Next != null)
                 {
-                    if (Next != null)
-                    {
-                        Next.Target = new WeakReference(value);
-                    }
-                    else
-                    {
-                        _observer.OnNext(value);
-                    }
+                    Next.Target = new WeakReference(value);
+                }
+                else
+                {
+                    _observer.OnNext(value);
                 }
             }
             else
@@ -144,44 +137,22 @@ namespace Avalonia.Markup.Data
                 }
                 else if (notification.HasValue)
                 {
-                    if (!HandleSpecialValue(notification.Value))
+                    if (Next != null)
                     {
-                        if (Next != null)
-                        {
-                            Next.Target = new WeakReference(notification.Value);
-                        }
-                        else
-                        {
-                            _observer.OnNext(value);
-                        }
+                        Next.Target = new WeakReference(notification.Value);
                     }
-                }
-            }
-        }
-
-        private bool HandleSpecialValue(object value)
-        {
-            if (_valuePluginSubscription == null)
-            {
-                var reference = new WeakReference(value);
-
-                foreach (var plugin in ExpressionObserver.ValueHandlers)
-                {
-                    if (plugin.Match(reference))
+                    else
                     {
-                        _valuePluginSubscription = plugin.Start(reference)?.Subscribe(TargetValueChanged);
-                        return true;
+                        _observer.OnNext(value);
                     }
                 }
             }
-
-            return false;
         }
 
         private BindingNotification TargetNullNotification()
         {
             return new BindingNotification(
-                new MarkupBindingChainNullException(),
+                new MarkupBindingChainException("Null value"),
                 BindingErrorType.Error,
                 AvaloniaProperty.UnsetValue);
         }

+ 7 - 7
src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs

@@ -41,14 +41,14 @@ namespace Avalonia.Markup.Data
             };
 
         /// <summary>
-        /// An ordered collection of value handlers that can be used to customize the handling
-        /// of certain values.
+        /// An ordered collection of stream plugins that can be used to customize the behavior
+        /// of the '^' stream binding operator.
         /// </summary>
-        public static readonly IList<IValuePlugin> ValueHandlers =
-            new List<IValuePlugin>
+        public static readonly IList<IStreamPlugin> StreamHandlers =
+            new List<IStreamPlugin>
             {
-                new TaskValuePlugin(),
-                new ObservableValuePlugin(),
+                new TaskStreamPlugin(),
+                new ObservableStreamPlugin(),
             };
 
         private static readonly object UninitializedValue = new object();
@@ -235,7 +235,7 @@ namespace Avalonia.Markup.Data
             }
             else
             {
-                var broken = BindingNotification.ExtractError(o) as MarkupBindingChainNullException;
+                var broken = BindingNotification.ExtractError(o) as MarkupBindingChainException;
 
                 if (broken != null)
                 {

+ 42 - 0
src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs

@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Data;
+
+namespace Avalonia.Markup.Data
+{
+    internal class MarkupBindingChainException : BindingChainException
+    {
+        private IList<string> _nodes = new List<string>();
+
+        public MarkupBindingChainException(string message)
+            : base(message)
+        {
+        }
+
+        public MarkupBindingChainException(string message, string node)
+            : base(message)
+        {
+            AddNode(node);
+        }
+
+        public MarkupBindingChainException(string message, string expression, string expressionNullPoint)
+            : base(message, expression, expressionNullPoint)
+        {
+            _nodes = null;
+        }
+
+        public bool HasNodes => _nodes.Count > 0;
+        public void AddNode(string node) => _nodes.Add(node);
+
+        public void Commit(string expression)
+        {
+            Expression = expression;
+            ExpressionErrorPoint = string.Join(".", _nodes.Reverse())
+                .Replace(".!", "!")
+                .Replace(".[", "[")
+                .Replace(".^", "^");
+            _nodes = null;
+        }
+    }
+}

+ 0 - 33
src/Markup/Avalonia.Markup/Data/MarkupBindingChainNullException.cs

@@ -1,33 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Avalonia.Data;
-
-namespace Avalonia.Markup.Data
-{
-    internal class MarkupBindingChainNullException : BindingChainNullException
-    {
-        private IList<string> _nodes = new List<string>();
-
-        public MarkupBindingChainNullException()
-        {
-        }
-
-        public MarkupBindingChainNullException(string expression, string expressionNullPoint)
-            : base(expression, expressionNullPoint)
-        {
-            _nodes = null;
-        }
-
-        public bool HasNodes => _nodes.Count > 0;
-        public void AddNode(string node) => _nodes.Add(node);
-
-        public void Commit(string expression)
-        {
-            Expression = expression;
-            ExpressionNullPoint = string.Join(".", _nodes.Reverse())
-                .Replace(".!", "!")
-                .Replace(".[", "[");
-            _nodes = null;
-        }
-    }
-}

+ 10 - 0
src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs

@@ -87,6 +87,11 @@ namespace Avalonia.Markup.Data.Parsers
             {
                 return State.BeforeMember;
             }
+            else if (ParseStreamOperator(r))
+            {
+                nodes.Add(new StreamNode());
+                return State.AfterMember;
+            }
             else
             {
                 var args = ArgumentListParser.Parse(r, '[', ']');
@@ -161,6 +166,11 @@ namespace Avalonia.Markup.Data.Parsers
             return !r.End && r.TakeIf('(');
         }
 
+        private static bool ParseStreamOperator(Reader r)
+        {
+            return !r.End && r.TakeIf('^');
+        }
+
         private enum State
         {
             Start,

+ 2 - 2
src/Markup/Avalonia.Markup/Data/Plugins/IValuePlugin.cs → src/Markup/Avalonia.Markup/Data/Plugins/IStreamPlugin.cs

@@ -6,9 +6,9 @@ using System;
 namespace Avalonia.Markup.Data.Plugins
 {
     /// <summary>
-    /// Defines how values are observed by an <see cref="ExpressionObserver"/>.
+    /// Defines a plugin that handles the '^' stream binding operator.
     /// </summary>
-    public interface IValuePlugin
+    public interface IStreamPlugin
     {
         /// <summary>
         /// Checks whether this plugin handles the specified value.

+ 3 - 15
src/Markup/Avalonia.Markup/Data/Plugins/ObservableValuePlugin.cs → src/Markup/Avalonia.Markup/Data/Plugins/ObservableStreamPlugin.cs

@@ -2,32 +2,20 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Reactive.Linq;
-using System.Reactive.Subjects;
-using System.Reflection;
-using System.Threading.Tasks;
-using System.Windows.Input;
-using Avalonia.Data;
 
 namespace Avalonia.Markup.Data.Plugins
 {
     /// <summary>
-    /// Handles binding to <see cref="IObservable{T}"/>s in an <see cref="ExpressionObserver"/>.
+    /// Handles binding to <see cref="IObservable{T}"/>s for the '^' stream binding operator.
     /// </summary>
-    public class ObservableValuePlugin : IValuePlugin
+    public class ObservableStreamPlugin : IStreamPlugin
     {
         /// <summary>
         /// Checks whether this plugin handles the specified value.
         /// </summary>
         /// <param name="reference">A weak reference to the value.</param>
         /// <returns>True if the plugin can handle the value; otherwise false.</returns>
-        public virtual bool Match(WeakReference reference)
-        {
-            var target = reference.Target;
-
-            // ReactiveCommand is an IObservable but we want to bind to it, not its value.
-            return target is IObservable<object> && !(target is ICommand);
-        }
+        public virtual bool Match(WeakReference reference) => reference.Target is IObservable<object>;
 
         /// <summary>
         /// Starts producing output based on the specified value.

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

@@ -12,9 +12,9 @@ using Avalonia.Data;
 namespace Avalonia.Markup.Data.Plugins
 {
     /// <summary>
-    /// Handles binding to <see cref="Task"/>s in an <see cref="ExpressionObserver"/>.
+    /// Handles binding to <see cref="Task"/>s for the '^' stream binding operator.
     /// </summary>
-    public class TaskValuePlugin : IValuePlugin
+    public class TaskStreamPlugin : IStreamPlugin
     {
         /// <summary>
         /// Checks whether this plugin handles the specified value.

+ 31 - 0
src/Markup/Avalonia.Markup/Data/StreamNode.cs

@@ -0,0 +1,31 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Globalization;
+using Avalonia.Data;
+using System.Reactive.Linq;
+
+namespace Avalonia.Markup.Data
+{
+    internal class StreamNode : ExpressionNode
+    {
+        public override string Description => "^";
+
+        protected override IObservable<object> StartListeningCore(WeakReference reference)
+        {
+            foreach (var plugin in ExpressionObserver.StreamHandlers)
+            {
+                if (plugin.Match(reference))
+                {
+                    return plugin.Start(reference);
+                }
+            }
+
+            // TODO: Improve error.
+            return Observable.Return(new BindingNotification(
+                new MarkupBindingChainException("Stream operator applied to unsupported type", Description),
+                BindingErrorType.Error));
+        }
+    }
+}

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

@@ -20,6 +20,12 @@ namespace Avalonia.Shared.PlatformSupport
 
         private AssemblyDescriptor _defaultAssembly;
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AssetLoader"/> class.
+        /// </summary>
+        /// <param name="assembly">
+        /// The default assembly from which to load assets for which no assembly is specified.
+        /// </param>
         public AssetLoader(Assembly assembly = null)
         {
             if (assembly == null)
@@ -28,6 +34,10 @@ namespace Avalonia.Shared.PlatformSupport
                 _defaultAssembly = new AssemblyDescriptor(assembly);
         }
 
+        /// <summary>
+        /// Sets the default assembly from which to load assets for which no assembly is specified.
+        /// </summary>
+        /// <param name="assembly">The default assembly.</param>
         public void SetDefaultAssembly(Assembly assembly)
         {
             _defaultAssembly = new AssemblyDescriptor(assembly);
@@ -73,8 +83,6 @@ namespace Avalonia.Shared.PlatformSupport
         {
             if (!uri.IsAbsoluteUri || uri.Scheme == "resm")
             {
-                var uriQueryParams = ParseQueryString(uri);
-                var baseUriQueryParams = uri != null ? ParseQueryString(uri) : null;
                 var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultAssembly;
 
                 if (asm == null && _defaultAssembly == null)

+ 7 - 0
src/Skia/Avalonia.Skia.Android.TestApp/App.cs

@@ -0,0 +1,7 @@
+
+namespace Avalonia.Skia.Android.TestApp
+{
+    public class App : Application
+    {
+    }
+}

+ 24 - 8
src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj

@@ -20,22 +20,19 @@
     <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
+    <DebugSymbols>True</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
+    <AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
     <AndroidLinkMode>None</AndroidLinkMode>
-    <AndroidLinkSkip />
-    <EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
+    <EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
     <BundleAssemblies>False</BundleAssemblies>
     <AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
-    <AndroidSupportedAbis>armeabi-v7a,x86</AndroidSupportedAbis>
-    <AndroidStoreUncompressedFileExtensions />
-    <MandroidI18n />
+    <AndroidSupportedAbis>armeabi;armeabi-v7a;x86</AndroidSupportedAbis>
     <Debugger>Xamarin</Debugger>
     <AndroidEnableMultiDex>False</AndroidEnableMultiDex>
     <DevInstrumentationEnabled>True</DevInstrumentationEnabled>
@@ -48,7 +45,17 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
-    <AndroidLinkMode>SdkOnly</AndroidLinkMode>
+    <AndroidLinkMode>Full</AndroidLinkMode>
+    <EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
+    <BundleAssemblies>False</BundleAssemblies>
+    <AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
+    <Debugger>Xamarin</Debugger>
+    <AotAssemblies>False</AotAssemblies>
+    <EnableLLVM>False</EnableLLVM>
+    <AndroidEnableMultiDex>False</AndroidEnableMultiDex>
+    <EnableProguard>False</EnableProguard>
+    <DebugSymbols>False</DebugSymbols>
+    <AndroidSupportedAbis>armeabi;armeabi-v7a;x86</AndroidSupportedAbis>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Mono.Android" />
@@ -61,6 +68,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="App.cs" />
     <Compile Include="MainActivity.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Resources\Resource.Designer.cs" />
@@ -70,6 +78,10 @@
     <AndroidResource Include="Resources\layout\Main.axml" />
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\..\Android\Avalonia.Android\Avalonia.Android.csproj">
+      <Project>{7b92af71-6287-4693-9dcb-bd5b6e927e23}</Project>
+      <Name>Avalonia.Android</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj">
       <Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
       <Name>Avalonia.Animation</Name>
@@ -82,6 +94,10 @@
       <Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
       <Name>Avalonia.Controls</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
+      <Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project>
+      <Name>Avalonia.DotNetFrameworkRuntime</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
       <Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
       <Name>Avalonia.Input</Name>

+ 16 - 9
src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs

@@ -1,15 +1,9 @@
-using System;
 using Android.App;
-using Android.Content;
-using Android.Graphics;
-using Android.Runtime;
-using Android.Views;
-using Android.Widget;
 using Android.OS;
-using Android.Util;
-using Avalonia.Media;
-using Avalonia.Platform;
+using Android.Views;
 using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
 
 namespace Avalonia.Skia.Android.TestApp
 {
@@ -20,6 +14,19 @@ namespace Avalonia.Skia.Android.TestApp
         protected override void OnCreate(Bundle bundle)
         {
             base.OnCreate(bundle);
+
+            App app;
+            if (Avalonia.Application.Current != null)
+                app = (App)Avalonia.Application.Current;
+            else
+            {
+                app = new App();
+                AppBuilder.Configure(app)
+                    .UseAndroid()
+                    .UseSkia()
+                    .SetupWithoutStarting();
+            }
+
             SetContentView(new MainView(this));
         }
 

+ 2 - 0
src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs

@@ -26,6 +26,8 @@ namespace Avalonia.Skia.Android.TestApp
 		
 		public static void UpdateIdValues()
 		{
+			global::Avalonia.Android.Resource.String.ApplicationName = global::Avalonia.Skia.Android.TestApp.Resource.String.ApplicationName;
+			global::Avalonia.Android.Resource.String.Hello = global::Avalonia.Skia.Android.TestApp.Resource.String.Hello;
 		}
 		
 		public partial class Attribute

+ 3 - 1
src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj

@@ -16,6 +16,7 @@
     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
     <AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
     <TargetFrameworkVersion>v4.4</TargetFrameworkVersion>
+    <ShouldIncludeNativeSkiaSharp>True</ShouldIncludeNativeSkiaSharp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -40,7 +41,7 @@
     <Reference Include="Mono.Android" />
     <Reference Include="mscorlib" />
     <Reference Include="SkiaSharp, Version=1.54.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
-      <HintPath>..\..\..\packages\SkiaSharp.1.54.0\lib\MonoAndroid\SkiaSharp.dll</HintPath>
+      <HintPath>..\..\..\packages\SkiaSharp.1.54.1\lib\MonoAndroid\SkiaSharp.dll</HintPath>
       <Private>True</Private>
     </Reference>
     <Reference Include="System" />
@@ -87,6 +88,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AndroidRenderTarget.cs" />
+    <Compile Include="RenderTarget.cs" />
     <Compile Include="SkiaRenderView.cs" />
     <Compile Include="SkiaView.cs" />
   </ItemGroup>

Some files were not shown because too many files changed in this diff