Browse Source

Merge pull request #1105 from AvaloniaUI/remote2

Remoting & New Previewer
pull/1205/head
Nikita Tsukanov 9 years ago
committed by GitHub
parent
commit
e755664bec
  1. 1
      .gitignore
  2. 219
      Avalonia.sln
  3. 27
      packages.cake
  4. 10
      samples/ControlCatalog.Desktop/Program.cs
  5. 17
      samples/ControlCatalog.NetCore/Program.cs
  6. 6
      samples/Previewer/App.xaml
  7. 14
      samples/Previewer/App.xaml.cs
  8. 19
      samples/Previewer/Center.cs
  9. 12
      samples/Previewer/MainWindow.xaml
  10. 86
      samples/Previewer/MainWindow.xaml.cs
  11. 27
      samples/Previewer/Previewer.csproj
  12. 13
      samples/Previewer/Program.cs
  13. 53
      samples/RemoteTest/Program.cs
  14. 25
      samples/RemoteTest/RemoteTest.csproj
  15. 3
      src/Avalonia.Base/AvaloniaObject.cs
  16. 3
      src/Avalonia.Controls/Avalonia.Controls.csproj
  17. 2
      src/Avalonia.Controls/Design.cs
  18. 63
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
  19. 66
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  20. 14
      src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs
  21. 40
      src/Avalonia.Controls/Remote/RemoteServer.cs
  22. 79
      src/Avalonia.Controls/Remote/RemoteWidget.cs
  23. 176
      src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
  24. 2
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  25. 76
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  26. 60
      src/Avalonia.DesignerSupport/DesignerAssist.cs
  27. 35
      src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs
  28. 96
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  29. 66
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs
  30. 172
      src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs
  31. 146
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  32. 1
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  33. 5
      src/Avalonia.Input/Key.cs
  34. 9
      src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj
  35. 19
      src/Avalonia.Remote.Protocol/AvaloniaRemoteMessageGuidAttribute.cs
  36. 150
      src/Avalonia.Remote.Protocol/BsonStreamTransport.cs
  37. 27
      src/Avalonia.Remote.Protocol/BsonTcpTransport.cs
  38. 35
      src/Avalonia.Remote.Protocol/DefaultMessageTypeResolver.cs
  39. 17
      src/Avalonia.Remote.Protocol/DesignMessages.cs
  40. 74
      src/Avalonia.Remote.Protocol/EventStash.cs
  41. 10
      src/Avalonia.Remote.Protocol/IMessageTypeResolver.cs
  42. 15
      src/Avalonia.Remote.Protocol/ITransport.cs
  43. 82
      src/Avalonia.Remote.Protocol/InputMessages.cs
  44. 1632
      src/Avalonia.Remote.Protocol/MetsysBson.cs
  45. 78
      src/Avalonia.Remote.Protocol/TcpTransportBase.cs
  46. 101
      src/Avalonia.Remote.Protocol/TransportConnectionWrapper.cs
  47. 64
      src/Avalonia.Remote.Protocol/ViewportMessages.cs
  48. 33
      src/Avalonia.Visuals/Platform/LockedFramebuffer.cs
  49. 24
      src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj
  50. 7
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  51. 2
      src/Linux/Avalonia.LinuxFramebuffer/Mice.cs
  52. 111
      src/tools/Avalonia.Designer.HostApp.NetFX/Avalonia.Designer.HostApp.NetFX.csproj
  53. 14
      src/tools/Avalonia.Designer.HostApp.NetFX/Program.cs
  54. 8
      src/tools/Avalonia.Designer.HostApp.NetFX/Properties/launchSettings.json
  55. 25
      src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj
  56. 10
      src/tools/Avalonia.Designer.HostApp/Program.cs
  57. 52
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Threading.cs

1
.gitignore

