Browse Source

Merge remote-tracking branch 'upstream/master'

pull/398/head
Ivan Kochurkin 10 years ago
parent
commit
78b98718c9
  1. 111
      Perspex.sln
  2. 6
      docs/build.md
  3. 10
      nuget/build-appveyor.ps1
  4. 39
      nuget/build-version.ps1
  5. 2
      nuget/build.ps1
  6. 1
      nuget/include.ps1
  7. 6
      nuget/template/Perspex.Desktop.nuspec
  8. 27
      nuget/template/Perspex.iOS.nuspec
  9. 12
      readme.md
  10. 5
      samples/BindingTest/BindingTest.csproj
  11. 8
      samples/BindingTest/MainWindow.paml
  12. 3
      samples/BindingTest/TestUserControl.paml
  13. 18
      samples/BindingTest/TestUserControl.paml.cs
  14. 1
      samples/BindingTest/ViewModels/MainWindowViewModel.cs
  15. 9
      samples/BindingTest/ViewModels/TestUserControlViewModel.cs
  16. 14
      samples/ControlCatalog/App.config
  17. 16
      samples/ControlCatalog/App.paml
  18. 55
      samples/ControlCatalog/App.paml.cs
  19. BIN
      samples/ControlCatalog/Assets/delicate-arch-896885_640.jpg
  20. BIN
      samples/ControlCatalog/Assets/hirsch-899118_640.jpg
  21. BIN
      samples/ControlCatalog/Assets/maple-leaf-888807_640.jpg
  22. 190
      samples/ControlCatalog/ControlCatalog.csproj
  23. 14
      samples/ControlCatalog/MainWindow.paml
  24. 19
      samples/ControlCatalog/MainWindow.paml.cs
  25. 29
      samples/ControlCatalog/Pages/BorderPage.paml
  26. 18
      samples/ControlCatalog/Pages/BorderPage.paml.cs
  27. 26
      samples/ControlCatalog/Pages/ButtonPage.paml
  28. 18
      samples/ControlCatalog/Pages/ButtonPage.paml.cs
  29. 13
      samples/ControlCatalog/Pages/CanvasPage.paml
  30. 18
      samples/ControlCatalog/Pages/CanvasPage.paml.cs
  31. 33
      samples/ControlCatalog/Pages/CarouselPage.paml
  32. 48
      samples/ControlCatalog/Pages/CarouselPage.paml.cs
  33. 31
      samples/ControlCatalog/Pages/DropDownPage.paml
  34. 18
      samples/ControlCatalog/Pages/DropDownPage.paml.cs
  35. 36
      samples/ControlCatalog/Properties/AssemblyInfo.cs
  36. 40
      samples/ControlCatalog/SideBar.paml
  37. 5
      samples/TestApplicationShared/App.cs
  38. 25
      samples/TestApplicationShared/GalleryStyle.cs
  39. 49
      samples/TestApplicationShared/MainWindow.cs
  40. 84
      samples/XamlTestApplicationPcl/TestScrollable.cs
  41. 34
      samples/XamlTestApplicationPcl/ViewModels/MainWindowViewModel.cs
  42. 11
      samples/XamlTestApplicationPcl/ViewModels/TestNode.cs
  43. 32
      samples/XamlTestApplicationPcl/Views/MainWindow.paml
  44. 17
      samples/XamlTestApplicationPcl/XamlTestApplicationPcl.csproj
  45. 5
      samples/XamlTestApplicationPcl/packages.config
  46. 24
      src/Android/Perspex.Android/AndroidPlatform.cs
  47. 16
      src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs
  48. 2
      src/Gtk/Perspex.Cairo/CairoPlatform.cs
  49. 4
      src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
  50. 2
      src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs
  51. 4
      src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs
  52. 18
      src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs
  53. 4
      src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs
  54. 2
      src/Gtk/Perspex.Cairo/RenderTarget.cs
  55. 32
      src/Gtk/Perspex.Gtk/CursorFactory.cs
  56. 19
      src/Gtk/Perspex.Gtk/GtkPlatform.cs
  57. 2
      src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs
  58. 5
      src/Gtk/Perspex.Gtk/PopupImpl.cs
  59. 33
      src/Gtk/Perspex.Gtk/WindowImpl.cs
  60. 4
      src/Markup/Perspex.Markup.Xaml/Context/NameScopeWrapper.cs
  61. 2
      src/Markup/Perspex.Markup.Xaml/Context/PerspexContentPropertyProvider.cs
  62. 2
      src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs
  63. 7
      src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs
  64. 53
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs
  65. 10
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs
  66. 13
      src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs
  67. 1
      src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs
  68. 36
      src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs
  69. 10
      src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs
  70. 142
      src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
  71. 35
      src/Markup/Perspex.Markup.Xaml/Data/IXamlBinding.cs
  72. 30
      src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs
  73. 5
      src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  74. 4
      src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
  75. 2
      src/Markup/Perspex.Markup.Xaml/OmniXAML
  76. 12
      src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs
  77. 2
      src/Markup/Perspex.Markup.Xaml/Parsers/SelectorParser.cs
  78. 10
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  79. 29
      src/Markup/Perspex.Markup.Xaml/PerspexXamlLoader.cs
  80. 8
      src/Markup/Perspex.Markup.Xaml/Templates/DataTemplate.cs
  81. 10
      src/Markup/Perspex.Markup.Xaml/Templates/MemberSelector.cs
  82. 11
      src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs
  83. 8
      src/Markup/Perspex.Markup/ControlLocator.cs
  84. 5
      src/Markup/Perspex.Markup/Data/ExpressionNode.cs
  85. 2
      src/Markup/Perspex.Markup/Data/ExpressionNodeBuilder.cs
  86. 69
      src/Markup/Perspex.Markup/Data/ExpressionObserver.cs
  87. 19
      src/Markup/Perspex.Markup/Data/ExpressionParseException.cs
  88. 29
      src/Markup/Perspex.Markup/Data/ExpressionSubject.cs
  89. 2
      src/Markup/Perspex.Markup/Data/IndexerNode.cs
  90. 4
      src/Markup/Perspex.Markup/Data/LogicalNotNode.cs
  91. 8
      src/Markup/Perspex.Markup/Data/Parsers/ArgumentListParser.cs
  92. 4
      src/Markup/Perspex.Markup/Data/Parsers/ExpressionParser.cs
  93. 2
      src/Markup/Perspex.Markup/Data/Parsers/Reader.cs
  94. 19
      src/Markup/Perspex.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs
  95. 14
      src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs
  96. 2
      src/Markup/Perspex.Markup/FuncMultiValueConverter.cs
  97. 2
      src/Markup/Perspex.Markup/FuncValueConverter.cs
  98. 2
      src/Markup/Perspex.Markup/StringConverters.cs
  99. 8
      src/Perspex.Animation/Animatable.cs
  100. 5
      src/Perspex.Animation/Animate.cs

