Browse Source

Merge remote-tracking branch 'AvaloniaUI/master' into linq-expression-expressionobserver

Jeremy Koritzinsky 7 years ago
parent
commit
775f9e7929
96 changed files with 1162 additions and 455 deletions
  1. 2 3
      Avalonia.sln
  2. 133 128
      build.cake
  3. 1 16
      build/XUnit.props
  4. 15 0
      cake.config
  5. 2 0
      packages.cake
  6. 0 2
      parameters.cake
  7. 2 2
      readme.md
  8. 2 7
      samples/ControlCatalog.Android/Resources/Resource.Designer.cs
  9. 2 2
      samples/ControlCatalog/DecoratedWindow.xaml.cs
  10. 0 1
      samples/interop/Direct3DInteropSample/MainWindow.cs
  11. 4 1
      src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs
  12. 0 2
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
  13. 2 5
      src/Android/Avalonia.Android/Resources/Resource.Designer.cs
  14. 2 7
      src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
  15. 1 1
      src/Avalonia.Animation/AnimatorKeyFrame.cs
  16. 6 0
      src/Avalonia.Base/Data/Core/ExpressionNode.cs
  17. 2 2
      src/Avalonia.Base/Data/Core/ExpressionObserver.cs
  18. 0 15
      src/Avalonia.Base/Data/Core/ISettableNode.cs
  19. 12 5
      src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
  20. 38 0
      src/Avalonia.Base/Data/Core/SettableNode.cs
  21. 1 10
      src/Avalonia.Controls/AppBuilderBase.cs
  22. 1 1
      src/Avalonia.Controls/AutoCompleteBox.cs
  23. 39 56
      src/Avalonia.Controls/Calendar/Calendar.cs
  24. 1 1
      src/Avalonia.Controls/Calendar/CalendarDateRange.cs
  25. 15 16
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  26. 1 1
      src/Avalonia.Controls/Calendar/DatePicker.cs
  27. 7 11
      src/Avalonia.Controls/Design.cs
  28. 6 7
      src/Avalonia.Controls/DropDownItem.cs
  29. 1 1
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
  30. 5 0
      src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
  31. 2 2
      src/Avalonia.Controls/Platform/InProcessDragSource.cs
  32. 30 1
      src/Avalonia.Controls/Presenters/CarouselPresenter.cs
  33. 16 0
      src/Avalonia.Controls/Primitives/Popup.cs
  34. 37 0
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  35. 53 0
      src/Avalonia.Controls/Primitives/ScrollEventType.cs
  36. 15 1
      src/Avalonia.Controls/TextBox.cs
  37. 2 1
      src/Avalonia.Controls/ToolTip.cs
  38. 15 3
      src/Avalonia.Controls/Window.cs
  39. 14 0
      src/Avalonia.Controls/WindowBase.cs
  40. 1 2
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  41. 5 1
      src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs
  42. 9 1
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  43. 5 1
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  44. 4 0
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  45. 12 12
      src/Avalonia.Input/DragDropDevice.cs
  46. 4 1
      src/Avalonia.Input/DragEventArgs.cs
  47. 3 1
      src/Avalonia.Input/Raw/RawDragEvent.cs
  48. 1 3
      src/Avalonia.Remote.Protocol/TcpTransportBase.cs
  49. 1 1
      src/Avalonia.Styling/Styling/Style.cs
  50. 3 2
      src/Avalonia.Themes.Default/Calendar.xaml
  51. 1 1
      src/Avalonia.Visuals/Media/DrawingContext.cs
  52. 3 3
      src/Avalonia.Visuals/Media/FontFamily.cs
  53. 3 3
      src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs
  54. 20 0
      src/Avalonia.Visuals/Rendering/IRendererFactory.cs
  55. 1 4
      src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs
  56. 7 2
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  57. 2 0
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  58. 1 1
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  59. 5 1
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  60. 7 7
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs
  61. 5 1
      src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs
  62. 2 1
      src/Markup/Avalonia.Markup/Data/MultiBinding.cs
  63. 2 1
      src/OSX/Avalonia.MonoMac/ClipboardImpl.cs
  64. 5 4
      src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs
  65. 2 1
      src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
  66. 1 0
      src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs
  67. 48 6
      src/Skia/Avalonia.Skia/FormattedTextImpl.cs
  68. 1 0
      src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs
  69. 1 0
      src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs
  70. 13 5
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  71. 5 4
      src/Windows/Avalonia.Win32/OleDragSource.cs
  72. 34 9
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  73. 1 1
      src/Windows/Avalonia.Win32/SystemDialogImpl.cs
  74. 24 4
      src/Windows/Avalonia.Win32/WindowImpl.cs
  75. 1 1
      src/iOS/Avalonia.iOS/DisplayLinkRenderLoop.cs
  76. 5 1
      src/iOS/Avalonia.iOS/EmbeddableImpl.cs
  77. 1 2
      src/iOS/Avalonia.iOS/TopLevelImpl.cs
  78. 49 0
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
  79. 2 0
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Threading.cs
  80. 1 4
      tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs
  81. 205 1
      tests/Avalonia.Controls.UnitTests/CarouselTests.cs
  82. 59 0
      tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs
  83. 53 0
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
  84. 1 1
      tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj
  85. 8 0
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs
  86. 1 1
      tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs
  87. 1 0
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
  88. 3 6
      tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj
  89. 8 0
      tests/Avalonia.LeakTests/Properties/AssemblyInfo.cs
  90. 0 11
      tests/Avalonia.LeakTests/toolproject/tool.csproj
  91. 2 0
      tests/Avalonia.RenderTests/TestBase.cs
  92. 2 20
      tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
  93. 16 0
      tests/Avalonia.UnitTests/RuntimeInfo.cs
  94. 14 0
      tests/Avalonia.UnitTests/TestServices.cs
  95. 0 11
      tests/Avalonia.UnitTests/app.config
  96. 1 1
      tools/packages.config

+ 2 - 3
Avalonia.sln

