Browse Source

Merge branch 'fixes/fix-getvisualroot' into scenegraph

 Conflicts:
	src/Skia/Avalonia.Skia.iOS/RenderTarget.cs
	src/Skia/Avalonia.Skia.iOS/WindowDrawingContextImpl.cs
	src/Skia/Avalonia.Skia/BitmapImpl.cs
	src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
	src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
	tests/Avalonia.UnitTests/TestRoot.cs
	tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests_HitTesting.cs
	tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs
	tests/Avalonia.Visuals.UnitTests/VisualTree/VisualExtensionsTests_GetVisualsAt.cs
Steven Kirk 8 years ago
parent
commit
cb3090e931
44 changed files with 820 additions and 373 deletions
  1. 4 0
      .travis.yml
  2. 43 0
      Avalonia.sln
  3. 5 1
      appveyor.yml
  4. 1 1
      docs/guidelines/build.md
  5. 6 0
      samples/interop/Direct3DInteropSample/App.paml
  6. 13 0
      samples/interop/Direct3DInteropSample/App.paml.cs
  7. 34 0
      samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
  8. 264 0
      samples/interop/Direct3DInteropSample/MainWindow.cs
  9. 14 0
      samples/interop/Direct3DInteropSample/MainWindow.paml
  10. 45 0
      samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
  11. 47 0
      samples/interop/Direct3DInteropSample/MiniCube.fx
  12. 17 0
      samples/interop/Direct3DInteropSample/Program.cs
  13. 1 0
      src/Android/Avalonia.Android/AndroidPlatform.cs
  14. 3 3
      src/Avalonia.Base/AvaloniaObject.cs
  15. 1 1
      src/Avalonia.Base/AvaloniaProperty.cs
  16. 1 1
      src/Avalonia.Base/PriorityValue.cs
  17. 162 75
      src/Avalonia.Base/Utilities/TypeUtilities.cs
  18. 3 1
      src/Avalonia.Controls/TopLevel.cs
  19. 5 5
      src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs
  20. 26 23
      src/Avalonia.Diagnostics/ViewModels/TreeNode.cs
  21. 2 2
      src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs
  22. 4 3
      src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs
  23. 2 2
      src/Avalonia.Diagnostics/Views/TreePage.xaml.cs
  24. 7 0
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  25. 1 1
      src/Avalonia.Visuals/Visual.cs
  26. 1 0
      src/Avalonia.Visuals/VisualTree/VisualExtensions.cs
  27. 1 0
      src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs
  28. 1 0
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  29. 14 50
      src/Markup/Avalonia.Markup/DefaultValueConverter.cs
  30. 0 2
      src/Skia/Avalonia.Skia.iOS/Avalonia.Skia.iOS.csproj
  31. 0 132
      src/Skia/Avalonia.Skia.iOS/RenderTarget.cs
  32. 0 23
      src/Skia/Avalonia.Skia.iOS/WindowDrawingContextImpl.cs
  33. 1 5
      src/Skia/Avalonia.Skia/BitmapImpl.cs
  34. 1 1
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  35. 29 0
      src/Windows/Avalonia.Direct2D1/Direct2DChecker.cs
  36. 1 0
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
  37. 1 1
      src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
  38. 3 3
      src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs
  39. 0 15
      src/Windows/Avalonia.Direct2D1/WindowsVersionChecker.cs
  40. 1 0
      src/iOS/Avalonia.iOS/iOSPlatform.cs
  41. 36 17
      tests/Avalonia.LeakTests/ControlTests.cs
  42. 17 0
      tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs
  43. 1 1
      tests/Avalonia.RenderTests/app.config
  44. 1 4
      tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs

+ 4 - 0
.travis.yml

@@ -3,6 +3,10 @@ os:
   - linux
   - osx
 dist: trusty
+env:
+  global:
+    - DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+    - DOTNET_CLI_TELEMETRY_OPTOUT=1
 mono:
   - latest
 dotnet: 1.0.1

+ 43 - 0
Avalonia.sln