@ -175,3 +175,4 @@ artifacts/
nuget
Avalonia.XBuild.sln
project.lock.json
.idea/*

219
Avalonia.sln

@ -1,3 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.3
@ -178,10 +179,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Remote.Protocol", "src\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj", "{D78A720C-C0C6-478B-8564-F167F9BDD01B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteTest", "samples\RemoteTest\RemoteTest.csproj", "{E2999E4A-9086-401F-898C-AEB0AD38E676}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{4ED8B739-6F4E-4CD4-B993-545E6B5CE637}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp", "src\tools\Avalonia.Designer.HostApp\Avalonia.Designer.HostApp.csproj", "{050CC912-FF49-4A8B-B534-9544017446DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Previewer", "samples\Previewer\Previewer.csproj", "{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OSX", "OSX", "{A59C4C0A-64DF-4621-B450-2BA00D6F61E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MonoMac", "src\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj", "{CBFD5788-567D-401B-9DFA-74E4224025A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Designer.HostApp.NetFX", "src\tools\Avalonia.Designer.HostApp.NetFX\Avalonia.Designer.HostApp.NetFX.csproj", "{4ADA61C8-D191-428D-9066-EF4F0D86520F}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -191,7 +204,6 @@ Global
tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{48840edd-24bf-495d-911e-2eb12ae75d3b}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7863ea94-f0fb-4386-bf8c-e5bfa761560a}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{9defc6b7-845b-4d8f-afc0-d32bf0032b8c}*SharedItemsImports = 13
@ -2355,6 +2367,166 @@ Global
{E1582370-37B3-403C-917F-8209551B1634}.Release|Mono.Build.0 = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.ActiveCfg = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Mono.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Mono.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|x86.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|x86.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Mono.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Mono.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|x86.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|x86.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Mono.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Mono.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|x86.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|x86.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Mono.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Mono.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|x86.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|x86.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Mono.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Mono.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|x86.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|x86.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Mono.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Mono.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|x86.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|x86.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Any CPU.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhone.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Mono.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Mono.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|x86.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|x86.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhone.Build.0 = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Mono.ActiveCfg = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Mono.Build.0 = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|x86.ActiveCfg = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Debug|x86.Build.0 = Debug|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhone.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhone.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Mono.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|Mono.Build.0 = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|x86.ActiveCfg = Release|Any CPU
{050CC912-FF49-4A8B-B534-9544017446DD}.Release|x86.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Any CPU.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhone.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Mono.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Mono.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|x86.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|x86.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhone.Build.0 = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Mono.ActiveCfg = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Mono.Build.0 = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|x86.ActiveCfg = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|x86.Build.0 = Debug|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Any CPU.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Mono.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Mono.Build.0 = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|x86.ActiveCfg = Release|Any CPU
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|x86.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
@ -2395,6 +2567,46 @@ Global
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Mono.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|x86.ActiveCfg = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|x86.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Any CPU.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhone.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Mono.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|Mono.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|x86.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.AppStore|x86.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhone.Build.0 = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Mono.ActiveCfg = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|Mono.Build.0 = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|x86.ActiveCfg = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Debug|x86.Build.0 = Debug|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Any CPU.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhone.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhone.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Mono.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|Mono.Build.0 = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|x86.ActiveCfg = Release|Any CPU
{4ADA61C8-D191-428D-9066-EF4F0D86520F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2448,7 +2660,10 @@ Global
{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2}
{E2999E4A-9086-401F-898C-AEB0AD38E676} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{050CC912-FF49-4A8B-B534-9544017446DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4ADA61C8-D191-428D-9066-EF4F0D86520F} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

27
packages.cake

@ -223,6 +223,17 @@ public class Packages
};
});
var toolsContent = new[] {
new NuSpecContent{
Source = ((FilePath)context.File("./src/tools/Avalonia.Designer.HostApp/bin/" + parameters.DirSuffix + "/netcoreapp2.0/Avalonia.Designer.HostApp.dll")).FullPath,
Target = "tools/netcoreapp2.0/previewer"
},
new NuSpecContent{
Source = ((FilePath)context.File("./src/tools/Avalonia.Designer.HostApp.NetFx/bin/" + parameters.DirSuffix + "/Avalonia.Designer.HostApp.exe")).FullPath,
Target = "tools/net461/previewer"
}
};
var nuspecNuGetSettingsCore = new []
{
///////////////////////////////////////////////////////////////////////////////
@ -237,6 +248,7 @@ public class Packages
new NuSpecDependency() { Id = "Splat", Version = SplatVersion },
new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion },
new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version },
//.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" },
@ -245,6 +257,7 @@ public class Packages
new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp2.0", Version = SerilogVersion },
new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp2.0", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp2.0", Version = SystemReactiveVersion },
new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", TargetFramework = "netcoreapp2.0", Version = parameters.Version },
}
.Deps(new string[]{null, "netcoreapp2.0"},
"System.ValueTuple", "System.ComponentModel.TypeConverter", "System.ComponentModel.Primitives",
@ -253,6 +266,7 @@ public class Packages
Files = coreLibrariesNuSpecContent
.Concat(win32CoreLibrariesNuSpecContent).Concat(net45RuntimePlatform)
.Concat(netcoreappCoreLibrariesNuSpecContent).Concat(netCoreRuntimePlatform)
.Concat(toolsContent)
.ToList(),
BasePath = context.Directory("./"),
OutputDirectory = parameters.NugetRoot
@ -291,6 +305,19 @@ public class Packages
BasePath = context.Directory("./src/Avalonia.ReactiveUI/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Remote.Protocol
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.Remote.Protocol",
Files = new []
{
new NuSpecContent { Source = "Avalonia.Remote.Protocol.dll", Target = "lib/netstandard2.0" }
},
BasePath = context.Directory("./src/Avalonia.Remote.Protocol/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot
},
};
var nuspecNuGetSettingsMobile = new []

10
samples/ControlCatalog.Desktop/Program.cs

@ -16,11 +16,15 @@ namespace ControlCatalog
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args
// again.
AppBuilder.Configure<App>()
.UsePlatformDetect()
.Start<MainWindow>();
BuildAvaloniaApp().Start<MainWindow>();
}
/// <summary>
/// This method is needed for IDE previewer infrastructure
/// </summary>
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>().UsePlatformDetect();
// This will be made into a runtime configuration extension soon!
private static void InitializeLogging()
{

17
samples/ControlCatalog.NetCore/Program.cs

@ -28,19 +28,14 @@ namespace ControlCatalog.NetCore
System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
});
else
AppBuilder.Configure<App>()
.CustomPlatformDetect()
.UseReactiveUI()
.Start<MainWindow>();
BuildAvaloniaApp().Start<MainWindow>();
}
static AppBuilder CustomPlatformDetect(this AppBuilder builder)
{
//This is needed because we still aren't ready to have MonoMac backend as default one
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return builder.UseSkia().UseMonoMac();
return builder.UsePlatformDetect();
}
/// <summary>
/// This method is needed for IDE previewer infrastructure
/// </summary>
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>().UsePlatformDetect().UseReactiveUI();
static void ConsoleSilencer()
{

6
samples/Previewer/App.xaml

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

14
samples/Previewer/App.xaml.cs

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

19
samples/Previewer/Center.cs

@ -0,0 +1,19 @@
using Avalonia;
using Avalonia.Controls;
namespace Previewer
{
public class Center : Decorator
{
protected override Size ArrangeOverride(Size finalSize)
{
if (Child != null)
{
var desired = Child.DesiredSize;
Child.Arrange(new Rect((finalSize.Width - desired.Width) / 2, (finalSize.Height - desired.Height) / 2,
desired.Width, desired.Height));
}
return finalSize;
}
}
}

12
samples/Previewer/MainWindow.xaml

@ -0,0 +1,12 @@
<Window xmlns="https://github.com/avaloniaui" Width="600" Height="500"
Title="Previewer">
<Grid RowDefinitions="0.5*,200">
<ScrollViewer Name="Remote"/>
<ScrollViewer Name="ErrorsContainer" Background="#ffe0e0">
<TextBlock Name="Errors"/>
</ScrollViewer>
<TextBox Grid.Row="1" AcceptsReturn="True" Name="Xaml"/>
</Grid>
</Window>

86
samples/Previewer/MainWindow.xaml.cs

@ -0,0 +1,86 @@
using System;
using System.Net;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Remote;
using Avalonia.Markup.Xaml;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Designer;
using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading;
namespace Previewer
{
public class MainWindow : Window
{
private const string InitialXaml = @"<Window xmlns=""https://github.com/avaloniaui"" Width=""600"" Height=""500"">
<TextBlock>Hello world!</TextBlock>
</Window>";
private IAvaloniaRemoteTransportConnection _connection;
private Control _errorsContainer;
private TextBlock _errors;
private RemoteWidget _remote;
public MainWindow()
{
this.InitializeComponent();
var tb = this.FindControl<TextBox>("Xaml");
tb.Text = InitialXaml;
var scroll = this.FindControl<ScrollViewer>("Remote");
var rem = new Center();
scroll.Content = rem;
_errorsContainer = this.FindControl<Control>("ErrorsContainer");
_errors = this.FindControl<TextBlock>("Errors");
tb.GetObservable(TextBox.TextProperty).Subscribe(text => _connection?.Send(new UpdateXamlMessage
{
Xaml = text
}));
new BsonTcpTransport().Listen(IPAddress.Loopback, 25000, t =>
{
Dispatcher.UIThread.InvokeAsync(() =>
{
if (_connection != null)
{
_connection.Dispose();
_connection.OnMessage -= OnMessage;
}
_connection = t;
rem.Child = _remote = new RemoteWidget(t);
t.Send(new UpdateXamlMessage
{
Xaml = tb.Text
});
t.OnMessage += OnMessage;
});
});
Title = "Listening on 127.0.0.1:25000";
}
private void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
if (transport != _connection)
return;
if (obj is UpdateXamlResultMessage result)
{
_errorsContainer.IsVisible = result.Error != null;
_errors.Text = result.Error ?? "";
}
if (obj is RequestViewportResizeMessage resize)
{
_remote.Width = Math.Min(4096, Math.Max(resize.Width, 1));
_remote.Height = Math.Min(4096, Math.Max(resize.Height, 1));
}
});
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

27
samples/Previewer/Previewer.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml" />
<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" />
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.HtmlRenderer\Avalonia.HtmlRenderer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<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" />
</ItemGroup>
</Project>

13
samples/Previewer/Program.cs

@ -0,0 +1,13 @@
using System;
using Avalonia;
namespace Previewer
{
class Program
{
static void Main(string[] args)
{
AppBuilder.Configure<App>().UsePlatformDetect().Start<MainWindow>();
}
}
}

53
samples/RemoteTest/Program.cs

@ -0,0 +1,53 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Remote;
using Avalonia.Remote.Protocol;
using Avalonia.Threading;
using ControlCatalog;
namespace RemoteTest
{
class Program
{
static void Main(string[] args)
{
AppBuilder.Configure<App>().UsePlatformDetect().SetupWithoutStarting();
var l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
var port = ((IPEndPoint) l.LocalEndpoint).Port;
l.Stop();
var transport = new BsonTcpTransport();
transport.Listen(IPAddress.Loopback, port, sc =>
{
Dispatcher.UIThread.InvokeAsync(() =>
{
new RemoteServer(sc).Content = new MainView();
});
});
var cts = new CancellationTokenSource();
transport.Connect(IPAddress.Loopback, port).ContinueWith(t =>
{
Dispatcher.UIThread.InvokeAsync(() =>
{
var window = new Window()
{
Content = new RemoteWidget(t.Result)
};
window.Closed += delegate { cts.Cancel(); };
window.Show();
});
});
Dispatcher.UIThread.MainLoop(cts.Token);
}
}
}

25
samples/RemoteTest/RemoteTest.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
<ProjectReference Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
</Project>

3
src/Avalonia.Base/AvaloniaObject.cs

@ -56,6 +56,7 @@ namespace Avalonia
/// </summary>
public AvaloniaObject()
{
VerifyAccess();
foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegistered(this))
{
object value = property.IsDirect ?
@ -817,4 +818,4 @@ namespace Avalonia
throw new ArgumentException($"Property '{p.Name} not registered on '{this.GetType()}");
}
}
}
}

3
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -12,7 +12,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.Controls.XML</DocumentationFile>
<NoWarn>CS1591</NoWarn>
<NoWarn>CS1591;CS0067</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
@ -36,6 +36,7 @@
<ProjectReference Include="..\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
</ItemGroup>

2
src/Avalonia.Controls/Design.cs

@ -64,7 +64,7 @@ namespace Avalonia.Controls
return rv;
}
internal static void ApplyDesignerProperties(Control target, Control source)
public static void ApplyDesignModeProperties(Control target, Control source)
{
if (source.IsSet(WidthProperty))
target.Width = source.GetValue(WidthProperty);

63
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Layout;
using Avalonia.Styling;
namespace Avalonia.Controls.Embedding.Offscreen
{
class OffscreenTopLevel : TopLevel, IStyleable
{
public OffscreenTopLevelImplBase Impl { get; }
public OffscreenTopLevel(OffscreenTopLevelImplBase impl) : base(impl)
{
Impl = impl;
Prepare();
}
public void Prepare()
{
EnsureInitialized();
ApplyTemplate();
LayoutManager.Instance.ExecuteInitialLayoutPass(this);
}
private void EnsureInitialized()
{
if (!this.IsInitialized)
{
var init = (ISupportInitialize)this;
init.BeginInit();
init.EndInit();
}
}
private readonly NameScope _nameScope = new NameScope();
public event EventHandler<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
public void Register(string name, object element) => _nameScope.Register(name, element);
public object Find(string name) => _nameScope.Find(name);
public void Unregister(string name) => _nameScope.Unregister(name);
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
public void Dispose()
{
PlatformImpl.Dispose();
}
}
}

66
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Rendering;
namespace Avalonia.Controls.Embedding.Offscreen
{
public abstract class OffscreenTopLevelImplBase : ITopLevelImpl
{
private double _scaling = 1;
private Size _clientSize;
public IInputRoot InputRoot { get; private set; }
public virtual void Dispose()
{
//No-op
}
public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
public abstract void Invalidate(Rect rect);
public abstract IEnumerable<object> Surfaces { get; }
public Size ClientSize
{
get { return _clientSize; }
set
{
_clientSize = value;
Resized?.Invoke(value);
}
}
public double Scaling
{
get { return _scaling; }
set
{
_scaling = value;
ScalingChanged?.Invoke(value);
}
}
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public void SetInputRoot(IInputRoot inputRoot) => InputRoot = inputRoot;
public virtual Point PointToClient(Point point) => point;
public virtual Point PointToScreen(Point point) => point;
public virtual void SetCursor(IPlatformHandle cursor)
{
}
public Action Closed { get; set; }
public abstract IMouseDevice MouseDevice { get; }
}
}

14
src/Linux/Avalonia.LinuxFramebuffer/PlatformThreadingInterface.cs → src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs

@ -1,20 +1,17 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
namespace Avalonia.LinuxFramebuffer
namespace Avalonia.Controls.Platform
{
class PlatformThreadingInterface : IPlatformThreadingInterface, IRenderLoop
public class InternalPlatformThreadingInterface : IPlatformThreadingInterface, IRenderLoop
{
public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface();
public PlatformThreadingInterface()
public InternalPlatformThreadingInterface()
{
TlsCurrentThreadIsLoopThread = true;
StartTimer(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 66), () => Tick?.Invoke(this, new EventArgs()));
@ -37,7 +34,7 @@ namespace Avalonia.LinuxFramebuffer
while (true)
{
Action item;
lock(_actions)
lock (_actions)
if (_actions.Count == 0)
break;
else
@ -67,6 +64,7 @@ namespace Avalonia.LinuxFramebuffer
_timer = timer;
_handle = GCHandle.Alloc(_timer);
}
public void Dispose()
{
_handle.Free();
@ -110,4 +108,4 @@ namespace Avalonia.LinuxFramebuffer
public event EventHandler<EventArgs> Tick;
}
}
}

40
src/Avalonia.Controls/Remote/RemoteServer.cs

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Embedding;
using Avalonia.Controls.Remote.Server;
using Avalonia.Platform;
using Avalonia.Remote.Protocol;
namespace Avalonia.Controls.Remote
{
public class RemoteServer
{
private EmbeddableControlRoot _topLevel;
class EmbeddableRemoteServerTopLevelImpl : RemoteServerTopLevelImpl, IEmbeddableWindowImpl
{
public EmbeddableRemoteServerTopLevelImpl(IAvaloniaRemoteTransportConnection transport) : base(transport)
{
}
#pragma warning disable 67
public event Action LostFocus;
}
public RemoteServer(IAvaloniaRemoteTransportConnection transport)
{
_topLevel = new EmbeddableControlRoot(new EmbeddableRemoteServerTopLevelImpl(transport));
_topLevel.Prepare();
//TODO: Somehow react on closed connection?
}
public object Content
{
get => _topLevel.Content;
set => _topLevel.Content = value;
}
}
}

79
src/Avalonia.Controls/Remote/RemoteWidget.cs

@ -0,0 +1,79 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading;
using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Controls.Remote
{
public class RemoteWidget : Control
{
private readonly IAvaloniaRemoteTransportConnection _connection;
private FrameMessage _lastFrame;
private WritableBitmap _bitmap;
public RemoteWidget(IAvaloniaRemoteTransportConnection connection)
{
_connection = connection;
_connection.OnMessage += (t, msg) => Dispatcher.UIThread.InvokeAsync(() => OnMessage(msg));
_connection.Send(new ClientSupportedPixelFormatsMessage
{
Formats = new[]
{
Avalonia.Remote.Protocol.Viewport.PixelFormat.Bgra8888,
Avalonia.Remote.Protocol.Viewport.PixelFormat.Rgba8888,
}
});
}
private void OnMessage(object msg)
{
if (msg is FrameMessage frame)
{
_connection.Send(new FrameReceivedMessage
{
SequenceId = frame.SequenceId
});
_lastFrame = frame;
InvalidateVisual();
}
}
protected override void ArrangeCore(Rect finalRect)
{
_connection.Send(new ClientViewportAllocatedMessage
{
Width = finalRect.Width,
Height = finalRect.Height,
DpiX = 96,
DpiY = 96 //TODO: Somehow detect the actual DPI
});
base.ArrangeCore(finalRect);
}
public override void Render(DrawingContext context)
{
if (_lastFrame != null)
{
var fmt = (PixelFormat) _lastFrame.Format;
if (_bitmap == null || _bitmap.PixelWidth != _lastFrame.Width ||
_bitmap.PixelHeight != _lastFrame.Height)
_bitmap = new WritableBitmap(_lastFrame.Width, _lastFrame.Height, fmt);
using (var l = _bitmap.Lock())
{
var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width;
for (var y = 0; y < _lastFrame.Height; y++)
Marshal.Copy(_lastFrame.Data, y * _lastFrame.Stride,
new IntPtr(l.Address.ToInt64() + l.RowBytes * y), lineLen);
}
context.DrawImage(_bitmap, 1, new Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight),
new Rect(Bounds.Size));
}
base.Render(context);
}
}
}

176
src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs

@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Embedding.Offscreen;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading;
using PixelFormat = Avalonia.Platform.PixelFormat;
using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat;
namespace Avalonia.Controls.Remote.Server
{
public class RemoteServerTopLevelImpl : OffscreenTopLevelImplBase, IFramebufferPlatformSurface
{
private readonly IAvaloniaRemoteTransportConnection _transport;
private LockedFramebuffer _framebuffer;
private object _lock = new object();
private long _lastSentFrame = -1;
private long _lastReceivedFrame = -1;
private long _nextFrameNumber = 1;
private ClientViewportAllocatedMessage _pendingAllocation;
private bool _invalidated;
private Vector _dpi = new Vector(96, 96);
private ProtocolPixelFormat[] _supportedFormats;
public RemoteServerTopLevelImpl(IAvaloniaRemoteTransportConnection transport)
{
_transport = transport;
_transport.OnMessage += OnMessage;
}
protected virtual void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
{
lock (_lock)
{
if (obj is FrameReceivedMessage lastFrame)
{
lock (_lock)
{
_lastReceivedFrame = lastFrame.SequenceId;
}
Dispatcher.UIThread.InvokeAsync(RenderIfNeeded);
}
if (obj is ClientSupportedPixelFormatsMessage supportedFormats)
{
lock (_lock)
_supportedFormats = supportedFormats.Formats;
Dispatcher.UIThread.InvokeAsync(RenderIfNeeded);
}
if (obj is MeasureViewportMessage measure)
Dispatcher.UIThread.InvokeAsync(() =>
{
var m = Measure(new Size(measure.Width, measure.Height));
_transport.Send(new MeasureViewportMessage
{
Width = m.Width,
Height = m.Height
});
});
if (obj is ClientViewportAllocatedMessage allocated)
{
lock (_lock)
{
if (_pendingAllocation == null)
Dispatcher.UIThread.InvokeAsync(() =>
{
ClientViewportAllocatedMessage allocation;
lock (_lock)
{
allocation = _pendingAllocation;
_pendingAllocation = null;
}
_dpi = new Vector(allocation.DpiX, allocation.DpiY);
ClientSize = new Size(allocation.Width, allocation.Height);
RenderIfNeeded();
});
_pendingAllocation = allocated;
}
}
}
}
protected void SetDpi(Vector dpi)
{
_dpi = dpi;
RenderIfNeeded();
}
protected virtual Size Measure(Size constaint)
{
var l = (ILayoutable) InputRoot;
l.Measure(constaint);
return l.DesiredSize;
}
public override IEnumerable<object> Surfaces => new[] { this };
FrameMessage RenderFrame(int width, int height, ProtocolPixelFormat? format)
{
var fmt = format ?? ProtocolPixelFormat.Rgba8888;
var bpp = fmt == ProtocolPixelFormat.Rgb565 ? 2 : 4;
var data = new byte[width * height * bpp];
var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), width, height, width * bpp, _dpi, (PixelFormat)fmt,
null);
Paint?.Invoke(new Rect(0, 0, width, height));
}
finally
{
_framebuffer = null;
handle.Free();
}
return new FrameMessage
{
Data = data,
Format = (ProtocolPixelFormat) format,
Width = width,
Height = height,
Stride = width * bpp,
};
}
public ILockedFramebuffer Lock()
{
if (_framebuffer == null)
throw new InvalidOperationException("Paint was not requested, wait for Paint event");
return _framebuffer;
}
protected void RenderIfNeeded()
{
lock (_lock)
{
if (_lastReceivedFrame != _lastSentFrame || !_invalidated || _supportedFormats == null)
return;
}
if (ClientSize.Width < 1 || ClientSize.Height < 1)
return;
var format = ProtocolPixelFormat.Rgba8888;
foreach(var fmt in _supportedFormats)
if (fmt <= ProtocolPixelFormat.MaxValue)
{
format = fmt;
break;
}
var frame = RenderFrame((int) ClientSize.Width, (int) ClientSize.Height, format);
lock (_lock)
{
_lastSentFrame = _nextFrameNumber++;
frame.SequenceId = _lastSentFrame;
_invalidated = false;
}
_transport.Send(frame);
}
public override void Invalidate(Rect rect)
{
_invalidated = true;
Dispatcher.UIThread.InvokeAsync(RenderIfNeeded);
}
public override IMouseDevice MouseDevice { get; } = new MouseDevice();
}
}

2
src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj

@ -12,7 +12,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.DesignerSupport.xml</DocumentationFile>
<NoWarn>CS1591</NoWarn>
<NoWarn>CS1591;CS0067</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>

76
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@ -0,0 +1,76 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
namespace Avalonia.DesignerSupport
{
public class DesignWindowLoader
{
public static Window LoadDesignerWindow(string xaml, string assemblyPath)
{
Window window;
Control control;
using (PlatformManager.DesignerMode())
{
var loader = new AvaloniaXamlLoader();
var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml));
Uri baseUri = null;
if (assemblyPath != null)
{
//Fabricate fake Uri
baseUri =
new Uri("resm:Fake.xaml?assembly=" + Path.GetFileNameWithoutExtension(assemblyPath));
}
var loaded = loader.Load(stream, null, baseUri);
var styles = loaded as Styles;
if (styles != null)
{
var substitute = Design.GetPreviewWith(styles) ??
styles.Select(Design.GetPreviewWith).FirstOrDefault(s => s != null);
if (substitute != null)
{
substitute.Styles.AddRange(styles);
control = substitute;
}
else
control = new StackPanel
{
Children =
{
new TextBlock {Text = "Styles can't be previewed without Design.PreviewWith. Add"},
new TextBlock {Text = "<Design.PreviewWith>"},
new TextBlock {Text = " <Border Padding=20><!-- YOUR CONTROL FOR PREVIEW HERE--></Border>"},
new TextBlock {Text = "<Design.PreviewWith>"},
new TextBlock {Text = "before setters in your first Style"}
}
};
}
if (loaded is Application)
control = new TextBlock {Text = "Application can't be previewed in design view"};
else
control = (Control) loaded;
window = control as Window;
if (window == null)
{
window = new Window() {Content = (Control)control};
}
if (!window.IsSet(Window.SizeToContentProperty))
window.SizeToContent = SizeToContent.WidthAndHeight;
}
window.Show();
Design.ApplyDesignModeProperties(window, control);
return window;
}
}
}

60
src/Avalonia.DesignerSupport/DesignerAssist.cs

@ -86,67 +86,11 @@ namespace Avalonia.DesignerSupport
private static void UpdateXaml2(Dictionary<string, object> dic)
{
var xamlInfo = new DesignerApiXamlFileInfo(dic);
Window window;
Control control;
using (PlatformManager.DesignerMode())
{
var loader = new AvaloniaXamlLoader();
var stream = new MemoryStream(Encoding.UTF8.GetBytes(xamlInfo.Xaml));
Uri baseUri = null;
if (xamlInfo.AssemblyPath != null)
{
//Fabricate fake Uri
baseUri =
new Uri("resm:Fake.xaml?assembly=" + Path.GetFileNameWithoutExtension(xamlInfo.AssemblyPath));
}
var loaded = loader.Load(stream, null, baseUri);
var styles = loaded as Styles;
if (styles != null)
{
var substitute = Design.GetPreviewWith(styles) ??
styles.Select(Design.GetPreviewWith).FirstOrDefault(s => s != null);
if (substitute != null)
{
substitute.Styles.AddRange(styles);
control = substitute;
}
else
control = new StackPanel
{
Children =
{
new TextBlock {Text = "Styles can't be previewed without Design.PreviewWith. Add"},
new TextBlock {Text = "<Design.PreviewWith>"},
new TextBlock {Text = " <Border Padding=20><!-- YOUR CONTROL FOR PREVIEW HERE--></Border>"},
new TextBlock {Text = "<Design.PreviewWith>"},
new TextBlock {Text = "before setters in your first Style"}
}
};
}
if (loaded is Application)
control = new TextBlock {Text = "Application can't be previewed in design view"};
else
control = (Control) loaded;
window = control as Window;
if (window == null)
{
window = new Window() {Content = (Control)control};
}
if (!window.IsSet(Window.SizeToContentProperty))
window.SizeToContent = SizeToContent.WidthAndHeight;
}
Window window = DesignWindowLoader.LoadDesignerWindow(xamlInfo.Xaml, xamlInfo.AssemblyPath);
s_currentWindow?.Close();
s_currentWindow = window;
window.Show();
Design.ApplyDesignerProperties(window, control);
// ReSharper disable once PossibleNullReferenceException
// Always not null at this point
Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle);

35
src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs

@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
using Avalonia.Remote.Protocol;
namespace Avalonia.DesignerSupport.Remote
{
class DetachableTransportConnection : IAvaloniaRemoteTransportConnection
{
private IAvaloniaRemoteTransportConnection _inner;
public DetachableTransportConnection(IAvaloniaRemoteTransportConnection inner)
{
_inner = inner;
_inner.OnMessage += FireOnMessage;
}
public void Dispose()
{
if (_inner != null)
_inner.OnMessage -= FireOnMessage;
_inner = null;
}
public void FireOnMessage(IAvaloniaRemoteTransportConnection transport, object obj) => OnMessage?.Invoke(transport, obj);
public Task Send(object data)
{
return _inner?.Send(data);
}
public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
}
}

96
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -0,0 +1,96 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Controls.Remote.Server;
using Avalonia.Platform;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading;
namespace Avalonia.DesignerSupport.Remote
{
class PreviewerWindowImpl : RemoteServerTopLevelImpl, IWindowImpl, IEmbeddableWindowImpl
{
private readonly IAvaloniaRemoteTransportConnection _transport;
public PreviewerWindowImpl(IAvaloniaRemoteTransportConnection transport) : base(transport)
{
_transport = transport;
ClientSize = new Size(1, 1);
}
public void Show()
{
}
public void Hide()
{
}
public void BeginMoveDrag()
{
}
public void BeginResizeDrag(WindowEdge edge)
{
}
public Point Position { get; set; }
public Action<Point> PositionChanged { get; set; }
public Action Deactivated { get; set; }
public Action Activated { get; set; }
public IPlatformHandle Handle { get; }
public WindowState WindowState { get; set; }
public Size MaxClientSize { get; } = new Size(4096, 4096);
public event Action LostFocus;
protected override void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj)
{
// In previewer mode we completely ignore client-side viewport size
if (obj is ClientViewportAllocatedMessage alloc)
{
Dispatcher.UIThread.InvokeAsync(() => SetDpi(new Vector(alloc.DpiX, alloc.DpiY)));
return;
}
base.OnMessage(transport, obj);
}
public void Resize(Size clientSize)
{
_transport.Send(new RequestViewportResizeMessage
{
Width = clientSize.Width,
Height = clientSize.Height
});
ClientSize = clientSize;
RenderIfNeeded();
}
public IScreenImpl Screen { get; } = new ScreenStub();
public void Activate()
{
}
public void SetTitle(string title)
{
}
public IDisposable ShowDialog()
{
return Disposable.Empty;
}
public void SetSystemDecorations(bool enabled)
{
}
public void SetIcon(IWindowIconImpl icon)
{
}
public void ShowTaskbarIcon(bool value)
{
}
}
}

66
src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Platform;
using Avalonia.Remote.Protocol;
using Avalonia.Rendering;
namespace Avalonia.DesignerSupport.Remote
{
class PreviewerWindowingPlatform : IWindowingPlatform, IPlatformSettings
{
static readonly IKeyboardDevice Keyboard = new KeyboardDevice();
private static IAvaloniaRemoteTransportConnection s_transport;
private static DetachableTransportConnection s_lastWindowTransport;
private static PreviewerWindowImpl s_lastWindow;
public static List<object> PreFlightMessages = new List<object>();
public IWindowImpl CreateWindow() => new WindowStub();
public IEmbeddableWindowImpl CreateEmbeddableWindow()
{
if (s_lastWindow != null)
{
s_lastWindowTransport.Dispose();
try
{
s_lastWindow.Dispose();
}
catch
{
//Ignore
}
}
s_lastWindow =
new PreviewerWindowImpl(s_lastWindowTransport = new DetachableTransportConnection(s_transport));
foreach (var pf in PreFlightMessages)
s_lastWindowTransport.FireOnMessage(s_lastWindowTransport, pf);
return s_lastWindow;
}
public IPopupImpl CreatePopup() => new WindowStub();
public static void Initialize(IAvaloniaRemoteTransportConnection transport)
{
s_transport = transport;
var instance = new PreviewerWindowingPlatform();
var threading = new InternalPlatformThreadingInterface();
AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToSingleton<ClipboardStub>()
.Bind<IStandardCursorFactory>().ToSingleton<CursorFactoryStub>()
.Bind<IKeyboardDevice>().ToConstant(Keyboard)
.Bind<IPlatformSettings>().ToConstant(instance)
.Bind<IPlatformThreadingInterface>().ToConstant(threading)
.Bind<IRenderLoop>().ToConstant(threading)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogsStub>()
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>();
}
public Size DoubleClickSize { get; } = new Size(2, 2);
public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500);
}
}

172
src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs

@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.DesignerSupport;
using Avalonia.Input;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Designer;
using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading;
namespace Avalonia.DesignerSupport.Remote
{
public class RemoteDesignerEntryPoint
{
private static ClientSupportedPixelFormatsMessage s_supportedPixelFormats;
private static ClientViewportAllocatedMessage s_viewportAllocatedMessage;
private static IAvaloniaRemoteTransportConnection s_transport;
class CommandLineArgs
{
public string AppPath { get; set; }
public Uri Transport { get; set; }
}
static Exception Die(string error)
{
if (error != null)
{
Console.Error.WriteLine(error);
Console.Error.Flush();
}
Environment.Exit(1);
return new Exception("APPEXIT");
}
static Exception PrintUsage()
{
Console.Error.WriteLine("Usage: --transport transport_spec app");
Console.Error.WriteLine();
Console.Error.WriteLine("Example: --transport tcp-bson://127.0.0.1:30243/ MyApp.exe");
Console.Error.Flush();
return Die(null);
}
static CommandLineArgs ParseCommandLineArgs(string[] args)
{
var rv = new CommandLineArgs();
Action<string> next = null;
try
{
foreach (var arg in args)
{
if (next != null)
{
next(arg);
next = null;
}
else if (arg == "--transport")
next = a => rv.Transport = new Uri(a, UriKind.Absolute);
else if (rv.AppPath == null)
rv.AppPath = arg;
else
PrintUsage();
}
if (rv.AppPath == null || rv.Transport == null)
PrintUsage();
}
catch
{
PrintUsage();
}
return rv;
}
static IAvaloniaRemoteTransportConnection CreateTransport(Uri transport)
{
if (transport.Scheme == "tcp-bson")
{
return new BsonTcpTransport().Connect(IPAddress.Parse(transport.Host), transport.Port).Result;
}
PrintUsage();
return null;
}
interface IAppInitializer
{
Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj);
}
class AppInitializer<T> : IAppInitializer where T : AppBuilderBase<T>, new()
{
public Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj)
{
var builder = (AppBuilderBase<T>) obj;
builder.UseWindowingSubsystem(() => PreviewerWindowingPlatform.Initialize(transport));
builder.SetupWithoutStarting();
return builder.Instance;
}
}
private const string BuilderMethodName = "BuildAvaloniaApp";
class NeverClose : ICloseable
{
public event EventHandler Closed;
}
public static void Main(string[] cmdline)
{
var args = ParseCommandLineArgs(cmdline);
var transport = CreateTransport(args.Transport);
var asm = Assembly.LoadFile(System.IO.Path.GetFullPath(args.AppPath));
var entryPoint = asm.EntryPoint;
if (entryPoint == null)
throw Die($"Assembly {args.AppPath} doesn't have an entry point");
var builderMethod = entryPoint.DeclaringType.GetMethod(BuilderMethodName,
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (builderMethod == null)
throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}");
var appBuilder = builderMethod.Invoke(null, null);
var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer<>).MakeGenericType(appBuilder.GetType()));
var app = initializer.GetConfiguredApp(transport, appBuilder);
s_transport = transport;
transport.OnMessage += OnTransportMessage;
transport.OnException += (t, e) => Die(e.ToString());
app.Run(new NeverClose());
}
private static void RebuildPreFlight()
{
PreviewerWindowingPlatform.PreFlightMessages = new List<object>
{
s_supportedPixelFormats,
s_viewportAllocatedMessage
};
}
private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.InvokeAsync(() =>
{
if (obj is ClientSupportedPixelFormatsMessage formats)
{
s_supportedPixelFormats = formats;
RebuildPreFlight();
}
if (obj is ClientViewportAllocatedMessage viewport)
{
s_viewportAllocatedMessage = viewport;
RebuildPreFlight();
}
if (obj is UpdateXamlMessage xaml)
{
try
{
DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath);
s_transport.Send(new UpdateXamlResultMessage());
}
catch (Exception e)
{
s_transport.Send(new UpdateXamlResultMessage
{
Error = e.ToString()
});
}
}
});
}
}

146
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reactive.Disposables;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Rendering;
namespace Avalonia.DesignerSupport.Remote
{
class WindowStub : IPopupImpl, IWindowImpl
{
public Action Deactivated { get; set; }
public Action Activated { get; set; }
public IPlatformHandle Handle { get; }
public Size MaxClientSize { get; }
public Size ClientSize { get; }
public double Scaling { get; }
public IEnumerable<object> Surfaces { get; }
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public Action Closed { get; set; }
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public Point Position { get; set; }
public Action<Point> PositionChanged { get; set; }
public WindowState WindowState { get; set; }
public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
public void Dispose()
{
}
public void Invalidate(Rect rect)
{
}
public void SetInputRoot(IInputRoot inputRoot)
{
}
public Point PointToClient(Point point) => point;
public Point PointToScreen(Point point) => point;
public void SetCursor(IPlatformHandle cursor)
{
}
public void Show()
{
}
public void Hide()
{
}
public void BeginMoveDrag()
{
}
public void BeginResizeDrag(WindowEdge edge)
{
}
public void Activate()
{
}
public void Resize(Size clientSize)
{
}
public IScreenImpl Screen { get; } = new ScreenStub();
public void SetTitle(string title)
{
}
public IDisposable ShowDialog() => Disposable.Empty;
public void SetSystemDecorations(bool enabled)
{
}
public void SetIcon(IWindowIconImpl icon)
{
}
public void ShowTaskbarIcon(bool value)
{
}
}
class ClipboardStub : IClipboard
{
public Task<string> GetTextAsync() => Task.FromResult("");
public Task SetTextAsync(string text) => Task.CompletedTask;
public Task ClearAsync() => Task.CompletedTask;
}
class CursorFactoryStub : IStandardCursorFactory
{
public IPlatformHandle GetCursor(StandardCursorType cursorType) => new PlatformHandle(IntPtr.Zero, "STUB");
}
class IconLoaderStub : IPlatformIconLoader
{
class IconStub : IWindowIconImpl
{
public void Save(Stream outputStream)
{
}
}
public IWindowIconImpl LoadIcon(string fileName) => new IconStub();
public IWindowIconImpl LoadIcon(Stream stream) => new IconStub();
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) => new IconStub();
}
class SystemDialogsStub : ISystemDialogImpl
{
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) =>
Task.FromResult((string[]) null);
public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) =>
Task.FromResult((string) null);
}
class ScreenStub : IScreenImpl
{
public int ScreenCount => 1;
public Screen[] AllScreens { get; } =
{new Screen(new Rect(0, 0, 4000, 4000), new Rect(0, 0, 4000, 4000), true)};
}
}

1
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@ -10,7 +10,6 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />

5
src/Avalonia.Input/Key.cs

@ -1,7 +1,10 @@
// 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.
#if AVALONIA_REMOTE_PROTOCOL
namespace Avalonia.Remote.Protocol.Input
#else
namespace Avalonia.Input
#endif
{
/// <summary>
/// Defines the keys available on a keyboard.

9
src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<DefineConstants>AVALONIA_REMOTE_PROTOCOL;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Input\Key.cs" />
</ItemGroup>
</Project>

19
src/Avalonia.Remote.Protocol/AvaloniaRemoteMessageGuidAttribute.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
[AttributeUsage(AttributeTargets.Class)]
public class AvaloniaRemoteMessageGuidAttribute : Attribute
{
public Guid Guid { get; }
public AvaloniaRemoteMessageGuidAttribute(string guid)
{
Guid = Guid.Parse(guid);
}
}
}

150
src/Avalonia.Remote.Protocol/BsonStreamTransport.cs

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Metsys.Bson;
namespace Avalonia.Remote.Protocol
{
class BsonStreamTransportConnection : IAvaloniaRemoteTransportConnection
{
private readonly IMessageTypeResolver _resolver;
private readonly Stream _inputStream;
private readonly Stream _outputStream;
private readonly Action _disposeCallback;
private readonly CancellationToken _cancel;
private readonly CancellationTokenSource _cancelSource;
private readonly MemoryStream _outputBlock = new MemoryStream();
private readonly object _lock = new object();
private bool _writeOperationPending;
private bool _readingAlreadyStarted;
private bool _writerIsBroken;
private static readonly byte[] ZeroLength = new byte[4];
public BsonStreamTransportConnection(IMessageTypeResolver resolver, Stream inputStream, Stream outputStream, Action disposeCallback)
{
_resolver = resolver;
_inputStream = inputStream;
_outputStream = outputStream;
_disposeCallback = disposeCallback;
_cancelSource = new CancellationTokenSource();
_cancel = _cancelSource.Token;
}
public void Dispose()
{
_cancelSource.Cancel();
_disposeCallback?.Invoke();
}
public void StartReading()
{
lock (_lock)
{
if(_readingAlreadyStarted)
throw new InvalidOperationException("Reading has already started");
_readingAlreadyStarted = true;
Task.Run(Reader, _cancel);
}
}
async Task ReadExact(byte[] buffer)
{
int read = 0;
while (read != buffer.Length)
{
var readNow = await _inputStream.ReadAsync(buffer, read, buffer.Length - read, _cancel)
.ConfigureAwait(false);
if (readNow == 0)
throw new EndOfStreamException();
read += readNow;
}
}
async Task Reader()
{
Task.Yield();
try
{
while (true)
{
var infoBlock = new byte[20];
await ReadExact(infoBlock).ConfigureAwait(false);
var length = BitConverter.ToInt32(infoBlock, 0);
var guidBytes = new byte[16];
Buffer.BlockCopy(infoBlock, 4, guidBytes, 0, 16);
var guid = new Guid(guidBytes);
var buffer = new byte[length];
await ReadExact(buffer).ConfigureAwait(false);
var message = Deserializer.Deserialize(new BinaryReader(new MemoryStream(buffer)),
_resolver.GetByGuid(guid));
OnMessage?.Invoke(this, message);
}
}
catch (Exception e)
{
FireException(e);
}
}
public async Task Send(object data)
{
lock (_lock)
{
if(_writerIsBroken) //Ignore further calls, since there is no point of writing to "broken" stream
return;
if (_writeOperationPending)
throw new InvalidOperationException("Previous send operation was not finished");
_writeOperationPending = true;
}
try
{
var guid = _resolver.GetGuid(data.GetType()).ToByteArray();
_outputBlock.Seek(0, SeekOrigin.Begin);
_outputBlock.SetLength(0);
_outputBlock.Write(ZeroLength, 0, 4);
_outputBlock.Write(guid, 0, guid.Length);
var serialized = Serializer.Serialize(data);
_outputBlock.Write(serialized, 0, serialized.Length);
_outputBlock.Seek(0, SeekOrigin.Begin);
var length = BitConverter.GetBytes((int)_outputBlock.Length - 20);
_outputBlock.Write(length, 0, length.Length);
_outputBlock.Seek(0, SeekOrigin.Begin);
try
{
await _outputBlock.CopyToAsync(_outputStream, 0x1000, _cancel).ConfigureAwait(false);
}
catch (Exception e) //We are only catching "network"-related exceptions here
{
lock (_lock)
{
_writerIsBroken = true;
}
FireException(e);
}
}
finally
{
lock (_lock)
{
_writeOperationPending = false;
}
}
}
void FireException(Exception e)
{
var cancel = e as OperationCanceledException;
if (cancel?.CancellationToken == _cancel)
return;
OnException?.Invoke(this, e);
}
public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
}
}

27
src/Avalonia.Remote.Protocol/BsonTcpTransport.cs

@ -0,0 +1,27 @@
using System;
using System.IO;
using System.Reflection;
namespace Avalonia.Remote.Protocol
{
public class BsonTcpTransport : TcpTransportBase
{
public BsonTcpTransport(IMessageTypeResolver resolver) : base(resolver)
{
}
public BsonTcpTransport() : this(new DefaultMessageTypeResolver(typeof(BsonTcpTransport).GetTypeInfo().Assembly))
{
}
protected override IAvaloniaRemoteTransportConnection CreateTransport(IMessageTypeResolver resolver,
Stream stream, Action dispose)
{
var t = new BsonStreamTransportConnection(resolver, stream, stream, dispose);
var wrap = new TransportConnectionWrapper(t);
t.StartReading();
return wrap;
}
}
}

35
src/Avalonia.Remote.Protocol/DefaultMessageTypeResolver.cs

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
public class DefaultMessageTypeResolver : IMessageTypeResolver
{
private readonly Dictionary<Guid, Type> _guidsToTypes = new Dictionary<Guid, Type>();
private readonly Dictionary<Type, Guid> _typesToGuids = new Dictionary<Type, Guid>();
public DefaultMessageTypeResolver(params Assembly[] assemblies)
{
foreach (var asm in
(assemblies ?? new Assembly[0]).Concat(new[]
{typeof(AvaloniaRemoteMessageGuidAttribute).GetTypeInfo().Assembly}))
{
foreach (var t in asm.ExportedTypes)
{
var attr = t.GetTypeInfo().GetCustomAttribute<AvaloniaRemoteMessageGuidAttribute>();
if (attr != null)
{
_guidsToTypes[attr.Guid] = t;
_typesToGuids[t] = attr.Guid;
}
}
}
}
public Type GetByGuid(Guid id) => _guidsToTypes[id];
public Guid GetGuid(Type type) => _typesToGuids[type];
}
}

17
src/Avalonia.Remote.Protocol/DesignMessages.cs

@ -0,0 +1,17 @@
namespace Avalonia.Remote.Protocol.Designer
{
[AvaloniaRemoteMessageGuid("9AEC9A2E-6315-4066-B4BA-E9A9EFD0F8CC")]
public class UpdateXamlMessage
{
public string Xaml { get; set; }
public string AssemblyPath { get; set; }
}
[AvaloniaRemoteMessageGuid("B7A70093-0C5D-47FD-9261-22086D43A2E2")]
public class UpdateXamlResultMessage
{
public string Error { get; set; }
}
}

74
src/Avalonia.Remote.Protocol/EventStash.cs

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
namespace Avalonia.Remote.Protocol
{
class EventStash<T>
{
private readonly IAvaloniaRemoteTransportConnection _transport;
private readonly Action<Exception> _exceptionHandler;
private List<T> _stash;
private Action<IAvaloniaRemoteTransportConnection, T> _delegate;
public EventStash(IAvaloniaRemoteTransportConnection transport, Action<Exception> exceptionHandler = null)
{
_transport = transport;
_exceptionHandler = exceptionHandler;
}
public void Add(Action<IAvaloniaRemoteTransportConnection, T> handler)
{
List<T> stash;
lock (this)
{
var needsReplay = _delegate == null;
_delegate += handler;
if(!needsReplay)
return;
lock (this)
{
stash = _stash;
if(_stash == null)
return;
_stash = null;
}
}
foreach (var m in stash)
{
if (_exceptionHandler != null)
try
{
_delegate?.Invoke(_transport, m);
}
catch (Exception e)
{
_exceptionHandler(e);
}
else
_delegate?.Invoke(_transport, m);
}
}
public void Remove(Action<IAvaloniaRemoteTransportConnection, T> handler)
{
lock (this)
_delegate -= handler;
}
public void Fire(IAvaloniaRemoteTransportConnection transport, T ev)
{
if (_delegate == null)
{
lock (this)
{
_stash = _stash ?? new List<T>();
_stash.Add(ev);
}
}
else
_delegate?.Invoke(_transport, ev);
}
}
}

10
src/Avalonia.Remote.Protocol/IMessageTypeResolver.cs

@ -0,0 +1,10 @@
using System;
namespace Avalonia.Remote.Protocol
{
public interface IMessageTypeResolver
{
Type GetByGuid(Guid id);
Guid GetGuid(Type type);
}
}

15
src/Avalonia.Remote.Protocol/ITransport.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
public interface IAvaloniaRemoteTransportConnection : IDisposable
{
Task Send(object data);
event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
}
}

82
src/Avalonia.Remote.Protocol/InputMessages.cs

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*
We are keeping copies of core events here, so they can be used
without referencing Avalonia itself, e. g. from projects that
are using WPF, GTK#, etc
*/
namespace Avalonia.Remote.Protocol.Input
{
/// <summary>
/// Keep this in sync with InputModifiers in the main library
/// </summary>
[Flags]
public enum InputModifiers
{
Alt,
Control,
Shift,
Windows,
LeftMouseButton,
RightMouseButton,
MiddleMouseButton
}
/// <summary>
/// Keep this in sync with InputModifiers in the main library
/// </summary>
public enum MouseButton
{
None,
Left,
Right,
Middle
}
public abstract class InputEventMessageBase
{
public InputModifiers[] Modifiers { get; set; }
}
public abstract class PointerEventMessageBase : InputEventMessageBase
{
public double X { get; set; }
public double Y { get; set; }
}
[AvaloniaRemoteMessageGuid("6228F0B9-99F2-4F62-A621-414DA2881648")]
public class PointerMovedEventMessage : PointerEventMessageBase
{
}
[AvaloniaRemoteMessageGuid("7E9E2818-F93F-411A-800E-6B1AEB11DA46")]
public class PointerPressedEventMessage : PointerEventMessageBase
{
public MouseButton Button { get; set; }
}
[AvaloniaRemoteMessageGuid("4ADC84EE-E7C8-4BCF-986C-DE3A2F78EDE4")]
public class PointerReleasedEventMessage : PointerEventMessageBase
{
public MouseButton Button { get; set; }
}
[AvaloniaRemoteMessageGuid("79301A05-F02D-4B90-BB39-472563B504AE")]
public class ScrollEventMessage : PointerEventMessageBase
{
public double DeltaX { get; set; }
public double DeltaY { get; set; }
}
[AvaloniaRemoteMessageGuid("1C3B691E-3D54-4237-BFB0-9FEA83BC1DB8")]
public class KeyEventMessage : InputEventMessageBase
{
public bool IsDown { get; set; }
public Key Key { get; set; }
}
}