@@ -105,9 +105,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Desktop", "s
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{52F55355-D120-42AC-8116-8410A7D602FA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.Tests", "tests\Avalonia.DesignerSupport.Tests\Avalonia.DesignerSupport.Tests.csproj", "{52F55355-D120-42AC-8116-8410A7D602FA}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DesignerSupport.TestApp", "tests\Avalonia.DesignerSupport.TestApp\Avalonia.DesignerSupport.TestApp.csproj", "{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DesignerSupport.TestApp", "tests\Avalonia.DesignerSupport.TestApp\Avalonia.DesignerSupport.TestApp.csproj", "{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VirtualizationTest", "samples\VirtualizationTest\VirtualizationTest.csproj", "{FBCAF3D0-2808-4934-8E96-3F607594517B}"
 EndProject
@@ -141,7 +141,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
 		build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
 		build\Moq.props = build\Moq.props
 		build\NetCore.props = build\NetCore.props
-		build\NetFX.props = build\NetFX.props
 		build\ReactiveUI.props = build\ReactiveUI.props
 		build\Rx.props = build\Rx.props
 		build\SampleApp.props = build\SampleApp.props

+ 133 - 128
build.cake

@@ -10,7 +10,8 @@
 // TOOLS
 ///////////////////////////////////////////////////////////////////////////////
 
-#tool "nuget:?package=xunit.runner.console&version=2.3.0-beta5-build3769"
+#tool "nuget:?package=xunit.runner.console&version=2.3.1"
+#tool "nuget:?package=JetBrains.dotMemoryUnit&version=3.0.20171219.105559"
 
 ///////////////////////////////////////////////////////////////////////////////
 // USINGS
@@ -34,20 +35,31 @@ using NuGet;
 // PARAMETERS
 //////////////////////////////////////////////////////////////////////
 
-Parameters parameters = new Parameters(Context);
-Packages packages = new Packages(Context, parameters);
+class AvaloniaBuildData
+{
+    public AvaloniaBuildData(Parameters parameters, Packages packages)
+    {
+        Parameters = parameters;
+        Packages = packages;
+    }
+
+    public Parameters Parameters { get; }
+    public Packages Packages { get; }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // SETUP
 ///////////////////////////////////////////////////////////////////////////////
 
-Setup(context =>
+Setup<AvaloniaBuildData>(context =>
 {
-    Information("Building version {0} of Avalonia ({1}, {2}, {3}) using version {4} of Cake.", 
+    var parameters = new Parameters(context);
+    var buildContext = new AvaloniaBuildData(parameters, new Packages(context, parameters));
+
+    Information("Building version {0} of Avalonia ({1}, {2}) using version {3} of Cake.", 
         parameters.Version,
         parameters.Platform,
         parameters.Configuration,
-        parameters.Target,
         typeof(ICakeContext).Assembly.GetName().Version.ToString());
 
     if (parameters.IsRunningOnAppVeyor)
@@ -55,8 +67,7 @@ Setup(context =>
         Information("Repository Name: " + BuildSystem.AppVeyor.Environment.Repository.Name);
         Information("Repository Branch: " + BuildSystem.AppVeyor.Environment.Repository.Branch);
     }
-
-    Information("Target: " + parameters.Target);
+    Information("Target:" + context.TargetTask.Name);
     Information("Platform: " + parameters.Platform);
     Information("Configuration: " + parameters.Configuration);
     Information("IsLocalBuild: " + parameters.IsLocalBuild);
@@ -70,13 +81,15 @@ Setup(context =>
     Information("IsReleasable: " + parameters.IsReleasable);
     Information("IsMyGetRelease: " + parameters.IsMyGetRelease);
     Information("IsNuGetRelease: " + parameters.IsNuGetRelease);
+
+    return buildContext;
 });
 
 ///////////////////////////////////////////////////////////////////////////////
 // TEARDOWN
 ///////////////////////////////////////////////////////////////////////////////
 
-Teardown(context =>
+Teardown<AvaloniaBuildData>((context, buildContext) =>
 {
     Information("Finished running tasks.");
 });
@@ -86,19 +99,19 @@ Teardown(context =>
 ///////////////////////////////////////////////////////////////////////////////
 
 Task("Clean")
-    .Does(() =>
+    .Does<AvaloniaBuildData>(data =>
 {
-    CleanDirectories(parameters.BuildDirs);
-    CleanDirectory(parameters.ArtifactsDir);
-    CleanDirectory(parameters.NugetRoot);
-    CleanDirectory(parameters.ZipRoot);
-    CleanDirectory(parameters.BinRoot);
+    CleanDirectories(data.Parameters.BuildDirs);
+    CleanDirectory(data.Parameters.ArtifactsDir);
+    CleanDirectory(data.Parameters.NugetRoot);
+    CleanDirectory(data.Parameters.ZipRoot);
+    CleanDirectory(data.Parameters.BinRoot);
 });
 
 Task("Restore-NuGet-Packages")
     .IsDependentOn("Clean")
-    .WithCriteria(parameters.IsRunningOnWindows)
-    .Does(() =>
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsRunningOnWindows)
+    .Does<AvaloniaBuildData>(data =>
 {
     var maxRetryCount = 5;
     var toolTimeout = 2d;
@@ -115,13 +128,13 @@ Task("Restore-NuGet-Packages")
                 toolTimeout+=0.5;
             }})
         .Execute(()=> {
-                NuGetRestore(parameters.MSBuildSolution, new NuGetRestoreSettings {
+                NuGetRestore(data.Parameters.MSBuildSolution, new NuGetRestoreSettings {
                     ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
                 });
         });
 });
 
-void DotNetCoreBuild()
+void DotNetCoreBuild(Parameters parameters)
 {
     var settings = new DotNetCoreBuildSettings 
     {
@@ -137,23 +150,24 @@ void DotNetCoreBuild()
 
 Task("Build")
     .IsDependentOn("Restore-NuGet-Packages")
-    .Does(() =>
+    .Does<AvaloniaBuildData>(data =>
 {
-    if(parameters.IsRunningOnWindows)
+    if(data.Parameters.IsRunningOnWindows)
     {
-        MSBuild(parameters.MSBuildSolution, settings => {
-            settings.SetConfiguration(parameters.Configuration);
+        MSBuild(data.Parameters.MSBuildSolution, settings => {
+            settings.SetConfiguration(data.Parameters.Configuration);
             settings.SetVerbosity(Verbosity.Minimal);
-            settings.WithProperty("Platform", "\"" + parameters.Platform + "\"");
+            settings.WithProperty("Platform", "\"" + data.Parameters.Platform + "\"");
             settings.WithProperty("UseRoslynPathHack", "true");
             settings.UseToolVersion(MSBuildToolVersion.VS2017);
             settings.WithProperty("Windows", "True");
             settings.SetNodeReuse(false);
+            settings.SetMaxCpuCount(0);
         });
     }
     else
     {
-        DotNetCoreBuild();
+        DotNetCoreBuild(data.Parameters);
     }
 });
 
@@ -182,68 +196,94 @@ void RunCoreTest(string project, Parameters parameters, bool coreOnly = false)
 
 Task("Run-Unit-Tests")
     .IsDependentOn("Build")
-    .IsDependentOn("Run-Designer-Tests")
-    .IsDependentOn("Run-Render-Tests")
-    .WithCriteria(() => !parameters.SkipTests)
-    .Does(() => {
-        RunCoreTest("./tests/Avalonia.Base.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Controls.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Input.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Layout.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Markup.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Styling.UnitTests", parameters, false);
-        RunCoreTest("./tests/Avalonia.Visuals.UnitTests", parameters, false);
-        if (parameters.IsRunningOnWindows)
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests)
+    .Does<AvaloniaBuildData>(data => {
+        RunCoreTest("./tests/Avalonia.Base.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Controls.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Input.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Layout.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Markup.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Styling.UnitTests", data.Parameters, false);
+        RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data.Parameters, false);
+        if (data.Parameters.IsRunningOnWindows)
         {
-            RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", parameters, true);
+            RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data.Parameters, true);
         }
     });
 
 Task("Run-Designer-Tests")
     .IsDependentOn("Build")
-    .WithCriteria(() => !parameters.SkipTests)
-    .Does(() => {
-        RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", parameters, false);
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests)
+    .Does<AvaloniaBuildData>(data => {
+        RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", data.Parameters, false);
     });
 
 Task("Run-Render-Tests")
     .IsDependentOn("Build")
-    .WithCriteria(() => !parameters.SkipTests && parameters.IsRunningOnWindows)
-    .Does(() => {
-        RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", parameters, true);
-        RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", parameters, true);
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests && data.Parameters.IsRunningOnWindows)
+    .Does<AvaloniaBuildData>(data => {
+        RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", data.Parameters, true);
+        RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", data.Parameters, true);
     });
 
-Task("Copy-Files")
-    .IsDependentOn("Run-Unit-Tests")
+Task("Run-Leak-Tests")
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.SkipTests && data.Parameters.IsRunningOnWindows)
+    .IsDependentOn("Build")
     .Does(() =>
+    {
+        var dotMemoryUnit = Context.Tools.Resolve("dotMemoryUnit.exe");
+        var leakTestsExitCode = StartProcess(dotMemoryUnit, new ProcessSettings
+        {
+            Arguments = new ProcessArgumentBuilder()
+                .Append(Context.Tools.Resolve("xunit.console.x86.exe").FullPath)
+                .Append("--propagate-exit-code")
+                .Append("--")
+                .Append("tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"),
+            Timeout = 120000
+        });
+
+        if (leakTestsExitCode != 0)
+        {
+            throw new Exception("Leak Tests failed");
+        }
+    });
+
+Task("Run-Tests")
+    .IsDependentOn("Run-Unit-Tests")
+    .IsDependentOn("Run-Render-Tests")
+    .IsDependentOn("Run-Designer-Tests")
+    .IsDependentOn("Run-Leak-Tests");
+
+Task("Copy-Files")
+    .IsDependentOn("Run-Tests")
+    .Does<AvaloniaBuildData>(data =>
 {
-    CopyFiles(packages.BinFiles, parameters.BinRoot);
+    CopyFiles(data.Packages.BinFiles, data.Parameters.BinRoot);
 });
 
 Task("Zip-Files")
     .IsDependentOn("Copy-Files")
-    .Does(() =>
+    .Does<AvaloniaBuildData>(data =>
 {
-    Zip(parameters.BinRoot, parameters.ZipCoreArtifacts);
-
-    Zip(parameters.ZipSourceControlCatalogDesktopDirs, 
-        parameters.ZipTargetControlCatalogDesktopDirs, 
-        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
-        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + 
-        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + 
-        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + 
-        GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
+    Zip(data.Parameters.BinRoot, data.Parameters.ZipCoreArtifacts);
+
+    Zip(data.Parameters.ZipSourceControlCatalogDesktopDirs, 
+        data.Parameters.ZipTargetControlCatalogDesktopDirs, 
+        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
+        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + 
+        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + 
+        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + 
+        GetFiles(data.Parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
 });
 
 Task("Create-NuGet-Packages")
-    .IsDependentOn("Run-Unit-Tests")
+    .IsDependentOn("Run-Tests")
     .IsDependentOn("Inspect")
-    .Does(() =>
+    .Does<AvaloniaBuildData>(data =>
 {
-    foreach(var nuspec in packages.NuspecNuGetSettings)
+    foreach(var nuspec in data.Packages.NuspecNuGetSettings)
     {
         NuGetPack(nuspec);
     }
@@ -251,12 +291,12 @@ Task("Create-NuGet-Packages")
 
 Task("Publish-MyGet")
     .IsDependentOn("Create-NuGet-Packages")
-    .WithCriteria(() => !parameters.IsLocalBuild)
-    .WithCriteria(() => !parameters.IsPullRequest)
-    .WithCriteria(() => parameters.IsMainRepo)
-    .WithCriteria(() => parameters.IsMasterBranch)
-    .WithCriteria(() => parameters.IsMyGetRelease)
-    .Does(() =>
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsLocalBuild)
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsPullRequest)
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMainRepo)
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMasterBranch)
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMyGetRelease)
+    .Does<AvaloniaBuildData>(data =>
 {
     var apiKey = EnvironmentVariable("MYGET_API_KEY");
     if(string.IsNullOrEmpty(apiKey)) 
@@ -270,7 +310,7 @@ Task("Publish-MyGet")
         throw new InvalidOperationException("Could not resolve MyGet API url.");
     }
 
-    foreach(var nupkg in packages.NugetPackages)
+    foreach(var nupkg in data.Packages.NugetPackages)
     {
         NuGetPush(nupkg, new NuGetPushSettings {
             Source = apiUrl,
@@ -285,11 +325,11 @@ Task("Publish-MyGet")
 
 Task("Publish-NuGet")
     .IsDependentOn("Create-NuGet-Packages")
-    .WithCriteria(() => !parameters.IsLocalBuild)
-    .WithCriteria(() => !parameters.IsPullRequest)
-    .WithCriteria(() => parameters.IsMainRepo)
-    .WithCriteria(() => parameters.IsNuGetRelease)
-    .Does(() =>
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsLocalBuild)
+    .WithCriteria<AvaloniaBuildData>((context, data) => !data.Parameters.IsPullRequest)
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsMainRepo)
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsNuGetRelease)
+    .Does<AvaloniaBuildData>(data =>
 {
     var apiKey = EnvironmentVariable("NUGET_API_KEY");
     if(string.IsNullOrEmpty(apiKey)) 
@@ -303,7 +343,7 @@ Task("Publish-NuGet")
         throw new InvalidOperationException("Could not resolve NuGet API url.");
     }
 
-    foreach(var nupkg in packages.NugetPackages)
+    foreach(var nupkg in data.Packages.NugetPackages)
     {
         NuGetPush(nupkg, new NuGetPushSettings {
             ApiKey = apiKey,
@@ -316,48 +356,8 @@ Task("Publish-NuGet")
     Information("Publish-NuGet Task failed, but continuing with next Task...");
 });
 
-Task("Run-Leak-Tests")
-    .WithCriteria(parameters.IsRunningOnWindows)
-    .IsDependentOn("Build")
-    .Does(() =>
-    {
-        DotNetCoreRestore("tests\\Avalonia.LeakTests\\toolproject\\tool.csproj");
-        DotNetBuild("tests\\Avalonia.LeakTests\\toolproject\\tool.csproj", settings => settings.SetConfiguration("Release"));
-        var report = "tests\\Avalonia.LeakTests\\bin\\Release\\report.xml";
-        if(System.IO.File.Exists(report))
-            System.IO.File.Delete(report);
-
-        var toolXunitConsoleX86 = Context.Tools.Resolve("xunit.console.x86.exe").FullPath;
-        var proc = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
-        {
-            FileName="tests\\Avalonia.LeakTests\\toolproject\\bin\\dotMemoryUnit.exe",
-            Arguments="-targetExecutable=\"" + toolXunitConsoleX86 + "\" -returnTargetExitCode  -- tests\\Avalonia.LeakTests\\bin\\Release\\Avalonia.LeakTests.dll -xml tests\\Avalonia.LeakTests\\bin\\Release\\report.xml ",
-            UseShellExecute = false,
-        });
-        var st = System.Diagnostics.Stopwatch.StartNew();
-        while(!proc.HasExited && !System.IO.File.Exists(report))
-        {
-            if(st.Elapsed.TotalSeconds>60)
-            {
-                Error("Timed out, probably a bug in dotMemoryUnit");
-                proc.Kill();
-                throw new Exception("dotMemory issue");
-            }
-            proc.WaitForExit(100);
-        }
-        try{
-            proc.Kill();
-        }catch{}
-        var doc =  System.Xml.Linq.XDocument.Load(report);
-        if(doc.Root.Descendants("assembly").Any(x=>x.Attribute("failed").Value.ToString() != "0"))
-        {
-            throw new Exception("Tests failed");
-        }
-
-    });
-
 Task("Inspect")
-    .WithCriteria(parameters.IsRunningOnWindows)
+    .WithCriteria<AvaloniaBuildData>((context, data) => data.Parameters.IsRunningOnWindows)
     .IsDependentOn("Restore-NuGet-Packages")
     .Does(() =>
     {
@@ -366,8 +366,13 @@ Task("Inspect")
             "src\\markup\\avalonia.markup.xaml\\portablexaml\\portable.xaml.github"};
         Information("Running code inspections");
         
-        StartProcess(Context.Tools.Resolve("inspectcode.exe"),
-            new ProcessSettings{ Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln" });
+        var exitCode = StartProcess(Context.Tools.Resolve("inspectcode.exe"),
+            new ProcessSettings
+            {
+                Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln",
+                RedirectStandardOutput = true
+            });
+
         Information("Analyzing report");
         var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml"));
         var failBuild = false;
@@ -395,23 +400,23 @@ Task("Inspect")
 Task("Package")
   .IsDependentOn("Create-NuGet-Packages");
 
-Task("Default").Does(() =>
-{
-    if(parameters.IsRunningOnWindows)
-        RunTarget("Package");
-    else
-        RunTarget("Run-Unit-Tests");
-});
 Task("AppVeyor")
   .IsDependentOn("Zip-Files")
   .IsDependentOn("Publish-MyGet")
   .IsDependentOn("Publish-NuGet");
 
 Task("Travis")
-  .IsDependentOn("Run-Unit-Tests");
+  .IsDependentOn("Run-Tests");
 
 ///////////////////////////////////////////////////////////////////////////////
 // EXECUTE
 ///////////////////////////////////////////////////////////////////////////////
 
-RunTarget(parameters.Target);
+var target = Context.Argument("target", "Default");
+
+if (target == "Default")
+{
+    target = Context.IsRunningOnWindows() ? "Package" : "Run-Tests";
+}
+
+RunTarget(target);

+ 1 - 16
build/XUnit.props

@@ -9,21 +9,6 @@
     <PackageReference Include="xunit.runner.console" Version="2.3.0" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" />
     <PackageReference Include="Xunit.SkippableFact" Version="1.3.6" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
-  </ItemGroup>
-  <PropertyGroup>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-  </PropertyGroup>
-  <Target Name="ForceGenerationOfBindingRedirects"
-          AfterTargets="ResolveAssemblyReferences"
-          BeforeTargets="GenerateBindingRedirects"
-          Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
-    <PropertyGroup>
-      <!-- Needs to be set in a target because it has to be set after the initial evaluation in the common targets -->
-      <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
-    </PropertyGroup>
-  </Target>
-  <Import Project="$(MSBuildThisFileDirectory)\NetFX.props" />
 </Project>

+ 15 - 0
cake.config

@@ -0,0 +1,15 @@
+; This is the default configuration file for Cake.
+; This file was downloaded from https://github.com/cake-build/resources
+
+[Nuget]
+Source=https://api.nuget.org/v3/index.json
+UseInProcessClient=true
+LoadDependencies=false
+
+[Paths]
+Tools=./tools
+Addins=./tools/Addins
+Modules=./tools/Modules
+
+[Settings]
+SkipVerification=false

+ 2 - 0
packages.cake

@@ -120,6 +120,7 @@ public class Packages
         var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
         var SharpDXDirect3D9Version = packageVersions["SharpDX.Direct3D9"].FirstOrDefault().Item1;
         var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1;
+        var SystemComponentModelAnnotationsVersion = packageVersions["System.ComponentModel.Annotations"].FirstOrDefault().Item1;
 
         context.Information("Package: Serilog, version: {0}", SerilogVersion);
         context.Information("Package: Sprache, version: {0}", SpracheVersion);
@@ -238,6 +239,7 @@ public class Packages
                     new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
                     new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion },
                     new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version },
+                    new NuSpecDependency() { Id = "System.ComponentModel.Annotations", Version = SystemComponentModelAnnotationsVersion },
                     //.NET Core
                     new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp2.0", Version = "4.3.0" },
                     new NuSpecDependency() { Id = "Microsoft.Extensions.DependencyModel", TargetFramework = "netcoreapp2.0", Version = "1.1.0" },

+ 0 - 2
parameters.cake

@@ -1,6 +1,5 @@
 public class Parameters
 {
-    public string Target { get; private set; }
     public string Platform { get; private set; }
     public string Configuration { get; private set; }
     public bool SkipTests { get; private set; }
@@ -43,7 +42,6 @@ public class Parameters
         var buildSystem = context.BuildSystem();
 
         // ARGUMENTS
-        Target = context.Argument("target", "Default");
         Platform = context.Argument("platform", "Any CPU");
         Configuration = context.Argument("configuration", "Release");
         SkipTests = context.HasArgument("skip-tests");

+ 2 - 2
readme.md

@@ -18,7 +18,7 @@ Avalonia is a WPF-inspired cross-platform XAML-based UI framework providing a fl
 
 ## Getting Started
 
-Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (<a href="http://avaloniaui.net/tutorial/images/add-dialogs.png">screenshot</a>). Now you can write code and markup that will work on multiple platforms!
+Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (<a href="http://avaloniaui.net/docs/quickstart/images/new-project-dialog.png">screenshot</a>). Now you can write code and markup that will work on multiple platforms!
 
 Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Avalonia/), [nightly](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed))
 
@@ -52,7 +52,7 @@ Please read the [contribution guidelines](http://avaloniaui.net/contributing/con
 ### Contributors
 
 This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing/contributing)].
-<a href="graphs/contributors"><img src="https://opencollective.com/Avalonia/contributors.svg?width=890&button=false" /></a>
+<a href="https://github.com/AvaloniaUI/Avalonia/graphs/contributors"><img src="https://opencollective.com/Avalonia/contributors.svg?width=890&button=false" /></a>
 
 
 ### Backers

+ 2 - 7
samples/ControlCatalog.Android/Resources/Resource.Designer.cs

@@ -28,8 +28,6 @@ namespace ControlCatalog.Android
 		{
 			global::Avalonia.Android.Resource.String.ApplicationName = global::ControlCatalog.Android.Resource.String.ApplicationName;
 			global::Avalonia.Android.Resource.String.Hello = global::ControlCatalog.Android.Resource.String.Hello;
-			global::Avalonia.Android.Resource.String.library_name = global::ControlCatalog.Android.Resource.String.library_name;
-			global::Splat.Resource.String.library_name = global::ControlCatalog.Android.Resource.String.library_name;
 		}
 		
 		public partial class Attribute
@@ -96,14 +94,11 @@ namespace ControlCatalog.Android
 		public partial class String
 		{
 			
-			// aapt resource value: 0x7f040002
-			public const int ApplicationName = 2130968578;
-			
 			// aapt resource value: 0x7f040001
-			public const int Hello = 2130968577;
+			public const int ApplicationName = 2130968577;
 			
 			// aapt resource value: 0x7f040000
-			public const int library_name = 2130968576;
+			public const int Hello = 2130968576;
 			
 			static String()
 			{

+ 2 - 2
samples/ControlCatalog/DecoratedWindow.xaml.cs

@@ -20,7 +20,7 @@ namespace ControlCatalog
             ctl.Cursor = new Cursor(cursor);
             ctl.PointerPressed += delegate
             {
-                PlatformImpl.BeginResizeDrag(edge);
+                PlatformImpl?.BeginResizeDrag(edge);
             };
         }
 
@@ -29,7 +29,7 @@ namespace ControlCatalog
             AvaloniaXamlLoader.Load(this);
             this.FindControl<Control>("TitleBar").PointerPressed += delegate
             {
-                PlatformImpl.BeginMoveDrag();
+                PlatformImpl?.BeginMoveDrag();
             };
             SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West);
             SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East);

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

@@ -88,7 +88,6 @@ namespace Direct3DInteropSample
             context.ClearDepthStencilView(depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
             context.ClearRenderTargetView(renderView, Color.White);
 
-            var time = 50;
             // Update WorldViewProj Matrix
             var worldViewProj = Matrix.RotationX((float) _model.RotationX) * Matrix.RotationY((float) _model.RotationY) *
                                 Matrix.RotationZ((float) _model.RotationZ)

+ 4 - 1
src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs

@@ -110,7 +110,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         {
             //Not supported
         }
-        
 
+        public void SetTopmost(bool value)
+        {
+            //Not supported
+        }
     }
 }

+ 0 - 2
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs

@@ -126,8 +126,6 @@ namespace Avalonia.Android.Platform.Specific.Helpers
             return e.Action != MotionEventActions.Up;
         }
 
-        private Paint _paint;
-
         public void Dispose()
         {
             HandleEvents = false;

+ 2 - 5
src/Android/Avalonia.Android/Resources/Resource.Designer.cs

@@ -40,14 +40,11 @@ namespace Avalonia.Android
 		public partial class String
 		{
 			
-			// aapt resource value: 0x7f020002
-			public static int ApplicationName = 2130837506;
-			
 			// aapt resource value: 0x7f020001
-			public static int Hello = 2130837505;
+			public static int ApplicationName = 2130837505;
 			
 			// aapt resource value: 0x7f020000
-			public static int library_name = 2130837504;
+			public static int Hello = 2130837504;
 			
 			static String()
 			{

+ 2 - 7
src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs

@@ -28,8 +28,6 @@ namespace Avalonia.AndroidTestApplication
 		{
 			global::Avalonia.Android.Resource.String.ApplicationName = global::Avalonia.AndroidTestApplication.Resource.String.ApplicationName;
 			global::Avalonia.Android.Resource.String.Hello = global::Avalonia.AndroidTestApplication.Resource.String.Hello;
-			global::Avalonia.Android.Resource.String.library_name = global::Avalonia.AndroidTestApplication.Resource.String.library_name;
-			global::Splat.Resource.String.library_name = global::Avalonia.AndroidTestApplication.Resource.String.library_name;
 		}
 		
 		public partial class Attribute
@@ -64,14 +62,11 @@ namespace Avalonia.AndroidTestApplication
 		public partial class String
 		{
 			
-			// aapt resource value: 0x7f030002
-			public const int ApplicationName = 2130903042;
-			
 			// aapt resource value: 0x7f030001
-			public const int Hello = 2130903041;
+			public const int ApplicationName = 2130903041;
 			
 			// aapt resource value: 0x7f030000
-			public const int library_name = 2130903040;
+			public const int Hello = 2130903040;
 			
 			static String()
 			{

+ 1 - 1
src/Avalonia.Animation/AnimatorKeyFrame.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Animation
 {
     /// <summary>
     /// Defines a KeyFrame that is used for
-    /// <see cref="Animators"/> objects.
+    /// <see cref="Animator{T}"/> objects.
     /// </summary>
     public class AnimatorKeyFrame
     {

+ 6 - 0
src/Avalonia.Base/Data/Core/ExpressionNode.cs

@@ -11,6 +11,7 @@ namespace Avalonia.Data.Core
 {
     public abstract class ExpressionNode : ISubject<object>
     {
+        private static readonly object CacheInvalid = new object();
         protected static readonly WeakReference UnsetReference = 
             new WeakReference(AvaloniaProperty.UnsetValue);
 
@@ -18,6 +19,8 @@ namespace Avalonia.Data.Core
         private IDisposable _valueSubscription;
         private IObserver<object> _observer;
 
+        protected WeakReference LastValue { get; private set; }
+
         public abstract string Description { get; }
         public ExpressionNode Next { get; set; }
 
@@ -61,6 +64,7 @@ namespace Avalonia.Data.Core
             {
                 _valueSubscription?.Dispose();
                 _valueSubscription = null;
+                LastValue = null;
                 nextSubscription?.Dispose();
                 _observer = null;
             });
@@ -120,6 +124,7 @@ namespace Avalonia.Data.Core
 
             if (notification == null)
             {
+                LastValue = new WeakReference(value);
                 if (Next != null)
                 {
                     Next.Target = new WeakReference(value);
@@ -131,6 +136,7 @@ namespace Avalonia.Data.Core
             }
             else
             {
+                LastValue = new WeakReference(notification.Value);
                 if (Next != null)
                 {
                     Next.Target = new WeakReference(notification.Value);

+ 2 - 2
src/Avalonia.Base/Data/Core/ExpressionObserver.cs

@@ -180,7 +180,7 @@ namespace Avalonia.Data.Core
         /// </returns>
         public bool SetValue(object value, BindingPriority priority = BindingPriority.LocalValue)
         {
-            if (Leaf is ISettableNode settable)
+            if (Leaf is SettableNode settable)
             {
                 var node = _node;
                 while (node != null)
@@ -214,7 +214,7 @@ namespace Avalonia.Data.Core
         /// Gets the type of the expression result or null if the expression could not be 
         /// evaluated.
         /// </summary>
-        public Type ResultType => (Leaf as ISettableNode)?.PropertyType;
+        public Type ResultType => (Leaf as SettableNode)?.PropertyType;
 
         /// <summary>
         /// Gets the leaf node.

+ 0 - 15
src/Avalonia.Base/Data/Core/ISettableNode.cs

@@ -1,15 +0,0 @@
-using Avalonia.Data;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Avalonia.Data.Core
-{
-    interface ISettableNode
-    {
-        bool SetTargetValue(object value, BindingPriority priority);
-        Type PropertyType { get; }
-    }
-}

+ 12 - 5
src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs

@@ -10,7 +10,7 @@ using Avalonia.Data.Core.Plugins;
 
 namespace Avalonia.Data.Core
 {
-    public class PropertyAccessorNode : ExpressionNode, ISettableNode
+    public class PropertyAccessorNode : SettableNode
     {
         private readonly bool _enableValidation;
         private IPropertyAccessor _accessor;
@@ -23,13 +23,17 @@ namespace Avalonia.Data.Core
 
         public override string Description => PropertyName;
         public string PropertyName { get; }
-        public Type PropertyType => _accessor?.PropertyType;
+        public override Type PropertyType => _accessor?.PropertyType;
 
-        public bool SetTargetValue(object value, BindingPriority priority)
+        protected override bool SetTargetValueCore(object value, BindingPriority priority)
         {
             if (_accessor != null)
             {
-                try { return _accessor.SetValue(value, priority); } catch { }
+                try
+                {
+                    return _accessor.SetValue(value, priority);
+                }
+                catch { }
             }
 
             return false;
@@ -56,7 +60,10 @@ namespace Avalonia.Data.Core
                 () =>
                 {
                     _accessor = accessor;
-                    return Disposable.Create(() => _accessor = null);
+                    return Disposable.Create(() =>
+                    {
+                        _accessor = null;
+                    });
                 },
                 _ => accessor);
         }

+ 38 - 0
src/Avalonia.Base/Data/Core/SettableNode.cs

@@ -0,0 +1,38 @@
+using Avalonia.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Data.Core
+{
+    internal abstract class SettableNode : ExpressionNode
+    {
+        public bool SetTargetValue(object value, BindingPriority priority)
+        {
+            if (ShouldNotSet(value))
+            {
+                return true;
+            }
+            return SetTargetValueCore(value, priority);
+        }
+
+        private bool ShouldNotSet(object value)
+        {
+            if (PropertyType == null)
+            {
+                return false;
+            }
+            if (PropertyType.IsValueType)
+            {
+                return LastValue?.Target != null && LastValue.Target.Equals(value);
+            }
+            return LastValue != null && Object.ReferenceEquals(LastValue?.Target, value);
+        }
+
+        protected abstract bool SetTargetValueCore(object value, BindingPriority priority);
+
+        public abstract Type PropertyType { get; }
+    }
+}

+ 1 - 10
src/Avalonia.Controls/AppBuilderBase.cs

@@ -209,16 +209,7 @@ namespace Avalonia.Controls
 
         public TAppBuilder UseAvaloniaModules() => AfterSetup(builder => SetupAvaloniaModules());
 
-        private bool CheckSetup { get; set; } = true;
-
-        /// <summary>
-        /// Set this AppBuilder to ignore the setup check. Used for testing purposes.
-        /// </summary>
-        internal TAppBuilder IgnoreSetupCheck()
-        {
-            CheckSetup = false;
-            return Self;
-        }
+        protected virtual bool CheckSetup => true;
 
         private void SetupAvaloniaModules()
         {

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

@@ -2150,7 +2150,7 @@ namespace Avalonia.Controls
             }
 
             // Update the view
-            if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace)
+            if ((e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) && e.OldItems != null)
             {
                 for (int index = 0; index < e.OldItems.Count; index++)
                 {

+ 39 - 56
src/Avalonia.Controls/Calendar/Calendar.cs

@@ -769,7 +769,7 @@ namespace Avalonia.Controls
         }
         private static void UpdateDisplayDate(Calendar c, DateTime addedDate, DateTime removedDate)
         {
-            Debug.Assert(c != null, "c should not be null!");
+            Contract.Requires<ArgumentNullException>(c != null);
 
             // If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart
             if (DateTime.Compare(addedDate, c.DisplayDateRangeStart) < 0)
@@ -1016,8 +1016,6 @@ namespace Avalonia.Controls
 
         internal CalendarDayButton FindDayButtonFromDay(DateTime day)
         {
-            CalendarDayButton b;
-            DateTime? d;
             CalendarItem monthControl = MonthControl;
 
             // REMOVE_RTM: should be updated if we support MultiCalendar
@@ -1028,14 +1026,16 @@ namespace Avalonia.Controls
                 {
                     for (int childIndex = ColumnsPerMonth; childIndex < count; childIndex++)
                     {
-                        b = monthControl.MonthView.Children[childIndex] as CalendarDayButton;
-                        d = b.DataContext as DateTime?;
-
-                        if (d.HasValue)
+                        if (monthControl.MonthView.Children[childIndex] is CalendarDayButton b)
                         {
-                            if (DateTimeHelper.CompareDays(d.Value, day) == 0)
+                            var d = b.DataContext as DateTime?;
+
+                            if (d.HasValue)
                             {
-                                return b;
+                                if (DateTimeHelper.CompareDays(d.Value, day) == 0)
+                                {
+                                    return b;
+                                }
                             }
                         }
                     }
@@ -1044,20 +1044,6 @@ namespace Avalonia.Controls
             return null;
         }
 
-        private void Calendar_SizeChanged(object sender, EventArgs e)
-        {
-            Debug.Assert(sender is Calendar, "The sender should be a Calendar!");
-
-            var size = Bounds.Size;
-            RectangleGeometry rg = new RectangleGeometry();
-            rg.Rect = new Rect(0, 0, size.Width, size.Height);
-
-            if (Root != null)
-            {
-                Root.Clip = rg;
-            }
-        }
-
         private void OnSelectedMonthChanged(DateTime? selectedMonth)
         {
             if (selectedMonth.HasValue)
@@ -1090,7 +1076,6 @@ namespace Avalonia.Controls
 
         internal void ResetStates()
         {
-            CalendarDayButton d;
             CalendarItem monthControl = MonthControl;
             int count = RowsPerMonth * ColumnsPerMonth;
             if (monthControl != null)
@@ -1099,7 +1084,7 @@ namespace Avalonia.Controls
                 {
                     for (int childIndex = ColumnsPerMonth; childIndex < count; childIndex++)
                     {
-                        d = monthControl.MonthView.Children[childIndex] as CalendarDayButton;
+                        var d = (CalendarDayButton)monthControl.MonthView.Children[childIndex];
                         d.IgnoreMouseOverState();
                     }
                 }
@@ -1190,8 +1175,6 @@ namespace Avalonia.Controls
             if (HoverEnd != null && HoverStart != null)
             {
                 int startIndex, endIndex, i;
-                CalendarDayButton b;
-                DateTime? d;
                 CalendarItem monthControl = MonthControl;
 
                 // This assumes a contiguous set of dates:
@@ -1201,18 +1184,20 @@ namespace Avalonia.Controls
 
                     for (i = startIndex; i <= endIndex; i++)
                     {
-                        b = monthControl.MonthView.Children[i] as CalendarDayButton;
-                        b.IsSelected = true;
-                        d = b.DataContext as DateTime?;
-
-                        if (d.HasValue && DateTimeHelper.CompareDays(HoverEnd.Value, d.Value) == 0)
+                        if (monthControl.MonthView.Children[i] is CalendarDayButton b)
                         {
-                            if (FocusButton != null)
+                            b.IsSelected = true;
+                            var d = b.DataContext as DateTime?;
+
+                            if (d.HasValue && DateTimeHelper.CompareDays(HoverEnd.Value, d.Value) == 0)
                             {
-                                FocusButton.IsCurrent = false;
+                                if (FocusButton != null)
+                                {
+                                    FocusButton.IsCurrent = false;
+                                }
+                                b.IsCurrent = HasFocusInternal;
+                                FocusButton = b;
                             }
-                            b.IsCurrent = HasFocusInternal;
-                            FocusButton = b;
                         }
                     }
                 }
@@ -1228,8 +1213,6 @@ namespace Avalonia.Controls
             if (HoverEnd != null && HoverStart != null)
             {
                 CalendarItem monthControl = MonthControl;
-                CalendarDayButton b;
-                DateTime? d;
 
                 if (HoverEndIndex != null && HoverStartIndex != null)
                 {
@@ -1240,15 +1223,17 @@ namespace Avalonia.Controls
                     {
                         for (i = startIndex; i <= endIndex; i++)
                         {
-                            b = monthControl.MonthView.Children[i] as CalendarDayButton;
-                            d = b.DataContext as DateTime?;
-
-                            if (d.HasValue)
+                            if (monthControl.MonthView.Children[i] is CalendarDayButton b)
                             {
-                                if (!SelectedDates.Contains(d.Value))
+                                var d = b.DataContext as DateTime?;
+
+                                if (d.HasValue)
                                 {
-                                    b.IsSelected = false;
-                                }
+                                    if (!SelectedDates.Contains(d.Value))
+                                    {
+                                        b.IsSelected = false;
+                                    }
+                                } 
                             }
                         }
                     }
@@ -1257,7 +1242,7 @@ namespace Avalonia.Controls
                         // It is SingleRange
                         for (i = startIndex; i <= endIndex; i++)
                         {
-                            (monthControl.MonthView.Children[i] as CalendarDayButton).IsSelected = false;
+                            ((CalendarDayButton)monthControl.MonthView.Children[i]).IsSelected = false;
                         }
                     }
                 }
@@ -1628,16 +1613,15 @@ namespace Avalonia.Controls
                 e.Handled = true;
             }
         }
-        internal void Calendar_KeyDown(object sender, KeyEventArgs e)
-        {
-            Calendar c = sender as Calendar;
-            Debug.Assert(c != null, "c should not be null!");
 
-            if (!e.Handled && c.IsEnabled)
+        internal void Calendar_KeyDown(KeyEventArgs e)
+        {
+            if (!e.Handled && IsEnabled)
             {
                 e.Handled = ProcessCalendarKey(e);
             }
         }
+
         internal bool ProcessCalendarKey(KeyEventArgs e)
         {
             if (DisplayMode == CalendarMode.Month)
@@ -1976,7 +1960,7 @@ namespace Avalonia.Controls
                     }
             }
         }
-        private void Calendar_KeyUp(object sender, KeyEventArgs e)
+        private void Calendar_KeyUp(KeyEventArgs e)
         {
             if (!e.Handled && (e.Key == Key.LeftShift || e.Key == Key.RightShift))
             {
@@ -2083,6 +2067,9 @@ namespace Avalonia.Controls
             DisplayDateProperty.Changed.AddClassHandler<Calendar>(x => x.OnDisplayDateChanged);
             DisplayDateStartProperty.Changed.AddClassHandler<Calendar>(x => x.OnDisplayDateStartChanged);
             DisplayDateEndProperty.Changed.AddClassHandler<Calendar>(x => x.OnDisplayDateEndChanged);
+            KeyDownEvent.AddClassHandler<Calendar>(x => x.Calendar_KeyDown);
+            KeyUpEvent.AddClassHandler<Calendar>(x => x.Calendar_KeyUp);
+            
         }
 
         /// <summary>
@@ -2122,10 +2109,6 @@ namespace Avalonia.Controls
                     month.Owner = this;
                 }
             }
-
-            LayoutUpdated += Calendar_SizeChanged;
-            KeyDown += Calendar_KeyDown;
-            KeyUp += Calendar_KeyUp;
         }
 
     }

+ 1 - 1
src/Avalonia.Controls/Calendar/CalendarDateRange.cs

@@ -66,7 +66,7 @@ namespace Avalonia.Controls
         /// <returns>Inherited code: Requires comment 2.</returns>
         internal bool ContainsAny(CalendarDateRange range)
         {
-            Debug.Assert(range != null, "range should not be null!");
+            Contract.Requires<ArgumentNullException>(range != null);
 
             int start = DateTime.Compare(Start, range.Start);
 

+ 15 - 16
src/Avalonia.Controls/Calendar/CalendarItem.cs

@@ -517,7 +517,7 @@ namespace Avalonia.Controls.Primitives
             for (int childIndex = Calendar.ColumnsPerMonth; childIndex < count; childIndex++)
             {
                 CalendarDayButton childButton = MonthView.Children[childIndex] as CalendarDayButton;
-                Debug.Assert(childButton != null, "childButton should not be null!");
+                Contract.Requires<ArgumentNullException>(childButton != null);
 
                 childButton.Index = childIndex;
                 SetButtonState(childButton, dateToAdd);
@@ -554,7 +554,7 @@ namespace Avalonia.Controls.Primitives
                     for (int i = childIndex; i < count; i++)
                     {
                         childButton = MonthView.Children[i] as CalendarDayButton;
-                        Debug.Assert(childButton != null, "childButton should not be null!");
+                        Contract.Requires<ArgumentNullException>(childButton != null);
                         // button needs a content to occupy the necessary space
                         // for the content presenter
                         childButton.Content = i.ToString(DateTimeHelper.GetCurrentDateFormat());
@@ -650,7 +650,7 @@ namespace Avalonia.Controls.Primitives
             foreach (object child in YearView.Children)
             {
                 CalendarButton childButton = child as CalendarButton;
-                Debug.Assert(childButton != null, "childButton should not be null!");
+                Contract.Requires<ArgumentNullException>(childButton != null);
                 // There should be no time component. Time is 12:00 AM
                 DateTime day = new DateTime(_currentMonth.Year, count + 1, 1);
                 childButton.DataContext = day;
@@ -746,7 +746,7 @@ namespace Avalonia.Controls.Primitives
             foreach (object child in YearView.Children)
             {
                 CalendarButton childButton = child as CalendarButton;
-                Debug.Assert(childButton != null, "childButton should not be null!");
+                Contract.Requires<ArgumentNullException>(childButton != null);
                 year = decade + count;
 
                 if (year <= DateTime.MaxValue.Year && year >= DateTime.MinValue.Year)
@@ -826,7 +826,7 @@ namespace Avalonia.Controls.Primitives
                 {
                     Owner.Focus();
                 }
-                Button b = sender as Button;
+                Button b = (Button)sender;
                 DateTime d;
 
                 if (b.IsEnabled)
@@ -863,7 +863,7 @@ namespace Avalonia.Controls.Primitives
                     Owner.Focus();
                 }
 
-                Button b = sender as Button;
+                Button b = (Button)sender;
                 if (b.IsEnabled)
                 {
                     Owner.OnPreviousClick();
@@ -878,7 +878,7 @@ namespace Avalonia.Controls.Primitives
                 {
                     Owner.Focus();
                 }
-                Button b = sender as Button;
+                Button b = (Button)sender;
 
                 if (b.IsEnabled)
                 {
@@ -891,8 +891,7 @@ namespace Avalonia.Controls.Primitives
         {
             if (Owner != null)
             {
-                CalendarDayButton b = sender as CalendarDayButton;
-                if (_isMouseLeftButtonDown && b != null && b.IsEnabled && !b.IsBlackout)
+                if (_isMouseLeftButtonDown && sender is CalendarDayButton b && b.IsEnabled && !b.IsBlackout)
                 {
                     // Update the states of all buttons to be selected starting
                     // from HoverStart to b
@@ -918,7 +917,7 @@ namespace Avalonia.Controls.Primitives
                                 Debug.Assert(b.DataContext != null, "The DataContext should not be null!");
                                 Owner.UnHighlightDays();
                                 Owner.HoverEndIndex = b.Index;
-                                Owner.HoverEnd = (DateTime)b.DataContext;
+                                Owner.HoverEnd = (DateTime?)b.DataContext;
                                 // Update the States of the buttons
                                 Owner.HighlightDays();
                                 return;
@@ -931,7 +930,7 @@ namespace Avalonia.Controls.Primitives
         {
             if (_isMouseLeftButtonDown)
             {
-                CalendarDayButton b = sender as CalendarDayButton;
+                CalendarDayButton b = (CalendarDayButton)sender;
                 // The button is in Pressed state. Change the state to normal.
                 if (e.Device.Captured == b)
                     e.Device.Capture(null);
@@ -973,7 +972,7 @@ namespace Avalonia.Controls.Primitives
                     if (b.IsEnabled && !b.IsBlackout)
                     {
                         DateTime selectedDate = (DateTime)b.DataContext;
-                        Debug.Assert(selectedDate != null, "selectedDate should not be null!");
+                        Contract.Requires<ArgumentNullException>(selectedDate != null);
                         _isMouseLeftButtonDown = true;
                         // null check is added for unit tests
                         if (e != null)
@@ -1149,7 +1148,7 @@ namespace Avalonia.Controls.Primitives
                 if (_isControlPressed && Owner.SelectionMode == CalendarSelectionMode.MultipleRange)
                 {
                     CalendarDayButton b = sender as CalendarDayButton;
-                    Debug.Assert(b != null, "The sender should be a non-null CalendarDayButton!");
+                    Contract.Requires<ArgumentNullException>(b != null);
 
                     if (b.IsSelected)
                     {
@@ -1169,7 +1168,7 @@ namespace Avalonia.Controls.Primitives
         private void Month_CalendarButtonMouseDown(object sender, PointerPressedEventArgs e)
         {
             CalendarButton b = sender as CalendarButton;
-            Debug.Assert(b != null, "The sender should be a non-null CalendarDayButton!");
+            Contract.Requires<ArgumentNullException>(b != null);
 
             _isMouseLeftButtonDownYearView = true;
 
@@ -1208,7 +1207,7 @@ namespace Avalonia.Controls.Primitives
             if (_isMouseLeftButtonDownYearView)
             {
                 CalendarButton b = sender as CalendarButton;
-                Debug.Assert(b != null, "The sender should be a non-null CalendarDayButton!");
+                Contract.Requires<ArgumentNullException>(b != null);
                 UpdateYearViewSelection(b);
             }
         }
@@ -1217,7 +1216,7 @@ namespace Avalonia.Controls.Primitives
         {
             if (_isMouseLeftButtonDownYearView)
             {
-                CalendarButton b = sender as CalendarButton;
+                CalendarButton b = (CalendarButton)sender;
                 // The button is in Pressed state. Change the state to normal.
                 if (e.Device.Captured == b)
                     e.Device.Capture(null);

+ 1 - 1
src/Avalonia.Controls/Calendar/DatePicker.cs

@@ -842,7 +842,7 @@ namespace Avalonia.Controls
         private void Calendar_KeyDown(object sender, KeyEventArgs e)
         {
             Calendar c = sender as Calendar;
-            Debug.Assert(c != null, "The Calendar should not be null!");
+            Contract.Requires<ArgumentNullException>(c != null);
 
             if (!e.Handled && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape) && c.DisplayMode == CalendarMode.Month)
             {

+ 7 - 11
src/Avalonia.Controls/Design.cs

@@ -1,5 +1,6 @@
 
 using System.Runtime.CompilerServices;
+using Avalonia.Styling;
 
 namespace Avalonia.Controls
 {
@@ -45,23 +46,18 @@ namespace Avalonia.Controls
         {
             return control.GetValue(DataContextProperty);
         }
-
-        static readonly ConditionalWeakTable<object, Control> Substitutes = new ConditionalWeakTable<object, Control>();
-
+        
         public static readonly AttachedProperty<Control> PreviewWithProperty = AvaloniaProperty
-            .RegisterAttached<AvaloniaObject, Control>("PreviewWith", typeof (Design));
+            .RegisterAttached<Style, Control>("PreviewWith", typeof (Design));
 
-        public static void SetPreviewWith(object target, Control control)
+        public static void SetPreviewWith(Style target, Control control)
         {
-            Substitutes.Remove(target);
-            Substitutes.Add(target, control);
+            target.SetValue(PreviewWithProperty, control);
         }
 
-        public static Control GetPreviewWith(object target)
+        public static Control GetPreviewWith(Style target)
         {
-            Control rv;
-            Substitutes.TryGetValue(target, out rv);
-            return rv;
+            return target.GetValue(PreviewWithProperty);
         }
 
         public static void ApplyDesignModeProperties(Control target, Control source)

+ 6 - 7
src/Avalonia.Controls/DropDownItem.cs

@@ -22,14 +22,13 @@ namespace Avalonia.Controls
         static DropDownItem()
         {
             FocusableProperty.OverrideDefaultValue<DropDownItem>(true);
-            IsFocusedProperty.Changed.Subscribe(x =>
-            {
-                var sender = x.Sender as IControl;
+        }
 
-                if (sender != null)
-                {
-                    ((IPseudoClasses)sender.Classes).Set(":selected", (bool)x.NewValue);
-                }
+        public DropDownItem()
+        {
+            this.GetObservable(DropDownItem.IsFocusedProperty).Subscribe(focused =>
+            {
+                PseudoClasses.Set(":selected", focused);                
             });
         }
 

+ 1 - 1
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs

@@ -57,7 +57,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
         Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
         public void Dispose()
         {
-            PlatformImpl.Dispose();
+            PlatformImpl?.Dispose();
         }
     }
 }

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

@@ -72,6 +72,11 @@ namespace Avalonia.Platform
         /// 
         void SetMinMaxSize(Size minSize, Size maxSize);
 
+        /// <summary>
+        /// Sets whether this window appears on top of all other windows
+        /// </summary>
+        void SetTopmost(bool value);
+
         /// <summary>
         /// Gets platform specific display information
         /// </summary>

+ 2 - 2
src/Avalonia.Controls/Platform/InProcessDragSource.cs

@@ -60,9 +60,9 @@ namespace Avalonia.Platform
         {
             _lastPosition = pt;
 
-            RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects);
+            RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects, modifiers);
             var tl = root.GetSelfAndVisualAncestors().OfType<TopLevel>().FirstOrDefault();
-            tl.PlatformImpl.Input(rawEvent);
+            tl.PlatformImpl?.Input(rawEvent);
 
             var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers);
             UpdateCursor(root, effect);

+ 30 - 1
src/Avalonia.Controls/Presenters/CarouselPresenter.cs

@@ -106,7 +106,6 @@ namespace Avalonia.Controls.Presenters
         /// <inheritdoc/>
         protected override void ItemsChanged(NotifyCollectionChangedEventArgs e)
         {
-            // TODO: Handle items changing.           
             switch (e.Action)
             {
                 case NotifyCollectionChangedAction.Remove:
@@ -115,9 +114,39 @@ namespace Avalonia.Controls.Presenters
                         var generator = ItemContainerGenerator;
                         var containers = generator.RemoveRange(e.OldStartingIndex, e.OldItems.Count);
                         Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl));
+
+#pragma warning disable 4014
+                        MoveToPage(-1, SelectedIndex);
+#pragma warning restore 4014
                     }
                     break;
 
+                case NotifyCollectionChangedAction.Reset:
+                    {
+                        var generator = ItemContainerGenerator;
+                        var containers = generator.Containers.ToList();
+                        generator.Clear();
+                        Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl));
+
+#pragma warning disable 4014
+                        var newIndex = SelectedIndex;
+
+                        if(SelectedIndex < 0)
+                        {
+                            if(Items != null && Items.Count() > 0)
+                            {
+                                newIndex = 0;
+                            }
+                            else
+                            {
+                                newIndex = -1;
+                            }
+                        }
+                        
+                        MoveToPage(-1, newIndex);
+#pragma warning restore 4014
+                    }
+                    break;     
             }
         }
 

+ 16 - 0
src/Avalonia.Controls/Primitives/Popup.cs

@@ -70,6 +70,12 @@ namespace Avalonia.Controls.Primitives
         public static readonly StyledProperty<bool> StaysOpenProperty =
             AvaloniaProperty.Register<Popup, bool>(nameof(StaysOpen), true);
 
+        /// <summary>
+        /// Defines the <see cref="Topmost"/> property.
+        /// </summary>
+        public static readonly StyledProperty<bool> TopmostProperty =
+            AvaloniaProperty.Register<Popup, bool>(nameof(Topmost));
+
         private bool _isOpen;
         private PopupRoot _popupRoot;
         private TopLevel _topLevel;
@@ -84,6 +90,7 @@ namespace Avalonia.Controls.Primitives
             IsHitTestVisibleProperty.OverrideDefaultValue<Popup>(false);
             ChildProperty.Changed.AddClassHandler<Popup>(x => x.ChildChanged);
             IsOpenProperty.Changed.AddClassHandler<Popup>(x => x.IsOpenChanged);
+            TopmostProperty.Changed.AddClassHandler<Popup>((p, e) => p.PopupRoot.Topmost = (bool)e.NewValue);
         }
 
         /// <summary>
@@ -194,6 +201,15 @@ namespace Avalonia.Controls.Primitives
             set { SetValue(StaysOpenProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets whether this popup appears on top of all other windows
+        /// </summary>
+        public bool Topmost
+        {
+            get { return GetValue(TopmostProperty); }
+            set { SetValue(TopmostProperty, value); }
+        }
+
         /// <summary>
         /// Gets the root of the popup window.
         /// </summary>

+ 37 - 0
src/Avalonia.Controls/Primitives/ScrollBar.cs

@@ -6,9 +6,21 @@ using System.Reactive;
 using System.Reactive.Linq;
 using Avalonia.Data;
 using Avalonia.Interactivity;
+using Avalonia.Input;
 
 namespace Avalonia.Controls.Primitives
 {
+    public class ScrollEventArgs : EventArgs
+    {
+        public ScrollEventArgs(ScrollEventType eventType, double newValue)
+        {
+            ScrollEventType = eventType;
+            NewValue = newValue;
+        }
+        public double NewValue { get; private set; }
+        public ScrollEventType ScrollEventType { get; private set; }
+    }
+
     /// <summary>
     /// A scrollbar control.
     /// </summary>
@@ -44,6 +56,9 @@ namespace Avalonia.Controls.Primitives
         {
             PseudoClass(OrientationProperty, o => o == Orientation.Vertical, ":vertical");
             PseudoClass(OrientationProperty, o => o == Orientation.Horizontal, ":horizontal");
+
+            Thumb.DragDeltaEvent.AddClassHandler<ScrollBar>(o => o.OnThumbDragDelta, RoutingStrategies.Bubble);
+            Thumb.DragCompletedEvent.AddClassHandler<ScrollBar>(o => o.OnThumbDragComplete, RoutingStrategies.Bubble);
         }
 
         /// <summary>
@@ -88,6 +103,8 @@ namespace Avalonia.Controls.Primitives
             set { SetValue(OrientationProperty, value); }
         }
 
+        public event EventHandler<ScrollEventArgs> Scroll;
+
         /// <summary>
         /// Calculates whether the scrollbar should be visible.
         /// </summary>
@@ -140,6 +157,8 @@ namespace Avalonia.Controls.Primitives
             _pageUpButton = e.NameScope.Find<Button>("PART_PageUpButton");
             _pageDownButton = e.NameScope.Find<Button>("PART_PageDownButton");
 
+
+
             if (_lineUpButton != null)
             {
                 _lineUpButton.Click += LineUpClick;
@@ -184,21 +203,39 @@ namespace Avalonia.Controls.Primitives
         private void SmallDecrement()
         {
             Value = Math.Max(Value - SmallChange * ViewportSize, Minimum);
+            OnScroll(ScrollEventType.SmallDecrement);
         }
 
         private void SmallIncrement()
         {
             Value = Math.Min(Value + SmallChange * ViewportSize, Maximum);
+            OnScroll(ScrollEventType.SmallIncrement);
         }
 
         private void LargeDecrement()
         {
             Value = Math.Max(Value - LargeChange * ViewportSize, Minimum);
+            OnScroll(ScrollEventType.LargeDecrement);
         }
 
         private void LargeIncrement()
         {
             Value = Math.Min(Value + LargeChange * ViewportSize, Maximum);
+            OnScroll(ScrollEventType.LargeIncrement);
+        }
+
+        private void OnThumbDragDelta(VectorEventArgs e)
+        {
+            OnScroll(ScrollEventType.ThumbTrack);
+        }
+        private void OnThumbDragComplete(VectorEventArgs e)
+        {
+            OnScroll(ScrollEventType.EndScroll);
+        }
+
+        protected void OnScroll(ScrollEventType scrollEventType)
+        {
+            Scroll?.Invoke(this, new ScrollEventArgs(scrollEventType, Value));
         }
     }
 }

+ 53 - 0
src/Avalonia.Controls/Primitives/ScrollEventType.cs

@@ -0,0 +1,53 @@
+// 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.
+
+namespace Avalonia.Controls.Primitives
+{
+    /// <summary>    
+    /// Specifies the type of Avalonia.Controls.Primitives.ScrollBar.Scroll event
+    /// that occurred.
+    /// </summary>
+    public enum ScrollEventType
+    {
+        /// <summary>    
+        /// Specifies that the Avalonia.Controls.Primitives.Thumb moved a specified
+        /// distance, as determined by the value of Avalonia.Controls.Primitives.RangeBase.SmallChange.
+        /// The Avalonia.Controls.Primitives.Thumb moved to the left for a horizontal
+        /// Avalonia.Controls.Primitives.ScrollBar or upward for a vertical Avalonia.Controls.Primitives.ScrollBar.
+        /// </summary>
+        SmallDecrement = 0,
+        /// <summary>    
+        /// Specifies that the Avalonia.Controls.Primitives.Thumb moved a specified
+        /// distance, as determined by the value of Avalonia.Controls.Primitives.RangeBase.SmallChange.
+        /// The Avalonia.Controls.Primitives.Thumb moved to the right for a horizontal
+        /// Avalonia.Controls.Primitives.ScrollBar or downward for a vertical Avalonia.Controls.Primitives.ScrollBar.
+        /// </summary>
+        SmallIncrement = 1,
+        /// <summary>    
+        /// Specifies that the Avalonia.Controls.Primitives.Thumb moved a specified
+        /// distance, as determined by the value of Avalonia.Controls.Primitives.RangeBase.LargeChange.
+        /// The Avalonia.Controls.Primitives.Thumb moved to the left for a horizontal
+        /// Avalonia.Controls.Primitives.ScrollBar or upward for a vertical Avalonia.Controls.Primitives.ScrollBar.
+        /// </summary>
+        LargeDecrement = 2,
+        /// <summary>    
+        /// Specifies that the Avalonia.Controls.Primitives.Thumb moved a specified
+        /// distance, as determined by the value of Avalonia.Controls.Primitives.RangeBase.LargeChange.
+        /// The Avalonia.Controls.Primitives.Thumb moved to the right for a horizontal
+        /// Avalonia.Controls.Primitives.ScrollBar or downward for a vertical Avalonia.Controls.Primitives.ScrollBar.
+        /// </summary>
+        LargeIncrement = 3,
+        /// <summary>    
+        /// The Avalonia.Controls.Primitives.Thumb was dragged and caused a Avalonia.UIElement.MouseMove
+        /// event. A Avalonia.Controls.Primitives.ScrollBar.Scroll event of this Avalonia.Controls.Primitives.ScrollEventType
+        /// may occur more than one time when the Avalonia.Controls.Primitives.Thumb
+        /// is dragged in the Avalonia.Controls.Primitives.ScrollBar.
+        /// </summary>
+        ThumbTrack = 4,
+        /// <summary>    
+        /// Specifies that the Avalonia.Controls.Primitives.Thumb was dragged to a
+        /// new position and is now no longer being dragged by the user.
+        /// </summary>
+        EndScroll = 5
+    }
+}

+ 15 - 1
src/Avalonia.Controls/TextBox.cs

@@ -68,6 +68,10 @@ namespace Avalonia.Controls
         public static readonly StyledProperty<bool> UseFloatingWatermarkProperty =
             AvaloniaProperty.Register<TextBox, bool>(nameof(UseFloatingWatermark));
 
+        public static readonly DirectProperty<TextBox, string> NewLineProperty =
+            AvaloniaProperty.RegisterDirect<TextBox, string>(nameof(NewLine),
+                textbox => textbox.NewLine, (textbox, newline) => textbox.NewLine = newline);
+
         struct UndoRedoState : IEquatable<UndoRedoState>
         {
             public string Text { get; }
@@ -90,6 +94,7 @@ namespace Avalonia.Controls
         private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
         private bool _isUndoingRedoing;
         private bool _ignoreTextChanges;
+        private string _newLine = Environment.NewLine;
         private static readonly string[] invalidCharacters = new String[1] { "\u007f" };
 
         static TextBox()
@@ -241,6 +246,15 @@ namespace Avalonia.Controls
             set { SetValue(TextWrappingProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets which characters are inserted when Enter is pressed. Default: <see cref="Environment.NewLine"/>
+        /// </summary>
+        public string NewLine
+        {
+            get { return _newLine; }
+            set { SetAndRaise(NewLineProperty, ref _newLine, value); }
+        }
+
         protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
         {
             _presenter = e.NameScope.Get<TextPresenter>("PART_TextPresenter");
@@ -498,7 +512,7 @@ namespace Avalonia.Controls
                 case Key.Enter:
                     if (AcceptsReturn)
                     {
-                        HandleTextInput("\r\n");
+                        HandleTextInput(NewLine);
                         handled = true;
                     }
 

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

@@ -234,11 +234,12 @@ namespace Avalonia.Controls
         {
             Close();
 
-            _popup = new PopupRoot { Content = this };
+            _popup = new PopupRoot { Content = this,  };
             ((ISetLogicalParent)_popup).SetParent(control);
             _popup.Position = Popup.GetPosition(control, GetPlacement(control), _popup,
                 GetHorizontalOffset(control), GetVerticalOffset(control));
             _popup.Show();
+            _popup.SnapInsideScreenEdges();
         }
 
         private void Close()

+ 15 - 3
src/Avalonia.Controls/Window.cs

@@ -145,11 +145,9 @@ namespace Avalonia.Controls
             : base(impl)
         {
             impl.Closing = HandleClosing;
+            impl.WindowStateChanged = HandleWindowStateChanged;
             _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
             Screens = new Screens(PlatformImpl?.Screen);
-
-            if (PlatformImpl != null)
-                PlatformImpl.WindowStateChanged = s => WindowState = s;
         }
         
         /// <inheritdoc/>
@@ -318,6 +316,20 @@ namespace Avalonia.Controls
             return args.Cancel;
         }
 
+        protected virtual void HandleWindowStateChanged(WindowState state)
+        {
+            WindowState = state;
+
+            if (state == WindowState.Minimized)
+            {
+                Renderer.Stop();
+            }
+            else
+            {
+                Renderer.Start();
+            }
+        }
+
         /// <summary>
         /// Hides the window but does not close it.
         /// </summary>

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

@@ -38,6 +38,9 @@ namespace Avalonia.Controls
                 o => o.Owner,
                 (o, v) => o.Owner = v);
 
+        public static readonly StyledProperty<bool> TopmostProperty =
+            AvaloniaProperty.Register<WindowBase, bool>(nameof(Topmost));
+
         private bool _hasExecutedInitialLayoutPass;
         private bool _isActive;
         private bool _ignoreVisibilityChange;
@@ -52,6 +55,8 @@ namespace Avalonia.Controls
             MinHeightProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue), new Size(w.MaxWidth, w.MaxHeight)));
             MaxWidthProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue, w.MaxHeight)));
             MaxHeightProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue)));
+            
+            TopmostProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetTopmost((bool)e.NewValue));
         }
 
         public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current)
@@ -124,6 +129,15 @@ namespace Avalonia.Controls
             set { SetAndRaise(OwnerProperty, ref _owner, value); }
         }
 
+        /// <summary>
+        /// Gets or sets whether this window appears on top of all other windows
+        /// </summary>
+        public bool Topmost
+        {
+            get { return GetValue(TopmostProperty); }
+            set { SetValue(TopmostProperty, value); }
+        }
+
         /// <summary>
         /// Activates the window.
         /// </summary>

+ 1 - 2
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@@ -36,8 +36,7 @@ namespace Avalonia.DesignerSupport
                 var styles = loaded as Styles;
                 if (styles != null)
                 {
-                    var substitute = Design.GetPreviewWith(styles) ??
-                                     styles.Select(Design.GetPreviewWith).FirstOrDefault(s => s != null);
+                    var substitute = styles.OfType<Style>().Select(Design.GetPreviewWith).FirstOrDefault(s => s != null);
                     if (substitute != null)
                     {
                         substitute.Styles.AddRange(styles);

+ 5 - 1
src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs

@@ -30,6 +30,10 @@ namespace Avalonia.DesignerSupport.Remote
 
         public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
 
-        public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
+        public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException
+        {
+            add {}
+            remove {}
+        }
     }
 }

+ 9 - 1
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@@ -44,7 +44,11 @@ namespace Avalonia.DesignerSupport.Remote
         public WindowState WindowState { get; set; }
         public Action<WindowState> WindowStateChanged { get; set; }
         public Size MaxClientSize { get; } = new Size(4096, 4096);
-        public event Action LostFocus;
+        public event Action LostFocus
+        {
+            add {}
+            remove {}
+        }
 
         protected override void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
         {
@@ -102,5 +106,9 @@ namespace Avalonia.DesignerSupport.Remote
         public void CanResize(bool value)
         {
         }
+
+        public void SetTopmost(bool value)
+        {
+        }
     }
 }

+ 5 - 1
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@@ -125,7 +125,11 @@ namespace Avalonia.DesignerSupport.Remote
 
         class NeverClose : ICloseable
         {
-            public event EventHandler Closed;
+            public event EventHandler Closed
+            {
+                add {}
+                remove {}
+            }
         }
         
         public static void Main(string[] cmdline)

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

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

+ 12 - 12
src/Avalonia.Input/DragDropDevice.cs

@@ -19,11 +19,11 @@ namespace Avalonia.Input
             return null;
         }
         
-        private DragDropEffects RaiseDragEvent(Interactive target, IInputElement inputRoot, Point point, RoutedEvent<DragEventArgs> routedEvent, DragDropEffects operation, IDataObject data)
+        private DragDropEffects RaiseDragEvent(Interactive target, IInputElement inputRoot, Point point, RoutedEvent<DragEventArgs> routedEvent, DragDropEffects operation, IDataObject data, InputModifiers modifiers)
         {
             if (target == null)
                 return DragDropEffects.None;
-            var args = new DragEventArgs(routedEvent, data, target, inputRoot.TranslatePoint(point, target))
+            var args = new DragEventArgs(routedEvent, data, target, inputRoot.TranslatePoint(point, target), modifiers)
             {
                 RoutedEvent = routedEvent,
                 DragEffects = operation
@@ -32,24 +32,24 @@ namespace Avalonia.Input
             return args.DragEffects;
         }
         
-        private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+        private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers)
         {
             _lastTarget = GetTarget(inputRoot, point);
-            return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data);
+            return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers);
         }
 
-        private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+        private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers)
         {
             var target = GetTarget(inputRoot, point);
 
             if (target == _lastTarget)
-                return RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data);
+                return RaiseDragEvent(target, inputRoot, point, DragDrop.DragOverEvent, effects, data, modifiers);
             
             try
             {
                 if (_lastTarget != null)
                     _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent));
-                return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data);
+                return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers);
             }
             finally
             {
@@ -71,11 +71,11 @@ namespace Avalonia.Input
             }
         }
 
-        private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects)
+        private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers)
         {
             try
             {
-                return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data);
+                return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DropEvent, effects, data, modifiers);
             }
             finally 
             {
@@ -94,16 +94,16 @@ namespace Avalonia.Input
             switch (e.Type)
             {
                 case RawDragEventType.DragEnter:
-                    e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects);
+                    e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers);
                     break;
                 case RawDragEventType.DragOver:
-                    e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects);
+                    e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers);
                     break;
                 case RawDragEventType.DragLeave:
                     DragLeave(e.InputRoot);
                     break;
                 case RawDragEventType.Drop:
-                    e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects);
+                    e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers);
                     break;
             }
         }

+ 4 - 1
src/Avalonia.Input/DragEventArgs.cs

@@ -13,6 +13,8 @@ namespace Avalonia.Input
 
         public IDataObject Data { get; private set; }
 
+        public InputModifiers Modifiers { get; private set; }
+
         public Point GetPosition(IVisual relativeTo)
         {
             var point = new Point(0, 0);
@@ -29,12 +31,13 @@ namespace Avalonia.Input
             return point;
         }
 
-        public DragEventArgs(RoutedEvent<DragEventArgs> routedEvent, IDataObject data, Interactive target, Point targetLocation)
+        public DragEventArgs(RoutedEvent<DragEventArgs> routedEvent, IDataObject data, Interactive target, Point targetLocation, InputModifiers modifiers)
             : base(routedEvent)
         {
             this.Data = data;
             this._target = target;
             this._targetLocation = targetLocation;
+            this.Modifiers = modifiers;
         }
 
     }

+ 3 - 1
src/Avalonia.Input/Raw/RawDragEvent.cs

@@ -11,9 +11,10 @@ namespace Avalonia.Input.Raw
         public IDataObject Data { get; }
         public DragDropEffects Effects { get; set; }
         public RawDragEventType Type { get; }
+        public InputModifiers Modifiers { get; }
 
         public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type, 
-            IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects)
+            IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects, InputModifiers modifiers)
             :base(inputDevice, 0)
         {
             Type = type;
@@ -21,6 +22,7 @@ namespace Avalonia.Input.Raw
             Location = location;
             Data = data;
             Effects = effects;
+            Modifiers = modifiers;
         }
     }
 }

+ 1 - 3
src/Avalonia.Remote.Protocol/TcpTransportBase.cs

@@ -48,14 +48,12 @@ namespace Avalonia.Remote.Protocol
                 {
                     var cl = await server.AcceptTcpClientAsync();
                     AcceptNew();
-                    Task.Run(async () =>
+                    await Task.Run(async () =>
                     {
                         var tcs = new TaskCompletionSource<int>();
                         var t = CreateTransport(_resolver, cl.GetStream(), () => tcs.TrySetResult(0));
                         cb(t);
                         await tcs.Task;
-
-
                     });
                 }
                 catch

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

@@ -15,7 +15,7 @@ namespace Avalonia.Styling
     /// <summary>
     /// Defines a style.
     /// </summary>
-    public class Style : IStyle, ISetStyleParent
+    public class Style : AvaloniaObject, IStyle, ISetStyleParent
     {
         private static Dictionary<IStyleable, List<IDisposable>> _applied =
             new Dictionary<IStyleable, List<IDisposable>>();

+ 3 - 2
src/Avalonia.Themes.Default/Calendar.xaml

@@ -15,9 +15,10 @@
     <Setter Property="Template">
       <ControlTemplate>
         <StackPanel Name="Root"
-                    HorizontalAlignment="Center">
+                    HorizontalAlignment="Center"
+                    ClipToBounds="True">
 
-          <CalendarItem Name="CalendarItem"
+                    <CalendarItem Name="CalendarItem"
                         Background="{TemplateBinding Background}"
                         BorderBrush="{TemplateBinding BorderBrush}"
                         BorderThickness="{TemplateBinding BorderThickness}"

+ 1 - 1
src/Avalonia.Visuals/Media/DrawingContext.cs

@@ -59,7 +59,7 @@ namespace Avalonia.Media
         //HACK: This is a temporary hack that is used in the render loop 
         //to update TransformedBounds property
         [Obsolete("HACK for render loop, don't use")]
-        internal Matrix CurrentContainerTransform => _currentContainerTransform;
+        public Matrix CurrentContainerTransform => _currentContainerTransform;
 
         /// <summary>
         /// Draws a bitmap image.

+ 3 - 3
src/Avalonia.Visuals/Media/FontFamily.cs

@@ -77,10 +77,10 @@ namespace Avalonia.Media
         /// <summary>
         /// Implicit conversion of string to FontFamily
         /// </summary>
-        /// <param name="fontFamily"></param>
-        public static implicit operator FontFamily(string fontFamily)
+        /// <param name="s"></param>
+        public static implicit operator FontFamily(string s)
         {
-            return new FontFamily(fontFamily);
+            return Parse(s);
         }
 
         /// <summary>

+ 3 - 3
src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs

@@ -7,7 +7,7 @@ using System.Linq;
 namespace Avalonia.Media.Fonts
 {
     /// <summary>
-    /// Represents an identifier for a <see cref="IFontFamily"/>
+    /// Represents an identifier for a <see cref="FontFamily"/>
     /// </summary>
     public class FontFamilyKey
     {
@@ -33,12 +33,12 @@ namespace Avalonia.Media.Fonts
         }
 
         /// <summary>
-        /// Location of stored font asset that belongs to a <see cref="IFontFamily"/>
+        /// Location of stored font asset that belongs to a <see cref="FontFamily"/>
         /// </summary>
         public Uri Location { get; }
 
         /// <summary>
-        /// Optional filename for a font asset that belongs to a <see cref="IFontFamily"/>
+        /// Optional filename for a font asset that belongs to a <see cref="FontFamily"/>
         /// </summary>
         public string FileName { get; }
 

+ 20 - 0
src/Avalonia.Visuals/Rendering/IRendererFactory.cs

@@ -0,0 +1,20 @@
+// 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;
+
+namespace Avalonia.Rendering
+{
+    /// <summary>
+    /// Defines the interface for a renderer factory.
+    /// </summary>
+    public interface IRendererFactory
+    {
+        /// <summary>
+        /// Creates a renderer.
+        /// </summary>
+        /// <param name="root">The root visual.</param>
+        /// <param name="renderLoop">The render loop.</param>
+        IRenderer Create(IRenderRoot root, IRenderLoop renderLoop);
+    }
+}

+ 1 - 4
src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs

@@ -21,20 +21,17 @@ namespace Avalonia.Gtk3.Interop
             }
             return true;
         }
-
-        private static readonly GCHandle PinnedHandle;
+        
         private static readonly Native.D.timeout_callback PinnedHandler;
         static GlibTimeout()
         {
             PinnedHandler = Handler;
-            
         }
 
 
         public static void Add(int priority, uint interval, Func<bool> callback)
         {
             var handle = GCHandle.Alloc(callback);
-            //Native.GTimeoutAdd(interval, PinnedHandler, GCHandle.ToIntPtr(handle));
             Native.GTimeoutAddFull(priority, interval, PinnedHandler, GCHandle.ToIntPtr(handle), IntPtr.Zero);
         }
 

+ 7 - 2
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@@ -1,4 +1,5 @@
-using System;
+#pragma warning disable 649
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.InteropServices;
@@ -261,10 +262,13 @@ namespace Avalonia.Gtk3.Interop
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
             public delegate void gtk_window_unmaximize(GtkWindow window);
-            
+
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
             public delegate void gtk_window_close(GtkWindow window);
 
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+            public delegate void gtk_window_set_keep_above(GtkWindow gtkWindow, bool setting);
+
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
             public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask);
 
@@ -472,6 +476,7 @@ namespace Avalonia.Gtk3.Interop
         public static D.gtk_window_maximize GtkWindowMaximize;
         public static D.gtk_window_unmaximize GtkWindowUnmaximize;
         public static D.gtk_window_close GtkWindowClose;
+        public static D.gtk_window_set_keep_above GtkWindowSetKeepAbove;
         public static D.gdk_window_begin_move_drag GdkWindowBeginMoveDrag;
         public static D.gdk_window_begin_resize_drag GdkWindowBeginResizeDrag;
         public static D.gdk_event_request_motions GdkEventRequestMotions;

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

@@ -416,6 +416,8 @@ namespace Avalonia.Gtk3
 
         public void Hide() => Native.GtkWidgetHide(GtkWidget);
 
+        public void SetTopmost(bool value) => Native.GtkWindowSetKeepAbove(GtkWidget, value);
+
         void GetGlobalPointer(out int x, out int y)
         {
             int mask;

+ 1 - 1
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@@ -81,7 +81,7 @@ namespace Avalonia.Gtk3
         public void ShowTaskbarIcon(bool value) => Native.GtkWindowSetSkipTaskbarHint(GtkWidget, !value);
 
         public void CanResize(bool value) => Native.GtkWindowSetResizable(GtkWidget, value);
-        
+
 
         class EmptyDisposable : IDisposable
         {

+ 5 - 1
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@@ -70,6 +70,10 @@ namespace Avalonia.LinuxFramebuffer
         public Action<Size> Resized { get; set; }
         public Action<double> ScalingChanged { get; set; }
         public Action Closed { get; set; }
-        public event Action LostFocus;
+        public event Action LostFocus
+        {
+            add {}
+            remove {}
+        }
     }
 }

+ 7 - 7
src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs

@@ -14,13 +14,13 @@ namespace Portable.Xaml.ComponentModel
         /// Gets the service from ITypeDescriptorContext
         /// usually in TypeConverter in xaml reader context
         /// examples:
-        /// context.GetService<IXamlTypeResolver>()
-        /// context.GetService<IXamlNamespaceResolver>()
-        /// context.GetService<IXamlNameProvider>()
-        /// context.GetService<INamespacePrefixLookup>()
-        /// context.GetService<IXamlSchemaContextProvider>()
-        /// context.GetService<IRootObjectProvider>()
-        /// context.GetService<IProvideValueTarget>()
+        /// context.GetService&lt;IXamlTypeResolver&gt;()
+        /// context.GetService&lt;IXamlNamespaceResolver&gt;()
+        /// context.GetService&lt;IXamlNameProvider&gt;()
+        /// context.GetService&lt;INamespacePrefixLookup&gt;()
+        /// context.GetService&lt;IXamlSchemaContextProvider&gt;()
+        /// context.GetService&lt;IRootObjectProvider&gt;()
+        /// context.GetService&lt;IProvideValueTarget&gt;()
         /// </summary>
         /// <typeparam name="T">Service Type</typeparam>
         /// <param name="ctx">The TypeDescriptor context.</param>

+ 5 - 1
src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs

@@ -26,7 +26,11 @@ namespace Avalonia.Markup.Xaml.Styling
         }
 
         /// <inheritdoc/>
-        public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
+        public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged
+        {
+            add {}
+            remove {}
+        }
 
         /// <summary>
         /// Gets or sets the source URL.

+ 2 - 1
src/Markup/Avalonia.Markup/Data/MultiBinding.cs

@@ -10,6 +10,7 @@ using System.Reactive.Subjects;
 using Avalonia.Controls;
 using Avalonia.Data.Converters;
 using Avalonia.Metadata;
+using JetBrains.Annotations;
 
 namespace Avalonia.Data
 {
@@ -65,7 +66,7 @@ namespace Avalonia.Data
             var children = Bindings.Select(x => x.Initiate(target, null));
             var input = children.Select(x => x.Subject).CombineLatest().Select(x => ConvertValue(x, targetType));
             var mode = Mode == BindingMode.Default ?
-                targetProperty.GetMetadata(target.GetType()).DefaultBindingMode : Mode;
+                targetProperty?.GetMetadata(target.GetType()).DefaultBindingMode : Mode;
 
             switch (mode)
             {

+ 2 - 1
src/OSX/Avalonia.MonoMac/ClipboardImpl.cs

@@ -22,9 +22,10 @@ namespace Avalonia.MonoMac
             return Task.CompletedTask;
         }
 
-        public async Task ClearAsync()
+        public Task ClearAsync()
         {
             NSPasteboard.GeneralPasteboard.ClearContents();
+            return Task.CompletedTask;
         }
     }
 }

+ 5 - 4
src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs

@@ -7,6 +7,7 @@ using Avalonia.Controls;
 using Avalonia.Controls.Platform;
 using Avalonia.Platform;
 using MonoMac.AppKit;
+using MonoMac.Foundation;
 
 namespace Avalonia.MonoMac
 {
@@ -24,9 +25,9 @@ namespace Avalonia.MonoMac
                 else
                 {
                     if (panel is NSOpenPanel openPanel)
-                        tcs.SetResult(openPanel.Filenames);
+                        tcs.SetResult(openPanel.Urls.Select(url => url.AbsoluteString).ToArray());
                     else
-                        tcs.SetResult(new[] { panel.Filename });
+                        tcs.SetResult(new[] { panel.Url.AbsoluteString });
                 }
                 panel.OrderOut(panel);
                 keyWindow?.MakeKeyAndOrderFront(keyWindow);
@@ -62,7 +63,7 @@ namespace Avalonia.MonoMac
                 panel = new NSSavePanel();
             panel.Title = panel.Title;
             if (dialog.InitialDirectory != null)
-                panel.Directory = dialog.InitialDirectory;
+                panel.DirectoryUrl = new NSUrl(dialog.InitialDirectory);
             if (dialog.InitialFileName != null)
                 panel.NameFieldStringValue = dialog.InitialFileName;
             if (dialog.Filters?.Count > 0)
@@ -84,7 +85,7 @@ namespace Avalonia.MonoMac
                 CanChooseFiles = false
             };
             if (dialog.DefaultDirectory != null)
-                panel.Directory = dialog.DefaultDirectory;
+                panel.DirectoryUrl = new NSUrl(dialog.DefaultDirectory);
             return (await RunPanel(panel, parent))?.FirstOrDefault();
         }
     }