@@ -189,6 +189,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Direct3DInteropSample", "samples\interop\Direct3DInteropSample\Direct3DInteropSample.csproj", "{638580B0-7910-40EF-B674-DCB34DA308CD}"
+EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
@@ -2547,6 +2549,46 @@ Global
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Mono.Build.0 = Release|Any CPU
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|x86.ActiveCfg = Release|Any CPU
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|x86.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Mono.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|x86.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|x86.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Mono.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|x86.Build.0 = Debug|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Mono.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Mono.Build.0 = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|x86.ActiveCfg = Release|Any CPU
+		{638580B0-7910-40EF-B674-DCB34DA308CD}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2606,5 +2648,6 @@ Global
 		{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A} = {74487168-7D91-487E-BF93-055F2251461E}
 		{4D6FAF79-58B4-482F-9122-0668C346364C} = {74487168-7D91-487E-BF93-055F2251461E}
 		{854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
+		{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 	EndGlobalSection
 EndGlobal

+ 5 - 1
appveyor.yml

@@ -1,16 +1,20 @@
-os: Previous Visual Studio 2017
+os: Visual Studio 2017
 platform:
 - Any CPU
 skip_branch_with_pr: true
 configuration:
 - Release
 environment:
+  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
+  DOTNET_CLI_TELEMETRY_OPTOUT: 1
   NUGET_API_KEY:
     secure: Xv89dlP2MSBZKhl1nrWSxqcDgCXB0HRhOd4SWQ+jRJ7QoLxQel5mLTipXM++J3G5
   NUGET_API_URL: https://www.nuget.org/api/v2/package
   MYGET_API_KEY:
     secure: OtVfyN3ErqQrDTnWH2HDfJDlCiu/i4/X4wFmK3ZXXP7HmCiXYPSbTjMPwwdOxRaK
   MYGET_API_URL: https://www.myget.org/F/avalonia-ci/api/v2/package
+init:
+- ps: (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/appveyor/ci/master/scripts/xamarin-vs2017-151-fixed.targets', "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Microsoft.Common.Targets\ImportAfter\Xamarin.Common.targets")
 install:
   - if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi
   - if not exist dotnet-1.0.1.exe appveyor DownloadFile https://go.microsoft.com/fwlink/?linkid=843448 -FileName "dotnet-1.0.1.exe"

+ 1 - 1
docs/guidelines/build.md

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

+ 6 - 0
samples/interop/Direct3DInteropSample/App.paml

@@ -0,0 +1,6 @@
+<Application xmlns="https://github.com/avaloniaui">
+  <Application.Styles>
+    <StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
+    <StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
+  </Application.Styles>
+</Application>

+ 13 - 0
samples/interop/Direct3DInteropSample/App.paml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Markup.Xaml;
+
+namespace Direct3DInteropSample
+{
+    public class App : Application
+    {
+        public override void Initialize()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 34 - 0
samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj

@@ -0,0 +1,34 @@
+<Project Sdk="Microsoft.NET.Sdk">
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net461</TargetFramework>
+    </PropertyGroup>
+    <ItemGroup>
+        <PackageReference Include="SharpDX.Mathematics" Version="3.1.1" />
+        <PackageReference Include="SharpDX.D3DCompiler" Version="3.1.1" />
+        <Compile Update="**\*.paml.cs">
+            <DependentUpon>%(Filename)</DependentUpon>
+        </Compile>
+        <EmbeddedResource Include="**\*.paml">
+            <SubType>Designer</SubType>
+        </EmbeddedResource>
+    </ItemGroup>
+    <ItemGroup>
+      <None Remove="MiniCube.fx" />
+    </ItemGroup>
+    <ItemGroup>
+      <EmbeddedResource Include="MiniCube.fx" />
+    </ItemGroup>
+    <ItemGroup>
+        <ProjectReference Include="..\..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
+        <ProjectReference Include="..\..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj" />
+        <ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
+        <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
+        <ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
+    </ItemGroup>
+    <Import Project="..\..\..\build\Serilog.props" />
+    <Import Project="..\..\..\build\Serilog.Sinks.Trace.props" />
+    <Import Project="..\..\..\build\Splat.props" />
+    <Import Project="..\..\..\build\Rx.props" />
+    <Import Project="$(MSBuildThisFileDirectory)..\..\..\src\Shared\nuget.workaround.targets" />
+</Project>

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

@@ -0,0 +1,264 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Direct2D1.Media;
+using Avalonia.Markup.Xaml;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+using SharpDX;
+using SharpDX.D3DCompiler;
+using SharpDX.Direct2D1;
+using SharpDX.Direct3D;
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using SharpDX.WIC;
+using SharpDX.Mathematics;
+using AlphaMode = SharpDX.Direct2D1.AlphaMode;
+using Buffer = SharpDX.Direct3D11.Buffer;
+using DeviceContext = SharpDX.Direct3D11.DeviceContext;
+using Factory1 = SharpDX.DXGI.Factory1;
+using InputElement = SharpDX.Direct3D11.InputElement;
+using Matrix = SharpDX.Matrix;
+using PixelFormat = SharpDX.Direct2D1.PixelFormat;
+
+namespace Direct3DInteropSample
+{
+    class MainWindow : Window
+    {
+        private SharpDX.Direct3D11.Device _d3dDevice;
+        private SharpDX.DXGI.Device _dxgiDevice;
+        Texture2D backBuffer = null;
+        RenderTargetView renderView = null;
+        Texture2D depthBuffer = null;
+        DepthStencilView depthView = null;
+        private readonly SwapChain _swapChain;
+        private SwapChainDescription _desc;
+        private Matrix _proj = Matrix.Identity;
+        private Matrix _view;
+        private Buffer _contantBuffer;
+        private SharpDX.Direct2D1.Device _d2dDevice;
+        private SharpDX.Direct2D1.DeviceContext _d2dContext;
+        private RenderTarget _d2dRenderTarget;
+        private MainWindowViewModel _model;
+
+        public MainWindow()
+        {
+            _dxgiDevice = AvaloniaLocator.Current.GetService<SharpDX.DXGI.Device>();
+            _d3dDevice = _dxgiDevice.QueryInterface<SharpDX.Direct3D11.Device>();
+            _d2dDevice = AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Device>();
+            DataContext = _model = new MainWindowViewModel();
+            _desc = new SwapChainDescription()
+            {
+                BufferCount = 1,
+                ModeDescription =
+                   new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height,
+                            new Rational(60, 1), Format.R8G8B8A8_UNorm),
+                IsWindowed = true,
+                OutputHandle = PlatformImpl.Handle.Handle,
+                SampleDescription = new SampleDescription(1, 0),
+                SwapEffect = SwapEffect.Discard,
+                Usage = Usage.RenderTargetOutput
+            };
+
+            _swapChain = new SwapChain(new Factory1(), _d3dDevice, _desc);
+
+            _d2dContext = new SharpDX.Direct2D1.DeviceContext(_d2dDevice, DeviceContextOptions.None)
+            {
+                DotsPerInch = new Size2F(96, 96)
+            };
+
+            CreateMesh();
+            _view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
+            this.GetObservable(ClientSizeProperty).Subscribe(Resize);
+            Resize(ClientSize);
+            AvaloniaXamlLoader.Load(this);
+            Background = Avalonia.Media.Brushes.Transparent;
+        }
+
+
+        protected override void HandlePaint(Rect rect)
+        {
+            var viewProj = Matrix.Multiply(_view, _proj);
+            var context = _d3dDevice.ImmediateContext;
+            // Clear views
+            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)
+                                * Matrix.Scaling((float) _model.Zoom) * viewProj;
+            worldViewProj.Transpose();
+            context.UpdateSubresource(ref worldViewProj, _contantBuffer);
+
+            // Draw the cube
+            context.Draw(36, 0);
+            base.HandlePaint(rect);
+            // Present!
+            _swapChain.Present(0, PresentFlags.None);
+        }
+
+        
+        void CreateMesh()
+        {
+            var device = _d3dDevice;
+            // Compile Vertex and Pixel shaders
+            var vertexShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "VS", "vs_4_0");
+            var vertexShader = new VertexShader(device, vertexShaderByteCode);
+
+            var pixelShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "PS", "ps_4_0");
+            var pixelShader = new PixelShader(device, pixelShaderByteCode);
+
+            var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
+            // Layout from VertexShader input signature
+            var layout = new InputLayout(device, signature, new[]
+                    {
+                        new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
+                        new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
+                    });
+            
+            // Instantiate Vertex buiffer from vertex data
+            var vertices = Buffer.Create(device, BindFlags.VertexBuffer, new[]
+                                  {
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
+                                      new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
+
+                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
+
+                                      new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
+                                      new Vector4(-1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, 1.0f,  1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, 1.0f, -1.0f,  1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
+
+                                      new Vector4(-1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
+                                      new Vector4( 1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4(-1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,-1.0f, -1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+                                      new Vector4( 1.0f,-1.0f,  1.0f,  1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
+
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
+                                      new Vector4(-1.0f, -1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f,  1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+                                      new Vector4(-1.0f,  1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
+
+                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                                      new Vector4( 1.0f,  1.0f,  1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
+                            });
+
+            // Create Constant Buffer
+            _contantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
+
+            var context = _d3dDevice.ImmediateContext;
+
+            // Prepare All the stages
+            context.InputAssembler.InputLayout = layout;
+            context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
+            context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0));
+            context.VertexShader.SetConstantBuffer(0, _contantBuffer);
+            context.VertexShader.Set(vertexShader);
+            context.PixelShader.Set(pixelShader);
+        }
+
+        void Resize(Size size)
+        {
+            Utilities.Dispose(ref _d2dRenderTarget);
+            Utilities.Dispose(ref backBuffer);
+            Utilities.Dispose(ref renderView);
+            Utilities.Dispose(ref depthBuffer);
+            Utilities.Dispose(ref depthView);
+            var context = _d3dDevice.ImmediateContext;
+            // Resize the backbuffer
+            _swapChain.ResizeBuffers(_desc.BufferCount, (int)size.Width, (int)size.Height, Format.Unknown, SwapChainFlags.None);
+
+            // Get the backbuffer from the swapchain
+            backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
+
+            // Renderview on the backbuffer
+            renderView = new RenderTargetView(_d3dDevice, backBuffer);
+
+            // Create the depth buffer
+            depthBuffer = new Texture2D(_d3dDevice, new Texture2DDescription()
+            {
+                Format = Format.D32_Float_S8X24_UInt,
+                ArraySize = 1,
+                MipLevels = 1,
+                Width = (int)size.Width,
+                Height = (int)size.Height,
+                SampleDescription = new SampleDescription(1, 0),
+                Usage = ResourceUsage.Default,
+                BindFlags = BindFlags.DepthStencil,
+                CpuAccessFlags = CpuAccessFlags.None,
+                OptionFlags = ResourceOptionFlags.None
+            });
+
+            // Create the depth buffer view
+            depthView = new DepthStencilView(_d3dDevice, depthBuffer);
+
+            // Setup targets and viewport for rendering
+            context.Rasterizer.SetViewport(new Viewport(0, 0, (int)size.Width, (int)size.Height, 0.0f, 1.0f));
+            context.OutputMerger.SetTargets(depthView, renderView);
+
+            // Setup new projection matrix with correct aspect ratio
+            _proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)(size.Width / size.Height), 0.1f, 100.0f);
+
+            using (var dxgiBackBuffer = _swapChain.GetBackBuffer<Surface>(0))
+            {
+                _d2dRenderTarget = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>()
+                    , dxgiBackBuffer, new RenderTargetProperties
+                    {
+                        DpiX = 96,
+                        DpiY = 96,
+                        Type = RenderTargetType.Default,
+                        PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)
+                    });
+            }
+
+        }
+
+        class D3DRenderTarget: IRenderTarget
+        {
+            private readonly MainWindow _window;
+
+            public D3DRenderTarget(MainWindow window)
+            {
+                _window = window;
+            }
+            public void Dispose()
+            {
+                
+            }
+
+            public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+            {
+                return new DrawingContextImpl(visualBrushRenderer, _window._d2dRenderTarget,
+                    AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>());
+            }
+        }
+
+
+        protected override IRenderTarget CreateRenderTarget() => new D3DRenderTarget(this);
+    }
+}

+ 14 - 0
samples/interop/Direct3DInteropSample/MainWindow.paml

@@ -0,0 +1,14 @@
+<Window xmlns="https://github.com/avaloniaui" Background="White" Title="Avalonia Direct3D Demo">
+    <Grid ColumnDefinitions="*,Auto" Margin="20">
+        <StackPanel Grid.Column="1" MinWidth="200">
+            <TextBlock>Rotation X</TextBlock>
+            <Slider Value="{Binding RotationX, Mode=TwoWay}" Maximum="10"/>
+            <TextBlock>Rotation Y</TextBlock>
+            <Slider Value="{Binding RotationY, Mode=TwoWay}" Maximum="10"/>
+            <TextBlock>Rotation Z</TextBlock>
+            <Slider Value="{Binding RotationZ, Mode=TwoWay}" Maximum="10"/>
+            <TextBlock>Zoom</TextBlock>
+            <Slider Value="{Binding Zoom, Mode=TwoWay}" Maximum="3" Minimum="0.5"/>
+        </StackPanel>
+    </Grid>
+</Window>

+ 45 - 0
samples/interop/Direct3DInteropSample/MainWindowViewModel.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ReactiveUI;
+
+namespace Direct3DInteropSample
+{
+    public class MainWindowViewModel : ReactiveObject
+    {
+        private double _rotationX;
+
+        public double RotationX
+        {
+            get { return _rotationX; }
+            set { this.RaiseAndSetIfChanged(ref _rotationX, value); }
+        }
+
+        private double _rotationY = 1;
+
+        public double RotationY
+        {
+            get { return _rotationY; }
+            set { this.RaiseAndSetIfChanged(ref _rotationY, value); }
+        }
+
+        private double _rotationZ = 2;
+
+        public double RotationZ
+        {
+            get { return _rotationZ; }
+            set { this.RaiseAndSetIfChanged(ref _rotationZ, value); }
+        }
+
+
+        private double _zoom = 1;
+
+        public double Zoom
+        {
+            get { return _zoom; }
+            set { this.RaiseAndSetIfChanged(ref _zoom, value); }
+        }
+    }
+}

+ 47 - 0
samples/interop/Direct3DInteropSample/MiniCube.fx

@@ -0,0 +1,47 @@
+// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+struct VS_IN
+{
+	float4 pos : POSITION;
+	float4 col : COLOR;
+};
+
+struct PS_IN
+{
+	float4 pos : SV_POSITION;
+	float4 col : COLOR;
+};
+
+float4x4 worldViewProj;
+
+PS_IN VS( VS_IN input )
+{
+	PS_IN output = (PS_IN)0;
+	
+	output.pos = mul(input.pos, worldViewProj);
+	output.col = input.col;
+	
+	return output;
+}
+
+float4 PS( PS_IN input ) : SV_Target
+{
+	return input.col;
+}

+ 17 - 0
samples/interop/Direct3DInteropSample/Program.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia;
+
+namespace Direct3DInteropSample
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            AppBuilder.Configure<App>().UseWin32().UseDirect2D1().Start<MainWindow>();
+        }
+    }
+}

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

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