1632
src/Avalonia.Remote.Protocol/MetsysBson.cs

File diff suppressed because it is too large

78
src/Avalonia.Remote.Protocol/TcpTransportBase.cs

@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
public abstract class TcpTransportBase
{
private readonly IMessageTypeResolver _resolver;
public TcpTransportBase(IMessageTypeResolver resolver)
{
_resolver = resolver;
}
protected abstract IAvaloniaRemoteTransportConnection CreateTransport(IMessageTypeResolver resolver,
Stream stream, Action disposeCallback);
class DisposableServer : IDisposable
{
private readonly TcpListener _l;
public DisposableServer(TcpListener l)
{
_l = l;
}
public void Dispose()
{
try
{
_l.Stop();
}
catch
{
//Ignore
}
}
}
public IDisposable Listen(IPAddress address, int port, Action<IAvaloniaRemoteTransportConnection> cb)
{
var server = new TcpListener(address, port);
async void AcceptNew()
{
try
{
var cl = await server.AcceptTcpClientAsync();
AcceptNew();
Task.Run(async () =>
{
var tcs = new TaskCompletionSource<int>();
var t = CreateTransport(_resolver, cl.GetStream(), () => tcs.TrySetResult(0));
cb(t);
await tcs.Task;
});
}
catch
{
//Ignore and stop
}
}
server.Start();
AcceptNew();
return new DisposableServer(server);
}
public async Task<IAvaloniaRemoteTransportConnection> Connect(IPAddress address, int port)
{
var c = new TcpClient();
await c.ConnectAsync(address, port);
return CreateTransport(_resolver, c.GetStream(), c.Dispose);
}
}
}