+ 2 - 1
src/OSX/Avalonia.MonoMac/TopLevelImpl.cs

@@ -164,8 +164,9 @@ namespace Avalonia.MonoMac
                 
                 var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask);
                 DraggingInfo info = new DraggingInfo(sender);
+                
                 var pt = TranslateLocalPoint(info.Location);
-                var args = new RawDragEvent(dragDevice, type, root, pt, info, dragOp);
+                var args = new RawDragEvent(dragDevice, type, root, pt, info, dragOp, GetModifiers(NSEvent.CurrentModifierFlags));
                 input(args);
                 return DraggingInfo.ConvertDragOperation(args.Effects);
             }

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

@@ -123,6 +123,7 @@ namespace Avalonia.MonoMac
 
         public void Hide() => Window?.OrderOut(Window);
 
+        public void SetTopmost(bool value) => Window.Level = value ? NSWindowLevel.Floating : NSWindowLevel.Normal;
 
         public void BeginMoveDrag()
         {

+ 48 - 6
src/Skia/Avalonia.Skia/FormattedTextImpl.cs

@@ -250,7 +250,26 @@ namespace Avalonia.Skia
                         {
                             float currX = x;
                             string subStr;
+                            float measure;
                             int len;
+                            float factor;
+                            switch (paint.TextAlign)
+                            {
+                                case SKTextAlign.Left:
+                                    factor = 0;
+                                    break;
+                                case SKTextAlign.Center:
+                                    factor = 0.5f;
+                                    break;
+                                case SKTextAlign.Right:
+                                    factor = 1;
+                                    break;
+                                default:
+                                    throw new ArgumentOutOfRangeException();
+                            }
+
+                            var textLine = Text.Substring(line.Start, line.Length);
+                            currX -= paint.MeasureText(textLine) * factor;
 
                             for (int i = line.Start; i < line.Start + line.Length;)
                             {
@@ -268,13 +287,15 @@ namespace Avalonia.Skia
                                 }
 
                                 subStr = Text.Substring(i, len);
+                                measure = paint.MeasureText(subStr);
+                                currX += measure * factor;
 
                                 ApplyWrapperTo(ref currentPaint, currentWrapper, ref currd, paint, canUseLcdRendering);
 
                                 canvas.DrawText(subStr, currX, origin.Y + line.Top + _lineOffset, paint);
 
                                 i += len;
-                                currX += paint.MeasureText(subStr);
+                                currX += measure * (1 - factor);
                             }
                         }
                     }