+ 3 - 3
src/Avalonia.Base/AvaloniaObject.cs

@@ -578,13 +578,13 @@ namespace Avalonia
 
             if (notification == null)
             {
-                return TypeUtilities.CastOrDefault(value, type);
+                return TypeUtilities.ConvertImplicitOrDefault(value, type);
             }
             else
             {
                 if (notification.HasValue)
                 {
-                    notification.SetValue(TypeUtilities.CastOrDefault(notification.Value, type));
+                    notification.SetValue(TypeUtilities.ConvertImplicitOrDefault(notification.Value, type));
                 }
 
                 return notification;
@@ -735,7 +735,7 @@ namespace Avalonia
                 ThrowNotRegistered(property);
             }
 
-            if (!TypeUtilities.TryCast(property.PropertyType, value, out value))
+            if (!TypeUtilities.TryConvertImplicit(property.PropertyType, value, out value))
             {
                 throw new ArgumentException(string.Format(
                     "Invalid value for Property '{0}': '{1}' ({2})",

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

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

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

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

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

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

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

@@ -188,8 +188,10 @@ namespace Avalonia.Controls
             get { return AvaloniaLocator.Current.GetService<IGlobalStyles>(); }
         }
 
+        IRenderTarget IRenderRoot.CreateRenderTarget() => CreateRenderTarget();
+
         /// <inheritdoc/>
-        IRenderTarget IRenderRoot.CreateRenderTarget()
+        protected virtual IRenderTarget CreateRenderTarget()
         {
             return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
         }

+ 5 - 5
src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs

@@ -3,19 +3,19 @@
 
 using System.Collections.Generic;
 using System.Linq;
-using Avalonia.Controls;
+using Avalonia.VisualTree;
 using ReactiveUI;
 
 namespace Avalonia.Diagnostics.ViewModels
 {
     internal class ControlDetailsViewModel : ReactiveObject
     {
-        public ControlDetailsViewModel(Control control)
+        public ControlDetailsViewModel(IVisual control)
         {
-            if (control != null)
+            if (control is AvaloniaObject avaloniaObject)
             {
-                Properties = AvaloniaPropertyRegistry.Instance.GetRegistered(control)
-                    .Select(x => new PropertyDetails(control, x))
+                Properties = AvaloniaPropertyRegistry.Instance.GetRegistered(avaloniaObject)
+                    .Select(x => new PropertyDetails(avaloniaObject, x))
                     .OrderBy(x => x.IsAttached)
                     .ThenBy(x => x.Name);
             }

+ 26 - 23
src/Avalonia.Diagnostics/ViewModels/TreeNode.cs

@@ -5,8 +5,8 @@ using System;
 using System.Collections.Specialized;
 using System.Reactive;
 using System.Reactive.Linq;
-using Avalonia.Controls;
 using Avalonia.Styling;
+using Avalonia.VisualTree;
 using ReactiveUI;
 
 namespace Avalonia.Diagnostics.ViewModels
@@ -16,32 +16,35 @@ namespace Avalonia.Diagnostics.ViewModels
         private string _classes;
         private bool _isExpanded;
 
-        public TreeNode(Control control, TreeNode parent)
+        public TreeNode(IVisual visual, TreeNode parent)
         {
-            Control = control;
             Parent = parent;
-            Type = control.GetType().Name;
+            Type = visual.GetType().Name;
+            Visual = visual;
 
-            var classesChanged = Observable.FromEventPattern<
-                    NotifyCollectionChangedEventHandler, 
-                    NotifyCollectionChangedEventArgs>(
-                x => control.Classes.CollectionChanged += x,
-                x => control.Classes.CollectionChanged -= x)
-                .TakeUntil(((IStyleable)control).StyleDetach);
+            if (visual is IStyleable styleable)
+            {
+                var classesChanged = Observable.FromEventPattern<
+                        NotifyCollectionChangedEventHandler,
+                        NotifyCollectionChangedEventArgs>(
+                    x => styleable.Classes.CollectionChanged += x,
+                    x => styleable.Classes.CollectionChanged -= x)
+                    .TakeUntil(((IStyleable)styleable).StyleDetach);
 
-            classesChanged.Select(_ => Unit.Default)
-                .StartWith(Unit.Default)
-                .Subscribe(_ =>
-                {
-                    if (control.Classes.Count > 0)
+                classesChanged.Select(_ => Unit.Default)
+                    .StartWith(Unit.Default)
+                    .Subscribe(_ =>
                     {
-                        Classes = "(" + string.Join(" ", control.Classes) + ")";
-                    }
-                    else
-                    {
-                        Classes = string.Empty;
-                    }
-                });
+                        if (styleable.Classes.Count > 0)
+                        {
+                            Classes = "(" + string.Join(" ", styleable.Classes) + ")";
+                        }
+                        else
+                        {
+                            Classes = string.Empty;
+                        }
+                    });
+            }
         }
 
         public IReadOnlyReactiveList<TreeNode> Children
@@ -56,7 +59,7 @@ namespace Avalonia.Diagnostics.ViewModels
             private set { this.RaiseAndSetIfChanged(ref _classes, value); }
         }
 
-        public Control Control
+        public IVisual Visual
         {
             get;
         }

+ 2 - 2
src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs

@@ -18,7 +18,7 @@ namespace Avalonia.Diagnostics.ViewModels
         {
             Nodes = nodes;
             _details = this.WhenAnyValue(x => x.SelectedNode)
-                .Select(x => x != null ? new ControlDetailsViewModel(x.Control) : null)
+                .Select(x => x != null ? new ControlDetailsViewModel(x.Visual) : null)
                 .ToProperty(this, x => x.Details);
         }
 
@@ -79,7 +79,7 @@ namespace Avalonia.Diagnostics.ViewModels
 
         private TreeNode FindNode(TreeNode node, IControl control)
         {
-            if (node.Control == control)
+            if (node.Visual == control)
             {
                 return node;
             }

+ 4 - 3
src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using Avalonia.Controls;
+using Avalonia.Styling;
 using Avalonia.VisualTree;
 using ReactiveUI;
 
@@ -10,7 +11,7 @@ namespace Avalonia.Diagnostics.ViewModels
     internal class VisualTreeNode : TreeNode
     {
         public VisualTreeNode(IVisual visual, TreeNode parent)
-            : base((Control)visual, parent)
+            : base(visual, parent)
         {
             var host = visual as IVisualTreeHost;
 
@@ -23,9 +24,9 @@ namespace Avalonia.Diagnostics.ViewModels
                 Children = new ReactiveList<VisualTreeNode>(new[] { new VisualTreeNode(host.Root, this) });
             }
 
-            if (Control != null)
+            if ((Visual is IStyleable styleable))
             {
-                IsInTemplate = Control.TemplatedParent != null;
+                IsInTemplate = styleable.TemplatedParent != null;
             }
         }
 

+ 2 - 2
src/Avalonia.Diagnostics/Views/TreePage.xaml.cs

@@ -23,14 +23,14 @@ namespace Avalonia.Diagnostics.Views
         protected void AddAdorner(object sender, PointerEventArgs e)
         {
             var node = (TreeNode)((Control)sender).DataContext;
-            var layer = AdornerLayer.GetAdornerLayer(node.Control);
+            var layer = AdornerLayer.GetAdornerLayer(node.Visual);
 
             if (layer != null)
             {
                 _adorner = new Rectangle
                 {
                     Fill = new SolidColorBrush(0x80a0c5e8),
-                    [AdornerLayer.AdornedElementProperty] = node.Control,
+                    [AdornerLayer.AdornedElementProperty] = node.Visual,
                 };
 
                 layer.Children.Add(_adorner);

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

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

+ 1 - 1
src/Avalonia.Visuals/Visual.cs

@@ -494,7 +494,7 @@ namespace Avalonia
             {
                 return;
             }
-            
+
             var old = _visualParent;
             _visualParent = value;
 

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

@@ -5,6 +5,7 @@ using Avalonia.Rendering;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using Avalonia.Rendering;
 
 namespace Avalonia.VisualTree
 {

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

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

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

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

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

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

+ 0 - 2
src/Skia/Avalonia.Skia.iOS/Avalonia.Skia.iOS.csproj

@@ -37,10 +37,8 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
-    <Compile Include="RenderTarget.cs" />
     <Compile Include="SkiaView.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="WindowDrawingContextImpl.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="System" />

+ 0 - 132
src/Skia/Avalonia.Skia.iOS/RenderTarget.cs

@@ -1,132 +0,0 @@
-using System;
-using Avalonia.Media;
-using Avalonia.Platform;
-using SkiaSharp;
-using CoreGraphics;
-using UIKit;
-using Avalonia.Rendering;
-
-namespace Avalonia.Skia
-{
-    internal partial class RenderTarget : IRenderTarget
-    {
-        public SKSurface Surface { get; protected set; }
-
-        public virtual IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
-        {
-            return new DrawingContextImpl(Surface.Canvas, visualBrushRenderer);
-        }
-
-        public void Dispose()
-        {
-            // Nothing to do here.
-        }
-    }
-
-    internal class WindowRenderTarget : RenderTarget
-    {
-
-        SKBitmap _bitmap;
-        int Width { get; set; }
-        int Height { get; set; }
-
-        public WindowRenderTarget()
-        {
-            FixSize();
-        }
-
-        private CGRect GetApplicationFrame()
-        {
-            // if we are excluding Status Bar then we use ApplicationFrame
-            // otherwise we use full screen bounds. Note that this must also match
-            // the Skia/AvaloniaView!!!
-            //
-            bool excludeStatusArea = false; // TODO: make this configurable later
-            if (excludeStatusArea)
-            {
-                return UIScreen.MainScreen.ApplicationFrame;
-            }
-            else
-            {
-                return UIScreen.MainScreen.Bounds;
-            }
-        }
-
-        private void FixSize()
-        {
-            int width, height;
-            GetPlatformWindowSize(out width, out height);
-            if (Width == width && Height == height)
-                return;
-
-            Width = width;
-            Height = height;
-
-            if (Surface != null)
-            {
-                Surface.Dispose();
-            }
-
-            if (_bitmap != null)
-            {
-                _bitmap.Dispose();
-            }
-
-            _bitmap = new SKBitmap(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
-
-            IntPtr length;
-            var pixels = _bitmap.GetPixels(out length);
-
-            // Wrap the bitmap in a Surface and keep it cached
-            Surface = SKSurface.Create(_bitmap.Info, pixels, _bitmap.RowBytes);
-        }
-
-        private void GetPlatformWindowSize(out int w, out int h)
-        {
-            var bounds = GetApplicationFrame();
-            w = (int)bounds.Width;
-            h = (int)bounds.Height;
-        }
-
-        public override IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
-        {
-            FixSize();
-
-            var canvas = Surface.Canvas;
-            canvas.RestoreToCount(0);
-            canvas.Save();
-
-            var screenScale = UIScreen.MainScreen.Scale;
-            canvas.Scale((float)screenScale, (float)screenScale);
-
-            canvas.Clear(SKColors.Red);
-            canvas.ResetMatrix();
-
-            return new WindowDrawingContextImpl(this);
-        }
-
-        public void Present()
-        {
-            _bitmap.LockPixels();
-            IntPtr length;
-            var pixels = _bitmap.GetPixels(out length);
-
-            const int bitmapInfo = ((int)CGBitmapFlags.ByteOrder32Big) | ((int)CGImageAlphaInfo.PremultipliedLast);
-            var bounds = GetApplicationFrame();
-            var statusBarOffset = UIScreen.MainScreen.Bounds.Height - bounds.Height;
-
-            using (var colorSpace = CGColorSpace.CreateDeviceRGB())
-            using (var bContext = new CGBitmapContext(pixels, _bitmap.Width, _bitmap.Height, 8, _bitmap.Width * 4, colorSpace, (CGImageAlphaInfo)bitmapInfo))
-            using (var image = bContext.ToImage())
-            using (var context = UIGraphics.GetCurrentContext())
-            {
-                // flip the image for CGContext.DrawImage
-                context.TranslateCTM(0, bounds.Height + statusBarOffset);
-                context.ScaleCTM(1, -1);
-                context.DrawImage(bounds, image);
-            }
-
-            _bitmap.UnlockPixels();
-        }
-    }
-}

+ 0 - 23
src/Skia/Avalonia.Skia.iOS/WindowDrawingContextImpl.cs

@@ -1,23 +0,0 @@
-
-namespace Avalonia.Skia
-{
-#if !DESKTOP
-    // not sure we need this yet
-    internal class WindowDrawingContextImpl : DrawingContextImpl
-    {
-        WindowRenderTarget _target;
-
-        public WindowDrawingContextImpl(WindowRenderTarget target)
-            : base(target.Surface.Canvas, null)
-        {
-            _target = target;
-        }
-
-        public override void Dispose()
-        {
-            base.Dispose();
-            _target.Present();
-        }
-    }
-#endif
-}

+ 1 - 5
src/Skia/Avalonia.Skia/BitmapImpl.cs

@@ -30,11 +30,7 @@ namespace Avalonia.Skia
             if (runtime?.IsDesktop == true && runtime?.OperatingSystem == OperatingSystemType.Linux)
                 colorType = SKColorType.Bgra8888;
             Bitmap = new SKBitmap(width, height, colorType, SKAlphaType.Premul);
-
-            using (var context = new BitmapDrawingContext(Bitmap, null))
-            {
-                context.Clear(Colors.Transparent);
-            }
+            Bitmap.Erase(SKColor.Empty);
         }
 
         public void Dispose()

+ 1 - 1
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@@ -98,7 +98,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RenderTarget.cs" />
     <Compile Include="SwapChainRenderTarget.cs" />
-    <Compile Include="WindowsVersionChecker.cs" />
+    <Compile Include="Direct2DChecker.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />

+ 29 - 0
src/Windows/Avalonia.Direct2D1/Direct2DChecker.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Platform;
+
+namespace Avalonia.Direct2D1
+{
+    class Direct2DChecker : IModuleEnvironmentChecker
+    {
+        //Direct2D backend doesn't work on some machines anymore
+        public bool IsCompatible
+        {
+            get
+            {
+                try
+                {
+                    Direct2D1Platform.InitializeDirect2D();
+                    return true;
+                }
+                catch
+                {
+                    return false;
+                }
+            }
+        }
+    }
+}

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

@@ -17,6 +17,7 @@ namespace Avalonia.Direct2D1.Media
     public class WicBitmapImpl : BitmapImpl
     {
         private readonly ImagingFactory _factory;
+        
 
         /// <summary>
         /// Initializes a new instance of the <see cref="WicBitmapImpl"/> class.

+ 1 - 1
src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs

@@ -7,5 +7,5 @@ using Avalonia.Direct2D1;
 
 [assembly: AssemblyTitle("Avalonia.Direct2D1")]
 [assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 1, "Direct2D1", typeof(Direct2D1Platform), nameof(Direct2D1Platform.Initialize),
-    typeof(WindowsVersionChecker))]
+    typeof(Direct2DChecker))]
 

+ 3 - 3
src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs

@@ -99,9 +99,9 @@ namespace Avalonia.Direct2D1
                         Quality = 0,
                     },
                     Usage = Usage.RenderTargetOutput,
-                    BufferCount = 2,
-                    Scaling = Scaling.None,
-                    SwapEffect = SwapEffect.FlipSequential,
+                    BufferCount = 1,
+                    Scaling = Scaling.Stretch,
+                    SwapEffect = SwapEffect.Discard,
                     Flags = 0,
                 };
 

+ 0 - 15
src/Windows/Avalonia.Direct2D1/WindowsVersionChecker.cs

@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Platform;
-
-namespace Avalonia.Direct2D1
-{
-    class WindowsVersionChecker : IModuleEnvironmentChecker
-    {
-        //Direct2D backend doesn't work with Win7 anymore
-        public bool IsCompatible => Environment.OSVersion.Version >= new Version(6, 2);
-    }
-}

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

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

+ 36 - 17
tests/Avalonia.LeakTests/ControlTests.cs

@@ -4,18 +4,15 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using JetBrains.dotMemoryUnit;
-using Avalonia.Collections;
 using Avalonia.Controls;
-using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Templates;
 using Avalonia.Diagnostics;
 using Avalonia.Layout;
 using Avalonia.Platform;
 using Avalonia.Rendering;
-using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Avalonia.VisualTree;
+using JetBrains.dotMemoryUnit;
 using Moq;
 using Xunit;
 using Xunit.Abstractions;
@@ -33,7 +30,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void Canvas_Is_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 Func<Window> run = () =>
                 {
@@ -66,7 +63,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void Named_Canvas_Is_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 Func<Window> run = () =>
                 {
@@ -103,7 +100,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void ScrollViewer_With_Content_Is_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 Func<Window> run = () =>
                 {
@@ -143,7 +140,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void TextBox_Is_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 Func<Window> run = () =>
                 {
@@ -178,7 +175,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void TextBox_With_Xaml_Binding_Is_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 Func<Window> run = () =>
                 {
@@ -225,7 +222,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void TextBox_Class_Listeners_Are_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 TextBox textBox;
 
@@ -261,7 +258,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void TreeView_Is_Freed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 Func<Window> run = () =>
                 {
@@ -313,7 +310,7 @@ namespace Avalonia.LeakTests
         [Fact]
         public void RendererIsDisposed()
         {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            using (Start())
             {
                 var renderer = new Mock<IRenderer>();
                 renderer.Setup(x => x.Dispose());
@@ -336,12 +333,10 @@ namespace Avalonia.LeakTests
             }
         }
 
-        private static void PurgeMoqReferences()
+        private IDisposable Start()
         {
-            // Moq holds onto references in its mock of IRenderer in case we want to check if a method has been called;
-            // clear these.
-            var renderer = Mock.Get(AvaloniaLocator.Current.GetService<IRenderer>());
-            renderer.ResetCalls();
+            var services = TestServices.StyledWindow.With(renderer: (root, loop) => new NullRenderer());
+            return UnitTestApplication.Start(services);
         }
 
         private class Node
@@ -349,5 +344,29 @@ namespace Avalonia.LeakTests
             public string Name { get; set; }
             public IEnumerable<Node> Children { get; set; }
         }
+
+        private class NullRenderer : IRenderer
+        {
+            public bool DrawFps { get; set; }
+            public bool DrawDirtyRects { get; set; }
+
+            public void AddDirty(IVisual visual)
+            {
+            }
+
+            public void Dispose()
+            {
+            }
+
+            public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter) => null;
+
+            public void Paint(Rect rect)
+            {
+            }
+
+            public void Resized(Size size)
+            {
+            }
+        }
     }
 }

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

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

+ 1 - 1
tests/Avalonia.RenderTests/app.config

@@ -4,7 +4,7 @@
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+        <bindingRedirect oldVersion="0.0.0.0-3.1.1.0" newVersion="3.1.1.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />

+ 1 - 4
tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests_HitTesting.cs

@@ -1,19 +1,16 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using System.Linq;
 using Avalonia.Controls;
 using Avalonia.Controls.Presenters;
 using Avalonia.Layout;
 using Avalonia.Media;
-using Avalonia.Platform;
 using Avalonia.Rendering;
 using Avalonia.UnitTests;
 using Avalonia.VisualTree;
-using Moq;
 using Xunit;
-using System;
-using Avalonia.Controls.Shapes;
 
 namespace Avalonia.Visuals.UnitTests.Rendering
 {