101
src/Avalonia.Remote.Protocol/TransportConnectionWrapper.cs

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
public class TransportConnectionWrapper : IAvaloniaRemoteTransportConnection
{
private readonly IAvaloniaRemoteTransportConnection _conn;
private EventStash<object> _onMessage;
private EventStash<Exception> _onException;
private Queue<SendOperation> _sendQueue = new Queue<SendOperation>();
private object _lock =new object();
private TaskCompletionSource<int> _signal;
private bool _workerIsAlive;
public TransportConnectionWrapper(IAvaloniaRemoteTransportConnection conn)
{
_conn = conn;
_onException = new EventStash<Exception>(this);
_onMessage = new EventStash<object>(this, e => _onException.Fire(this, e));
_conn.OnException +=_onException.Fire;
conn.OnMessage += _onMessage.Fire;
}
class SendOperation
{
public object Message { get; set; }
public TaskCompletionSource<int> Tcs { get; set; }
}
public void Dispose() => _conn.Dispose();
async void Worker()
{
while (true)
{
SendOperation wi = null;
lock (_lock)
{
if (_sendQueue.Count != 0)
wi = _sendQueue.Dequeue();
}
if (wi == null)
{
var signal = new TaskCompletionSource<int>();
lock (_lock)
_signal = signal;
await signal.Task.ConfigureAwait(false);
continue;
}
try
{
await _conn.Send(wi.Message).ConfigureAwait(false);
wi.Tcs.TrySetResult(0);
}
catch (Exception e)
{
wi.Tcs.TrySetException(e);
}
}
}
public Task Send(object data)
{
var tcs = new TaskCompletionSource<int>();
lock (_lock)
{
if (!_workerIsAlive)
{
_workerIsAlive = true;
Worker();
}
_sendQueue.Enqueue(new SendOperation
{
Message = data,
Tcs = tcs
});
if (_signal != null)
{
_signal.SetResult(0);
_signal = null;
}
}
return tcs.Task;
}
public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage
{
add => _onMessage.Add(value);
remove => _onMessage.Remove(value);
}
public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException
{
add => _onException.Add(value);
remove => _onException.Remove(value);
}
}
}