@@ -560,13 +581,11 @@ namespace Avalonia.Skia
                 }
 
                 measured = LineBreak(Text, curOff, length, _paint, constraint, out trailingnumber);
-
                 AvaloniaFormattedTextLine line = new AvaloniaFormattedTextLine();
+                line.Start = curOff;
                 line.TextLength = measured;
-
                 subString = Text.Substring(line.Start, line.TextLength);
                 lineWidth = _paint.MeasureText(subString);
-                line.Start = curOff;
                 line.Length = measured - trailingnumber;
                 line.Width = lineWidth;
                 line.Height = _lineHeight;
@@ -575,10 +594,33 @@ namespace Avalonia.Skia
                 _skiaLines.Add(line);
 
                 curY += _lineHeight;
-
                 curY += mLeading;
-
                 curOff += measured;
+
+                //if this is the last line and there are trailing newline characters then
+                //insert a additional line
+                if (curOff >= length)
+                {
+                    var subStringMinusNewlines = subString.TrimEnd('\n', '\r');
+                    var lengthDiff = subString.Length - subStringMinusNewlines.Length;
+                    if (lengthDiff > 0)
+                    {
+                        AvaloniaFormattedTextLine lastLine = new AvaloniaFormattedTextLine();
+                        lastLine.TextLength = lengthDiff;
+                        lastLine.Start = curOff - lengthDiff;
+                        var lastLineSubString = Text.Substring(line.Start, line.TextLength);
+                        var lastLineWidth = _paint.MeasureText(lastLineSubString);
+                        lastLine.Length = 0;
+                        lastLine.Width = lastLineWidth;
+                        lastLine.Height = _lineHeight;
+                        lastLine.Top = curY;
+
+                        _skiaLines.Add(lastLine);
+
+                        curY += _lineHeight;
+                        curY += mLeading;
+                    }
+                }
             }
 
             // Now convert to Avalonia data formats