111
Perspex.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base", "src\Perspex.Base\Perspex.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
@ -130,9 +130,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Android", "src\Andr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.AndroidTestApplication", "src\Android\Perspex.AndroidTestApplication\Perspex.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.iOS", "src\iOS\Perspex.iOS\Perspex.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.iOSTestApplication", "src\iOS\Perspex.iOSTestApplication\Perspex.iOSTestApplication.csproj", "{8C923867-8A8F-4F6B-8B80-47D9E8436166}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.LeakTests", "tests\Perspex.LeakTests\Perspex.LeakTests.csproj", "{E1AA3DBF-9056-4530-9376-18119A7A3FFE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{61BEC86C-F307-4295-B5B8-9428610D7D55}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
@ -146,10 +157,12 @@ Global
src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{8c923867-8a8f-4f6b-8b80-47d9e8436166}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{e3a1060b-50d0-44e8-88b6-f44ef2e5bd72}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{e1aa3dbf-9056-4530-9376-18119a7a3ffe}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@ -1189,6 +1202,98 @@ Global
{FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Deploy.0 = Release|Any CPU
{FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhone.ActiveCfg = Release|Any CPU
{FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.Build.0 = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.Build.0 = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhone.Build.0 = AppStore|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhone.ActiveCfg = Debug|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhone.Build.0 = Debug|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|Any CPU.ActiveCfg = Release|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhone.ActiveCfg = Release|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhone.Build.0 = Release|iPhone
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.Build.0 = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.Build.0 = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.AppStore|Any CPU.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.AppStore|iPhone.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Debug|iPhone.Build.0 = Debug|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Release|Any CPU.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Release|iPhone.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Release|iPhone.Build.0 = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{61BEC86C-F307-4295-B5B8-9428610D7D55}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1229,5 +1334,9 @@ Global
{78345174-5B52-4A14-B9FD-D5F2428137F0} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}
{8C923867-8A8F-4F6B-8B80-47D9E8436166} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}
{E1AA3DBF-9056-4530-9376-18119A7A3FFE} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{61BEC86C-F307-4295-B5B8-9428610D7D55} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
EndGlobal

6
docs/build.md

@ -12,12 +12,14 @@ Perspex.Gtk project in Visual Studio.
### Clone the Perspex repository
git clone https://github.com/grokys/Perspex.git
git clone https://github.com/Perspex/Perspex.git
We currently need to build our own private version of ReactiveUI as it doesn't work on mono. This
is linked as a submodule in the git repository, so run:
git submodule update --init
The next step is to download the Skia native libraries. Run ```getnatives.ps1``` PowerShell script which can be found under the folder ```Perspex\src\Skia\```.
## Linux
@ -43,6 +45,8 @@ We currently need to build our own private version of ReactiveUI as it doesn't w
is linked as a submodule in the git repository, so run:
git submodule update --init
The next step is to download the Skia native libraries. Run ```getnatives.sh``` script which can be found under the folder ```Perspex\src\Skia\```.
### Load the Project in MonoDevelop

10
nuget/build-appveyor.ps1

@ -1,3 +1,4 @@
$ErrorActionPreference = "Stop"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Push-Location $dir
@ -9,6 +10,7 @@ sv version $env:APPVEYOR_BUILD_NUMBER
sv version 9999.0.$version-nightly
sv key $env:myget_key
. ".\include.ps1"
.\build-version.ps1 $version
sv reponame $env:APPVEYOR_REPO_NAME
@ -23,10 +25,10 @@ if ([string]::IsNullOrWhiteSpace($pullreq))
if($repobranch -eq "master")
{
echo "Repo branch matched"
nuget.exe push Perspex.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
nuget.exe push Perspex.Desktop.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
nuget.exe push Perspex.Skia.Desktop.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
nuget.exe push Perspex.Android.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
foreach($pkg in $Packages)
{
nuget.exe push "$($pkg).$($version).nupkg" $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
}
}
}

39
nuget/build-version.ps1

@ -1,9 +1,11 @@
$ErrorActionPreference = "Stop"
rm -Force -Recurse .\Perspex -ErrorAction SilentlyContinue
rm -Force -Recurse .\Perspex.Desktop -ErrorAction SilentlyContinue
rm -Force -Recurse .\Perspex.Skia.Desktop -ErrorAction SilentlyContinue
rm -Force -Recurse .\Perspex.Android -ErrorAction SilentlyContinue
. ".\include.ps1"
foreach($pkg in $Packages)
{
rm -Force -Recurse .\$pkg -ErrorAction SilentlyContinue
}
rm -Force -Recurse *.nupkg -ErrorAction SilentlyContinue
Copy-Item template Perspex -Recurse
@ -14,11 +16,13 @@ sv skia_root "Perspex.Skia.Desktop"
sv skia_lib "Perspex.Skia.Desktop\lib\net45"
sv skia_native "Perspex.Skia.Desktop\build\net45\native"
sv android "Perspex.Android\lib\MonoAndroid10"
sv ios "Perspex.iOS\lib\Xamarin.iOS10"
mkdir $lib -ErrorAction SilentlyContinue
mkdir $build -ErrorAction SilentlyContinue
mkdir $skia_lib
mkdir $android
mkdir $ios
Copy-Item ..\src\Perspex.Animation\bin\Release\Perspex.Animation.dll $lib
@ -65,17 +69,20 @@ Copy-Item ..\src\Skia\Perspex.Skia.Desktop\bin\Release\Perspex.Skia.Desktop.dll
Copy-Item ..\src\Android\Perspex.Android\bin\Release\Perspex.Android.dll $android
Copy-Item ..\src\Skia\Perspex.Skia.Android\bin\Release\Perspex.Skia.Android.dll $android
(gc Perspex\Perspex.nuspec).replace('#VERSION#', $args[0]) | sc Perspex\Perspex.nuspec
(gc Perspex\Perspex.Desktop.nuspec).replace('#VERSION#', $args[0]) | sc Perspex.Desktop\Perspex.Desktop.nuspec
(gc Perspex\Perspex.Skia.Desktop.nuspec).replace('#VERSION#', $args[0]) | sc Perspex.Skia.Desktop\Perspex.Skia.Desktop.nuspec
(gc Perspex\Perspex.Android.nuspec).replace('#VERSION#', $args[0]) | sc Perspex.Android\Perspex.Android.nuspec
Copy-Item ..\src\iOS\Perspex.iOS\bin\iPhone\Release\Perspex.iOS.dll $ios
Copy-Item ..\src\Skia\Perspex.Skia.iOS\bin\iPhone\Release\Perspex.Skia.iOS.dll $ios
foreach($pkg in $Packages)
{
(gc Perspex\$pkg.nuspec).replace('#VERSION#', $args[0]) | sc $pkg\$pkg.nuspec
}
nuget.exe pack Perspex\Perspex.nuspec
nuget.exe pack Perspex.Desktop\Perspex.Desktop.nuspec
nuget.exe pack Perspex.Skia.Desktop\Perspex.Skia.Desktop.nuspec
nuget.exe pack Perspex.Android\Perspex.Android.nuspec
foreach($pkg in $Packages)
{
nuget.exe pack $pkg\$pkg.nuspec
}
rm -Force -Recurse .\Perspex
rm -Force -Recurse .\Perspex.Desktop
rm -Force -Recurse .\Perspex.Skia.Desktop
rm -Force -Recurse .\Perspex.Android
foreach($pkg in $Packages)
{
rm -Force -Recurse .\$pkg
}

2
nuget/build.ps1

@ -1 +1 @@
.\build-version.ps1 0.1.1-alpha2
.\build-version.ps1 0.2.0-alpha3

1
nuget/include.ps1

@ -0,0 +1 @@
$Packages = @("Perspex", "Perspex.Desktop", "Perspex.Skia.Desktop", "Perspex.Android", "Perspex.iOS")

6
nuget/template/Perspex.Desktop.nuspec

@ -21,9 +21,9 @@
<dependency id="Rx-Linq" version="2.2.5" />
<dependency id="Rx-Main" version="2.2.5" />
<dependency id="Rx-PlatformServices" version="2.2.5" />
<dependency id="SharpDX" version="2.6.3"/>
<dependency id="SharpDX.Direct2D1" version="2.6.3"/>
<dependency id="SharpDX.DXGI" version="2.6.3"/>
<dependency id="SharpDX" version="3.0.0"/>
<dependency id="SharpDX.Direct2D1" version="3.0.0"/>
<dependency id="SharpDX.DXGI" version="3.0.0"/>
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>

27
nuget/template/Perspex.iOS.nuspec

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Perspex.iOS</id>
<version>#VERSION#</version>
<authors>Perspex Team</authors>
<owners>stevenk</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>https://github.com/Perspex/Perspex/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>The Perspex UI framework</description>
<releaseNotes></releaseNotes>
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Serilog" version="1.5.9" />
<dependency id="Splat" version="1.6.2" />
<dependency id="Sprache" version="2.0.0.47" />
<dependency id="Rx-Core" version="2.2.5" />
<dependency id="Rx-Interfaces" version="2.2.5" />
<dependency id="Rx-Linq" version="2.2.5" />
<dependency id="Rx-Main" version="2.2.5" />
<dependency id="Rx-PlatformServices" version="2.2.5" />
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>
</package>

12
readme.md

@ -1,14 +1,20 @@
# Perspex
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/grokys/Perspex?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Perspex/Perspex?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge)
[![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/Perspex/Perspex/branch/master)
A multi-platform .NET UI framework.
A multi-platform .NET UI framework. It can run on Windows, Linux, Mac OS X, iOS and Android.
![](docs/screen.png)
Desktop platforms:
<a href='https://www.youtube.com/watch?t=28&v=c_AB_XSILp0' target='_blank'>![](docs/perspex-video.png)<a/>
Mobile platforms:
<a href='https://www.youtube.com/watch?v=NJ9-hnmUbBM' target='_blank'>![](https://i.ytimg.com/vi/NJ9-hnmUbBM/hqdefault.jpg)<a/>
## NuGet
Perspex is delivered as a NuGet package.
@ -39,7 +45,7 @@ framework.
As mentioned above, Perspex is still in alpha and as such there's not much documentation yet. You can
take a look at the [getting started page](docs/gettingstarted.md) for an
overview of how to get started but probably the best thing to do for now is to already know a little bit
about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/grokys/Perspex).
about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/Perspex/Perspex).
There's also a high-level [architecture document](docs/architecture.md) that is currently a little bit
out of date, and I've also started writing blog posts on Perspex at http://grokys.github.io/.

5
samples/BindingTest/BindingTest.csproj

@ -79,6 +79,10 @@
<DependentUpon>MainWindow.paml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestUserControl.paml.cs">
<DependentUpon>TestUserControl.paml</DependentUpon>
</Compile>
<Compile Include="ViewModels\TestUserControlViewModel.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="ViewModels\TestItem.cs" />
</ItemGroup>
@ -89,6 +93,7 @@
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
<None Include="packages.config" />
<EmbeddedResource Include="TestUserControl.paml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">

8
samples/BindingTest/MainWindow.paml

@ -1,5 +1,6 @@
<Window xmlns="https://github.com/perspex"
xmlns:vm="clr-namespace:BindingTest.ViewModels;assembly=BindingTest">
xmlns:vm="clr-namespace:BindingTest.ViewModels;assembly=BindingTest"
xmlns:local="clr-namespace:BindingTest;assembly=BindingTest">
<TabControl>
<TabItem Header="Basic">
<StackPanel Orientation="Vertical">
@ -55,5 +56,10 @@
</StackPanel>
</StackPanel>
</TabItem>
<TabItem Header="UserControl">
<local:TestUserControl DataContext="{Binding UserControl}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</TabItem>
</TabControl>
</Window>

3
samples/BindingTest/TestUserControl.paml

@ -0,0 +1,3 @@
<UserControl xmlns="https://github.com/perspex">
<TextBlock Text="{Binding Content}"/>
</UserControl>

18
samples/BindingTest/TestUserControl.paml.cs

@ -0,0 +1,18 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace BindingTest
{
public class TestUserControl : UserControl
{
public TestUserControl()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

1
samples/BindingTest/ViewModels/MainWindowViewModel.cs

@ -32,6 +32,7 @@ namespace BindingTest.ViewModels
public ObservableCollection<TestItem> Items { get; }
public ObservableCollection<TestItem> SelectedItems { get; }
public ReactiveCommand<object> ShuffleItems { get; }
public TestUserControlViewModel UserControl { get; } = new TestUserControlViewModel();
public string BooleanString
{

9
samples/BindingTest/ViewModels/TestUserControlViewModel.cs

@ -0,0 +1,9 @@
using ReactiveUI;
namespace BindingTest.ViewModels
{
public class TestUserControlViewModel : ReactiveObject
{
public string Content { get; } = "User Control Content";
}
}

14
samples/ControlCatalog/App.config

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

16
samples/ControlCatalog/App.paml

@ -0,0 +1,16 @@
<Application xmlns="https://github.com/perspex">
<Application.Styles>
<Style Selector="TextBlock.h1">
<Setter Property="Foreground" Value="#212121"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontWeight" Value="Medium"/>
</Style>
<Style Selector="TextBlock.h2">
<Setter Property="Foreground" Value="#727272"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<StyleInclude Source="resm:ControlCatalog.SideBar.paml"/>
</Application.Styles>
</Application>

55
samples/ControlCatalog/App.paml.cs

@ -0,0 +1,55 @@
using System;
using System.Linq;
using Perspex;
using Perspex.Controls;
using Perspex.Diagnostics;
using Perspex.Markup.Xaml;
using Perspex.Themes.Default;
namespace ControlCatalog
{
class App : Application
{
public App()
{
RegisterServices();
InitializeSubsystems(GetPlatformId());
Styles = new DefaultTheme();
InitializeComponent();
}
public static void AttachDevTools(Window window)
{
#if DEBUG
DevTools.Attach(window);
#endif
}
static void Main(string[] args)
{
var app = new App();
var window = new MainWindow();
window.Show();
app.Run(window);
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
private int GetPlatformId()
{
var args = Environment.GetCommandLineArgs();
if (args.Contains("--gtk"))
{
return (int)PlatformID.Unix;
}
else
{
return (int)Environment.OSVersion.Platform;
}
}
}
}

BIN
samples/ControlCatalog/Assets/delicate-arch-896885_640.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
samples/ControlCatalog/Assets/hirsch-899118_640.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
samples/ControlCatalog/Assets/maple-leaf-888807_640.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

190
samples/ControlCatalog/ControlCatalog.csproj

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{61BEC86C-F307-4295-B5B8-9428610D7D55}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ControlCatalog</RootNamespace>
<AssemblyName>ControlCatalog</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</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>AnyCPU</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.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="App.paml.cs">
<DependentUpon>App.paml</DependentUpon>
</Compile>
<Compile Include="MainWindow.paml.cs">
<DependentUpon>MainWindow.paml</DependentUpon>
</Compile>
<Compile Include="Pages\BorderPage.paml.cs">
<DependentUpon>BorderPage.paml</DependentUpon>
</Compile>
<Compile Include="Pages\CarouselPage.paml.cs">
<DependentUpon>CarouselPage.paml</DependentUpon>
</Compile>
<Compile Include="Pages\CanvasPage.paml.cs">
<DependentUpon>CanvasPage.paml</DependentUpon>
</Compile>
<Compile Include="Pages\ButtonPage.paml.cs">
<DependentUpon>ButtonPage.paml</DependentUpon>
</Compile>
<Compile Include="Pages\DropDownPage.paml.cs">
<DependentUpon>DropDownPage.paml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<EmbeddedResource Include="App.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\ButtonPage.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="SideBar.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="MainWindow.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\BorderPage.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\CanvasPage.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\CarouselPage.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\DropDownPage.paml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Gtk\Perspex.Cairo\Perspex.Cairo.csproj">
<Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project>
<Name>Perspex.Cairo</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Gtk\Perspex.Gtk\Perspex.Gtk.csproj">
<Project>{54f237d5-a70a-4752-9656-0c70b1a7b047}</Project>
<Name>Perspex.Gtk</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Perspex.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Markup\Perspex.Markup\Perspex.Markup.csproj">
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Perspex.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Application\Perspex.Application.csproj">
<Project>{799a7bb5-3c2c-48b6-85a7-406a12c420da}</Project>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Diagnostics\Perspex.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Perspex.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.HtmlRenderer\Perspex.HtmlRenderer.csproj">
<Project>{5fb2b005-0a7f-4dad-add4-3ed01444e63d}</Project>
<Name>Perspex.HtmlRenderer</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Interactivity\Perspex.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Perspex.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Layout\Perspex.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Perspex.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Themes.Default\Perspex.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj">
<Project>{3e908f67-5543-4879-a1dc-08eace79b3cd}</Project>
<Name>Perspex.Direct2D1</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Windows\Perspex.Win32\Perspex.Win32.csproj">
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
<Name>Perspex.Win32</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\hirsch-899118_640.jpg" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\delicate-arch-896885_640.jpg" />
<EmbeddedResource Include="Assets\maple-leaf-888807_640.jpg" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

14
samples/ControlCatalog/MainWindow.paml

@ -0,0 +1,14 @@
<Window xmlns="https://github.com/perspex"
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
Title="Perspex Control Gallery">
<TabControl Classes="sidebar">
<TabControl.Transition>
<CrossFade Duration="0.25"/>
</TabControl.Transition>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>
<TabItem Header="Canvas"><pages:CanvasPage/></TabItem>
<TabItem Header="Carousel"><pages:CarouselPage/></TabItem>
<TabItem Header="DropDown"><pages:DropDownPage/></TabItem>
</TabControl>
</Window>

19
samples/ControlCatalog/MainWindow.paml.cs

@ -0,0 +1,19 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace ControlCatalog
{
public class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
App.AttachDevTools(this);
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

29
samples/ControlCatalog/Pages/BorderPage.paml

@ -0,0 +1,29 @@
<UserControl xmlns="https://github.com/perspex">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">Border</TextBlock>
<TextBlock Classes="h2">A control which decorates a child with a border and background</TextBlock>
<StackPanel Orientation="Vertical"
Margin="0,16,0,0"
HorizontalAlignment="Center"
Gap="16">
<Border BorderBrush="#f44336" BorderThickness="2" Padding="16">
<TextBlock>Border</TextBlock>
</Border>
<Border Background="#f44336" BorderBrush="#4285f4" BorderThickness="4" Padding="16">
<TextBlock>Border and Background</TextBlock>
</Border>
<Border BorderBrush="#4285f4"
BorderThickness="4"
CornerRadius="8"
Padding="16">
<TextBlock>Rounded Corners</TextBlock>
</Border>
<Border Background="#f44336"
CornerRadius="8"
Padding="16">
<TextBlock>Rounded Corners</TextBlock>
</Border>
</StackPanel>
</StackPanel>
</UserControl>

18
samples/ControlCatalog/Pages/BorderPage.paml.cs

@ -0,0 +1,18 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class BorderPage : UserControl
{
public BorderPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

26
samples/ControlCatalog/Pages/ButtonPage.paml

@ -0,0 +1,26 @@
<UserControl xmlns="https://github.com/perspex">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">Button</TextBlock>
<TextBlock Classes="h2">A button control</TextBlock>
<StackPanel Orientation="Horizontal"
Margin="0,16,0,0"
HorizontalAlignment="Center"
Gap="16">
<StackPanel Orientation="Vertical" Gap="8" Width="150">
<Button>Button</Button>
<Button Foreground="Blue">Foreground</Button>
<Button Background="#f44336">Background</Button>
<Button IsEnabled="False">Disabled</Button>
</StackPanel>
<StackPanel Orientation="Vertical" Gap="8" Width="150">
<Button BorderThickness="0">No Border</Button>
<Button BorderBrush="#f44336">Border Color</Button>
<Button BorderBrush="#f44336" BorderThickness="4">Thick Border</Button>
<Button BorderBrush="#f44336" BorderThickness="4" IsEnabled="False">Disabled</Button>
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>

18
samples/ControlCatalog/Pages/ButtonPage.paml.cs

@ -0,0 +1,18 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class ButtonPage : UserControl
{
public ButtonPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

13
samples/ControlCatalog/Pages/CanvasPage.paml

@ -0,0 +1,13 @@
<UserControl xmlns="https://github.com/perspex">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">Canvas</TextBlock>
<TextBlock Classes="h2">A panel which lays out its children by explicit coordinates</TextBlock>
<Canvas Background="Yellow" Width="300" Height="200">
<Rectangle Fill="Blue" Width="63" Height="41" Canvas.Left="40" Canvas.Top="31"/>
<Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="160" Canvas.Top="79"/>
<Path Fill="Red" Data="M50,0 L0,50 100,50 Z" Canvas.Left="50" Canvas.Top="140"/>
</Canvas>
</StackPanel>
</UserControl>

18
samples/ControlCatalog/Pages/CanvasPage.paml.cs

@ -0,0 +1,18 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class CanvasPage : UserControl
{
public CanvasPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

33
samples/ControlCatalog/Pages/CarouselPage.paml

@ -0,0 +1,33 @@
<UserControl xmlns="https://github.com/perspex">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">Carousel</TextBlock>
<TextBlock Classes="h2">An items control that displays its items as pages that fill the control.</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 16 0 0" Gap="8">
<Button Name="left" VerticalAlignment="Center" Padding="20">
<Path Data="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" Fill="Black"/>
</Button>
<Carousel Name="carousel">
<Carousel.Transition>
<PageSlide Duration="0.25"/>
</Carousel.Transition>
<Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"/>
<Image Source="resm:ControlCatalog.Assets.hirsch-899118_640.jpg"/>
<Image Source="resm:ControlCatalog.Assets.maple-leaf-888807_640.jpg"/>
</Carousel>
<Button Name="right" VerticalAlignment="Center" Padding="20">
<Path Data="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" Fill="Black"/>
</Button>
</StackPanel>
<StackPanel Orientation="Horizontal" Gap="4">
<TextBlock VerticalAlignment="Center">Transition</TextBlock>
<DropDown Name="transition" SelectedIndex="1" VerticalAlignment="Center">
<DropDownItem>None</DropDownItem>
<DropDownItem>Slide</DropDownItem>
<DropDownItem>Crossfade</DropDownItem>
</DropDown>
</StackPanel>
</StackPanel>
</UserControl>

48
samples/ControlCatalog/Pages/CarouselPage.paml.cs

@ -0,0 +1,48 @@
using System;
using Perspex.Animation;
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class CarouselPage : UserControl
{
private Carousel _carousel;
private Button _left;
private Button _right;
private DropDown _transition;
public CarouselPage()
{
this.InitializeComponent();
_left.Click += (s, e) => _carousel.Previous();
_right.Click += (s, e) => _carousel.Next();
//_transition.SelectionChanged += TransitionChanged;
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
_carousel = this.FindControl<Carousel>("carousel");
_left = this.FindControl<Button>("left");
_right = this.FindControl<Button>("right");
_transition = this.FindControl<DropDown>("transition");
}
private void TransitionChanged(object sender, SelectionChangedEventArgs e)
{
switch (_transition.SelectedIndex)
{
case 0:
_carousel.Transition = null;
break;
case 1:
_carousel.Transition = new PageSlide(TimeSpan.FromSeconds(0.25));
break;
case 2:
_carousel.Transition = new CrossFade(TimeSpan.FromSeconds(0.25));
break;
}
}
}
}

31
samples/ControlCatalog/Pages/DropDownPage.paml

@ -0,0 +1,31 @@
<UserControl xmlns="https://github.com/perspex">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">DropDown</TextBlock>
<TextBlock Classes="h2">A drop-down list.</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 16 0 0" Gap="8">
<DropDown SelectedIndex="0">
<DropDownItem>Inline Items</DropDownItem>
<DropDownItem>Inline Item 2</DropDownItem>
<DropDownItem>Inline Item 3</DropDownItem>
<DropDownItem>Inline Item 4</DropDownItem>
</DropDown>
<DropDown SelectedIndex="0">
<DropDownItem>
<Panel>
<Rectangle Fill="Red"/>
<TextBlock Margin="8">Control Items</TextBlock>
</Panel>
</DropDownItem>
<DropDownItem>
<Ellipse Width="50" Height="50" Fill="Yellow"/>
</DropDownItem>
<DropDownItem>
<TextBox Text="TextBox"/>
</DropDownItem>
</DropDown>
</StackPanel>
</StackPanel>
</UserControl>

18
samples/ControlCatalog/Pages/DropDownPage.paml.cs

@ -0,0 +1,18 @@
using Perspex.Controls;
using Perspex.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class DropDownPage : UserControl
{
public DropDownPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

36
samples/ControlCatalog/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ControlCatalog")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ControlCatalog")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("61bec86c-f307-4295-b5b8-9428610d7d55")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

40
samples/ControlCatalog/SideBar.paml

@ -0,0 +1,40 @@
<Styles xmlns="https://github.com/perspex">
<Style Selector="TabControl.sidebar">
<Setter Property="Template">
<ControlTemplate>
<DockPanel>
<Border MinWidth="190" Background="#1976D2" DockPanel.Dock="Left">
<TabStrip Name="PART_TabStrip"
MemberSelector="{Static TabControl.HeaderSelector}"
Items="{TemplateBinding Items}"
SelectedIndex="{TemplateBinding Path=SelectedIndex, Mode=TwoWay}">
<TabStrip.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</TabStrip.ItemsPanel>
</TabStrip>
</Border>
<Carousel Name="PART_Content"
Margin="8 0 0 0"
MemberSelector="{Static TabControl.ContentSelector}"
Items="{TemplateBinding Items}"
SelectedIndex="{TemplateBinding Path=SelectedIndex}"
Transition="{TemplateBinding Transition}"
Grid.Row="1"/>
</DockPanel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="TabControl.sidebar TabStripItem">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="16"/>
</Style>
<Style Selector="TabControl.sidebar TabStripItem:selected">
<Setter Property="Background" Value="#20ffffff"/>
</Style>
</Styles>

5
samples/TestApplicationShared/App.cs

@ -21,11 +21,8 @@ namespace TestApplication
{
new FuncTreeDataTemplate<Node>(
x => new TextBlock {Text = x.Name},
x => x.Children,
x => true),
x => x.Children),
};
}
}
}

25
samples/TestApplicationShared/GalleryStyle.cs

@ -19,23 +19,23 @@ namespace TestApplication
{
this.AddRange(new[]
{
new Style (s => s.Class(":container").OfType<TabControl> ())
new Style (s => s.Class("container").OfType<TabControl> ())
{
Setters = new[]
{
new Setter (TemplatedControl.TemplateProperty, new FuncControlTemplate<TabControl> (TabControlTemplate))
new Setter (TemplatedControl.TemplateProperty, new FuncControlTemplate<TabControl>(TabControlTemplate))
}
},
new Style(s => s.Class(":container").OfType<TabControl>().Child().Child().Child().Child().Child().OfType<TabItem>())
new Style(s => s.Class("container").OfType<TabControl>().Child().Child().Child().Child().Child().OfType<TabStripItem>())
{
Setters = new[]
{
new Setter (TemplatedControl.TemplateProperty, new FuncControlTemplate<TabItem> (TabItemTemplate)),
new Setter (TemplatedControl.TemplateProperty, new FuncControlTemplate<TabStripItem>(TabStripItemTemplate)),
}
},
new Style(s => s.Name("internalStrip").OfType<TabStrip>().Child().OfType<TabItem>())
new Style(s => s.Name("PART_TabStrip").OfType<TabStrip>().Child().OfType<TabStripItem>())
{
Setters = new[]
{
@ -44,7 +44,7 @@ namespace TestApplication
}
},
new Style(s => s.Name("internalStrip").OfType<TabStrip>().Child().OfType<TabItem>().Class(":selected"))
new Style(s => s.Name("PART_TabStrip").OfType<TabStrip>().Child().OfType<TabStripItem>().Class(":selected"))
{
Setters = new[]
{
@ -55,7 +55,7 @@ namespace TestApplication
});
}
public static Control TabItemTemplate(TabItem control)
public static Control TabStripItemTemplate(TabStripItem control)
{
return new ContentPresenter
{
@ -72,8 +72,8 @@ namespace TestApplication
}
})
},
Name = "headerPresenter",
[~ContentPresenter.ContentProperty] = control[~HeaderedContentControl.HeaderProperty],
Name = "PART_ContentPresenter",
[~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty],
};
}
@ -96,9 +96,10 @@ namespace TestApplication
{
Content = new TabStrip
{
Name = "PART_TabStrip",
ItemsPanel = new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical, Gap = 4 }),
Margin = new Thickness(0, 10, 0, 0),
Name = "internalStrip",
MemberSelector = TabControl.HeaderSelector,
[!ItemsControl.ItemsProperty] = control[!ItemsControl.ItemsProperty],
[!!SelectingItemsControl.SelectedItemProperty] = control[!!SelectingItemsControl.SelectedItemProperty],
}
@ -106,8 +107,8 @@ namespace TestApplication
},
new Carousel
{
Name = "carousel",
MemberSelector = control.ContentSelector,
Name = "PART_Content",
MemberSelector = TabControl.ContentSelector,
[~Carousel.TransitionProperty] = control[~TabControl.TransitionProperty],
[!Carousel.ItemsProperty] = control[!ItemsControl.ItemsProperty],
[!Carousel.SelectedItemProperty] = control[!SelectingItemsControl.SelectedItemProperty],

49
samples/TestApplicationShared/MainWindow.cs

@ -11,11 +11,13 @@ using Perspex.Controls.Html;
using Perspex.Controls.Primitives;
using Perspex.Controls.Shapes;
using Perspex.Controls.Templates;
using Perspex.Data;
using Perspex.Diagnostics;
using Perspex.Layout;
using Perspex.Media;
using Perspex.Media.Imaging;
using Perspex.Platform;
using Perspex.Threading;
using TestApplication;
namespace TestApplication
@ -103,8 +105,7 @@ namespace TestApplication
};
container.Classes.Add(":container");
container.Classes.Add("container");
window.Show();
return window;
@ -358,7 +359,7 @@ namespace TestApplication
static Stream GetImage(string path)
{
return PerspexLocator.Current.GetService<IAssetLoader>().Open(new Uri("res:///" + RootNamespace + "." + path));
return PerspexLocator.Current.GetService<IAssetLoader>().Open(new Uri("resm:" + RootNamespace + "." + path));
}
private static TabItem ListsTab()
@ -785,12 +786,44 @@ namespace TestApplication
VerticalAlignment = VerticalAlignment.Center,
Background = Brushes.Crimson,
RenderTransform = new RotateTransform(),
Child = new TextBox
Child = new Grid
{
Background = Brushes.White,
Text = "Hello!",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Children = new Controls
{
new Ellipse()
{
Width = 100,
Height = 100,
Fill =
new RadialGradientBrush()
{
GradientStops =
{
new GradientStop(Colors.Blue, 0),
new GradientStop(Colors.Green, 1)
},
Radius = 75
}
},
new Perspex.Controls.Shapes.Path
{
Data =
StreamGeometry.Parse(
"F1 M 16.6309,18.6563C 17.1309,8.15625 29.8809,14.1563 29.8809,14.1563C 30.8809,11.1563 34.1308,11.4063 34.1308,11.4063C 33.5,12 34.6309,13.1563 34.6309,13.1563C 32.1309,13.1562 31.1309,14.9062 31.1309,14.9062C 41.1309,23.9062 32.6309,27.9063 32.6309,27.9062C 24.6309,24.9063 21.1309,22.1562 16.6309,18.6563 Z M 16.6309,19.9063C 21.6309,24.1563 25.1309,26.1562 31.6309,28.6562C 31.6309,28.6562 26.3809,39.1562 18.3809,36.1563C 18.3809,36.1563 18,38 16.3809,36.9063C 15,36 16.3809,34.9063 16.3809,34.9063C 16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z"),
Fill =
new LinearGradientBrush()
{
GradientStops =
{
new GradientStop(Colors.Green, 0),
new GradientStop(Colors.LightSeaGreen, 1)
}
},
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
RenderTransform = new MatrixTransform(Matrix.CreateScale(2, 2))
}
}
},
[Canvas.LeftProperty] = 100,
[Canvas.TopProperty] = 100,

84
samples/XamlTestApplicationPcl/TestScrollable.cs

@ -0,0 +1,84 @@
using System;
using Perspex;
using Perspex.Controls;
using Perspex.Controls.Primitives;
using Perspex.Media;
namespace XamlTestApplication
{
public class TestScrollable : Control, IScrollable
{
private int itemCount = 100;
private Size _extent;
private Vector _offset;
private Size _viewport;
private Size _lineSize;
public Action InvalidateScroll { get; set; }
Size IScrollable.Extent
{
get { return _extent; }
}
Vector IScrollable.Offset
{
get { return _offset; }
set
{
_offset = value;
InvalidateVisual();
}
}
Size IScrollable.Viewport
{
get { return _viewport; }
}
protected override Size MeasureOverride(Size availableSize)
{
using (var line = new FormattedText(
"Item 100",
TextBlock.GetFontFamily(this),
TextBlock.GetFontSize(this),
TextBlock.GetFontStyle(this),
TextAlignment.Left,
TextBlock.GetFontWeight(this)))
{
line.Constraint = availableSize;
_lineSize = line.Measure();
return new Size(_lineSize.Width, _lineSize.Height * itemCount);
}
}
protected override Size ArrangeOverride(Size finalSize)
{
_viewport = new Size(finalSize.Width, finalSize.Height / _lineSize.Height);
_extent = new Size(_lineSize.Width, itemCount + 1);
InvalidateScroll?.Invoke();
return finalSize;
}
public override void Render(DrawingContext context)
{
var y = 0.0;
for (var i = (int)_offset.Y; i < itemCount; ++i)
{
using (var line = new FormattedText(
"Item " + (i + 1),
TextBlock.GetFontFamily(this),
TextBlock.GetFontSize(this),
TextBlock.GetFontStyle(this),
TextAlignment.Left,
TextBlock.GetFontWeight(this)))
{
context.DrawText(Brushes.Black, new Point(-_offset.X, y), line);
y += _lineSize.Height;
}
}
}
}
}

34
samples/XamlTestApplicationPcl/ViewModels/MainWindowViewModel.cs

@ -1,7 +1,9 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using ReactiveUI;
namespace XamlTestApplication.ViewModels
{
@ -22,6 +24,7 @@ namespace XamlTestApplication.ViewModels
{
Header = "Root",
SubHeader = "Root Item",
IsExpanded = true,
Children = new[]
{
new TestNode
@ -33,6 +36,7 @@ namespace XamlTestApplication.ViewModels
{
Header = "Child 2",
SubHeader = "Child 2 Value",
IsExpanded = false,
Children = new[]
{
new TestNode
@ -50,9 +54,39 @@ namespace XamlTestApplication.ViewModels
}
}
};
CollapseNodesCommand = ReactiveCommand.Create();
CollapseNodesCommand.Subscribe(_ => ExpandNodes(false));
ExpandNodesCommand = ReactiveCommand.Create();
ExpandNodesCommand.Subscribe(_ => ExpandNodes(true));
}
public List<TestItem> Items { get; }
public List<TestNode> Nodes { get; }
public ReactiveCommand<object> CollapseNodesCommand { get; }
public ReactiveCommand<object> ExpandNodesCommand { get; }
public void ExpandNodes(bool expanded)
{
foreach (var node in Nodes)
{
ExpandNodes(node, expanded);
}
}
private void ExpandNodes(TestNode node, bool expanded)
{
node.IsExpanded = expanded;
if (node.Children != null)
{
foreach (var child in node.Children)
{
ExpandNodes(child, expanded);
}
}
}
}
}

11
samples/XamlTestApplicationPcl/ViewModels/TestNode.cs

@ -2,13 +2,22 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using ReactiveUI;
namespace XamlTestApplication.ViewModels
{
public class TestNode
public class TestNode : ReactiveObject
{
private bool _isExpanded;
public string Header { get; set; }
public string SubHeader { get; set; }
public IEnumerable<TestNode> Children { get; set; }
public bool IsExpanded
{
get { return _isExpanded; }
set { this.RaiseAndSetIfChanged(ref this._isExpanded, value); }
}
}
}

32
samples/XamlTestApplicationPcl/Views/MainWindow.paml

@ -1,15 +1,16 @@
<Window x:Class="XamlTestApplication.MainWindow"
xmlns="https://github.com/perspex"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:XamlTestApplication;assembly=XamlTestApplicationPcl"
xmlns:vm="clr-namespace:XamlTestApplication.ViewModels;assembly=XamlTestApplicationPcl"
Title="Perspex Test Application" Width="800" Height="600">
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
<Menu Grid.ColumnSpan="2">
<MenuItem Header="_File">
<MenuItem Header="_File" Background="Red">
<MenuItem Header="_Hello">
<MenuItem Header="_Goodbye"/>
<Separator/>
<MenuItem Header="_World"/>
<MenuItem Header="_World" Background="Red"/>
</MenuItem>
<Separator Background="Red"/>
<MenuItem Header="_Test"/>
@ -146,6 +147,11 @@
</StackPanel>
</DropDown>
<TreeView Items="{Binding Nodes}">
<TreeView.Styles>
<Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
</Style>
</TreeView.Styles>
<TreeView.DataTemplates>
<TreeDataTemplate DataType="vm:TestNode" ItemsSource="{Binding Children}">
<StackPanel>
@ -155,6 +161,10 @@
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
<StackPanel Orientation="Vertical" Gap="4">
<Button Command="{Binding CollapseNodesCommand}">Collapse Nodes</Button>
<Button Command="{Binding ExpandNodesCommand}">Expand Nodes</Button>
</StackPanel>
</StackPanel>
</TabItem>
<TabItem Header="Layout">
@ -220,6 +230,19 @@
<Rectangle Fill="Yellow" Height="25" DockPanel.Dock="Bottom" />
<Rectangle Fill="Pink" />
</DockPanel>
<TextBlock Text="GridSplitter" FontWeight="Medium" FontSize="20" Foreground="#212121" />
<Grid Height="500" Width="500" ColumnDefinitions="*,Auto,*,Auto,*" RowDefinitions="*,Auto,*">
<Border Grid.Column="0" Grid.Row="0" Background="Red" />
<GridSplitter Grid.Column="0" Grid.Row="1" Orientation="Horizontal" />
<Border Grid.Column="0" Grid.Row="2" Background="Yellow" />
<GridSplitter Grid.Column="1" Grid.RowSpan="3" Orientation="Vertical" />
<Border Grid.Column="2" Grid.RowSpan="3" Background="Green" />
<GridSplitter Grid.Column="3" Grid.RowSpan="3" Orientation="Vertical"/>
<Border Grid.Column="4" Grid.Row="0" Background="Blue" />
<GridSplitter Grid.Column="4" Grid.Row="1" Orientation="Horizontal" />
<Border Grid.Column="4" Grid.Row="3" Background="Pink" />
</Grid>
</StackPanel>
</ScrollViewer>
</TabItem>
@ -272,6 +295,11 @@
</Border>
</Grid>
</TabItem>
<TabItem Header="IScrollable">
<ScrollViewer>
<local:TestScrollable/>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</Window>

17
samples/XamlTestApplicationPcl/XamlTestApplicationPcl.csproj

@ -41,6 +41,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestScrollable.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="ViewModels\TestItem.cs" />
<Compile Include="ViewModels\TestNode.cs" />
@ -122,6 +123,22 @@
<HintPath>..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Interfaces, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Linq, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.PlatformServices, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="XamlTestApp.paml">

5
samples/XamlTestApplicationPcl/packages.config

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Core" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Rx-Linq" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Rx-Main" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Splat" version="1.6.2" targetFramework="portable45-net45+win8" />
</packages>

24
src/Android/Perspex.Android/AndroidPlatform.cs

@ -10,10 +10,11 @@ using Perspex.Shared.PlatformSupport;
using Perspex.Skia;
using System;
using System.Collections.Generic;
using Perspex.Android.Platform.SkiaPlatform;
namespace Perspex.Android
{
public class AndroidPlatform : IPlatformSettings
public class AndroidPlatform : IPlatformSettings, IWindowingPlatform
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public Size DoubleClickSize => new Size(4, 4);
@ -33,11 +34,11 @@ namespace Perspex.Android
.Bind<IPlatformSettings>().ToConstant(this)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>();
.Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>()
.Bind<IWindowingPlatform>().ToConstant(this);
SkiaPlatform.Initialize();
Application.SuppressPlatformInitialization();
PerspexLocator.CurrentMutable.Bind<IWindowImpl>().ToSingleton<Platform.SkiaPlatform.MainWindowImpl>();
Application.RegisterPlatformCallback(() => { });
_scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
@ -50,5 +51,20 @@ namespace Perspex.Android
{
SharedPlatform.Register(applicationType.Assembly);
}
public IWindowImpl CreateWindow()
{
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup()
{
throw new NotImplementedException();
}
}
}

16
src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs

@ -9,6 +9,7 @@ using Perspex.Input.Raw;
using Perspex.Platform;
using Perspex.Skia.Android;
using System;
using Perspex.Controls;
namespace Perspex.Android.Platform.SkiaPlatform
{
@ -94,6 +95,9 @@ namespace Perspex.Android.Platform.SkiaPlatform
this.Visibility = ViewStates.Invisible;
}
public void SetSystemDecorations(bool enabled)
{
}
public void Invalidate(Rect rect)
{
if (Holder?.Surface?.IsValid == true) base.Invalidate();
@ -123,6 +127,18 @@ namespace Perspex.Android.Platform.SkiaPlatform
this.Visibility = ViewStates.Visible;
}
public void BeginMoveDrag()
{
//Not supported
}
public void BeginResizeDrag(WindowEdge edge)
{
//Not supported
}
public Point Position { get; set; }
public IDisposable ShowDialog()
{
throw new NotImplementedException();

2
src/Gtk/Perspex.Cairo/CairoPlatform.cs

@ -16,7 +16,7 @@ namespace Perspex.Cairo
{
private static readonly CairoPlatform s_instance = new CairoPlatform();
private static Pango.Context s_pangoContext = CreatePangoContext();
private static readonly Pango.Context s_pangoContext = CreatePangoContext();
public static void Initialize() => PerspexLocator.CurrentMutable.Bind<IPlatformRenderInterface>().ToConstant(s_instance);

4
src/Gtk/Perspex.Cairo/Media/DrawingContext.cs

@ -148,6 +148,10 @@ namespace Perspex.Cairo.Media
_context.AppendPath(impl.Path);
using (var b = SetBrush(brush, geometry.Bounds.Size))
{
_context.FillRule = impl.FillRule == FillRule.EvenOdd
? Cairo.FillRule.EvenOdd
: Cairo.FillRule.Winding;
if (pen != null)
_context.FillPreserve();
else

2
src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs

@ -13,7 +13,7 @@ namespace Perspex.Cairo.Media
public class FormattedTextImpl : IFormattedTextImpl
{
private Size _size;
private string _text;
private readonly string _text;
public FormattedTextImpl(
Pango.Context context,

4
src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs

@ -15,10 +15,10 @@ namespace Perspex.Cairo
foreach (var stop in brush.GradientStops)
{
((LinearGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo());
((RadialGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo());
}
((LinearGradient)this.PlatformBrush).Extend = Extend.Pad;
((RadialGradient)this.PlatformBrush).Extend = Extend.Pad;
}
}
}

18
src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs

@ -13,11 +13,13 @@ namespace Perspex.Cairo.Media
public class StreamGeometryContextImpl : IStreamGeometryContextImpl
{
private readonly StreamGeometryImpl _target;
private Point _currentPoint;
public StreamGeometryContextImpl(Cairo.Path path = null)
public StreamGeometryContextImpl(StreamGeometryImpl target, Cairo.Path path)
{
_target = target;
_surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0);
_surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0);
_context = new Cairo.Context (_surf);
this.Path = path;
@ -42,7 +44,7 @@ namespace Perspex.Cairo.Media
}
}
public void BezierTo(Point point1, Point point2, Point point3)
public void CubicBezierTo(Point point1, Point point2, Point point3)
{
if (this.Path == null)
{
@ -51,11 +53,11 @@ namespace Perspex.Cairo.Media
}
}
public void QuadTo(Point control, Point endPoint)
public void QuadraticBezierTo(Point control, Point endPoint)
{
if (this.Path == null)
{
QuadBezierHelper.QuadTo(this, _currentPoint, control, endPoint);
QuadBezierHelper.QuadraticBezierTo(this, _currentPoint, control, endPoint);
_currentPoint = endPoint;
}
}
@ -86,6 +88,12 @@ namespace Perspex.Cairo.Media
}
}
public void SetFillRule(FillRule fillRule)
{
_target.FillRule = fillRule;
}
public void Dispose()
{
_context.Dispose ();

4
src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs

@ -14,7 +14,7 @@ namespace Perspex.Cairo.Media
{
public StreamGeometryImpl()
{
_impl = new StreamGeometryContextImpl(null);
_impl = new StreamGeometryContextImpl(this, null);
}
public StreamGeometryImpl(StreamGeometryContextImpl impl)
@ -50,6 +50,8 @@ namespace Perspex.Cairo.Media
}
}
public FillRule FillRule { get; set; }
public IStreamGeometryImpl Clone()
{
return new StreamGeometryImpl(_impl);

2
src/Gtk/Perspex.Cairo/RenderTarget.cs

@ -19,7 +19,7 @@ namespace Perspex.Cairo
public class RenderTarget : IRenderTarget
{
private readonly Surface _surface;
private Gtk.Window _window;
private readonly Gtk.Window _window;
/// <summary>
/// Initializes a new instance of the <see cref="RenderTarget"/> class.

32
src/Gtk/Perspex.Gtk/CursorFactory.cs

@ -21,20 +21,28 @@ namespace Perspex.Gtk
private static readonly Dictionary<StandardCursorType, object> CursorTypeMapping = new Dictionary
<StandardCursorType, object>
{
{ StandardCursorType.AppStarting, CursorType.Watch },
{ StandardCursorType.Arrow, CursorType.LeftPtr },
{ StandardCursorType.Cross, CursorType.Cross },
{ StandardCursorType.Hand, CursorType.Hand1 },
{ StandardCursorType.Ibeam, CursorType.Xterm },
{ StandardCursorType.No, Gtk.Stock.Cancel},
{ StandardCursorType.SizeAll, CursorType.Sizing },
{StandardCursorType.AppStarting, CursorType.Watch},
{StandardCursorType.Arrow, CursorType.LeftPtr},
{StandardCursorType.Cross, CursorType.Cross},
{StandardCursorType.Hand, CursorType.Hand1},
{StandardCursorType.Ibeam, CursorType.Xterm},
{StandardCursorType.No, Gtk.Stock.Cancel},
{StandardCursorType.SizeAll, CursorType.Sizing},
//{ StandardCursorType.SizeNorthEastSouthWest, 32643 },
{ StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow},
{StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow},
//{ StandardCursorType.SizeNorthWestSouthEast, 32642 },
{ StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow },
{ StandardCursorType.UpArrow, CursorType.BasedArrowUp },
{ StandardCursorType.Wait, CursorType.Watch },
{ StandardCursorType.Help, Gtk.Stock.Help }
{StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow},
{StandardCursorType.UpArrow, CursorType.BasedArrowUp},
{StandardCursorType.Wait, CursorType.Watch},
{StandardCursorType.Help, Gtk.Stock.Help},
{StandardCursorType.TopSide, CursorType.TopSide},
{StandardCursorType.BottomSize, CursorType.BottomSide},
{StandardCursorType.LeftSide, CursorType.LeftSide},
{StandardCursorType.RightSide, CursorType.RightSide},
{StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner},
{StandardCursorType.TopRightCorner, CursorType.TopRightCorner},
{StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner},
{StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner}
};
private static readonly Dictionary<StandardCursorType, IPlatformHandle> Cache =

19
src/Gtk/Perspex.Gtk/GtkPlatform.cs

@ -14,7 +14,7 @@ namespace Perspex.Gtk
{
using Gtk = global::Gtk;
public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings
public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform
{
private static readonly GtkPlatform s_instance = new GtkPlatform();
private static Thread _uiThread;
@ -33,8 +33,7 @@ namespace Perspex.Gtk
public static void Initialize()
{
PerspexLocator.CurrentMutable
.Bind<IWindowImpl>().ToTransient<WindowImpl>()
.Bind<IPopupImpl>().ToTransient<PopupImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToConstant(CursorFactory.Instance)
.Bind<IKeyboardDevice>().ToConstant(GtkKeyboardDevice.Instance)
@ -86,5 +85,19 @@ namespace Perspex.Gtk
public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread;
public event Action Signaled;
public IWindowImpl CreateWindow()
{
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotSupportedException();
}
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
}
}

2
src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs

@ -214,7 +214,7 @@ namespace Perspex.Gtk
//{ Gdk.Key.?, Key.DeadCharProcessed }
};
public static GtkKeyboardDevice Instance { get; } = new GtkKeyboardDevice();
public new static GtkKeyboardDevice Instance { get; } = new GtkKeyboardDevice();
public static Key ConvertKey(Gdk.Key key)
{

5
src/Gtk/Perspex.Gtk/PopupImpl.cs

@ -12,10 +12,5 @@ namespace Perspex.Gtk
: base(WindowType.Popup)
{
}
public void SetPosition(Point p)
{
Move((int)p.X, (int)p.Y);
}
}
}

33
src/Gtk/Perspex.Gtk/WindowImpl.cs

@ -11,6 +11,7 @@ using Perspex.Platform;
using Perspex.Input;
using Perspex.Threading;
using Action = System.Action;
using WindowEdge = Perspex.Controls.WindowEdge;
namespace Perspex.Gtk
{
@ -162,6 +163,36 @@ namespace Perspex.Gtk
GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
}
public void BeginMoveDrag()
{
int x, y;
ModifierType mod;
Screen.RootWindow.GetPointer(out x, out y, out mod);
BeginMoveDrag(1, x, y, 0);
}
public void BeginResizeDrag(WindowEdge edge)
{
int x, y;
ModifierType mod;
Screen.RootWindow.GetPointer(out x, out y, out mod);
BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0);
}
public Point Position
{
get
{
int x, y;
GetPosition(out x, out y);
return new Point(x, y);
}
set
{
Move((int)value.X, (int)value.Y);
}
}
public IDisposable ShowDialog()
{
Modal = true;
@ -170,6 +201,8 @@ namespace Perspex.Gtk
return Disposable.Empty;
}
public void SetSystemDecorations(bool enabled) => Decorated = enabled;
void ITopLevelImpl.Activate()
{
Activate();

4
src/Markup/Perspex.Markup.Xaml/Context/NameScopeWrapper.cs

@ -5,9 +5,9 @@ namespace Perspex.Markup.Xaml.Context
{
internal class NameScopeWrapper : OmniXaml.INameScope
{
private Perspex.INameScope _inner;
private readonly Perspex.Controls.INameScope _inner;
public NameScopeWrapper(Perspex.INameScope inner)
public NameScopeWrapper(Perspex.Controls.INameScope inner)
{
_inner = inner;
}

2
src/Markup/Perspex.Markup.Xaml/Context/PerspexContentPropertyProvider.cs

@ -15,7 +15,7 @@ namespace Perspex.Markup.Xaml.Context
{
public class PerspexContentPropertyProvider : IContentPropertyProvider
{
private Dictionary<Type, string> _values = new Dictionary<Type, string>();
private readonly Dictionary<Type, string> _values = new Dictionary<Type, string>();
public string GetContentPropertyName(Type type)
{

2
src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs

@ -29,6 +29,8 @@ namespace Perspex.Markup.Xaml.Context
public object Result => _objectAssembler.Result;
public InstanceLifeCycleHandler InstanceLifeCycleHandler { get; set; } = new InstanceLifeCycleHandler();
public EventHandler<XamlSetValueEventArgs> XamlSetValueHandler { get; set; }
public IWiringContext WiringContext => _objectAssembler.WiringContext;

7
src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs

@ -15,6 +15,7 @@ using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Input;
using Perspex.Markup.Xaml.Converters;
using Perspex.Markup.Xaml.Data;
using Perspex.Media;
using Perspex.Media.Imaging;
using Perspex.Metadata;
@ -58,9 +59,10 @@ namespace Perspex.Markup.Xaml.Context
var forcedAssemblies = new[]
{
typeof(Binding),
typeof(Control),
typeof(Style),
typeof(IValueConverter),
typeof(Style),
}.Select(t => t.GetTypeInfo().Assembly);
foreach (var nsa in
@ -88,7 +90,7 @@ namespace Perspex.Markup.Xaml.Context
var typeConverterProvider = new TypeConverterProvider();
var converters = new[]
{
new TypeConverterRegistration(typeof(Bitmap), new BitmapTypeConverter()),
new TypeConverterRegistration(typeof(IBitmap), new BitmapTypeConverter()),
new TypeConverterRegistration(typeof(Brush), new BrushTypeConverter()),
new TypeConverterRegistration(typeof(Color), new ColorTypeConverter()),
new TypeConverterRegistration(typeof(Classes), new ClassesTypeConverter()),
@ -107,6 +109,7 @@ namespace Perspex.Markup.Xaml.Context
new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()),
new TypeConverterRegistration(typeof(TimeSpan), new TimeSpanTypeConverter()),
new TypeConverterRegistration(typeof(Uri), new UriTypeConverter()),
new TypeConverterRegistration(typeof(Cursor), new CursorTypeConverter())
};
typeConverterProvider.AddAll(converters);

53
src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs

@ -9,6 +9,8 @@ using System.Runtime.CompilerServices;
using Glass;
using OmniXaml.ObjectAssembler;
using OmniXaml.Typing;
using Perspex.Controls;
using Perspex.Data;
using Perspex.Markup.Xaml.Data;
using Perspex.Styling;
@ -39,9 +41,9 @@ namespace Perspex.Markup.Xaml.Context
public override void SetValue(object instance, object value)
{
if (value is IXamlBinding)
if (value is IBinding)
{
HandleBinding(instance, (IXamlBinding)value);
HandleBinding(instance, (IBinding)value);
}
else if (IsPerspexProperty)
{
@ -68,35 +70,38 @@ namespace Perspex.Markup.Xaml.Context
po.SetValue(pp, value);
}
private void HandleBinding(object instance, IXamlBinding binding)
private void HandleBinding(object instance, IBinding binding)
{
if (typeof(IXamlBinding).GetTypeInfo().IsAssignableFrom(_xamlMember.XamlType.UnderlyingType.GetTypeInfo()))
if (!(AssignBinding(instance, binding) || ApplyBinding(instance, binding)))
{
var property = instance.GetType().GetRuntimeProperty(_xamlMember.Name);
throw new InvalidOperationException(
$"Cannot assign to '{_xamlMember.Name}' on '{instance.GetType()}");
}
}
if (property == null || !property.CanWrite)
{
throw new InvalidOperationException(
$"Cannot assign to '{_xamlMember.Name}' on '{instance.GetType()}");
}
private bool AssignBinding(object instance, IBinding binding)
{
var property = instance.GetType()
.GetRuntimeProperties()
.FirstOrDefault(x => x.Name == _xamlMember.Name);
if (property?.GetCustomAttribute<AssignBindingAttribute>() != null)
{
property.SetValue(instance, binding);
return true;
}
else
{
ApplyBinding(instance, binding);
}
return false;
}
private void ApplyBinding(object instance, IXamlBinding binding)
private bool ApplyBinding(object instance, IBinding binding)
{
var perspexObject = instance as PerspexObject;
var targetControl = instance as IControl;
var attached = _xamlMember as PerspexAttachableXamlMember;
if (perspexObject == null)
if (targetControl == null)
{
throw new InvalidOperationException(
$"Cannot bind to an object of type '{instance.GetType()}");
return false;
}
PerspexProperty property;
@ -105,7 +110,7 @@ namespace Perspex.Markup.Xaml.Context
if (attached == null)
{
propertyName = _xamlMember.Name;
property = PerspexPropertyRegistry.Instance.GetRegistered(perspexObject)
property = PerspexPropertyRegistry.Instance.GetRegistered((PerspexObject)targetControl)
.FirstOrDefault(x => x.Name == propertyName);
}
else
@ -115,18 +120,18 @@ namespace Perspex.Markup.Xaml.Context
propertyName = attached.DeclaringType.UnderlyingType.Name + '.' + _xamlMember.Name;
property = PerspexPropertyRegistry.Instance.GetRegistered(perspexObject)
property = PerspexPropertyRegistry.Instance.GetRegistered((PerspexObject)targetControl)
.Where(x => x.IsAttached && x.OwnerType == attached.DeclaringType.UnderlyingType)
.FirstOrDefault(x => x.Name == _xamlMember.Name);
}
if (property == null)
{
throw new InvalidOperationException(
$"Cannot find '{propertyName}' on '{instance.GetType()}");
return false;
}
binding.Bind(perspexObject, property);
targetControl.Bind(property, binding);
return true;
}
private bool ValueRequiresSpecialHandling(object value)

10
src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs

@ -5,7 +5,7 @@ using System;
using System.Reflection;
using OmniXaml;
using OmniXaml.Typing;
using Perspex.Markup.Xaml.Data;
using Perspex.Controls;
namespace Perspex.Markup.Xaml.Context
{
@ -20,15 +20,15 @@ namespace Perspex.Markup.Xaml.Context
public override OmniXaml.INameScope GetNamescope(object instance)
{
var result = this.UnderlyingType as OmniXaml.INameScope;
var result = instance as OmniXaml.INameScope;
if (result == null)
{
var visual = instance as Visual;
var control = instance as Control;
if (visual != null)
if (control != null)
{
var perspexNs = (instance as Perspex.INameScope) ?? NameScope.GetNameScope(visual);
var perspexNs = (instance as Perspex.Controls.INameScope) ?? NameScope.GetNameScope(control);
if (perspexNs != null)
{

13
src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs

@ -5,6 +5,7 @@ using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Media.Imaging;
using Perspex.Platform;
namespace Perspex.Markup.Xaml.Converters
{
@ -22,7 +23,17 @@ namespace Perspex.Markup.Xaml.Converters
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return new Bitmap((string)value);
var uri = new Uri((string)value, UriKind.RelativeOrAbsolute);
var scheme = uri.IsAbsoluteUri ? uri.Scheme : "file";
switch (scheme)
{
case "file":
return new Bitmap((string)value);
default:
var assets = PerspexLocator.Current.GetService<IAssetLoader>();
return new Bitmap(assets.Open(uri));
}
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)

1
src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs

@ -4,6 +4,7 @@
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Controls;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.Converters

36
src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs

@ -0,0 +1,36 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Input;
using Perspex.Media.Imaging;
using Perspex.Platform;
namespace Perspex.Markup.Xaml.Converters
{
public class CursorTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
var cursor = (StandardCursorType)Enum.Parse(typeof (StandardCursorType), ((string) value).Trim(), true);
return new Cursor(cursor);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

10
src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs

@ -55,13 +55,9 @@ namespace Perspex.Markup.Xaml.Converters
}
// First look for non-attached property on the type and then look for an attached property.
var property = PerspexPropertyRegistry.Instance.FindRegistered(type, s);
if (property == null)
{
property = PerspexPropertyRegistry.Instance.GetAttached(type)
.FirstOrDefault(x => x.Name == propertyName);
}
var property = PerspexPropertyRegistry.Instance.FindRegistered(type, s) ??
PerspexPropertyRegistry.Instance.GetAttached(type)
.FirstOrDefault(x => x.Name == propertyName);
if (property == null)
{

142
src/Markup/Perspex.Markup.Xaml/Data/Binding.cs

@ -2,9 +2,11 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Controls;
using Perspex.Data;
using Perspex.Markup.Data;
namespace Perspex.Markup.Xaml.Data
@ -12,13 +14,18 @@ namespace Perspex.Markup.Xaml.Data
/// <summary>
/// A XAML binding.
/// </summary>
public class Binding : IXamlBinding
public class Binding : IBinding
{
/// <summary>
/// Gets or sets the <see cref="IValueConverter"/> to use.
/// </summary>
public IValueConverter Converter { get; set; }
/// <summary>
/// Gets or sets a parameter to pass to <see cref="Converter"/>.
/// </summary>
public object ConverterParameter { get; set; }
/// <summary>
/// Gets or sets the name of the element to use as the binding source.
/// </summary>
@ -44,66 +51,41 @@ namespace Perspex.Markup.Xaml.Data
/// </summary>
public string Path { get; set; }
/// <summary>
/// Applies the binding to a property on an instance.
/// </summary>
/// <param name="instance">The target instance.</param>
/// <param name="property">The target property.</param>
public void Bind(IObservablePropertyBag instance, PerspexProperty property)
{
Contract.Requires<ArgumentNullException>(instance != null);
Contract.Requires<ArgumentNullException>(property != null);
var subject = CreateSubject(
instance,
property.PropertyType,
property == Control.DataContextProperty);
if (subject != null)
{
Bind(instance, property, subject);
}
}
/// <summary>
/// Creates a subject that can be used to get and set the value of the binding.
/// </summary>
/// <param name="target">The target instance.</param>
/// <param name="targetType">The type of the target property.</param>
/// <param name="targetIsDataContext">
/// Whether the target property is the DataContext property.
/// </param>
/// <returns>An <see cref="ISubject{object}"/>.</returns>
/// <param name="targetProperty">The target property. May be null.</param>
/// <returns>An <see cref="ISubject{Object}"/>.</returns>
public ISubject<object> CreateSubject(
IObservablePropertyBag target,
Type targetType,
bool targetIsDataContext = false)
IPerspexObject target,
PerspexProperty targetProperty)
{
Contract.Requires<ArgumentNullException>(target != null);
Contract.Requires<ArgumentNullException>(targetType != null);
var pathInfo = ParsePath(Path);
ValidateState(pathInfo);
ExpressionObserver observer;
var targetIsDataContext = targetProperty == Control.DataContextProperty;
if (pathInfo.ElementName != null || ElementName != null)
{
observer = CreateElementSubject(
observer = CreateElementObserver(
(IControl)target,
pathInfo.ElementName ?? ElementName,
pathInfo.Path);
}
else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext)
{
observer = CreateDataContextSubject(
observer = CreateDataContexObserver(
target,
pathInfo.Path,
targetIsDataContext);
}
else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
{
observer = CreateTemplatedParentSubject(
observer = CreateTemplatedParentObserver(
target,
pathInfo.Path);
}
@ -114,44 +96,9 @@ namespace Perspex.Markup.Xaml.Data
return new ExpressionSubject(
observer,
targetType,
Converter ?? DefaultValueConverter.Instance);
}
/// <summary>
/// Applies a binding subject to a property on an instance.
/// </summary>
/// <param name="target">The target instance.</param>
/// <param name="property">The target property.</param>
/// <param name="subject">The binding subject.</param>
internal void Bind(IObservablePropertyBag target, PerspexProperty property, ISubject<object> subject)
{
Contract.Requires<ArgumentNullException>(target != null);
Contract.Requires<ArgumentNullException>(property != null);
Contract.Requires<ArgumentNullException>(subject != null);
var mode = Mode == BindingMode.Default ?
property.DefaultBindingMode : Mode;
switch (mode)
{
case BindingMode.Default:
case BindingMode.OneWay:
target.Bind(property, subject, Priority);
break;
case BindingMode.TwoWay:
target.BindTwoWay(property, subject, Priority);
break;
case BindingMode.OneTime:
target.GetObservable(Control.DataContextProperty).Subscribe(dataContext =>
{
subject.Take(1).Subscribe(x => target.SetValue(property, x, Priority));
});
break;
case BindingMode.OneWayToSource:
target.GetObservable(property).Subscribe(subject);
break;
}
targetProperty?.PropertyType ?? typeof(object),
Converter ?? DefaultValueConverter.Instance,
ConverterParameter);
}
private static PathInfo ParsePath(string path)
@ -201,56 +148,55 @@ namespace Perspex.Markup.Xaml.Data
}
}
private ExpressionObserver CreateDataContextSubject(
IObservablePropertyBag target,
private ExpressionObserver CreateDataContexObserver(
IPerspexObject target,
string path,
bool targetIsDataContext)
{
Contract.Requires<ArgumentNullException>(target != null);
var dataContextHost = targetIsDataContext ?
target.InheritanceParent as IObservablePropertyBag : target;
if (dataContextHost != null)
if (!targetIsDataContext)
{
var update = target.GetObservable(Control.DataContextProperty)
.Skip(1)
.Select(_ => Unit.Default);
var result = new ExpressionObserver(
() => dataContextHost.GetValue(Control.DataContextProperty),
path);
dataContextHost.GetObservable(Control.DataContextProperty).Subscribe(x =>
result.UpdateRoot());
() => target.GetValue(Control.DataContextProperty),
path,
update);
return result;
}
else
{
throw new InvalidOperationException(
"Cannot bind to DataContext of object with no parent.");
return new ExpressionObserver(
target.GetObservable(Visual.VisualParentProperty)
.OfType<IPerspexObject>()
.Select(x => x.GetObservable(Control.DataContextProperty))
.Switch(),
path);
}
}
private ExpressionObserver CreateTemplatedParentSubject(
IObservablePropertyBag target,
private ExpressionObserver CreateTemplatedParentObserver(
IPerspexObject target,
string path)
{
Contract.Requires<ArgumentNullException>(target != null);
var update = target.GetObservable(Control.TemplatedParentProperty)
.Skip(1)
.Select(_ => Unit.Default);
var result = new ExpressionObserver(
() => target.GetValue(Control.TemplatedParentProperty),
path);
if (target.GetValue(Control.TemplatedParentProperty) == null)
{
// TemplatedParent should only be set once, so only listen for the first non-null
// value.
target.GetObservable(Control.TemplatedParentProperty)
.Where(x => x != null)
.Take(1)
.Subscribe(x => result.UpdateRoot());
}
path,
update);
return result;
}
private ExpressionObserver CreateElementSubject(
private ExpressionObserver CreateElementObserver(
IControl target,
string elementName,
string path)

35
src/Markup/Perspex.Markup.Xaml/Data/IXamlBinding.cs

@ -1,35 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Subjects;
namespace Perspex.Markup.Xaml.Data
{
/// <summary>
/// Defines a binding that can be created in XAML markup.
/// </summary>
public interface IXamlBinding
{
/// <summary>
/// Applies the binding to a property on an instance.
/// </summary>
/// <param name="instance">The target instance.</param>
/// <param name="property">The target property.</param>
void Bind(IObservablePropertyBag instance, PerspexProperty property);
/// <summary>
/// Creates a subject that can be used to get and set the value of the binding.
/// </summary>
/// <param name="target">The target instance.</param>
/// <param name="targetType">The type of the target property.</param>
/// <param name="targetIsDataContext">
/// Whether the target property is the DataContext property.
/// </param>
/// <returns>An <see cref="ISubject{object}"/>.</returns>
ISubject<object> CreateSubject(
IObservablePropertyBag target,
Type targetType,
bool targetIsDataContext = false);
}
}

30
src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs

@ -8,6 +8,7 @@ using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Controls;
using Perspex.Data;
using Perspex.Metadata;
namespace Perspex.Markup.Xaml.Data
@ -15,13 +16,13 @@ namespace Perspex.Markup.Xaml.Data
/// <summary>
/// A XAML binding that calculates an aggregate value from multiple child <see cref="Bindings"/>.
/// </summary>
public class MultiBinding : IXamlBinding
public class MultiBinding : IBinding
{
/// <summary>
/// Gets the collection of child bindings.
/// </summary>
[Content]
public IList<IXamlBinding> Bindings { get; set; } = new List<IXamlBinding>();
public IList<IBinding> Bindings { get; set; } = new List<IBinding>();
/// <summary>
/// Gets or sets the <see cref="IValueConverter"/> to use.
@ -31,7 +32,7 @@ namespace Perspex.Markup.Xaml.Data
/// <summary>
/// Gets or sets the binding mode.
/// </summary>
public BindingMode Mode { get; set; }
public BindingMode Mode { get; set; } = BindingMode.OneWay;
/// <summary>
/// Gets or sets the binding priority.
@ -48,9 +49,9 @@ namespace Perspex.Markup.Xaml.Data
/// </summary>
/// <param name="instance">The target instance.</param>
/// <param name="property">The target property.</param>
public void Bind(IObservablePropertyBag instance, PerspexProperty property)
public void Bind(IPerspexObject instance, PerspexProperty property)
{
var subject = CreateSubject(instance, property.PropertyType);
var subject = CreateSubject(instance, property);
if (subject != null)
{
@ -62,24 +63,19 @@ namespace Perspex.Markup.Xaml.Data
/// Creates a subject that can be used to get and set the value of the binding.
/// </summary>
/// <param name="target">The target instance.</param>
/// <param name="targetType">The type of the target property.</param>
/// <param name="targetIsDataContext">
/// Whether the target property is the DataContext property.
/// </param>
/// <returns>An <see cref="ISubject{object}"/>.</returns>
public ISubject<object> CreateSubject(
IObservablePropertyBag target,
Type targetType,
bool targetIsDataContext = false)
/// <param name="targetProperty">The target property.</param>
/// <returns>An <see cref="ISubject{Object}"/>.</returns>
public ISubject<object> CreateSubject(IPerspexObject target, PerspexProperty targetProperty)
{
if (Converter == null)
{
throw new NotSupportedException("MultiBinding without Converter not currently supported.");
}
var targetType = targetProperty?.PropertyType ?? typeof(object);
var result = new BehaviorSubject<object>(PerspexProperty.UnsetValue);
var children = Bindings.Select(x => x.CreateSubject(target, typeof(object)));
var input = Observable.CombineLatest(children).Select(x =>
var children = Bindings.Select(x => x.CreateSubject(target, null));
var input = children.CombineLatest().Select(x =>
Converter.Convert(x, targetType, null, CultureInfo.CurrentUICulture));
input.Subscribe(result);
return result;
@ -91,7 +87,7 @@ namespace Perspex.Markup.Xaml.Data
/// <param name="target">The target instance.</param>
/// <param name="property">The target property.</param>
/// <param name="subject">The binding subject.</param>
internal void Bind(IObservablePropertyBag target, PerspexProperty property, ISubject<object> subject)
internal void Bind(IPerspexObject target, PerspexProperty property, ISubject<object> subject)
{
var mode = Mode == BindingMode.Default ?
property.DefaultBindingMode : Mode;

5
src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using OmniXaml;
using Perspex.Data;
using Perspex.Markup.Xaml.Data;
namespace Perspex.Markup.Xaml.MarkupExtensions
@ -22,15 +23,19 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
return new Binding
{
Converter = Converter,
ConverterParameter = ConverterParameter,
ElementName = ElementName,
Mode = Mode,
Path = Path,
Priority = Priority,
};
}
public IValueConverter Converter { get; set; }
public object ConverterParameter { get; set; }
public string ElementName { get; set; }
public BindingMode Mode { get; set; }
public string Path { get; set; }
public BindingPriority Priority { get; set; } = BindingPriority.LocalValue;
}
}

4
src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using OmniXaml;
using Perspex.Data;
using Perspex.Markup.Xaml.Data;
namespace Perspex.Markup.Xaml.MarkupExtensions
@ -24,9 +25,9 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
Converter = Converter,
ElementName = ElementName,
Mode = Mode,
Priority = BindingPriority.TemplatedParent,
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Path = Path,
Priority = Priority,
};
}
@ -34,5 +35,6 @@ namespace Perspex.Markup.Xaml.MarkupExtensions
public string ElementName { get; set; }
public BindingMode Mode { get; set; }
public string Path { get; set; }
public BindingPriority Priority { get; set; } = BindingPriority.TemplatedParent;
}
}

2
src/Markup/Perspex.Markup.Xaml/OmniXAML

@ -1 +1 @@
Subproject commit 3e3b46ba66941da925092e2977003d0553cfc907
Subproject commit 0904dcb07175ca0cdf2ae1fda1434c0f1425a53e

12
src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs

@ -3,10 +3,12 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Perspex.Styling;
using Sprache;
// Don't need to override GetHashCode as the ISyntax objects will not be stored in a hash; the
// only reason they have overridden Equals methods is for unit testing.
#pragma warning disable 659
namespace Perspex.Markup.Xaml.Parsers
{
internal class SelectorGrammar
@ -129,7 +131,8 @@ namespace Perspex.Markup.Xaml.Parsers
public override bool Equals(object obj)
{
return obj is OfTypeSyntax && ((OfTypeSyntax)obj).TypeName == TypeName;
var other = obj as OfTypeSyntax;
return other != null && other.TypeName == TypeName && other.Xmlns == Xmlns;
}
}
@ -141,7 +144,8 @@ namespace Perspex.Markup.Xaml.Parsers
public override bool Equals(object obj)
{
return obj is IsSyntax && ((IsSyntax)obj).TypeName == TypeName;
var other = obj as IsSyntax;
return other != null && other.TypeName == TypeName && other.Xmlns == Xmlns;
}
}

2
src/Markup/Perspex.Markup.Xaml/Parsers/SelectorParser.cs

@ -14,7 +14,7 @@ namespace Perspex.Markup.Xaml.Parsers
/// </summary>
public class SelectorParser
{
private Func<string, string, Type> _typeResolver;
private readonly Func<string, string, Type> _typeResolver;
/// <summary>
/// Initializes a new instance of the <see cref="SelectorParser"/> class.

10
src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj

@ -39,9 +39,9 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Context\NameScopeWrapper.cs" />
<Compile Include="Converters\CursorTypeConverter.cs" />
<Compile Include="Converters\PerspexListTypeConverter.cs" />
<Compile Include="Converters\RelativeRectTypeConverter.cs" />
<Compile Include="Data\IXamlBinding.cs" />
<Compile Include="Data\MultiBinding.cs" />
<Compile Include="Data\RelativeSource.cs" />
<Compile Include="Data\SourceBindingEndpoint.cs" />
@ -108,6 +108,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\IDeferredLoader.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IMarkupExtension.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\INameScope.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\InstanceLifeCycleHandler.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\InstructionNode.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\InstructionTreeBuilder.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IObjectAssembler.cs" />
@ -118,6 +119,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\ITypeProvider.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IValueConverter.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IWiringContext.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlLoader.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlParser.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlParserFactory.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\IXamlXmlLoader.cs" />
@ -129,6 +131,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\MemberReverserVisitor.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\NamespaceDeclaration.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\NamespacePrefix.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssemblerMixin.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Command.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Commands\EndMemberCommand.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Commands\EndObjectCommand.cs" />
@ -140,6 +143,7 @@
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Commands\ValueCommand.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\ConstructionArgument.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\CurrentLevelWrapper.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\InstanceLifeCycleNotifier.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\InstanceProperties.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\Level.cs" />
<Compile Include="OmniXAML\Source\OmniXaml\ObjectAssembler\NullLevel.cs" />
@ -272,10 +276,6 @@
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Application\Perspex.Application.csproj">
<Project>{799A7BB5-3C2C-48B6-85A7-406A12C420DA}</Project>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name>

29
src/Markup/Perspex.Markup.Xaml/PerspexXamlLoader.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using OmniXaml;
using Perspex.Markup.Xaml.Context;
using Perspex.Platform;
@ -39,6 +40,8 @@ namespace Perspex.Markup.Xaml
/// <param name="obj">The object to load the XAML into.</param>
public static void Load(object obj)
{
Contract.Requires<ArgumentNullException>(obj != null);
var loader = new PerspexXamlLoader();
loader.Load(obj.GetType(), obj);
}
@ -53,6 +56,8 @@ namespace Perspex.Markup.Xaml
/// <returns>The loaded object.</returns>
public object Load(Type type, object rootInstance = null)
{
Contract.Requires<ArgumentNullException>(type != null);
// HACK: Currently Visual Studio is forcing us to change the extension of xaml files
// in certain situations, so we try to load .xaml and if that's not found we try .paml.
// Ideally we'd be able to use .xaml everywhere
@ -85,6 +90,8 @@ namespace Perspex.Markup.Xaml
/// <returns>The loaded object.</returns>
public object Load(Uri uri, object rootInstance = null)
{
Contract.Requires<ArgumentNullException>(uri != null);
var assetLocator = PerspexLocator.Current.GetService<IAssetLoader>();
if (assetLocator == null)
@ -99,6 +106,24 @@ namespace Perspex.Markup.Xaml
}
}
/// <summary>
/// Loads XAML from a string.
/// </summary>
/// <param name="xaml">The string containing the XAML.</param>
/// <param name="rootInstance">
/// The optional instance into which the XAML should be loaded.
/// </param>
/// <returns>The loaded object.</returns>
public object Load(string xaml, object rootInstance = null)
{
Contract.Requires<ArgumentNullException>(xaml != null);
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)))
{
return Load(stream, rootInstance);
}
}
/// <summary>
/// Gets the URI for a type.
/// </summary>
@ -108,8 +133,8 @@ namespace Perspex.Markup.Xaml
{
var asm = type.GetTypeInfo().Assembly.GetName().Name;
var typeName = type.FullName;
yield return new Uri("resource://application/" + asm + "/" + typeName + ".xaml");
yield return new Uri("resource://application/" + asm + "/" + typeName + ".paml");
yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm);
yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm);
}
}

8
src/Markup/Perspex.Markup.Xaml/Templates/DataTemplate.cs

@ -20,10 +20,12 @@ namespace Perspex.Markup.Xaml.Templates
{
if (DataType == null)
{
throw new InvalidOperationException("DataTemplate must have a DataType.");
return true;
}
else
{
return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo());
}
return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo());
}
public IControl Build(object data)

10
src/Markup/Perspex.Markup.Xaml/Templates/MemberSelector.cs

@ -14,15 +14,7 @@ namespace Perspex.Markup.Xaml.Templates
{
// TODO: Handle nested property paths, changing values etc.
var property = o.GetType().GetRuntimeProperty(MemberName);
if (property != null)
{
return property.GetValue(o);
}
else
{
return null;
}
return property?.GetValue(o);
}
}
}

11
src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs

@ -4,8 +4,10 @@
using System;
using System.Collections;
using System.Reactive.Linq;
using System.Reflection;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Data;
using Perspex.Markup.Data;
using Perspex.Markup.Xaml.Data;
using Perspex.Metadata;
@ -19,16 +21,19 @@ namespace Perspex.Markup.Xaml.Templates
[Content]
public TemplateContent Content { get; set; }
[AssignBinding]
public Binding ItemsSource { get; set; }
public bool Match(object data)
{
if (DataType == null)
{
throw new InvalidOperationException("DataTemplate must have a DataType.");
return true;
}
else
{
return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo());
}
return DataType == data.GetType();
}
public IEnumerable ItemsSelector(object item)

8
src/Markup/Perspex.Markup/ControlLocator.cs

@ -25,7 +25,7 @@ namespace Perspex.Markup
var attached = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => relativeTo.AttachedToVisualTree += x,
x => relativeTo.DetachedFromVisualTree += x)
.Select(x => x.EventArgs.NameScope)
.Select(x => ((IControl)x.Sender).FindNameScope())
.StartWith(relativeTo.FindNameScope());
var detached = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
@ -45,10 +45,12 @@ namespace Perspex.Markup
.OfType<IControl>();
var unregistered = Observable.FromEventPattern<NameScopeEventArgs>(
x => nameScope.Unregistered += x,
x => nameScope.Unregistered -= x);
x => nameScope.Unregistered -= x)
.Where(x => x.EventArgs.Name == name)
.Select(_ => (IControl)null);
return registered
.StartWith(nameScope.Find<IControl>(name))
.TakeUntil(unregistered);
.Merge(unregistered);
}
else
{

5
src/Markup/Perspex.Markup/Data/ExpressionNode.cs

@ -63,10 +63,7 @@ namespace Perspex.Markup.Data
Next.Target = value;
}
if (_subject != null)
{
_subject.OnNext(value);
}
_subject?.OnNext(value);
}
}

2
src/Markup/Perspex.Markup/Data/ExpressionNodeBuilder.cs

@ -20,7 +20,7 @@ namespace Perspex.Markup.Data
if (!reader.End)
{
throw new ExpressionParseException(reader, "Expected end of expression.");
throw new ExpressionParseException(reader.Position, "Expected end of expression.");
}
return node;

69
src/Markup/Perspex.Markup/Data/ExpressionObserver.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Markup.Data.Plugins;
@ -29,10 +30,11 @@ namespace Perspex.Markup.Data
private readonly object _root;
private readonly Func<object> _rootGetter;
private readonly IObservable<object> _rootObservable;
private readonly IObservable<Unit> _update;
private IDisposable _rootObserverSubscription;
private IDisposable _updateSubscription;
private int _count;
private readonly ExpressionNode _node;
private ISubject<object> _empty;
/// <summary>
/// Initializes a new instance of the <see cref="ExpressionObserver"/> class.
@ -78,12 +80,18 @@ namespace Perspex.Markup.Data
/// </summary>
/// <param name="rootGetter">A function which gets the root object.</param>
/// <param name="expression">The expression.</param>
public ExpressionObserver(Func<object> rootGetter, string expression)
/// <param name="update">An observable which triggers a re-read of the getter.</param>
public ExpressionObserver(
Func<object> rootGetter,
string expression,
IObservable<Unit> update)
{
Contract.Requires<ArgumentNullException>(rootGetter != null);
Contract.Requires<ArgumentNullException>(expression != null);
Contract.Requires<ArgumentNullException>(update != null);
_rootGetter = rootGetter;
_update = update;
if (!string.IsNullOrWhiteSpace(expression))
{
@ -104,7 +112,11 @@ namespace Perspex.Markup.Data
public bool SetValue(object value)
{
IncrementCount();
UpdateRoot();
if (_rootGetter != null && _node != null)
{
_node.Target = _rootGetter();
}
try
{
@ -156,6 +168,11 @@ namespace Perspex.Markup.Data
/// <inheritdoc/>
string IDescription.Description => Expression;
/// <summary>
/// Gets the root expression node. Used for testing.
/// </summary>
internal ExpressionNode Node => _node;
/// <summary>
/// Gets the leaf node.
/// </summary>
@ -169,24 +186,6 @@ namespace Perspex.Markup.Data
}
}
/// <summary>
/// Causes the root object to be re-read from the root getter.
/// </summary>
public void UpdateRoot()
{
if (_count > 0 && _rootGetter != null)
{
if (_node != null)
{
_node.Target = _rootGetter();
}
else if (_empty != null)
{
_empty.OnNext(_rootGetter());
}
}
}
/// <inheritdoc/>
protected override IDisposable SubscribeCore(IObserver<object> observer)
{
@ -202,14 +201,23 @@ namespace Perspex.Markup.Data
subscription.Dispose();
});
}
else if (_rootObservable != null)
{
return _rootObservable.Subscribe(observer);
}
else
{
if (_empty == null)
if (_update == null)
{
_empty = new BehaviorSubject<object>(_rootGetter());
return Observable.Never<object>().StartWith(_root).Subscribe(observer);
}
else
{
return _update
.Select(_ => _rootGetter())
.StartWith(_rootGetter())
.Subscribe(observer);
}
return _empty.Subscribe(observer);
}
}
@ -220,6 +228,11 @@ namespace Perspex.Markup.Data
if (_rootGetter != null)
{
_node.Target = _rootGetter();
if (_update != null)
{
_updateSubscription = _update.Subscribe(x => _node.Target = _rootGetter());
}
}
else if (_rootObservable != null)
{
@ -242,6 +255,12 @@ namespace Perspex.Markup.Data
_rootObserverSubscription = null;
}
if (_updateSubscription != null)
{
_updateSubscription.Dispose();
_updateSubscription = null;
}
_node.Target = null;
}
}

19
src/Markup/Perspex.Markup/Data/ExpressionParseException.cs

@ -6,19 +6,26 @@ using Perspex.Markup.Data.Parsers;
namespace Perspex.Markup.Data
{
/// <summary>
/// Exception thrown when <see cref="ExpressionObserver"/> could not parse the provided
/// expression string.
/// </summary>
public class ExpressionParseException : Exception
{
internal ExpressionParseException(int column, string message)
/// <summary>
/// Initializes a new instance of the <see cref="ExpressionParseException"/> class.
/// </summary>
/// <param name="column">The column position of the error.</param>
/// <param name="message">The exception message.</param>
public ExpressionParseException(int column, string message)
: base(message)
{
Column = column;
}
internal ExpressionParseException(Reader r, string message)
: this(r.Position, message)
{
}
/// <summary>
/// Gets the column position at which the error occurred.
/// </summary>
public int Column { get; }
}
}

29
src/Markup/Perspex.Markup/Data/ExpressionSubject.cs

@ -15,8 +15,8 @@ namespace Perspex.Markup.Data
/// </summary>
public class ExpressionSubject : ISubject<object>, IDescription
{
private ExpressionObserver _inner;
private Type _targetType;
private readonly ExpressionObserver _inner;
private readonly Type _targetType;
/// <summary>
/// Initializes a new instance of the <see cref="ExpressionObserver"/> class.
@ -34,7 +34,12 @@ namespace Perspex.Markup.Data
/// <param name="inner">The <see cref="ExpressionObserver"/>.</param>
/// <param name="targetType">The type to convert the value to.</param>
/// <param name="converter">The value converter to use.</param>
public ExpressionSubject(ExpressionObserver inner, Type targetType, IValueConverter converter)
/// <param name="converterParameter">A parameter to pass to <paramref name="converter"/>.</param>
public ExpressionSubject(
ExpressionObserver inner,
Type targetType,
IValueConverter converter,
object converterParameter = null)
{
Contract.Requires<ArgumentNullException>(inner != null);
Contract.Requires<ArgumentNullException>(targetType != null);
@ -43,6 +48,7 @@ namespace Perspex.Markup.Data
_inner = inner;
_targetType = targetType;
Converter = converter;
ConverterParameter = converterParameter;
}
/// <summary>
@ -50,6 +56,11 @@ namespace Perspex.Markup.Data
/// </summary>
public IValueConverter Converter { get; }
/// <summary>
/// Gets a parameter to pass to <see cref="Converter"/>.
/// </summary>
public object ConverterParameter { get; }
/// <inheritdoc/>
string IDescription.Description => _inner.Expression;
@ -70,7 +81,11 @@ namespace Perspex.Markup.Data
if (type != null)
{
var converted = Converter.ConvertBack(value, type, null, CultureInfo.CurrentUICulture);
var converted = Converter.ConvertBack(
value,
type,
ConverterParameter,
CultureInfo.CurrentUICulture);
if (converted == PerspexProperty.UnsetValue)
{
@ -85,7 +100,11 @@ namespace Perspex.Markup.Data
public IDisposable Subscribe(IObserver<object> observer)
{
return _inner
.Select(x => Converter.Convert(x, _targetType, null, CultureInfo.CurrentUICulture))
.Select(x => Converter.Convert(
x,
_targetType,
ConverterParameter,
CultureInfo.CurrentUICulture))
.Subscribe(observer);
}
}

2
src/Markup/Perspex.Markup/Data/IndexerNode.cs

@ -12,7 +12,7 @@ namespace Perspex.Markup.Data
{
internal class IndexerNode : ExpressionNode
{
private int[] _intArgs;
private readonly int[] _intArgs;
public IndexerNode(IList<object> arguments)
{

4
src/Markup/Perspex.Markup/Data/LogicalNotNode.cs

@ -16,10 +16,10 @@ namespace Perspex.Markup.Data
public override IDisposable Subscribe(IObserver<object> observer)
{
return Next.Select(x => Negate(x)).Subscribe(observer);
return Next.Select(Negate).Subscribe(observer);
}
private object Negate(object v)
private static object Negate(object v)
{
if (v != PerspexProperty.UnsetValue)
{

8
src/Markup/Perspex.Markup/Data/Parsers/ArgumentListParser.cs

@ -26,14 +26,14 @@ namespace Perspex.Markup.Data.Parsers
}
else
{
throw new ExpressionParseException(r, "Expected integer.");
throw new ExpressionParseException(r.Position, "Expected integer.");
}
r.SkipWhitespace();
if (r.End)
{
throw new ExpressionParseException(r, "Expected ','.");
throw new ExpressionParseException(r.Position, "Expected ','.");
}
else if (r.TakeIf(close))
{
@ -43,7 +43,7 @@ namespace Perspex.Markup.Data.Parsers
{
if (r.Take() != ',')
{
throw new ExpressionParseException(r, "Expected ','.");
throw new ExpressionParseException(r.Position, "Expected ','.");
}
r.SkipWhitespace();
@ -57,7 +57,7 @@ namespace Perspex.Markup.Data.Parsers
}
else
{
throw new ExpressionParseException(r, "Expected ']'.");
throw new ExpressionParseException(r.Position, "Expected ']'.");
}
}

4
src/Markup/Perspex.Markup/Data/Parsers/ExpressionParser.cs

@ -34,7 +34,7 @@ namespace Perspex.Markup.Data.Parsers
if (state == State.BeforeMember)
{
throw new ExpressionParseException(r, "Unexpected end of expression.");
throw new ExpressionParseException(r.Position, "Unexpected end of expression.");
}
for (int n = 0; n < nodes.Count - 1; ++n)
@ -80,7 +80,7 @@ namespace Perspex.Markup.Data.Parsers
{
if (args.Count == 0)
{
throw new ExpressionParseException(r, "Indexer may not be empty.");
throw new ExpressionParseException(r.Position, "Indexer may not be empty.");
}
nodes.Add(new IndexerNode(args));

2
src/Markup/Perspex.Markup/Data/Parsers/Reader.cs

@ -7,7 +7,7 @@ namespace Perspex.Markup.Data.Parsers
{
internal class Reader
{
private string _s;
private readonly string _s;
private int _i;
public Reader(string s)

19
src/Markup/Perspex.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs

@ -3,6 +3,7 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
@ -42,7 +43,7 @@ namespace Perspex.Markup.Data.Plugins
Contract.Requires<ArgumentNullException>(propertyName != null);
Contract.Requires<ArgumentNullException>(changed != null);
var p = instance.GetType().GetRuntimeProperty(propertyName);
var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(_ => _.Name == propertyName);
if (p != null)
{
@ -56,9 +57,9 @@ namespace Perspex.Markup.Data.Plugins
private class Accessor : IPropertyAccessor
{
private object _instance;
private PropertyInfo _property;
private Action<object> _changed;
private readonly object _instance;
private readonly PropertyInfo _property;
private readonly Action<object> _changed;
public Accessor(object instance, PropertyInfo property, Action<object> changed)
{
@ -77,15 +78,9 @@ namespace Perspex.Markup.Data.Plugins
}
}
public Type PropertyType
{
get { return _property.PropertyType; }
}
public Type PropertyType => _property.PropertyType;
public object Value
{
get { return _property.GetValue(_instance); }
}
public object Value => _property.GetValue(_instance);
public void Dispose()
{

14
src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs

@ -56,8 +56,8 @@ namespace Perspex.Markup.Data.Plugins
private class Accessor : IPropertyAccessor
{
private PerspexObject _instance;
private PerspexProperty _property;
private readonly PerspexObject _instance;
private readonly PerspexProperty _property;
private IDisposable _subscription;
public Accessor(PerspexObject instance, PerspexProperty property, Action<object> changed)
@ -70,15 +70,9 @@ namespace Perspex.Markup.Data.Plugins
_subscription = instance.GetObservable(property).Skip(1).Subscribe(changed);
}
public Type PropertyType
{
get { return _property.PropertyType; }
}
public Type PropertyType => _property.PropertyType;
public object Value
{
get { return _instance.GetValue(_property); }
}
public object Value => _instance.GetValue(_property);
public void Dispose()
{

2
src/Markup/Perspex.Markup/FuncMultiValueConverter.cs

@ -16,7 +16,7 @@ namespace Perspex.Markup
/// <typeparam name="TOut">The output type.</typeparam>
public class FuncMultiValueConverter<TIn, TOut> : IMultiValueConverter
{
private Func<IEnumerable<TIn>, TOut> _convert;
private readonly Func<IEnumerable<TIn>, TOut> _convert;
/// <summary>
/// Initializes a new instance of the <see cref="FuncValueConverter{TIn, TOut}"/> class.

2
src/Markup/Perspex.Markup/FuncValueConverter.cs

@ -15,7 +15,7 @@ namespace Perspex.Markup
/// <typeparam name="TOut">The output type.</typeparam>
public class FuncValueConverter<TIn, TOut> : IValueConverter
{
private Func<TIn, TOut> _convert;
private readonly Func<TIn, TOut> _convert;
/// <summary>
/// Initializes a new instance of the <see cref="FuncValueConverter{TIn, TOut}"/> class.

2
src/Markup/Perspex.Markup/StringConverters.cs

@ -16,7 +16,7 @@ namespace Perspex.Markup
/// A value converter that returns true if the input string is null or an empty string.
/// </summary>
public static readonly IValueConverter NullOrEmpty =
new FuncValueConverter<string, bool>(x => string.IsNullOrEmpty(x));
new FuncValueConverter<string, bool>(string.IsNullOrEmpty);
/// <summary>
/// A value converter that returns true if the input string is not null or empty.

8
src/Perspex.Animation/Animatable.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Linq;
using Perspex.Data;
namespace Perspex.Animation
{
@ -25,12 +26,7 @@ namespace Perspex.Animation
{
get
{
if (_propertyTransitions == null)
{
_propertyTransitions = new PropertyTransitions();
}
return _propertyTransitions;
return _propertyTransitions ?? (_propertyTransitions = new PropertyTransitions());
}
set

5
src/Perspex.Animation/Animate.cs

@ -5,6 +5,7 @@ using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using Perspex.Data;
using Perspex.Threading;
namespace Perspex.Animation
@ -96,7 +97,7 @@ namespace Perspex.Animation
/// <param name="duration">The duration of the animation.</param>
/// <returns>An <see cref="Animation"/> that can be used to track or stop the animation.</returns>
public static Animation Property(
IObservablePropertyBag target,
IPerspexObject target,
PerspexProperty property,
object start,
object finish,
@ -119,7 +120,7 @@ namespace Perspex.Animation
/// <param name="duration">The duration of the animation.</param>
/// <returns>An <see cref="Animation"/> that can be used to track or stop the animation.</returns>
public static Animation<T> Property<T>(
IObservablePropertyBag target,
IPerspexObject target,
PerspexProperty<T> property,
T start,
T finish,

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

Loading…
Cancel
Save