64
src/Avalonia.Remote.Protocol/ViewportMessages.cs

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol.Viewport
{
public enum PixelFormat
{
Rgb565,
Rgba8888,
Bgra8888,
MaxValue = Bgra8888
}
[AvaloniaRemoteMessageGuid("6E3C5310-E2B1-4C3D-8688-01183AA48C5B")]
public class MeasureViewportMessage
{
public double Width { get; set; }
public double Height { get; set; }
}
[AvaloniaRemoteMessageGuid("BD7A8DE6-3DB8-4A13-8583-D6D4AB189A31")]
public class ClientViewportAllocatedMessage
{
public double Width { get; set; }
public double Height { get; set; }
public double DpiX { get; set; }
public double DpiY { get; set; }
}
[AvaloniaRemoteMessageGuid("9B47B3D8-61DF-4C38-ACD4-8C1BB72554AC")]
public class RequestViewportResizeMessage
{
public double Width { get; set; }
public double Height { get; set; }
}
[AvaloniaRemoteMessageGuid("63481025-7016-43FE-BADC-F2FD0F88609E")]
public class ClientSupportedPixelFormatsMessage
{
public PixelFormat[] Formats { get; set; }
}
[AvaloniaRemoteMessageGuid("68014F8A-289D-4851-8D34-5367EDA7F827")]
public class FrameReceivedMessage
{
public long SequenceId { get; set; }
}
[AvaloniaRemoteMessageGuid("F58313EE-FE69-4536-819D-F52EDF201A0E")]
public class FrameMessage
{
public long SequenceId { get; set; }
public PixelFormat Format { get; set; }
public byte[] Data { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int Stride { get; set; }
}
}

33
src/Avalonia.Visuals/Platform/LockedFramebuffer.cs

@ -0,0 +1,33 @@
using System;
namespace Avalonia.Platform
{
public class LockedFramebuffer : ILockedFramebuffer
{
private readonly Action _onDispose;
public LockedFramebuffer(IntPtr address, int width, int height, int rowBytes, Vector dpi, PixelFormat format,
Action onDispose)
{
_onDispose = onDispose;
Address = address;
Width = width;
Height = height;
RowBytes = rowBytes;
Dpi = dpi;
Format = format;
}
public IntPtr Address { get; }
public int Width { get; }
public int Height { get; }
public int RowBytes { get; }
public Vector Dpi { get; }
public PixelFormat Format { get; }
public void Dispose()
{
_onDispose?.Invoke();
}
}
}

24
src/Linux/Avalonia.LinuxFramebuffer/Avalonia.LinuxFramebuffer.csproj

@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
</Project>

7
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -12,6 +12,7 @@ using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia;
using Avalonia.Controls.Platform;
namespace Avalonia.LinuxFramebuffer
{
@ -22,6 +23,7 @@ namespace Avalonia.LinuxFramebuffer
public static MouseDevice MouseDevice = new MouseDevice();
private static readonly Stopwatch St = Stopwatch.StartNew();
internal static uint Timestamp => (uint)St.ElapsedTicks;
public static InternalPlatformThreadingInterface Threading;
public static FramebufferToplevelImpl TopLevel;
LinuxFramebufferPlatform(string fbdev = null)
{
@ -31,12 +33,13 @@ namespace Avalonia.LinuxFramebuffer
void Initialize()
{
Threading = new InternalPlatformThreadingInterface();
AvaloniaLocator.CurrentMutable
.Bind<IStandardCursorFactory>().ToTransient<CursorFactoryStub>()
.Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
.Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
.Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
.Bind<IRenderLoop>().ToConstant(PlatformThreadingInterface.Instance);
.Bind<IPlatformThreadingInterface>().ToConstant(Threading)
.Bind<IRenderLoop>().ToConstant(Threading);
}
internal static TopLevel Initialize<T>(T builder, string fbdev = null) where T : AppBuilderBase<T>, new()

2
src/Linux/Avalonia.LinuxFramebuffer/Mice.cs

@ -55,7 +55,7 @@ namespace Avalonia.LinuxFramebuffer
if (!ev.HasValue)
break;
PlatformThreadingInterface.Instance.Send(() => ProcessEvent(dev, ev.Value));
LinuxFramebufferPlatform.Threading.Send(() => ProcessEvent(dev, ev.Value));
}
}
}