+ 1 - 0
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs

@@ -19,6 +19,7 @@ namespace Avalonia.Direct2D1.Media
         /// Initialize a new instance of the <see cref="BitmapImpl"/> class
         /// with a bitmap backed by GPU memory.
         /// </summary>
+        /// <param name="imagingFactory">The image factory to use when saving out this bitmap.</param>
         /// <param name="d2DBitmap">The GPU bitmap.</param>
         /// <remarks>
         /// This bitmap must be either from the same render target,

+ 1 - 0
src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs

@@ -11,6 +11,7 @@ namespace Avalonia.Direct2D1.Media
         /// <summary>
         /// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
         /// </summary>
+        /// <param name="source">The source geometry.</param>
         /// <param name="geometry">An existing Direct2D <see cref="TransformedGeometry"/>.</param>
         public TransformedGeometryImpl(TransformedGeometry geometry, GeometryImpl source)
             : base(geometry)

+ 13 - 5
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@@ -78,6 +78,14 @@ namespace Avalonia.Win32.Interop
             SWP_RESIZE = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER
         }
 
+        public static class WindowPosZOrder
+        {
+            public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
+            public static readonly IntPtr HWND_TOP = new IntPtr(0);
+            public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
+            public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
+        }
+
         public enum SizeCommand
         {
             Restored,
@@ -218,6 +226,8 @@ namespace Avalonia.Win32.Interop
 
             MK_SHIFT = 0x0004,
 
+            MK_ALT = 0x0020,
+
             MK_XBUTTON1 = 0x0020,
 
             MK_XBUTTON2 = 0x0040
@@ -998,7 +1008,7 @@ namespace Avalonia.Win32.Interop
         public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
 
         [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
-        public static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect);
+        internal static extern void DoDragDrop(IOleDataObject dataObject, IDropSource dropSource, int allowedEffects, int[] finalEffect);
 
 
 
@@ -1375,9 +1385,7 @@ namespace Avalonia.Win32.Interop
         Link = 4,
         Scroll = -2147483648,
     }
-    
-    
-    
+
     [ComImport]
     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
     [Guid("00000122-0000-0000-C000-000000000046")]
@@ -1408,7 +1416,7 @@ namespace Avalonia.Win32.Interop
     [ComImport]
     [Guid("0000010E-0000-0000-C000-000000000046")]
     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-    public interface IOleDataObject
+    internal interface IOleDataObject
     {
         void GetData([In] ref FORMATETC format, out STGMEDIUM medium);
         void GetDataHere([In] ref FORMATETC format, ref STGMEDIUM medium);

+ 5 - 4
src/Windows/Avalonia.Win32/OleDragSource.cs

@@ -11,10 +11,11 @@ namespace Avalonia.Win32
         private const int DRAGDROP_S_DROP = 0x00040100;
         private const int DRAGDROP_S_CANCEL = 0x00040101;
 
-        private const int KEYSTATE_LEFTMB = 1;
-        private const int KEYSTATE_MIDDLEMB = 16;
-        private const int KEYSTATE_RIGHTMB = 2;
-        private static readonly int[] MOUSE_BUTTONS = new int[] { KEYSTATE_LEFTMB, KEYSTATE_MIDDLEMB, KEYSTATE_RIGHTMB };
+        private static readonly int[] MOUSE_BUTTONS = new int[] {
+            (int)UnmanagedMethods.ModifierKeys.MK_LBUTTON,
+            (int)UnmanagedMethods.ModifierKeys.MK_MBUTTON,
+            (int)UnmanagedMethods.ModifierKeys.MK_RBUTTON
+        };
 
         public int QueryContinueDrag(int fEscapePressed, int grfKeyState)
         {

+ 34 - 9
src/Windows/Avalonia.Win32/OleDropTarget.cs

@@ -45,6 +45,26 @@ namespace Avalonia.Win32
             return result;
         }
         
+        private static InputModifiers ConvertKeyState(int grfKeyState)
+        {
+            InputModifiers modifiers = InputModifiers.None;
+            var state = (UnmanagedMethods.ModifierKeys)grfKeyState;
+
+            if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
+                modifiers |= InputModifiers.LeftMouseButton;
+            if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
+                modifiers |= InputModifiers.MiddleMouseButton;
+            if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
+                modifiers |= InputModifiers.RightMouseButton;
+            if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_SHIFT))
+                modifiers |= InputModifiers.Shift;
+            if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_CONTROL))
+                modifiers |= InputModifiers.Control;
+            if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_ALT))
+                modifiers |= InputModifiers.Alt;
+            return modifiers;
+        }
+
         UnmanagedMethods.HRESULT IDropTarget.DragEnter(IOleDataObject pDataObj, int grfKeyState, long pt, ref DropEffect pdwEffect)
         {
             var dispatch = _tl?.Input;
@@ -56,13 +76,15 @@ namespace Avalonia.Win32
             _currentDrag = pDataObj as IDataObject;
             if (_currentDrag == null)
                 _currentDrag = new OleDataObject(pDataObj);
+
             var args = new RawDragEvent(
                 _dragDevice,
                 RawDragEventType.DragEnter, 
                 _target, 
                 GetDragLocation(pt), 
                 _currentDrag, 
-                ConvertDropEffect(pdwEffect)
+                ConvertDropEffect(pdwEffect),
+                ConvertKeyState(grfKeyState)
             );
             dispatch(args);
             pdwEffect = ConvertDropEffect(args.Effects);
@@ -85,7 +107,8 @@ namespace Avalonia.Win32
                 _target, 
                 GetDragLocation(pt), 
                 _currentDrag, 
-                ConvertDropEffect(pdwEffect)
+                ConvertDropEffect(pdwEffect),
+                ConvertKeyState(grfKeyState)
             );
             dispatch(args);
             pdwEffect = ConvertDropEffect(args.Effects);