111
src/tools/Avalonia.Designer.HostApp.NetFX/Avalonia.Designer.HostApp.NetFX.csproj

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4ADA61C8-D191-428D-9066-EF4F0D86520F}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Avalonia.Designer.HostApp</RootNamespace>
<AssemblyName>Avalonia.Designer.HostApp</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<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.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj">
<Project>{799a7bb5-3c2c-48b6-85a7-406a12c420da}</Project>
<Name>Avalonia.DesignerSupport</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
<Project>{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}</Project>
<Name>Avalonia.DotNetFrameworkRuntime</Name>
</ProjectReference>
<ProjectReference Include="..\..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
<Project>{3E53A01A-B331-47F3-B828-4A5717E77A24}</Project>
<Name>Avalonia.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
<Project>{6417E941-21BC-467B-A771-0DE389353CE6}</Project>
<Name>Avalonia.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Avalonia.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj">
<Project>{B61B66A3-B82D-4875-8001-89D3394FE0C9}</Project>
<Name>Avalonia.Logging.Serilog</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Avalonia.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project>
<Name>Avalonia.Themes.Default</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

14
src/tools/Avalonia.Designer.HostApp.NetFX/Program.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Designer.HostApp.NetFX
{
class Program
{
public static void Main(string[] args)
=> Avalonia.DesignerSupport.Remote.RemoteDesignerEntryPoint.Main(args);
}
}