@@ -98,12 +121,13 @@ namespace Avalonia.Win32
             try
             {
                 _tl?.Input(new RawDragEvent(
-                    _dragDevice,  
-                    RawDragEventType.DragLeave, 
-                    _target, 
-                    default(Point), 
-                    null, 
-                    DragDropEffects.None
+                    _dragDevice,
+                    RawDragEventType.DragLeave,
+                    _target,
+                    default(Point),
+                    null,
+                    DragDropEffects.None,
+                    InputModifiers.None
                 ));
                 return UnmanagedMethods.HRESULT.S_OK;
             }
@@ -134,7 +158,8 @@ namespace Avalonia.Win32
                     _target, 
                     GetDragLocation(pt), 
                     _currentDrag, 
-                    ConvertDropEffect(pdwEffect)
+                    ConvertDropEffect(pdwEffect),
+                    ConvertKeyState(grfKeyState)
                 );
                 dispatch(args);
                 pdwEffect = ConvertDropEffect(args.Effects);

+ 1 - 1
src/Windows/Avalonia.Win32/SystemDialogImpl.cs

@@ -54,7 +54,7 @@ namespace Avalonia.Win32
                 var fileBuffer = new char[256];
                 dialog.InitialFileName?.CopyTo(0, fileBuffer, 0, dialog.InitialFileName.Length);
 
-                string userSelectedExt = null;
+                string userSelectedExt = string.Empty;
 
 
                 var title = ToChars(dialog.Title);

+ 24 - 4
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -32,6 +32,7 @@ namespace Avalonia.Win32
         private bool _trackingMouse;
         private bool _decorated = true;
         private bool _resizable = true;
+        private bool _topmost = false;
         private double _scaling = 1;
         private WindowState _showWindowState;
         private WindowState _lastWindowState;
@@ -124,9 +125,12 @@ namespace Avalonia.Win32
         public IRenderer CreateRenderer(IRenderRoot root)
         {
             var loop = AvaloniaLocator.Current.GetService<IRenderLoop>();
-            return Win32Platform.UseDeferredRendering ?
-                (IRenderer)new DeferredRenderer(root, loop) :
-                new ImmediateRenderer(root);
+            var customRendererFactory = AvaloniaLocator.Current.GetService<IRendererFactory>();
+
+            if (customRendererFactory != null)
+                return customRendererFactory.Create(root, loop);
+
+            return Win32Platform.UseDeferredRendering ? (IRenderer)new DeferredRenderer(root, loop) : new ImmediateRenderer(root);
         }
 
         public void Resize(Size value)
@@ -838,7 +842,7 @@ namespace Avalonia.Win32
                     var cx = Math.Abs(monitorInfo.rcWork.right - x);
                     var cy = Math.Abs(monitorInfo.rcWork.bottom - y);
 
-                    SetWindowPos(_hwnd, new IntPtr(-2), x, y, cx, cy, SetWindowPosFlags.SWP_SHOWWINDOW);
+                    SetWindowPos(_hwnd, WindowPosZOrder.HWND_NOTOPMOST, x, y, cx, cy, SetWindowPosFlags.SWP_SHOWWINDOW);
                 }
             }
         }
@@ -901,5 +905,21 @@ namespace Avalonia.Win32
 
             _resizable = value;
         }
+
+        public void SetTopmost(bool value)
+        {
+            if (value == _topmost)
+            {
+                return;
+            }
+
+            IntPtr hWndInsertAfter = value ? WindowPosZOrder.HWND_TOPMOST : WindowPosZOrder.HWND_NOTOPMOST;
+            UnmanagedMethods.SetWindowPos(_hwnd,
+                   hWndInsertAfter,
+                   0, 0, 0, 0,
+                   SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
+
+            _topmost = value;
+        }
     }
 }

+ 1 - 1
src/iOS/Avalonia.iOS/DisplayLinkRenderLoop.cs

@@ -26,7 +26,7 @@ namespace Avalonia.iOS
             {
                 Tick?.Invoke(this, new EventArgs());
             }
-            catch (Exception e)
+            catch (Exception)
             {
                 //TODO: log
             }

+ 5 - 1
src/iOS/Avalonia.iOS/EmbeddableImpl.cs

@@ -27,6 +27,10 @@ namespace Avalonia.iOS
         {
         }
 
-        public event Action LostFocus;
+        public event Action LostFocus
+        {
+            add {}
+            remove {}
+        }
     }
 }

+ 1 - 2
src/iOS/Avalonia.iOS/TopLevelImpl.cs

@@ -26,7 +26,6 @@ namespace Avalonia.iOS
     {
         private IInputRoot _inputRoot;
         private readonly KeyboardEventsHelper<TopLevelImpl> _keyboardHelper;
-        private Point _position;
 
         public TopLevelImpl()
         {
@@ -52,7 +51,7 @@ namespace Avalonia.iOS
         public Action<Size> Resized { get; set; }
         public Action<double> ScalingChanged { get; set; }
 
-        public IPlatformHandle Handle => null;
+        public new IPlatformHandle Handle => null;
 
         public double Scaling => UIScreen.MainScreen.Scale;
 

+ 49 - 0
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

@@ -457,6 +457,28 @@ namespace Avalonia.Base.UnitTests
             Assert.True(target.IsAnimating(Class1.FooProperty));
         }
 
+        [Fact]
+        public void TwoWay_Binding_Should_Not_Call_Setter_On_Creation()
+        {
+            var target = new Class1();
+            var source = new TestTwoWayBindingViewModel();
+
+            target.Bind(Class1.DoubleValueProperty, new Binding(nameof(source.Value), BindingMode.TwoWay) { Source = source });
+
+            Assert.False(source.SetterCalled);
+        }
+
+        [Fact]
+        public void TwoWay_Binding_Should_Not_Call_Setter_On_Creation_Indexer()
+        {
+            var target = new Class1();
+            var source = new TestTwoWayBindingViewModel();
+
+            target.Bind(Class1.DoubleValueProperty, new Binding("[0]", BindingMode.TwoWay) { Source = source });
+
+            Assert.False(source.SetterCalled);
+        }
+
         /// <summary>
         /// Returns an observable that returns a single value but does not complete.
         /// </summary>
@@ -545,5 +567,32 @@ namespace Avalonia.Base.UnitTests
                 }
             }
         }
+
+        private class TestTwoWayBindingViewModel
+        {
+            private double _value;
+
+            public double Value
+            {
+                get => _value;
+                set
+                {
+                    _value = value;
+                    SetterCalled = true;
+                }
+            }
+
+            public double this[int index]
+            {
+                get => _value;
+                set
+                {
+                    _value = value;
+                    SetterCalled = true;
+                }
+            }
+
+            public bool SetterCalled { get; private set; }
+        }
     }
 }

+ 2 - 0
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Threading.cs

@@ -160,7 +160,9 @@ namespace Avalonia.Base.UnitTests
 
             public bool CurrentThreadIsLoopThread { get; set; }
 
+#pragma warning disable 67
             public event Action<DispatcherPriority?> Signaled;
+#pragma warning restore 67
 
             public void RunLoop(CancellationToken cancellationToken)
             {

+ 1 - 4
tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
 using Xunit;
 using Avalonia.Controls.UnitTests;
 using Avalonia.Platform;
+using Avalonia.UnitTests;
 
 [assembly: ExportAvaloniaModule("DefaultModule", typeof(AppBuilderTests.DefaultModule))]
 [assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.Direct2DModule), ForRenderingSubsystem = "Direct2D1")]
@@ -65,7 +66,6 @@ namespace Avalonia.Controls.UnitTests
             {
                 ResetModuleLoadStates();
                 AppBuilder.Configure<App>()
-                    .IgnoreSetupCheck()
                     .UseWindowingSubsystem(() => { })
                     .UseRenderingSubsystem(() => { })
                     .UseAvaloniaModules()
@@ -82,7 +82,6 @@ namespace Avalonia.Controls.UnitTests
             {
                 ResetModuleLoadStates();
                 var builder = AppBuilder.Configure<App>()
-                    .IgnoreSetupCheck()
                     .UseWindowingSubsystem(() => { })
                     .UseRenderingSubsystem(() => { }, "Direct2D1");
                 builder.UseAvaloniaModules().SetupWithoutStarting();
@@ -92,7 +91,6 @@ namespace Avalonia.Controls.UnitTests
 
                 ResetModuleLoadStates();
                 builder = AppBuilder.Configure<App>()
-                    .IgnoreSetupCheck()
                     .UseWindowingSubsystem(() => { })
                     .UseRenderingSubsystem(() => { }, "Skia");
                 builder.UseAvaloniaModules().SetupWithoutStarting();
@@ -109,7 +107,6 @@ namespace Avalonia.Controls.UnitTests
             {
                 ResetModuleLoadStates();
                 var builder = AppBuilder.Configure<App>()
-                    .IgnoreSetupCheck()
                     .UseWindowingSubsystem(() => { })
                     .UseRenderingSubsystem(() => { }, "TBD");
                 builder.UseAvaloniaModules().SetupWithoutStarting();

+ 205 - 1
tests/Avalonia.Controls.UnitTests/CarouselTests.cs

@@ -1,11 +1,13 @@
 // 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.Collections.ObjectModel;
 using System.Linq;
 using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.LogicalTree;
+using Avalonia.VisualTree;
 using Xunit;
 
 namespace Avalonia.Controls.UnitTests
@@ -50,7 +52,7 @@ namespace Avalonia.Controls.UnitTests
             Assert.Single(target.GetLogicalChildren());
 
             var child = target.GetLogicalChildren().Single();
-            
+
             Assert.IsType<TextBlock>(child);
             Assert.Equal("Foo", ((TextBlock)child).Text);
         }
@@ -93,6 +95,208 @@ namespace Avalonia.Controls.UnitTests
             Assert.Equal(2, target.ItemContainerGenerator.Containers.Count());
         }
 
+        [Fact]
+        public void Selected_Item_Changes_To_First_Item_When_Items_Property_Changes()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "FooBar"
+            };
+
+            var target = new Carousel
+            {
+                Template = new FuncControlTemplate<Carousel>(CreateTemplate),
+                Items = items,
+                IsVirtualized = false
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            Assert.Single(target.GetLogicalChildren());
+
+            var child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Foo", ((TextBlock)child).Text);
+
+            var newItems = items.ToList();
+            newItems.RemoveAt(0);
+
+            target.Items = newItems;
+
+            child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Bar", ((TextBlock)child).Text);
+        }
+
+        [Fact]
+        public void Selected_Item_Changes_To_First_Item_When_Items_Property_Changes_And_Virtualized()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "FooBar"
+            };
+
+            var target = new Carousel
+            {
+                Template = new FuncControlTemplate<Carousel>(CreateTemplate),
+                Items = items
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            Assert.Single(target.GetLogicalChildren());
+
+            var child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Foo", ((TextBlock)child).Text);
+
+            var newItems = items.ToList();
+            newItems.RemoveAt(0);
+
+            target.Items = newItems;
+
+            child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Bar", ((TextBlock)child).Text);
+        }
+
+        [Fact]
+        public void Selected_Index_Changes_To_When_Items_Assigned_Null()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "FooBar"
+            };
+
+            var target = new Carousel
+            {
+                Template = new FuncControlTemplate<Carousel>(CreateTemplate),
+                Items = items,
+                IsVirtualized = false
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            Assert.Single(target.GetLogicalChildren());
+
+            var child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Foo", ((TextBlock)child).Text);
+
+            target.Items = null;
+
+            var numChildren = target.GetLogicalChildren().Count();
+
+            Assert.Equal(0, numChildren);
+            Assert.Equal(-1, target.SelectedIndex);
+        }
+
+        [Fact]
+        public void Selected_Index_Is_Maintained_Carousel_Created_With_Non_Zero_SelectedIndex()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "FooBar"
+            };
+
+            var target = new Carousel
+            {
+                Template = new FuncControlTemplate<Carousel>(CreateTemplate),
+                Items = items,
+                IsVirtualized = false,
+                SelectedIndex = 2
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            Assert.Equal("FooBar", target.SelectedItem);
+
+            var child = target.GetVisualDescendants().LastOrDefault();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("FooBar", ((TextBlock)child).Text);
+        }
+
+        [Fact]
+        public void Selected_Item_Changes_To_Next_First_Item_When_Item_Removed_From_Beggining_Of_List()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "FooBar"
+            };
+
+            var target = new Carousel
+            {
+                Template = new FuncControlTemplate<Carousel>(CreateTemplate),
+                Items = items,
+                IsVirtualized = false
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            Assert.Single(target.GetLogicalChildren());
+
+            var child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Foo", ((TextBlock)child).Text);
+
+            items.RemoveAt(0);
+
+            child = target.GetLogicalChildren().Single();
+
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Bar", ((TextBlock)child).Text);
+        }
+
+        [Fact]
+        public void Selected_Item_Changes_To_NextAvailable_Item_If_SelectedItem_Is_Removed_From_Middle()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "FooBar"
+            };
+
+            var target = new Carousel
+            {
+                Template = new FuncControlTemplate<Carousel>(CreateTemplate),
+                Items = items,
+                IsVirtualized = false
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            target.SelectedIndex = 1;
+
+            items.RemoveAt(1);
+
+            Assert.Equal(1, target.SelectedIndex);
+            Assert.Equal("FooBar", target.SelectedItem);
+        }
+
         private Control CreateTemplate(Carousel control)
         {
             return new CarouselPresenter

+ 59 - 0
tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs

@@ -5,6 +5,7 @@ using System;
 using System.Linq;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
+using Avalonia.Input;
 using Avalonia.Media;
 using Xunit;
 
@@ -59,6 +60,64 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal(50, target.Value);
         }
 
+        [Fact]
+        public void Thumb_DragDelta_Event_Should_Raise_Scroll_Event()
+        {
+            var target = new ScrollBar
+            {
+                Template = new FuncControlTemplate<ScrollBar>(Template),
+            };
+
+            target.ApplyTemplate();
+
+            var track = (Track)target.GetTemplateChildren().First(x => x.Name == "track");
+
+            var raisedEvent = Assert.Raises<ScrollEventArgs>(
+                handler => target.Scroll += handler,
+                handler => target.Scroll -= handler,
+                () =>
+                {
+                    var ev = new VectorEventArgs
+                    {
+                        RoutedEvent = Thumb.DragDeltaEvent,
+                        Vector = new Vector(0, 0)
+                    };
+
+                    track.Thumb.RaiseEvent(ev);
+                });
+
+            Assert.Equal(ScrollEventType.ThumbTrack, raisedEvent.Arguments.ScrollEventType);
+        }
+
+        [Fact]
+        public void Thumb_DragComplete_Event_Should_Raise_Scroll_Event()
+        {
+            var target = new ScrollBar
+            {
+                Template = new FuncControlTemplate<ScrollBar>(Template),
+            };
+
+            target.ApplyTemplate();
+
+            var track = (Track)target.GetTemplateChildren().First(x => x.Name == "track");
+
+            var raisedEvent = Assert.Raises<ScrollEventArgs>(
+                handler => target.Scroll += handler,
+                handler => target.Scroll -= handler,
+                () =>
+                {
+                    var ev = new VectorEventArgs
+                    {
+                        RoutedEvent = Thumb.DragCompletedEvent,
+                        Vector = new Vector(0, 0)
+                    };
+
+                    track.Thumb.RaiseEvent(ev);
+                });
+
+            Assert.Equal(ScrollEventType.EndScroll, raisedEvent.Arguments.ScrollEventType);
+        }
+
         [Fact]
         public void ScrollBar_Can_AutoHide()
         {

+ 53 - 0
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@@ -247,6 +247,59 @@ namespace Avalonia.Controls.UnitTests
             }
         }
 
+        [Fact]
+        public void Press_Enter_Does_Not_Accept_Return()
+        {
+            using (UnitTestApplication.Start(Services))
+            {
+                var target = new TextBox
+                {
+                    Template = CreateTemplate(),
+                    AcceptsReturn = false,
+                    Text = "1234"
+                };
+
+                RaiseKeyEvent(target, Key.Enter, 0);
+
+                Assert.Equal("1234", target.Text);
+            }
+        }
+
+        [Fact]
+        public void Press_Enter_Add_Default_Newline()
+        {
+            using (UnitTestApplication.Start(Services))
+            {
+                var target = new TextBox
+                {
+                    Template = CreateTemplate(),
+                    AcceptsReturn = true
+                };
+
+                RaiseKeyEvent(target, Key.Enter, 0);
+
+                Assert.Equal(Environment.NewLine, target.Text);
+            }
+        }
+
+        [Fact]
+        public void Press_Enter_Add_Custom_Newline()
+        {
+            using (UnitTestApplication.Start(Services))
+            {
+                var target = new TextBox
+                {
+                    Template = CreateTemplate(),
+                    AcceptsReturn = true,
+                    NewLine = "Test"
+                };
+
+                RaiseKeyEvent(target, Key.Enter, 0);
+
+                Assert.Equal("Test", target.Text);
+            }
+        }
+
         [Theory]
         [InlineData(new object[] { false, TextWrapping.NoWrap, ScrollBarVisibility.Hidden })]
         [InlineData(new object[] { false, TextWrapping.Wrap, ScrollBarVisibility.Hidden })]

+ 1 - 1
tests/Avalonia.DesignerSupport.TestApp/Avalonia.DesignerSupport.TestApp.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp2.0</TargetFramework>    
+    <TargetFramework>netcoreapp2.0</TargetFramework> 
   </PropertyGroup>
   <ItemGroup>
     <Compile Update="**\*.xaml.cs">

+ 8 - 0
tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

@@ -19,6 +19,12 @@ namespace Avalonia.DesignerSupport.Tests
     public class DesignerSupportTests
     {
         private const string DesignerAppPath = "../../../../../src/tools/Avalonia.Designer.HostApp/bin/$BUILD/netcoreapp2.0/Avalonia.Designer.HostApp.dll";
+        private readonly Xunit.Abstractions.ITestOutputHelper outputHelper;
+
+        public DesignerSupportTests(Xunit.Abstractions.ITestOutputHelper outputHelper)
+        {
+            this.outputHelper = outputHelper;
+        }
 
         [SkippableTheory,
          InlineData(
@@ -73,6 +79,8 @@ namespace Avalonia.DesignerSupport.Tests
                     }
                     else if (msg is UpdateXamlResultMessage result)
                     {
+                        if (result.Error != null)
+                            outputHelper.WriteLine(result.Error);
                         handle = result.Handle != null ? long.Parse(result.Handle) : 0;
                         resultMessageReceivedToken.Cancel();
                         conn.Dispose();

+ 1 - 1
tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs

@@ -403,7 +403,7 @@ namespace Avalonia.Interactivity.UnitTests
         private class TestInteractive : Interactive
         {
             public bool ClassHandlerInvoked { get; private set; }
-            public string Name { get; set; }
+            public new string Name { get; set; }
 
             public IEnumerable<IVisual> Children
             {

+ 1 - 0
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@@ -21,6 +21,7 @@ using Xunit;
 using Avalonia.Media;
 using System;
 using System.Collections.Generic;
+using Avalonia.UnitTests;
 
 namespace Avalonia.Layout.UnitTests
 {

+ 3 - 6
tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj

@@ -1,13 +1,13 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.0</TargetFrameworks>
+    <TargetFrameworks>net461</TargetFrameworks>
   </PropertyGroup>
   <Import Project="..\..\build\JetBrains.dotMemoryUnit.props" />
   <Import Project="..\..\build\Moq.props" />
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\XUnit.props" />
+  <Import Project="..\..\build\NetFX.props" />
   <ItemGroup>
-    <ProjectReference Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
@@ -19,13 +19,10 @@
     <ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
-    <ProjectReference Include="..\Avalonia.Controls.UnitTests\Avalonia.Controls.UnitTests.csproj" />
     <ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />
+    <Compile Remove="testproject/**/*.cs" />
   </ItemGroup>
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Properties\" />
-  </ItemGroup>
 </Project>

+ 8 - 0
tests/Avalonia.LeakTests/Properties/AssemblyInfo.cs

@@ -0,0 +1,8 @@
+// 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.Reflection;
+using Xunit;
+
+// Don't run tests in parallel.
+[assembly: CollectionBehavior(DisableTestParallelization = true)]

+ 0 - 11
tests/Avalonia.LeakTests/toolproject/tool.csproj

@@ -1,11 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
-  <PropertyGroup>
-    <OutputPath>$(MSBuildThisFileDirectory)\bin</OutputPath>
-    <OutDir>$(OutputPath)</OutDir>
-    <TargetFrameworks>net461</TargetFrameworks>
-    <OutputType>Library</OutputType>
-  </PropertyGroup>
-  <ItemGroup>
-    <PackageReference Include="JetBrains.dotMemory.Unit" Version="109.0.20170720.104130-eap09" />
-  </ItemGroup>
-</Project>

+ 2 - 0
tests/Avalonia.RenderTests/TestBase.cs

@@ -161,7 +161,9 @@ namespace Avalonia.Direct2D1.RenderTests
 
             public Thread MainThread { get; set; }
 
+#pragma warning disable 67
             public event Action<DispatcherPriority?> Signaled;
+#pragma warning restore 67
 
             public void RunLoop(CancellationToken cancellationToken)
             {

+ 2 - 20
tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj

@@ -1,22 +1,10 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.0</TargetFrameworks>
+    <TargetFrameworks>netstandard2.0</TargetFrameworks>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <OutputType>Library</OutputType>
   </PropertyGroup>
-  <ItemGroup Condition="'$(TargetFramework)' == 'net461'">
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
   <ItemGroup>
-    <ProjectReference Condition="'$(TargetFramework)' == 'net461'" Include="..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
-	  <ProjectReference Condition="'$(TargetFramework)' == 'netcoreapp2.0'" Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
     <ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
@@ -29,13 +17,7 @@
     <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="app.config" />
-  </ItemGroup>
   <Import Project="..\..\build\Moq.props" />
   <Import Project="..\..\build\Rx.props" />
-  <Import Project="..\..\build\XUnit.props" />
-  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
-      <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
-  </ItemGroup>
+  <Import Project="..\..\src\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
 </Project>

+ 16 - 0
tests/Avalonia.UnitTests/RuntimeInfo.cs

@@ -0,0 +1,16 @@
+using Avalonia.Platform;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Avalonia.Shared.PlatformSupport
+{
+    internal partial class StandardRuntimePlatform : IRuntimePlatform
+    {
+        public RuntimePlatformInfo GetRuntimeInfo()
+        {
+            return new RuntimePlatformInfo();
+        }
+    }
+}

+ 14 - 0
tests/Avalonia.UnitTests/TestServices.cs

@@ -14,6 +14,8 @@ using Avalonia.Themes.Default;
 using Avalonia.Rendering;
 using System.Reactive.Concurrency;
 using System.Collections.Generic;
+using Avalonia.Controls;
+using System.Reflection;
 
 namespace Avalonia.UnitTests
 {
@@ -178,4 +180,16 @@ namespace Avalonia.UnitTests
                     y => y.Open() == Mock.Of<IStreamGeometryContextImpl>()));
         }
     }
+
+    public class AppBuilder : AppBuilderBase<AppBuilder>
+    {
+        public AppBuilder()
+            : base(new StandardRuntimePlatform(),
+                  builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType()
+                      ?.GetTypeInfo().Assembly))
+        {
+        }
+
+        protected override bool CheckSetup => false;
+    }
 }

+ 0 - 11
tests/Avalonia.UnitTests/app.config

@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Moq" publicKeyToken="69f491c39445e920" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.1510.2205" newVersion="4.2.1510.2205" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>

+ 1 - 1
tools/packages.config

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-    <package id="Cake" version="0.25.0" />
+    <package id="Cake" version="0.28.0" />
 </packages>