8
src/tools/Avalonia.Designer.HostApp.NetFX/Properties/launchSettings.json

@ -0,0 +1,8 @@
{
"profiles": {
"Avalonia.Designer.HostApp.NetFX": {
"commandName": "Project",
"commandLineArgs": "--transport tcp-bson://127.0.0.1:25000/ bin/Debug/net461/ControlCatalog.Desktop.exe"
}
}
}

25
src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
<ProjectReference Include="..\..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\..\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj" />
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\Avalonia.HtmlRenderer\Avalonia.HtmlRenderer.csproj" />
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\..\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\..\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
<ProjectReference Include="..\..\..\samples\ControlCatalog.NetCore\ControlCatalog.NetCore.csproj" />
</ItemGroup>
</Project>

10
src/tools/Avalonia.Designer.HostApp/Program.cs

@ -0,0 +1,10 @@

namespace Avalonia.Designer.HostApp
{
class Program
{
public static void Main(string[] args)
=> Avalonia.DesignerSupport.Remote.RemoteDesignerEntryPoint.Main(args);
}
}

52
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Threading.cs

@ -14,13 +14,24 @@ namespace Avalonia.Base.UnitTests
{
public class AvaloniaObjectTests_Threading
{
private ThreadingInterface _threading = new ThreadingInterface(true);
[Fact]
public void StyledProperty_GetValue_Should_Throw()
public void AvaloniaObject_Constructor_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
{
var target = new Class1();
Assert.Throws<InvalidOperationException>(() => new Class1());
}
}
[Fact]
public void StyledProperty_GetValue_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.GetValue(Class1.StyledProperty));
}
}
@ -28,10 +39,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void StyledProperty_SetValue_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.SetValue(Class1.StyledProperty, "foo"));
}
}
@ -39,10 +50,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void Setting_StyledProperty_Binding_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() =>
target.Bind(
Class1.StyledProperty,
@ -53,10 +64,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void StyledProperty_ClearValue_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.ClearValue(Class1.StyledProperty));
}
}
@ -64,10 +75,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void StyledProperty_IsSet_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.IsSet(Class1.StyledProperty));
}
}
@ -75,10 +86,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void DirectProperty_GetValue_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.GetValue(Class1.DirectProperty));
}
}
@ -86,10 +97,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void DirectProperty_SetValue_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.SetValue(Class1.DirectProperty, "foo"));
}
}
@ -97,10 +108,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void Setting_DirectProperty_Binding_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() =>
target.Bind(
Class1.DirectProperty,
@ -111,10 +122,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void DirectProperty_ClearValue_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.ClearValue(Class1.DirectProperty));
}
}
@ -122,10 +133,10 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void DirectProperty_IsSet_Should_Throw()
{
using (UnitTestApplication.Start(new TestServices(threadingInterface: new ThreadingInterface())))
using (UnitTestApplication.Start(new TestServices(threadingInterface: _threading)))
{
var target = new Class1();
_threading.CurrentThreadIsLoopThread = false;
Assert.Throws<InvalidOperationException>(() => target.IsSet(Class1.DirectProperty));
}
}
@ -141,6 +152,7 @@ namespace Avalonia.Base.UnitTests
private class ThreadingInterface : IPlatformThreadingInterface
{
public ThreadingInterface(bool isLoopThread = false)
{
CurrentThreadIsLoopThread = isLoopThread;

Loading…
Cancel
Save