Browse Source

Merge remote-tracking branch 'Perspex/master' into DocFX

pull/419/head
Wiesław Šoltés 11 years ago
parent
commit
d420e46902
  1. 34
      Perspex.sln
  2. 2
      docs/spec/architecture.md
  3. 6
      nuget/template/Perspex.Android.nuspec
  4. 12
      nuget/template/Perspex.Desktop.nuspec
  5. 2
      nuget/template/Perspex.Skia.Desktop.nuspec
  6. 6
      nuget/template/Perspex.iOS.nuspec
  7. 4
      nuget/template/Perspex.nuspec
  8. 12
      samples/TestApplication/App.config
  9. 10
      samples/XamlTestApplication/App.config
  10. 2
      src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
  11. 5
      src/Gtk/Perspex.Gtk/WindowImpl.cs
  12. 15
      src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
  13. 12
      src/Markup/Perspex.Markup/ControlLocator.cs
  14. 15
      src/Perspex.Application/Application.cs
  15. 10
      src/Perspex.Base/PerspexObject.cs
  16. 7
      src/Perspex.Base/Threading/DispatcherTimer.cs
  17. 2
      src/Perspex.Controls/Button.cs
  18. 2
      src/Perspex.Controls/Carousel.cs
  19. 11
      src/Perspex.Controls/ContextMenu.cs
  20. 21
      src/Perspex.Controls/Control.cs
  21. 2
      src/Perspex.Controls/DropDown.cs
  22. 8
      src/Perspex.Controls/Grid.cs
  23. 11
      src/Perspex.Controls/IControl.cs
  24. 2
      src/Perspex.Controls/ListBox.cs
  25. 2
      src/Perspex.Controls/Menu.cs
  26. 9
      src/Perspex.Controls/MenuItem.cs
  27. 7
      src/Perspex.Controls/Mixins/ContentControlMixin.cs
  28. 5
      src/Perspex.Controls/Mixins/SelectableMixin.cs
  29. 10
      src/Perspex.Controls/Platform/PlatformManager.cs
  30. 8
      src/Perspex.Controls/Presenters/ScrollContentPresenter.cs
  31. 2
      src/Perspex.Controls/Primitives/Popup.cs
  32. 17
      src/Perspex.Controls/Primitives/SelectingItemsControl.cs
  33. 2
      src/Perspex.Controls/Primitives/TabStrip.cs
  34. 48
      src/Perspex.Controls/Primitives/TemplatedControl.cs
  35. 2
      src/Perspex.Controls/Primitives/Thumb.cs
  36. 31
      src/Perspex.Controls/Templates/TemplateExtensions.cs
  37. 63
      src/Perspex.Controls/TextBox.cs
  38. 6
      src/Perspex.Controls/TreeView.cs
  39. 2
      src/Perspex.HtmlRenderer/HtmlControl.cs
  40. 16
      src/Perspex.Input/Cursors.cs
  41. 2
      src/Perspex.Input/FocusManager.cs
  42. 2
      src/Perspex.Input/IInputElement.cs
  43. 8
      src/Perspex.Input/InputElement.cs
  44. 11
      src/Perspex.Input/KeyboardDevice.cs
  45. 52
      src/Perspex.Input/MouseDevice.cs
  46. 2
      src/Perspex.Input/PointerEventArgs.cs
  47. 2
      src/Perspex.Input/Raw/RawInputEventArgs.cs
  48. 5
      src/Perspex.SceneGraph/Media/FormattedText.cs
  49. 8
      src/Perspex.Themes.Default/TreeViewItem.paml
  50. 2
      src/Skia/Perspex.Skia/DrawingContextImpl.cs
  51. 12
      src/Windows/Perspex.Direct2D1/app.config
  52. 8
      src/Windows/Perspex.Win32/WindowImpl.cs
  53. 3
      tests/Perspex.Base.UnitTests/PerspexObjectTests_Binding.cs
  54. 12
      tests/Perspex.Base.UnitTests/PerspexObjectTests_Metadata.cs
  55. 2
      tests/Perspex.Base.UnitTests/StyledPropertyTests.cs
  56. 75
      tests/Perspex.Controls.UnitTests/ContentControlTests.cs
  57. 42
      tests/Perspex.Controls.UnitTests/ControlTests.cs
  58. 76
      tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs
  59. 10
      tests/Perspex.Controls.UnitTests/DropDownTests.cs
  60. 2
      tests/Perspex.Controls.UnitTests/GridSplitterTests.cs
  61. 2
      tests/Perspex.Controls.UnitTests/ListBoxTests.cs
  62. 22
      tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs
  63. 5
      tests/Perspex.Controls.UnitTests/PanelTests.cs
  64. 12
      tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
  65. 1
      tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs
  66. 1
      tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs
  67. 5
      tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs
  68. 36
      tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs
  69. 12
      tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs
  70. 5
      tests/Perspex.Controls.UnitTests/TabControlTests.cs
  71. 38
      tests/Perspex.Controls.UnitTests/TestRoot.cs
  72. 91
      tests/Perspex.Controls.UnitTests/TopLevelTests.cs
  73. 3
      tests/Perspex.Controls.UnitTests/TreeViewTests.cs
  74. 372
      tests/Perspex.LeakTests/ControlTests.cs
  75. 5
      tests/Perspex.LeakTests/Perspex.LeakTests.csproj
  76. 47
      tests/Perspex.LeakTests/TestApp.cs
  77. 1
      tests/Perspex.Markup.UnitTests/ControlLocatorTests.cs
  78. 5
      tests/Perspex.Markup.UnitTests/Data/ExpressionSubjectTests.cs
  79. 5
      tests/Perspex.Markup.UnitTests/Perspex.Markup.UnitTests.csproj
  80. 1
      tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs
  81. 5
      tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs
  82. 10
      tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj
  83. 24
      tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs
  84. 9
      tests/Perspex.Markup.Xaml.UnitTests/Templates/TreeDataTemplateTests.cs
  85. 67
      tests/Perspex.Markup.Xaml.UnitTests/TestRoot.cs
  86. 11
      tests/Perspex.Markup.Xaml.UnitTests/app.config
  87. 12
      tests/Perspex.RenderTests/app.config
  88. 12
      tests/Perspex.Styling.UnitTests/ActivatedSubjectTests.cs
  89. 5
      tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj
  90. 13
      tests/Perspex.Styling.UnitTests/StyleActivatorTests.cs
  91. 1
      tests/Perspex.Styling.UnitTests/StyleTests.cs
  92. 39
      tests/Perspex.Styling.UnitTests/TestRoot.cs
  93. 30
      tests/Perspex.UnitTests/MockWindowingPlatform.cs
  94. 143
      tests/Perspex.UnitTests/Perspex.UnitTests.csproj
  95. 36
      tests/Perspex.UnitTests/Properties/AssemblyInfo.cs
  96. 37
      tests/Perspex.UnitTests/TestRoot.cs
  97. 110
      tests/Perspex.UnitTests/TestServices.cs
  98. 65
      tests/Perspex.UnitTests/TestTemplatedRoot.cs
  99. 47
      tests/Perspex.UnitTests/UnitTestApplication.cs
  100. 11
      tests/Perspex.UnitTests/app.config

34
Perspex.sln

@ -140,6 +140,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.LeakTests", "tests\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{61BEC86C-F307-4295-B5B8-9428610D7D55}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.UnitTests", "tests\Perspex.UnitTests\Perspex.UnitTests.csproj", "{88060192-33D5-4932-B0F9-8BD2763E857D}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4
@ -148,19 +150,20 @@ Global
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
src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{78345174-5b52-4a14-b9fd-d5f2428137f0}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{ff69b927-c545-49ae-8e16-3d14d621aa12}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*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\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*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
@ -1294,6 +1297,30 @@ Global
{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
{88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.Build.0 = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.Build.0 = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1338,5 +1365,6 @@ Global
{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}
{88060192-33D5-4932-B0F9-8BD2763E857D} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
EndGlobalSection
EndGlobal

2
docs/spec/architecture.md

@ -31,7 +31,7 @@ The assemblies are as follows, from lowest to highest level:
The main classes in this assembly are `PerspexObject` and `PerspexProperty`.
These are Perspex's versions of XAML's `DependencyObject` and `DepenendencyProperty`. It also
These are Perspex's versions of XAML's `DependencyObject` and `DependencyProperty`. It also
defines a `PerspexDispatcher` which is - surprise - our version of XAML's `Dispatcher`.
### Perspex.Animation

6
nuget/template/Perspex.Android.nuspec

@ -13,15 +13,15 @@
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Serilog" version="1.5.9" />
<dependency id="Serilog" version="1.5.14" />
<dependency id="Splat" version="1.6.2" />
<dependency id="Sprache" version="2.0.0.47" />
<dependency id="Sprache" version="2.0.0.50" />
<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#" />
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>
</package>

12
nuget/template/Perspex.Desktop.nuspec

@ -13,18 +13,18 @@
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Serilog" version="1.5.9" />
<dependency id="Serilog" version="1.5.14" />
<dependency id="Splat" version="1.6.2" />
<dependency id="Sprache" version="2.0.0.47" />
<dependency id="Sprache" version="2.0.0.50" />
<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="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#" />
<dependency id="SharpDX" version="3.0.1"/>
<dependency id="SharpDX.Direct2D1" version="3.0.1"/>
<dependency id="SharpDX.DXGI" version="3.0.1"/>
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>
</package>

2
nuget/template/Perspex.Skia.Desktop.nuspec

@ -13,7 +13,7 @@
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Perspex" version="#VERSION#" />
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>
</package>

6
nuget/template/Perspex.iOS.nuspec

@ -13,15 +13,15 @@
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Serilog" version="1.5.9" />
<dependency id="Serilog" version="1.5.14" />
<dependency id="Splat" version="1.6.2" />
<dependency id="Sprache" version="2.0.0.47" />
<dependency id="Sprache" version="2.0.0.50" />
<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#" />
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>
</package>

4
nuget/template/Perspex.nuspec

@ -13,9 +13,9 @@
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Serilog" version="1.5.9" />
<dependency id="Serilog" version="1.5.14" />
<dependency id="Splat" version="1.6.2" />
<dependency id="Sprache" version="2.0.0.47" />
<dependency id="Sprache" version="2.0.0.50" />
<dependency id="Rx-Core" version="2.2.5" />
<dependency id="Rx-Interfaces" version="2.2.5" />
<dependency id="Rx-Linq" version="2.2.5" />

12
samples/TestApplication/App.config

@ -18,8 +18,16 @@
<bindingRedirect oldVersion="0.0.0.0-2.2.5.0" newVersion="2.2.5.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.0" newVersion="2.6.3.0" />
<assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" />

10
samples/XamlTestApplication/App.config

@ -17,9 +17,17 @@
<assemblyIdentity name="System.Reactive.Linq" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.2.5.0" newVersion="2.2.5.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.6.3.0" newVersion="2.6.3.0"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

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

@ -215,8 +215,6 @@ namespace Perspex.Cairo.Media
}
}
private static Random Random = new Random();
/// <summary>
/// Pushes a clip rectange.
/// </summary>

5
src/Gtk/Perspex.Gtk/WindowImpl.cs

@ -379,10 +379,5 @@ namespace Perspex.Gtk
Input(e);
return true;
}
private IPlatformHandle GetHandle(Gdk.Window window)
{
return new PlatformHandle(window.Handle, "GdkWindow");
}
}
}

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

@ -226,21 +226,6 @@ namespace Perspex.Markup.Xaml.Data
return result;
}
private IControl LookupNamedControl(IControl target)
{
Contract.Requires<ArgumentNullException>(target != null);
var nameScope = target.FindNameScope();
if (nameScope == null)
{
throw new InvalidOperationException(
"Could not find name scope for ElementName binding.");
}
return nameScope.Find<IControl>(ElementName);
}
private class PathInfo
{
public string Path { get; set; }

12
src/Markup/Perspex.Markup/ControlLocator.cs

@ -22,15 +22,15 @@ namespace Perspex.Markup
/// <param name="name">The name of the control to find.</param>
public static IObservable<IControl> Track(IControl relativeTo, string name)
{
var attached = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => relativeTo.AttachedToVisualTree += x,
x => relativeTo.DetachedFromVisualTree += x)
var attached = Observable.FromEventPattern<LogicalTreeAttachmentEventArgs>(
x => relativeTo.AttachedToLogicalTree += x,
x => relativeTo.DetachedFromLogicalTree += x)
.Select(x => ((IControl)x.Sender).FindNameScope())
.StartWith(relativeTo.FindNameScope());
var detached = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => relativeTo.DetachedFromVisualTree += x,
x => relativeTo.DetachedFromVisualTree += x)
var detached = Observable.FromEventPattern<LogicalTreeAttachmentEventArgs>(
x => relativeTo.DetachedFromLogicalTree += x,
x => relativeTo.DetachedFromLogicalTree += x)
.Select(x => (INameScope)null);
return attached.Merge(detached).Select(nameScope =>

15
src/Perspex.Application/Application.cs

@ -59,12 +59,7 @@ namespace Perspex
throw new InvalidOperationException("Cannot create more than one Application instance.");
}
Current = this;
}
public static void RegisterPlatformCallback(Action cb)
{
_platformInitializationCallback = cb;
PerspexLocator.CurrentMutable.BindToSelf(this);
}
/// <summary>
@ -75,8 +70,7 @@ namespace Perspex
/// </value>
public static Application Current
{
get;
private set;
get { return PerspexLocator.Current.GetService<Application>(); }
}
/// <summary>
@ -140,6 +134,11 @@ namespace Perspex
/// </summary>
IStyleHost IStyleHost.StylingParent => null;
public static void RegisterPlatformCallback(Action cb)
{
_platformInitializationCallback = cb;
}
/// <summary>
/// Runs the application's main loop until the <see cref="ICloseable"/> is closed.
/// </summary>

10
src/Perspex.Base/PerspexObject.cs

@ -678,16 +678,6 @@ namespace Perspex
}
}
/// <summary>
/// Gets a description of a property that van be used in observables.
/// </summary>
/// <param name="property">The property</param>
/// <returns>The description.</returns>
private string GetDescription(PerspexProperty property)
{
return $"{GetType().Name}.{property.Name}";
}
/// <summary>
/// Gets a description of an observable that van be used in logs.
/// </summary>

7
src/Perspex.Base/Threading/DispatcherTimer.cs

@ -181,6 +181,12 @@ namespace Perspex.Threading
if (!IsEnabled)
{
IPlatformThreadingInterface threading = PerspexLocator.Current.GetService<IPlatformThreadingInterface>();
if (threading == null)
{
throw new Exception("Could not start timer: IPlatformThreadingInterface is not registered.");
}
_timer = threading.StartTimer(Interval, InternalTick);
}
}
@ -192,7 +198,6 @@ namespace Perspex.Threading
{
if (IsEnabled)
{
IPlatformThreadingInterface threading = PerspexLocator.Current.GetService<IPlatformThreadingInterface>();
_timer.Dispose();
_timer = null;
}

2
src/Perspex.Controls/Button.cs

@ -211,7 +211,7 @@ namespace Perspex.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);

2
src/Perspex.Controls/Carousel.cs

@ -74,7 +74,7 @@ namespace Perspex.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
// Ignore pointer presses.
}

11
src/Perspex.Controls/ContextMenu.cs

@ -119,17 +119,6 @@
}
}
private void PopupOpened(object sender, EventArgs e)
{
var selectedIndex = SelectedIndex;
if (selectedIndex != -1)
{
var container = ItemContainerGenerator.ContainerFromIndex(selectedIndex);
container?.Focus();
}
}
private static void ControlPointerReleased(object sender, PointerReleasedEventArgs e)
{
var control = (Control)sender;

21
src/Perspex.Controls/Control.cs

@ -69,8 +69,7 @@ namespace Perspex.Controls
/// Defines the <see cref="ContextMenu"/> property.
/// </summary>
public static readonly StyledProperty<ContextMenu> ContextMenuProperty =
PerspexProperty.Register<Control, ContextMenu>(nameof(ContextMenu));
PerspexProperty.Register<Control, ContextMenu>(nameof(ContextMenu));
/// <summary>
/// Event raised when an element wishes to be scrolled into view.
@ -393,6 +392,15 @@ namespace Perspex.Controls
});
}
/// <summary>
/// Gets the element that recieves the focus adorner.
/// </summary>
/// <returns>The control that recieves the focus adorner.</returns>
protected virtual IControl GetTemplateFocusTarget()
{
return this;
}
/// <summary>
/// Called when the control is added to a logical tree.
/// </summary>
@ -488,8 +496,13 @@ namespace Perspex.Controls
if (_focusAdorner != null)
{
AdornerLayer.SetAdornedElement((Visual)_focusAdorner, this);
adornerLayer.Children.Add(_focusAdorner);
var target = (Visual)GetTemplateFocusTarget();
if (target != null)
{
AdornerLayer.SetAdornedElement((Visual)_focusAdorner, target);
adornerLayer.Children.Add(_focusAdorner);
}
}
}
}

2
src/Perspex.Controls/DropDown.cs

@ -99,7 +99,7 @@ namespace Perspex.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (!IsDropDownOpen && ((IVisual)e.Source).GetVisualRoot() != typeof(PopupRoot))
{

8
src/Perspex.Controls/Grid.cs

@ -876,14 +876,6 @@ namespace Perspex.Controls
Stars = 0;
Type = type;
}
public void Init(double offeredSize, double min, double max, GridUnitType type)
{
OfferedSize = offeredSize;
Min = min;
Max = max;
Type = type;
}
}
private struct GridNode

11
src/Perspex.Controls/IControl.cs

@ -1,6 +1,7 @@
// 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 Perspex.Controls.Templates;
using Perspex.Input;
using Perspex.Layout;
@ -13,6 +14,16 @@ namespace Perspex.Controls
/// </summary>
public interface IControl : IVisual, ILogical, ILayoutable, IInputElement, INamed, IStyleable, IStyleHost
{
/// <summary>
/// Raised when the control is attached to a rooted logical tree.
/// </summary>
event EventHandler<LogicalTreeAttachmentEventArgs> AttachedToLogicalTree;
/// <summary>
/// Raised when the control is detached from a rooted logical tree.
/// </summary>
event EventHandler<LogicalTreeAttachmentEventArgs> DetachedFromLogicalTree;
/// <summary>
/// Gets or sets the control's styling classes.
/// </summary>

2
src/Perspex.Controls/ListBox.cs

@ -59,7 +59,7 @@ namespace Perspex.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);

2
src/Perspex.Controls/Menu.cs

@ -211,7 +211,7 @@ namespace Perspex.Controls
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void TopLevelPreviewPointerPress(object sender, PointerPressEventArgs e)
private void TopLevelPreviewPointerPress(object sender, PointerPressedEventArgs e)
{
if (IsOpen)
{

9
src/Perspex.Controls/MenuItem.cs

@ -310,7 +310,7 @@ namespace Perspex.Controls
/// Called when the pointer is pressed over the <see cref="MenuItem"/>.
/// </summary>
/// <param name="e">The event args.</param>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
@ -447,13 +447,6 @@ namespace Perspex.Controls
/// </summary>
public static readonly DependencyResolver Instance = new DependencyResolver();
/// <summary>
/// Disposes of all managed resources.
/// </summary>
public void Dispose()
{
}
/// <summary>
/// Gets a service of the specified type.
/// </summary>

7
src/Perspex.Controls/Mixins/ContentControlMixin.cs

@ -118,13 +118,6 @@ namespace Perspex.Controls.Mixins
});
}
private static event EventHandler<TemplateAppliedEventArgs> TemplateApplied;
private static void OnTemplateApplied(object sender, RoutedEventArgs e)
{
TemplateApplied?.Invoke(sender, (TemplateAppliedEventArgs)e);
}
private static void UpdateLogicalChild(
IControl control,
IPerspexList<ILogical> logicalChildren,

5
src/Perspex.Controls/Mixins/SelectableMixin.cs

@ -50,11 +50,14 @@ namespace Perspex.Controls.Mixins
if (sender != null)
{
var itemsControl = sender.Parent as SelectingItemsControl;
if ((bool)x.NewValue)
{
((IPseudoClasses)sender.Classes).Add(":selected");
if (((IVisual)sender).IsAttachedToVisualTree)
if (((IVisual)sender).IsAttachedToVisualTree &&
itemsControl?.AutoScrollToSelectedItem == true)
{
sender.BringIntoView();
}

10
src/Perspex.Controls/Platform/PlatformManager.cs

@ -192,8 +192,14 @@ namespace Perspex.Controls.Platform
public static IWindowImpl CreateWindow()
{
var platform = PerspexLocator.Current.GetService<IWindowingPlatform>();
return
new WindowDecorator(s_designerMode ? platform.CreateEmbeddableWindow() : platform.CreateWindow());
if (platform == null)
{
throw new Exception("Could not CreateWindow(): IWindowingPlatform is not registered.");
}
var window = s_designerMode ? platform.CreateEmbeddableWindow() : platform.CreateWindow();
return new WindowDecorator(window);
}
public static IPopupImpl CreatePopup()

8
src/Perspex.Controls/Presenters/ScrollContentPresenter.cs

@ -256,13 +256,5 @@ namespace Perspex.Controls.Presenters
Extent = scrollable.Extent;
Offset = scrollable.Offset;
}
private static Vector ValidateOffset(ScrollContentPresenter o, Vector value)
{
return ScrollViewer.CoerceOffset(
o.GetValue(ExtentProperty),
o.GetValue(ViewportProperty),
value);
}
}
}

2
src/Perspex.Controls/Primitives/Popup.cs

@ -288,7 +288,7 @@ namespace Perspex.Controls.Primitives
}
}
private void PointerPressedOutside(object sender, PointerPressEventArgs e)
private void PointerPressedOutside(object sender, PointerPressedEventArgs e)
{
if (!StaysOpen)
{

17
src/Perspex.Controls/Primitives/SelectingItemsControl.cs

@ -38,6 +38,14 @@ namespace Perspex.Controls.Primitives
/// </remarks>
public class SelectingItemsControl : ItemsControl
{
/// <summary>
/// Defines the <see cref="AutoScrollToSelectedItem"/> property.
/// </summary>
public static readonly StyledProperty<bool> AutoScrollToSelectedItemProperty =
PerspexProperty.Register<SelectingItemsControl, bool>(
nameof(AutoScrollToSelectedItem),
defaultValue: true);
/// <summary>
/// Defines the <see cref="SelectedIndex"/> property.
/// </summary>
@ -123,6 +131,15 @@ namespace Perspex.Controls.Primitives
remove { RemoveHandler(SelectionChangedEvent, value); }
}
/// <summary>
/// Gets or sets a value indicating whether to automatically scroll to newly selected items.
/// </summary>
public bool AutoScrollToSelectedItem
{
get { return GetValue(AutoScrollToSelectedItemProperty); }
set { SetValue(AutoScrollToSelectedItemProperty, value); }
}
/// <summary>
/// Gets or sets the index of the selected item.
/// </summary>

2
src/Perspex.Controls/Primitives/TabStrip.cs

@ -35,7 +35,7 @@ namespace Perspex.Controls.Primitives
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);

48
src/Perspex.Controls/Primitives/TemplatedControl.cs

@ -74,6 +74,12 @@ namespace Perspex.Controls.Primitives
public static readonly StyledProperty<IControlTemplate> TemplateProperty =
PerspexProperty.Register<TemplatedControl, IControlTemplate>("Template");
/// <summary>
/// Defines the IsTemplateFocusTarget attached property.
/// </summary>
public static readonly AttachedProperty<bool> IsTemplateFocusTargetProperty =
PerspexProperty.RegisterAttached<TemplatedControl, Control, bool>("IsTemplateFocusTarget");
/// <summary>
/// Defines the <see cref="TemplateApplied"/> routed event.
/// </summary>
@ -198,6 +204,33 @@ namespace Perspex.Controls.Primitives
set { SetValue(TemplateProperty, value); }
}
/// <summary>
/// Gets the value of the IsTemplateFocusTargetProperty attached property on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The property value.</returns>
/// <see cref="SetIsTemplateFocusTarget(Control, bool)"/>
public bool GetIsTemplateFocusTarget(Control control)
{
return control.GetValue(IsTemplateFocusTargetProperty);
}
/// <summary>
/// Sets the value of the IsTemplateFocusTargetProperty attached property on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value.</param>
/// <remarks>
/// When a control is navigated to using the keyboard, a focus adorner is shown - usually
/// around the control itself. However if the TemplatedControl.IsTemplateFocusTarget
/// attached property is set to true on an element in the control template, then the focus
/// adorner will be shown around that control instead.
/// </remarks>
public void SetIsTemplateFocusTarget(Control control, bool value)
{
control.SetValue(IsTemplateFocusTargetProperty, value);
}
/// <inheritdoc/>
public sealed override void ApplyTemplate()
{
@ -224,6 +257,7 @@ namespace Perspex.Controls.Primitives
}
}
/// <inheritdoc/>
protected sealed override IndexerDescriptor CreateBindingDescriptor(IndexerDescriptor source)
{
var result = base.CreateBindingDescriptor(source);
@ -240,6 +274,20 @@ namespace Perspex.Controls.Primitives
return result;
}
/// <inheritdoc/>
protected override IControl GetTemplateFocusTarget()
{
foreach (Control child in this.GetTemplateChildren())
{
if (GetIsTemplateFocusTarget(child))
{
return child;
}
}
return this;
}
/// <summary>
/// Called when the control's template is applied.
/// </summary>

2
src/Perspex.Controls/Primitives/Thumb.cs

@ -72,7 +72,7 @@ namespace Perspex.Controls.Primitives
}
}
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
e.Device.Capture(this);
_lastPoint = e.GetPosition(this);

31
src/Perspex.Controls/Templates/TemplateExtensions.cs

@ -12,21 +12,30 @@ namespace Perspex.Controls.Templates
{
public static class TemplateExtensions
{
public static IEnumerable<Control> GetTemplateChildren(this ITemplatedControl control)
public static IEnumerable<IControl> GetTemplateChildren(this ITemplatedControl control)
{
var visual = control as IVisual;
if (visual != null)
foreach (IControl child in GetTemplateChildren((IControl)control, control))
{
// TODO: This searches the whole descendent tree - it can stop when it exits the
// template.
return visual.GetVisualDescendents()
.OfType<Control>()
.Where(x => x.TemplatedParent == control);
yield return child;
}
else
}
private static IEnumerable<IControl> GetTemplateChildren(IControl control, ITemplatedControl templatedParent)
{
foreach (IControl child in control.GetVisualChildren())
{
return Enumerable.Empty<Control>();
if (child.TemplatedParent == templatedParent)
{
yield return child;
}
if (child.TemplatedParent != null)
{
foreach (var descendent in GetTemplateChildren(child, templatedParent))
{
yield return descendent;
}
}
}
}
}

63
src/Perspex.Controls/TextBox.cs

@ -51,6 +51,9 @@ namespace Perspex.Controls
public static readonly StyledProperty<bool> UseFloatingWatermarkProperty =
PerspexProperty.Register<TextBox, bool>("UseFloatingWatermark");
public static readonly StyledProperty<bool> IsReadOnlyProperty =
PerspexProperty.Register<TextBox, bool>(nameof(IsReadOnly));
struct UndoRedoState : IEquatable<UndoRedoState>
{
public string Text { get; }
@ -154,6 +157,12 @@ namespace Perspex.Controls
set { SetValue(UseFloatingWatermarkProperty, value); }
}
public bool IsReadOnly
{
get { return GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public TextWrapping TextWrapping
{
get { return GetValue(TextWrappingProperty); }
@ -187,17 +196,20 @@ namespace Perspex.Controls
private void HandleTextInput(string input)
{
string text = Text ?? string.Empty;
int caretIndex = CaretIndex;
if (!string.IsNullOrEmpty(input))
if (!IsReadOnly)
{
DeleteSelection();
caretIndex = CaretIndex;
text = Text ?? string.Empty;
Text = text.Substring(0, caretIndex) + input + text.Substring(caretIndex);
CaretIndex += input.Length;
SelectionStart = SelectionEnd = CaretIndex;
_undoRedoHelper.DiscardRedo();
string text = Text ?? string.Empty;
int caretIndex = CaretIndex;
if (!string.IsNullOrEmpty(input))
{
DeleteSelection();
caretIndex = CaretIndex;
text = Text ?? string.Empty;
Text = text.Substring(0, caretIndex) + input + text.Substring(caretIndex);
CaretIndex += input.Length;
SelectionStart = SelectionEnd = CaretIndex;
_undoRedoHelper.DiscardRedo();
}
}
}
@ -343,7 +355,7 @@ namespace Perspex.Controls
}
}
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.Source == _presenter)
{
@ -510,21 +522,28 @@ namespace Perspex.Controls
private bool DeleteSelection()
{
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
if (selectionStart != selectionEnd)
if (!IsReadOnly)
{
var start = Math.Min(selectionStart, selectionEnd);
var end = Math.Max(selectionStart, selectionEnd);
var text = Text;
Text = text.Substring(0, start) + text.Substring(end);
SelectionStart = SelectionEnd = CaretIndex = start;
return true;
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
if (selectionStart != selectionEnd)
{
var start = Math.Min(selectionStart, selectionEnd);
var end = Math.Max(selectionStart, selectionEnd);
var text = Text;
Text = text.Substring(0, start) + text.Substring(end);
SelectionStart = SelectionEnd = CaretIndex = start;
return true;
}
else
{
return false;
}
}
else
{
return false;
return true;
}
}

6
src/Perspex.Controls/TreeView.cs

@ -22,9 +22,7 @@ namespace Perspex.Controls
/// Defines the <see cref="AutoScrollToSelectedItem"/> property.
/// </summary>
public static readonly StyledProperty<bool> AutoScrollToSelectedItemProperty =
PerspexProperty.Register<TreeView, bool>(
nameof(AutoScrollToSelectedItem),
defaultValue: true);
SelectingItemsControl.AutoScrollToSelectedItemProperty.AddOwner<TreeView>();
/// <summary>
/// Defines the <see cref="SelectedItem"/> property.
@ -118,7 +116,7 @@ namespace Perspex.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);

2
src/Perspex.HtmlRenderer/HtmlControl.cs

@ -401,7 +401,7 @@ namespace Perspex.Controls.Html
/// <summary>
/// Handle mouse down to handle selection.
/// </summary>
protected override void OnPointerPressed(PointerPressEventArgs e)
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
LeftMouseButton = true;

16
src/Perspex.Input/Cursors.cs

@ -56,12 +56,22 @@ namespace Perspex.Input
}
public Cursor(StandardCursorType cursorType)
: this(
((IStandardCursorFactory)PerspexLocator.Current.GetService(typeof(IStandardCursorFactory))).GetCursor(
cursorType))
: this(GetCursor(cursorType))
{
}
public IPlatformHandle PlatformCursor { get; }
private static IPlatformHandle GetCursor(StandardCursorType type)
{
var platform = PerspexLocator.Current.GetService<IStandardCursorFactory>();
if (platform == null)
{
throw new Exception("Could not create Cursor: IStandardCursorFactory not registered.");
}
return platform.GetCursor(type);
}
}
}

2
src/Perspex.Input/FocusManager.cs

@ -175,7 +175,7 @@ namespace Perspex.Input
{
if (sender == e.Source)
{
var ev = (PointerPressEventArgs)e;
var ev = (PointerPressedEventArgs)e;
var element = (ev.Device.Captured as IInputElement) ?? (e.Source as IInputElement);
if (element == null || !CanFocus(element))

2
src/Perspex.Input/IInputElement.cs

@ -51,7 +51,7 @@ namespace Perspex.Input
/// <summary>
/// Occurs when the pointer is pressed over the control.
/// </summary>
event EventHandler<PointerPressEventArgs> PointerPressed;
event EventHandler<PointerPressedEventArgs> PointerPressed;
/// <summary>
/// Occurs when the pointer moves over the control.

8
src/Perspex.Input/InputElement.cs

@ -116,8 +116,8 @@ namespace Perspex.Input
/// <summary>
/// Defines the <see cref="PointerPressed"/> event.
/// </summary>
public static readonly RoutedEvent<PointerPressEventArgs> PointerPressedEvent =
RoutedEvent.Register<InputElement, PointerPressEventArgs>(
public static readonly RoutedEvent<PointerPressedEventArgs> PointerPressedEvent =
RoutedEvent.Register<InputElement, PointerPressedEventArgs>(
"PointerPressed",
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
@ -235,7 +235,7 @@ namespace Perspex.Input
/// <summary>
/// Occurs when the pointer is pressed over the control.
/// </summary>
public event EventHandler<PointerPressEventArgs> PointerPressed
public event EventHandler<PointerPressedEventArgs> PointerPressed
{
add { AddHandler(PointerPressedEvent, value); }
remove { RemoveHandler(PointerPressedEvent, value); }
@ -437,7 +437,7 @@ namespace Perspex.Input
/// Called before the <see cref="PointerPressed"/> event occurs.
/// </summary>
/// <param name="e">The event args.</param>
protected virtual void OnPointerPressed(PointerPressEventArgs e)
protected virtual void OnPointerPressed(PointerPressedEventArgs e)
{
}

11
src/Perspex.Input/KeyboardDevice.cs

@ -83,6 +83,7 @@ namespace Perspex.Input
if (element != null)
{
var keyInput = e as RawKeyEventArgs;
if (keyInput != null)
{
switch (keyInput.Type)
@ -117,19 +118,25 @@ namespace Perspex.Input
}
element.RaiseEvent(ev);
e.Handled = ev.Handled;
break;
}
}
var text = e as RawTextInputEventArgs;
if (text != null)
{
element.RaiseEvent(new TextInputEventArgs()
var ev = new TextInputEventArgs()
{
Device = this,
Text = text.Text,
Source = element,
RoutedEvent = InputElement.TextInputEvent
});
};
element.RaiseEvent(ev);
e.Handled = ev.Handled;
}
}
}

52
src/Perspex.Input/MouseDevice.cs

@ -115,7 +115,7 @@ namespace Perspex.Input
case RawMouseEventType.LeftButtonDown:
case RawMouseEventType.RightButtonDown:
case RawMouseEventType.MiddleButtonDown:
MouseDown(mouse, e.Timestamp, e.Root, e.Position,
e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position,
e.Type == RawMouseEventType.LeftButtonDown
? MouseButton.Left
: e.Type == RawMouseEventType.RightButtonDown ? MouseButton.Right : MouseButton.Middle,
@ -124,17 +124,17 @@ namespace Perspex.Input
case RawMouseEventType.LeftButtonUp:
case RawMouseEventType.RightButtonUp:
case RawMouseEventType.MiddleButtonUp:
MouseUp(mouse, e.Root, e.Position,
e.Handled = MouseUp(mouse, e.Root, e.Position,
e.Type == RawMouseEventType.LeftButtonUp
? MouseButton.Left
: e.Type == RawMouseEventType.RightButtonUp ? MouseButton.Right : MouseButton.Middle,
e.InputModifiers);
break;
case RawMouseEventType.Move:
MouseMove(mouse, e.Root, e.Position, e.InputModifiers);
e.Handled = MouseMove(mouse, e.Root, e.Position, e.InputModifiers);
break;
case RawMouseEventType.Wheel:
MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta, e.InputModifiers);
e.Handled = MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta, e.InputModifiers);
break;
}
}
@ -144,7 +144,7 @@ namespace Perspex.Input
ClearPointerOver(this, root);
}
private void MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers)
private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers)
{
var hit = HitTest(root, p);
@ -167,7 +167,7 @@ namespace Perspex.Input
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2));
var e = new PointerPressEventArgs
var e = new PointerPressedEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerPressedEvent,
@ -178,11 +178,14 @@ namespace Perspex.Input
};
source.RaiseEvent(e);
return e.Handled;
}
}
return false;
}
private void MouseMove(IMouseDevice device, IInputRoot root, Point p, InputModifiers inputModifiers)
private bool MouseMove(IMouseDevice device, IInputRoot root, Point p, InputModifiers inputModifiers)
{
IInputElement source;
@ -197,51 +200,62 @@ namespace Perspex.Input
source = Captured;
}
source.RaiseEvent(new PointerEventArgs
var e = new PointerEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerMovedEvent,
Source = source,
InputModifiers = inputModifiers
});
};
source.RaiseEvent(e);
return e.Handled;
}
private void MouseUp(IMouseDevice device, IInputRoot root, Point p, MouseButton button, InputModifiers inputModifiers)
private bool MouseUp(IMouseDevice device, IInputRoot root, Point p, MouseButton button, InputModifiers inputModifiers)
{
var hit = HitTest(root, p);
if (hit != null)
{
IInteractive source = GetSource(hit);
source?.RaiseEvent(new PointerReleasedEventArgs
var source = GetSource(hit);
var e = new PointerReleasedEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerReleasedEvent,
Source = source,
MouseButton = button,
InputModifiers = inputModifiers
});
};
source?.RaiseEvent(e);
return e.Handled;
}
return false;
}
private void MouseWheel(IMouseDevice device, IInputRoot root, Point p, Vector delta, InputModifiers inputModifiers)
private bool MouseWheel(IMouseDevice device, IInputRoot root, Point p, Vector delta, InputModifiers inputModifiers)
{
var hit = HitTest(root, p);
if (hit != null)
{
IInteractive source = GetSource(hit);
source?.RaiseEvent(new PointerWheelEventArgs
var source = GetSource(hit);
var e = new PointerWheelEventArgs
{
Device = this,
RoutedEvent = InputElement.PointerWheelChangedEvent,
Source = source,
Delta = delta,
InputModifiers = inputModifiers
});
};
source?.RaiseEvent(e);
return e.Handled;
}
return false;
}
private IInteractive GetSource(IVisual hit)

2
src/Perspex.Input/PointerEventArgs.cs

@ -26,7 +26,7 @@ namespace Perspex.Input
Middle
}
public class PointerPressEventArgs : PointerEventArgs
public class PointerPressedEventArgs : PointerEventArgs
{
public int ClickCount { get; set; }
public MouseButton MouseButton { get; set; }

2
src/Perspex.Input/Raw/RawInputEventArgs.cs

@ -16,7 +16,7 @@ namespace Perspex.Input.Raw
}
public IInputDevice Device { get; private set; }
public bool Handled { get; set; }
public uint Timestamp { get; private set; }
}
}

5
src/Perspex.SceneGraph/Media/FormattedText.cs

@ -42,6 +42,11 @@ namespace Perspex.Media
var platform = PerspexLocator.Current.GetService<IPlatformRenderInterface>();
if (platform == null)
{
throw new Exception("Could not create FormattedText: IPlatformRenderInterface not registered.");
}
PlatformImpl = platform.CreateFormattedText(
text,
fontFamilyName,

8
src/Perspex.Themes.Default/TreeViewItem.paml

@ -11,18 +11,12 @@
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
TemplatedControl.IsTemplateFocusTarget="True"
Grid.Column="1">
<ContentPresenter Name="PART_HeaderPresenter"
Content="{TemplateBinding Header}"
Margin="{TemplateBinding Padding}"/>
</Border>
<Rectangle Name="focus"
IsHitTestVisible="False"
IsVisible="{TemplateBinding IsFocused}"
Stroke="Black"
StrokeThickness="1"
StrokeDashArray="1,2"
Grid.Column="1"/>
</Grid>
<ItemsPresenter Name="PART_ItemsPresenter"
IsVisible="{TemplateBinding IsExpanded}"

2
src/Skia/Perspex.Skia/DrawingContextImpl.cs

@ -180,7 +180,7 @@ namespace Perspex.Skia
public void PopOpacity() => _settings->Opacity = _opacityStack.Pop();
private Matrix _currentTransform = Matrix.Identity;
private readonly float[] _fmatrix = new float[6];
public Matrix Transform
{
get { return _currentTransform; }

12
src/Windows/Perspex.Direct2D1/app.config

@ -15,8 +15,16 @@
<bindingRedirect oldVersion="0.0.0.0-2.1.30214.0" newVersion="2.1.30214.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.0" newVersion="2.6.3.0" />
<assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

8
src/Windows/Perspex.Win32/WindowImpl.cs

@ -553,10 +553,10 @@ namespace Perspex.Win32
{
Input(e);
if (msg >= 161 && msg <= 173)
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
return IntPtr.Zero;
if (e.Handled)
{
return IntPtr.Zero;
}
}
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);

3
tests/Perspex.Base.UnitTests/PerspexObjectTests_Binding.cs

@ -262,9 +262,6 @@ namespace Perspex.Base.UnitTests
public static readonly StyledProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo", "foodefault");
public static readonly StyledProperty<string> BazProperty =
PerspexProperty.Register<Class1, string>("Baz", "bazdefault", true);
public static readonly StyledProperty<double> QuxProperty =
PerspexProperty.Register<Class1, double>("Qux", 5.6);
}

12
tests/Perspex.Base.UnitTests/PerspexObjectTests_Metadata.cs

@ -51,24 +51,12 @@ namespace Perspex.Base.UnitTests
{
public static readonly StyledProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo");
public static readonly StyledProperty<string> BazProperty =
PerspexProperty.Register<Class1, string>("Baz");
public static readonly StyledProperty<int> QuxProperty =
PerspexProperty.Register<Class1, int>("Qux");
}
private class Class2 : Class1
{
public static readonly StyledProperty<string> BarProperty =
PerspexProperty.Register<Class2, string>("Bar");
public static readonly StyledProperty<double> FlobProperty =
PerspexProperty.Register<Class2, double>("Flob");
public static readonly StyledProperty<double?> FredProperty =
PerspexProperty.Register<Class2, double?>("Fred");
}
private class AttachedOwner

2
tests/Perspex.Base.UnitTests/StyledPropertyTests.cs

@ -35,8 +35,6 @@ namespace Perspex.Base.UnitTests
private class Class1 : PerspexObject
{
public static readonly StyledProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo", "default");
}
private class Class2 : PerspexObject

75
tests/Perspex.Controls.UnitTests/ContentControlTests.cs

@ -1,18 +1,15 @@
// 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.Specialized;
using System.Linq;
using Moq;
using Perspex.Controls.Presenters;
using Perspex.Controls.Templates;
using Perspex.LogicalTree;
using Perspex.Platform;
using Perspex.Styling;
using Perspex.UnitTests;
using Perspex.VisualTree;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Xunit;
namespace Perspex.Controls.UnitTests
@ -22,44 +19,38 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Template_Should_Be_Instantiated()
{
using (var ctx = RegisterServices())
{
var target = new ContentControl();
target.Content = "Foo";
target.Template = GetTemplate();
target.ApplyTemplate();
((ContentPresenter)target.Presenter).UpdateChild();
var child = ((IVisual)target).VisualChildren.Single();
Assert.IsType<Border>(child);
child = child.VisualChildren.Single();
Assert.IsType<ContentPresenter>(child);
child = child.VisualChildren.Single();
Assert.IsType<TextBlock>(child);
}
var target = new ContentControl();
target.Content = "Foo";
target.Template = GetTemplate();
target.ApplyTemplate();
((ContentPresenter)target.Presenter).UpdateChild();
var child = ((IVisual)target).VisualChildren.Single();
Assert.IsType<Border>(child);
child = child.VisualChildren.Single();
Assert.IsType<ContentPresenter>(child);
child = child.VisualChildren.Single();
Assert.IsType<TextBlock>(child);
}
[Fact]
public void Templated_Children_Should_Be_Styled()
{
using (var ctx = RegisterServices())
{
var root = new TestRoot();
var target = new ContentControl();
var styler = new Mock<IStyler>();
PerspexLocator.CurrentMutable.Bind<IStyler>().ToConstant(styler.Object);
target.Content = "Foo";
target.Template = GetTemplate();
root.Child = target;
target.ApplyTemplate();
styler.Verify(x => x.ApplyStyles(It.IsAny<ContentControl>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<Border>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<ContentPresenter>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<TextBlock>()), Times.Once());
}
var root = new TestRoot();
var target = new ContentControl();
var styler = new Mock<IStyler>();
PerspexLocator.CurrentMutable.Bind<IStyler>().ToConstant(styler.Object);
target.Content = "Foo";
target.Template = GetTemplate();
root.Child = target;
target.ApplyTemplate();
styler.Verify(x => x.ApplyStyles(It.IsAny<ContentControl>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<Border>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<ContentPresenter>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<TextBlock>()), Times.Once());
}
[Fact]
@ -261,15 +252,5 @@ namespace Perspex.Controls.UnitTests
};
});
}
private IDisposable RegisterServices()
{
var result = PerspexLocator.EnterScope();
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var renderInterface = fixture.Create<IPlatformRenderInterface>();
PerspexLocator.CurrentMutable
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface);
return result;
}
}
}

42
tests/Perspex.Controls.UnitTests/ControlTests.cs

@ -5,10 +5,8 @@ using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Moq;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Controls.UnitTests
@ -147,44 +145,6 @@ namespace Perspex.Controls.UnitTests
}
}
private class TestRoot : Decorator, ILayoutRoot, IRenderRoot, IStyleRoot
{
public Size ClientSize
{
get { throw new NotImplementedException(); }
}
public Size MaxClientSize
{
get { throw new NotImplementedException(); }
}
public ILayoutManager LayoutManager
{
get { throw new NotImplementedException(); }
}
public IRenderTarget RenderTarget
{
get { throw new NotImplementedException(); }
}
public IRenderQueueManager RenderQueueManager
{
get { throw new NotImplementedException(); }
}
public Point PointToClient(Point p)
{
throw new NotImplementedException();
}
public Point PointToScreen(Point p)
{
throw new NotImplementedException();
}
}
private class TestControl : Control
{
public new PerspexObject InheritanceParent => base.InheritanceParent;

76
tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs

@ -6,6 +6,7 @@ using Perspex.Controls.Presenters;
using Perspex.Controls.Templates;
using Perspex.Rendering;
using Perspex.Styling;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Controls.UnitTests
@ -17,7 +18,7 @@ namespace Perspex.Controls.UnitTests
{
var root = new TestRoot
{
Content = new Border
Child = new Border
{
Name = "foo",
Child = new Border
@ -28,10 +29,9 @@ namespace Perspex.Controls.UnitTests
};
root.ApplyTemplate();
((ContentPresenter)root.Presenter).UpdateChild();
Assert.Same(root.Find("foo"), root.Content);
Assert.Same(root.Find("bar"), ((Border)root.Content).Child);
Assert.Same(root.FindControl<Border>("foo"), root.Child);
Assert.Same(root.FindControl<Border>("bar"), ((Border)root.Child).Child);
}
[Fact]
@ -39,7 +39,7 @@ namespace Perspex.Controls.UnitTests
{
var root = new TestRoot
{
Content = new Border
Child = new Border
{
Name = "foo",
Child = new Border
@ -49,18 +49,16 @@ namespace Perspex.Controls.UnitTests
}
};
root.ApplyTemplate();
root.Content = null;
root.Presenter.ApplyTemplate();
root.Child = null;
Assert.Null(root.Find("foo"));
Assert.Null(root.Find("bar"));
Assert.Null(root.FindControl<Border>("foo"));
Assert.Null(root.FindControl<Border>("bar"));
}
[Fact]
public void Control_Should_Not_Register_With_Template_NameScope()
{
var root = new TestRoot
var root = new TestTemplatedRoot
{
Content = new Border
{
@ -72,61 +70,5 @@ namespace Perspex.Controls.UnitTests
Assert.Null(NameScope.GetNameScope((Control)root.Presenter).Find("foo"));
}
private class TestRoot : ContentControl, IRenderRoot, INameScope, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
public TestRoot()
{
Template = new FuncControlTemplate<TestRoot>(x => new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
});
}
public event EventHandler<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
public IRenderQueueManager RenderQueueManager
{
get { throw new NotImplementedException(); }
}
public Point PointToClient(Point p)
{
throw new NotImplementedException();
}
public Point PointToScreen(Point p)
{
throw new NotImplementedException();
}
public void Register(string name, object element)
{
_nameScope.Register(name, element);
}
public object Find(string name)
{
return _nameScope.Find(name);
}
public void Unregister(string name)
{
_nameScope.Unregister(name);
}
}
}
}

10
tests/Perspex.Controls.UnitTests/DropDownTests.cs

@ -41,15 +41,5 @@ namespace Perspex.Controls.UnitTests
};
});
}
private IDisposable RegisterServices()
{
var result = PerspexLocator.EnterScope();
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var renderInterface = fixture.Create<IPlatformRenderInterface>();
PerspexLocator.CurrentMutable.Bind<IPlatformRenderInterface>().ToConstant(renderInterface);
return result;
}
}
}

2
tests/Perspex.Controls.UnitTests/GridSplitterTests.cs

@ -3,7 +3,7 @@
using Perspex.Controls.Primitives;
using Perspex.Input;
using Perspex.Platform;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Controls.UnitTests

2
tests/Perspex.Controls.UnitTests/ListBoxTests.cs

@ -115,7 +115,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.Presenter.Panel.Children[1].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[1].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,

22
tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs

@ -65,7 +65,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,
@ -86,7 +86,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.SelectedIndex = 0;
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,
@ -107,7 +107,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,
@ -129,7 +129,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.SelectedIndex = 0;
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,
@ -151,7 +151,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.SelectedIndex = 0;
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,
@ -173,7 +173,7 @@ namespace Perspex.Controls.UnitTests
ApplyTemplate(target);
target.SelectedIndex = 1;
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs
target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,
@ -236,15 +236,5 @@ namespace Perspex.Controls.UnitTests
// Now the ItemsPresenter should be reigstered, so apply its template.
target.Presenter.ApplyTemplate();
}
private class Item
{
public Item(string value)
{
Value = value;
}
public string Value { get; }
}
}
}

5
tests/Perspex.Controls.UnitTests/PanelTests.cs

@ -117,10 +117,5 @@ namespace Perspex.Controls.UnitTests
Assert.Equal(new Control[0], panel.Children);
Assert.Equal(new ILogical[0], panel.GetLogicalChildren());
}
private class TestReparent : Panel
{
public new IPerspexList<ILogical> LogicalChildren => base.LogicalChildren;
}
}
}

12
tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

@ -137,7 +137,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Templates\TemplateExtensionsTests.cs" />
<Compile Include="TestTemplatedControl.cs" />
<Compile Include="TestRoot.cs" />
<Compile Include="Utils\AncestorFinderTests.cs" />
<Compile Include="Utils\HotKeyManagerTests.cs" />
<Compile Include="WrapPanelTests.cs" />
@ -151,6 +150,10 @@
<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>
@ -179,6 +182,10 @@
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.UnitTests\Perspex.UnitTests.csproj">
<Project>{88060192-33d5-4932-b0f9-8bd2763e857d}</Project>
<Name>Perspex.UnitTests</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
@ -187,6 +194,9 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>

1
tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs

@ -6,6 +6,7 @@ using Moq;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.UnitTests;
using Perspex.VisualTree;
using Xunit;

1
tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs

@ -12,6 +12,7 @@ using Perspex.Layout;
using Perspex.LogicalTree;
using Perspex.Platform;
using Perspex.Styling;
using Perspex.UnitTests;
using Perspex.VisualTree;
using Xunit;

5
tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs

@ -100,10 +100,5 @@ namespace Perspex.Controls.UnitTests.Primitives
SelectionModeProperty.OverrideDefaultValue<TestSelector>(SelectionMode.AlwaysSelected);
}
}
private class Item : Control, ISelectable
{
public bool IsSelected { get; set; }
}
}
}

36
tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs

@ -10,6 +10,7 @@ using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.LogicalTree;
using Perspex.Styling;
using Perspex.UnitTests;
using Perspex.VisualTree;
using Xunit;
@ -176,12 +177,8 @@ namespace Perspex.Controls.UnitTests.Primitives
[Fact]
public void Templated_Children_Should_Be_Styled()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.MockStyler))
{
var styler = new Mock<IStyler>();
PerspexLocator.CurrentMutable.Bind<IStyler>().ToConstant(styler.Object);
TestTemplatedControl target;
var root = new TestRoot
@ -205,6 +202,7 @@ namespace Perspex.Controls.UnitTests.Primitives
target.ApplyTemplate();
var styler = Mock.Get(UnitTestApplication.Current.Services.Styler);
styler.Verify(x => x.ApplyStyles(It.IsAny<TestTemplatedControl>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<StackPanel>()), Times.Once());
styler.Verify(x => x.ApplyStyles(It.IsAny<TextBlock>()), Times.Once());
@ -330,23 +328,6 @@ namespace Perspex.Controls.UnitTests.Primitives
};
}
private static IControl ItemsControlTemplate(ItemsControl control)
{
return new Border
{
Child = new ScrollViewer
{
Template = new FuncControlTemplate<ScrollViewer>(ScrollViewerTemplate),
Content = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
[!ItemsPresenter.ItemsProperty] = control[!ItemsControl.ItemsProperty],
[!ItemsPresenter.ItemsPanelProperty] = control[!ItemsControl.ItemsPanelProperty],
}
}
};
}
private static Control ScrollViewerTemplate(ScrollViewer control)
{
var result = new ScrollContentPresenter
@ -357,16 +338,5 @@ namespace Perspex.Controls.UnitTests.Primitives
return result;
}
private class ApplyTemplateTracker : Control
{
public List<Tuple<IVisual, ILogical>> Invocations { get; } = new List<Tuple<IVisual, ILogical>>();
public override void ApplyTemplate()
{
base.ApplyTemplate();
Invocations.Add(Tuple.Create(this.GetVisualParent(), this.GetLogicalParent()));
}
}
}
}

12
tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs

@ -84,17 +84,5 @@ namespace Perspex.Controls.UnitTests
},
};
}
private Control CreateNestedTemplate(ContentControl control)
{
return new ScrollViewer
{
Template = new FuncControlTemplate<ScrollViewer>(CreateTemplate),
Content = new ContentPresenter
{
Name = "PART_ContentPresenter",
}
};
}
}
}

5
tests/Perspex.Controls.UnitTests/TabControlTests.cs

@ -9,6 +9,7 @@ using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.LogicalTree;
using Perspex.Styling;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Controls.UnitTests
@ -130,10 +131,8 @@ namespace Perspex.Controls.UnitTests
var template = new FuncControlTemplate<TabItem>(x => new Decorator());
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.RealStyler))
{
PerspexLocator.CurrentMutable.Bind<IStyler>().ToConstant(new Styler());
var root = new TestRoot
{
Styles = new Styles

38
tests/Perspex.Controls.UnitTests/TestRoot.cs

@ -1,38 +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 Moq;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
namespace Perspex.Controls.UnitTests
{
internal class TestRoot : Decorator, ILayoutRoot, IRenderRoot, IStyleRoot
{
public Size ClientSize => new Size(100, 100);
public Size MaxClientSize => Size.Infinity;
public ILayoutManager LayoutManager => new Mock<ILayoutManager>().Object;
public IRenderTarget RenderTarget
{
get { throw new NotImplementedException(); }
}
public IRenderQueueManager RenderQueueManager => null;
public Point PointToClient(Point p)
{
throw new NotImplementedException();
}
public Point PointToScreen(Point p)
{
return new Point();
}
}
}

91
tests/Perspex.Controls.UnitTests/TopLevelTests.cs

@ -13,6 +13,7 @@ using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
using Perspex.UnitTests;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Xunit;
@ -24,10 +25,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void ClientSize_Should_Be_Set_On_Construction()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
@ -40,10 +39,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Width_Should_Not_Be_Set_On_Construction()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
@ -56,10 +53,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Height_Should_Not_Be_Set_On_Construction()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
@ -72,10 +67,10 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Layout_Pass_Should_Not_Be_Automatically_Scheduled()
{
using (PerspexLocator.EnterScope())
{
RegisterServices();
var services = TestServices.StyledWindow.With(layoutManager: Mock.Of<ILayoutManager>());
using (UnitTestApplication.Start(services))
{
var impl = new Mock<ITopLevelImpl>();
var target = new TestTopLevel(impl.Object);
@ -88,11 +83,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Bounds_Should_Be_Set_After_Layout_Pass()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
PerspexLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(new LayoutManager());
var impl = new Mock<ITopLevelImpl>();
impl.SetupProperty(x => x.ClientSize);
impl.SetupProperty(x => x.Resized);
@ -116,11 +108,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Impl_ClientSize_Should_Be_Set_After_Layout_Pass()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
PerspexLocator.CurrentMutable.Bind<ILayoutManager>().ToConstant(new LayoutManager());
var impl = new Mock<ITopLevelImpl>();
var target = new TestTopLevel(impl.Object)
@ -142,10 +131,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Width_And_Height_Should_Not_Be_Set_After_Layout_Pass()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
@ -160,10 +147,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Width_And_Height_Should_Be_Set_After_Window_Resize_Notification()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
impl.Setup(x => x.ClientSize).Returns(new Size(123, 456));
@ -180,10 +165,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Activate_Should_Call_Impl_Activate()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
var target = new TestTopLevel(impl.Object);
@ -196,10 +179,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Impl_Activate_Should_Call_Raise_Activated_Event()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
@ -216,10 +197,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Impl_Close_Should_Call_Raise_Closed_Event()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
@ -236,10 +215,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Impl_Deactivate_Should_Call_Raise_Activated_Event()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
@ -256,12 +233,14 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Impl_Input_Should_Pass_Input_To_InputManager()
{
using (PerspexLocator.EnterScope())
{
RegisterServices();
var inputManagerMock = new Mock<IInputManager>();
var services = TestServices.StyledWindow.With(inputManager: inputManagerMock.Object);
using (UnitTestApplication.Start(services))
{
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
var target = new TestTopLevel(impl.Object);
var input = new RawKeyEventArgs(
@ -271,7 +250,6 @@ namespace Perspex.Controls.UnitTests
Key.A, InputModifiers.None);
impl.Object.Input(input);
var inputManagerMock = Mock.Get(InputManager.Instance);
inputManagerMock.Verify(x => x.Process(input));
}
}
@ -279,10 +257,8 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Adding_Top_Level_As_Child_Should_Throw_Exception()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
RegisterServices();
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
var target = new TestTopLevel(impl.Object);
@ -305,31 +281,6 @@ namespace Perspex.Controls.UnitTests
});
}
private void RegisterServices()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var l = PerspexLocator.CurrentMutable;
var formattedText = fixture.Create<IFormattedTextImpl>();
var globalStyles = new Mock<IGlobalStyles>();
var layoutManager = fixture.Create<ILayoutManager>();
var renderInterface = fixture.Create<IPlatformRenderInterface>();
var renderManager = fixture.Create<IRenderQueueManager>();
var windowImpl = new Mock<IWindowImpl>();
var theme = new Styles();
globalStyles.Setup(x => x.Styles).Returns(theme);
PerspexLocator.CurrentMutable
.Bind<IInputManager>().ToConstant(new Mock<IInputManager>().Object)
.Bind<IFocusManager>().ToConstant(new Mock<IFocusManager>().Object)
.Bind<IGlobalStyles>().ToConstant(globalStyles.Object)
.Bind<ILayoutManager>().ToConstant(layoutManager)
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
.Bind<IRenderQueueManager>().ToConstant(renderManager)
.Bind<IStyler>().ToConstant(new Styler());
}
private class TestTopLevel : TopLevel
{
public TestTopLevel(ITopLevelImpl impl)

3
tests/Perspex.Controls.UnitTests/TreeViewTests.cs

@ -8,6 +8,7 @@ using Perspex.Controls.Presenters;
using Perspex.Controls.Templates;
using Perspex.Input;
using Perspex.LogicalTree;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Controls.UnitTests
@ -97,7 +98,7 @@ namespace Perspex.Controls.UnitTests
Assert.NotNull(container);
container.RaiseEvent(new PointerPressEventArgs
container.RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
MouseButton = MouseButton.Left,

372
tests/Perspex.LeakTests/ControlTests.cs

@ -9,6 +9,7 @@ using Perspex.Controls;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Layout;
using Perspex.UnitTests;
using Perspex.VisualTree;
using Xunit;
using Xunit.Abstractions;
@ -20,282 +21,305 @@ namespace Perspex.LeakTests
{
public ControlTests(ITestOutputHelper atr)
{
TestApp.Initialize();
DotMemoryUnitTestOutput.SetOutputMethod(atr.WriteLine);
}
[Fact]
public void Canvas_Is_Freed()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
Content = new Canvas()
};
var window = new Window
{
Content = new Canvas()
};
// Do a layout and make sure that Canvas gets added to visual tree.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<Canvas>(window.Presenter.Child);
// Do a layout and make sure that Canvas gets added to visual tree.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<Canvas>(window.Presenter.Child);
// Clear the content and ensure the Canvas is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
// Clear the content and ensure the Canvas is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
}
}
[Fact]
public void Named_Canvas_Is_Freed()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
Content = new Canvas
var window = new Window
{
Name = "foo"
}
};
Content = new Canvas
{
Name = "foo"
}
};
// Do a layout and make sure that Canvas gets added to visual tree.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<Canvas>(window.Find<Canvas>("foo"));
Assert.IsType<Canvas>(window.Presenter.Child);
// Do a layout and make sure that Canvas gets added to visual tree.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<Canvas>(window.Find<Canvas>("foo"));
Assert.IsType<Canvas>(window.Presenter.Child);
// Clear the content and ensure the Canvas is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
// Clear the content and ensure the Canvas is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
}
}
[Fact]
public void Templated_Child_Is_Freed_When_Template_Cleared()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
Content = new TestTemplatedControl()
};
var window = new Window
{
Content = new TestTemplatedControl()
};
// Do a layout and make sure that the control gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TestTemplatedControl>(window.Presenter.Child);
Assert.IsType<Canvas>(window.Presenter.Child.GetVisualChildren().SingleOrDefault());
// Do a layout and make sure that the control gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TestTemplatedControl>(window.Presenter.Child);
Assert.IsType<Canvas>(window.Presenter.Child.GetVisualChildren().SingleOrDefault());
// Clear the template and ensure the control template gets removed
((TestTemplatedControl)window.Content).Template = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Equal(0, window.Presenter.Child.GetVisualChildren().Count());
// Clear the template and ensure the control template gets removed
((TestTemplatedControl)window.Content).Template = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Equal(0, window.Presenter.Child.GetVisualChildren().Count());
return window;
};
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
}
}
[Fact]
public void ScrollViewer_With_Content_Is_Freed()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
Content = new ScrollViewer
var window = new Window
{
Content = new Canvas()
}
Content = new ScrollViewer
{
Content = new Canvas()
}
};
// Do a layout and make sure that ScrollViewer gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<ScrollViewer>(window.Presenter.Child);
Assert.IsType<Canvas>(((ScrollViewer)window.Presenter.Child).Presenter.Child);
// Clear the content and ensure the ScrollViewer is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
// Do a layout and make sure that ScrollViewer gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<ScrollViewer>(window.Presenter.Child);
Assert.IsType<Canvas>(((ScrollViewer)window.Presenter.Child).Presenter.Child);
// Clear the content and ensure the ScrollViewer is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
var result = run();
return window;
};
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
}
}
[Fact]
public void TextBox_Is_Freed()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
Content = new TextBox()
};
var window = new Window
{
Content = new TextBox()
};
// Do a layout and make sure that TextBox gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TextBox>(window.Presenter.Child);
Assert.NotEqual(0, window.Presenter.Child.GetVisualChildren().Count());
// Do a layout and make sure that TextBox gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TextBox>(window.Presenter.Child);
Assert.NotEqual(0, window.Presenter.Child.GetVisualChildren().Count());
// Clear the content and ensure the TextBox is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
// Clear the content and ensure the TextBox is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
}
}
[Fact]
public void TextBox_With_Xaml_Binding_Is_Freed()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
DataContext = new Node { Name = "foo" },
Content = new TextBox()
};
var window = new Window
{
DataContext = new Node { Name = "foo" },
Content = new TextBox()
};
var binding = new Perspex.Markup.Xaml.Data.Binding
{
Path = "Name"
};
var binding = new Perspex.Markup.Xaml.Data.Binding
{
Path = "Name"
};
var textBox = (TextBox)window.Content;
textBox.Bind(TextBox.TextProperty, binding);
var textBox = (TextBox)window.Content;
textBox.Bind(TextBox.TextProperty, binding);
// Do a layout and make sure that TextBox gets added to visual tree and its
// Text property set.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TextBox>(window.Presenter.Child);
Assert.Equal("foo", ((TextBox)window.Presenter.Child).Text);
// Do a layout and make sure that TextBox gets added to visual tree and its
// Text property set.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TextBox>(window.Presenter.Child);
Assert.Equal("foo", ((TextBox)window.Presenter.Child).Text);
// Clear the content and DataContext and ensure the TextBox is removed.
window.Content = null;
window.DataContext = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
// Clear the content and DataContext and ensure the TextBox is removed.
window.Content = null;
window.DataContext = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Node>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Node>()).ObjectsCount));
}
}
[Fact]
public void TextBox_ScrollViewer_Is_Freed_When_Template_Cleared()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
Func<Window> run = () =>
{
Content = new TextBox()
};
var window = new Window
{
Content = new TextBox()
};
// Do a layout and make sure that TextBox gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TextBox>(window.Presenter.Child);
Assert.NotEqual(0, window.Presenter.Child.GetVisualChildren().Count());
// Do a layout and make sure that TextBox gets added to visual tree and its
// template applied.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.IsType<TextBox>(window.Presenter.Child);
Assert.NotEqual(0, window.Presenter.Child.GetVisualChildren().Count());
// Clear the template and ensure the TextBox template gets removed
((TextBox)window.Content).Template = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Equal(0, window.Presenter.Child.GetVisualChildren().Count());
// Clear the template and ensure the TextBox template gets removed
((TextBox)window.Content).Template = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Equal(0, window.Presenter.Child.GetVisualChildren().Count());
return window;
};
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<ScrollViewer>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<ScrollViewer>()).ObjectsCount));
}
}
[Fact]
public void TreeView_Is_Freed()
{
Func<Window> run = () =>
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var nodes = new[]
Func<Window> run = () =>
{
new Node
var nodes = new[]
{
Children = new[] { new Node() },
}
};
new Node
{
Children = new[] { new Node() },
}
};
TreeView target;
TreeView target;
var window = new Window
{
Content = target = new TreeView
var window = new Window
{
DataTemplates = new DataTemplates
Content = target = new TreeView
{
new FuncTreeDataTemplate<Node>(
x => new TextBlock { Text = x.Name },
x => x.Children)
},
Items = nodes
}
DataTemplates = new DataTemplates
{
new FuncTreeDataTemplate<Node>(
x => new TextBlock { Text = x.Name },
x => x.Children)
},
Items = nodes
}
};
// Do a layout and make sure that TreeViewItems get realized.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.Equal(1, target.ItemContainerGenerator.Containers.Count());
// Clear the content and ensure the TreeView is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
// Do a layout and make sure that TreeViewItems get realized.
LayoutManager.Instance.ExecuteInitialLayoutPass(window);
Assert.Equal(1, target.ItemContainerGenerator.Containers.Count());
// Clear the content and ensure the TreeView is removed.
window.Content = null;
LayoutManager.Instance.ExecuteLayoutPass();
Assert.Null(window.Presenter.Child);
return window;
};
var result = run();
var result = run();
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TreeView>()).ObjectsCount));
dotMemory.Check(memory =>
Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TreeView>()).ObjectsCount));
}
}
private class TestTemplatedControl : TemplatedControl

5
tests/Perspex.LeakTests/Perspex.LeakTests.csproj

@ -93,7 +93,6 @@
<ItemGroup>
<Compile Include="ControlTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestApp.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
@ -152,6 +151,10 @@
<Project>{5ccb5571-7c30-4e7d-967d-0e2158ebd91f}</Project>
<Name>Perspex.Controls.UnitTests</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.UnitTests\Perspex.UnitTests.csproj">
<Project>{88060192-33d5-4932-b0f9-8bd2763e857d}</Project>
<Name>Perspex.UnitTests</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

47
tests/Perspex.LeakTests/TestApp.cs

@ -1,47 +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 Moq;
using Perspex.Controls.UnitTests;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Shared.PlatformSupport;
using Perspex.Themes.Default;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
namespace Perspex.LeakTests
{
internal class TestApp : Application
{
private TestApp()
{
RegisterServices();
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var windowImpl = new Mock<IWindowImpl>();
var renderInterface = fixture.Create<IPlatformRenderInterface>();
var threadingInterface = Mock.Of<IPlatformThreadingInterface>(x =>
x.CurrentThreadIsLoopThread == true);
PerspexLocator.CurrentMutable
.Bind<IAssetLoader>().ToConstant(new AssetLoader())
.Bind<ILayoutManager>().ToConstant(new LayoutManager())
.Bind<IPclPlatformWrapper>().ToConstant(new PclPlatformWrapper())
.Bind<IPlatformRenderInterface>().ToConstant(renderInterface)
.Bind<IPlatformThreadingInterface>().ToConstant(threadingInterface)
.Bind<IStandardCursorFactory>().ToConstant(new Mock<IStandardCursorFactory>().Object)
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock(() => windowImpl.Object));
Styles = new DefaultTheme();
}
public static void Initialize()
{
if (Current == null)
{
new TestApp();
}
}
}
}

1
tests/Perspex.Markup.UnitTests/ControlLocatorTests.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Perspex.Controls;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Markup.UnitTests

5
tests/Perspex.Markup.UnitTests/Data/ExpressionSubjectTests.cs

@ -176,11 +176,6 @@ namespace Perspex.Markup.UnitTests.Data
public string StringValue { get; set; }
public double DoubleValue { get; set; }
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

5
tests/Perspex.Markup.UnitTests/Perspex.Markup.UnitTests.csproj

@ -99,7 +99,6 @@
<Compile Include="Data\NotifyingBase.cs" />
<Compile Include="DefaultValueConverterTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestRoot.cs" />
<Compile Include="UnitTestSynchronizationContext.cs" />
</ItemGroup>
<ItemGroup>
@ -142,6 +141,10 @@
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.UnitTests\Perspex.UnitTests.csproj">
<Project>{88060192-33d5-4932-b0f9-8bd2763e857d}</Project>
<Name>Perspex.UnitTests</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

1
tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs

@ -3,6 +3,7 @@
using Perspex.Controls;
using Perspex.Markup.Xaml.Data;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Markup.Xaml.UnitTests.Data

5
tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs

@ -55,11 +55,6 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
BindingPriority.TemplatedParent));
}
private Mock<IPerspexObject> CreateTarget(ITemplatedControl templatedParent)
{
return CreateTarget(templatedParent: templatedParent);
}
private Mock<IControl> CreateTarget(
ITemplatedControl templatedParent = null,
string text = null)

10
tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj

@ -112,7 +112,6 @@
<Compile Include="StyleTests.cs" />
<Compile Include="Templates\DataTemplateTests.cs" />
<Compile Include="Templates\TreeDataTemplateTests.cs" />
<Compile Include="TestRoot.cs" />
<Compile Include="TypeProviderMock.cs" />
<Compile Include="ViewModelMock.cs" />
</ItemGroup>
@ -129,6 +128,10 @@
<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>
@ -165,8 +168,13 @@
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.UnitTests\Perspex.UnitTests.csproj">
<Project>{88060192-33d5-4932-b0f9-8bd2763e857d}</Project>
<Name>Perspex.UnitTests</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>

24
tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs

@ -3,13 +3,11 @@
using System.Linq;
using System.Reactive.Linq;
using Moq;
using Perspex.Controls;
using Perspex.Controls.Primitives;
using Perspex.Data;
using Perspex.Markup.Xaml.Data;
using Perspex.Platform;
using Perspex.Styling;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Markup.Xaml.UnitTests
@ -19,12 +17,8 @@ namespace Perspex.Markup.Xaml.UnitTests
[Fact]
public void Binding_Should_Be_Assigned_To_Setter_Value_Instead_Of_Bound()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
{
PerspexLocator.CurrentMutable
.Bind<IPclPlatformWrapper>()
.ToConstant(Mock.Of<IPclPlatformWrapper>());
var xaml = "<Style xmlns='https://github.com/perspex'><Setter Value='{Binding}'/></Style>";
var loader = new PerspexXamlLoader();
var style = (Style)loader.Load(xaml);
@ -37,13 +31,8 @@ namespace Perspex.Markup.Xaml.UnitTests
[Fact]
public void Setter_With_TwoWay_Binding_Should_Update_Source()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.MockThreadingInterface))
{
PerspexLocator.CurrentMutable
.Bind<IPlatformThreadingInterface>()
.ToConstant(Mock.Of<IPlatformThreadingInterface>(x =>
x.CurrentThreadIsLoopThread == true));
var data = new Data
{
Foo = "foo",
@ -75,13 +64,8 @@ namespace Perspex.Markup.Xaml.UnitTests
[Fact]
public void Setter_With_TwoWay_Binding_And_Activator_Should_Update_Source()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.MockThreadingInterface))
{
PerspexLocator.CurrentMutable
.Bind<IPlatformThreadingInterface>()
.ToConstant(Mock.Of<IPlatformThreadingInterface>(x =>
x.CurrentThreadIsLoopThread == true));
var data = new Data
{
Foo = "foo",

9
tests/Perspex.Markup.Xaml.UnitTests/Templates/TreeDataTemplateTests.cs

@ -2,11 +2,10 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Linq;
using Moq;
using Perspex.Controls.Templates;
using Perspex.Markup.Xaml.Data;
using Perspex.Markup.Xaml.Templates;
using Perspex.Platform;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Markup.Xaml.UnitTests
@ -16,12 +15,8 @@ namespace Perspex.Markup.Xaml.UnitTests
[Fact]
public void Binding_Should_Be_Assigned_To_ItemsSource_Instead_Of_Bound()
{
using (PerspexLocator.EnterScope())
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
{
PerspexLocator.CurrentMutable
.Bind<IPclPlatformWrapper>()
.ToConstant(Mock.Of<IPclPlatformWrapper>());
var xaml = "<DataTemplates xmlns='https://github.com/perspex'><TreeDataTemplate ItemsSource='{Binding}'/></DataTemplates>";
var loader = new PerspexXamlLoader();
var templates = (DataTemplates)loader.Load(xaml);

67
tests/Perspex.Markup.Xaml.UnitTests/TestRoot.cs

@ -1,67 +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 Perspex.Controls;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.UnitTests
{
public class TestRoot : Decorator, IRenderRoot, INameScope, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
event EventHandler<NameScopeEventArgs> INameScope.Registered
{
add { _nameScope.Registered += value; ++NameScopeRegisteredSubscribers; }
remove { _nameScope.Registered -= value; --NameScopeRegisteredSubscribers; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; ++NameScopeUnregisteredSubscribers; }
remove { _nameScope.Unregistered -= value; --NameScopeUnregisteredSubscribers; }
}
public int NameScopeRegisteredSubscribers { get; private set; }
public int NameScopeUnregisteredSubscribers { get; private set; }
public IRenderTarget RenderTarget
{
get { throw new NotImplementedException(); }
}
public IRenderQueueManager RenderQueueManager
{
get { throw new NotImplementedException(); }
}
public Point PointToClient(Point p)
{
throw new NotImplementedException();
}
public Point PointToScreen(Point p)
{
throw new NotImplementedException();
}
public void Register(string name, object element)
{
_nameScope.Register(name, element);
}
public object Find(string name)
{
return _nameScope.Find(name);
}
public void Unregister(string name)
{
_nameScope.Unregister(name);
}
}
}

11
tests/Perspex.Markup.Xaml.UnitTests/app.config

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

12
tests/Perspex.RenderTests/app.config

@ -15,8 +15,16 @@
<bindingRedirect oldVersion="0.0.0.0-2.1.30214.0" newVersion="2.1.30214.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.0" newVersion="2.6.3.0" />
<assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" />

12
tests/Perspex.Styling.UnitTests/ActivatedSubjectTests.cs

@ -53,18 +53,6 @@ namespace Perspex.Styling.UnitTests
Assert.NotNull(source.Error);
}
private class Class1 : PerspexObject
{
public static readonly StyledProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo", "foodefault");
public string Foo
{
get { return GetValue(FooProperty); }
set { SetValue(FooProperty, value); }
}
}
private class TestSubject : ISubject<object>
{
private IObserver<object> _observer;

5
tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj

@ -104,7 +104,6 @@
<Compile Include="TestControlBase.cs" />
<Compile Include="TestObservable.cs" />
<Compile Include="TestObserver.cs" />
<Compile Include="TestRoot.cs" />
<Compile Include="TestSelectors.cs" />
<Compile Include="TestSubject.cs" />
<Compile Include="TestTemplatedControl.cs" />
@ -142,6 +141,10 @@
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.UnitTests\Perspex.UnitTests.csproj">
<Project>{88060192-33d5-4932-b0f9-8bd2763e857d}</Project>
<Name>Perspex.UnitTests</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

13
tests/Perspex.Styling.UnitTests/StyleActivatorTests.cs

@ -165,18 +165,5 @@ namespace Perspex.Styling.UnitTests
Assert.True(completed);
}
private Recorded<Notification<bool>>[] OnNextValues(params bool[] values)
{
var result = new List<Recorded<Notification<bool>>>();
var time = 1;
foreach (var value in values)
{
result.Add(new Recorded<Notification<bool>>(time, Notification.CreateOnNext<bool>(value)));
}
return result.ToArray();
}
}
}

1
tests/Perspex.Styling.UnitTests/StyleTests.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Reactive.Subjects;
using Perspex.Controls;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Styling.UnitTests

39
tests/Perspex.Styling.UnitTests/TestRoot.cs

@ -1,39 +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 Moq;
using Perspex.Controls;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
namespace Perspex.Styling.UnitTests
{
internal class TestRoot : Decorator, ILayoutRoot, IRenderRoot, IStyleRoot
{
public Size ClientSize => new Size(100, 100);
public Size MaxClientSize => Size.Infinity;
public IRenderTarget RenderTarget
{
get { throw new NotImplementedException(); }
}
public IRenderQueueManager RenderQueueManager
{
get { throw new NotImplementedException(); }
}
public Point PointToClient(Point p)
{
throw new NotImplementedException();
}
public Point PointToScreen(Point p)
{
return new Point();
}
}
}

30
tests/Perspex.UnitTests/MockWindowingPlatform.cs

@ -0,0 +1,30 @@
using System;
using Moq;
using Perspex.Platform;
namespace Perspex.UnitTests
{
public class MockWindowingPlatform : IWindowingPlatform
{
private readonly Func<IWindowImpl> _windowImpl;
private readonly Func<IPopupImpl> _popupImpl;
public MockWindowingPlatform(Func<IWindowImpl> windowImpl = null, Func<IPopupImpl> popupImpl = null )
{
_windowImpl = windowImpl;
_popupImpl = popupImpl;
}
public IWindowImpl CreateWindow()
{
return _windowImpl?.Invoke() ?? Mock.Of<IWindowImpl>();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
public IPopupImpl CreatePopup() => _popupImpl?.Invoke() ?? Mock.Of<IPopupImpl>();
}
}

143
tests/Perspex.UnitTests/Perspex.UnitTests.csproj

@ -0,0 +1,143 @@
<?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>{88060192-33D5-4932-B0F9-8BD2763E857D}</ProjectGuid>
<ProjectGuid>{88060192-33D5-4932-B0F9-8BD2763E857D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.UnitTests</RootNamespace>
<AssemblyName>Perspex.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Moq, Version=4.2.1510.2205, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ploeh.AutoFixture, Version=3.40.0.0, Culture=neutral, PublicKeyToken=b24654c590009d4f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AutoFixture.3.40.0\lib\net40\Ploeh.AutoFixture.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ploeh.AutoFixture.AutoMoq, Version=3.40.0.0, Culture=neutral, PublicKeyToken=b24654c590009d4f, processorArchitecture=MSIL">
<HintPath>..\..\packages\AutoFixture.AutoMoq.3.40.0\lib\net40\Ploeh.AutoFixture.AutoMoq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-Core.2.2.5\lib\net45\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\net45\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\net45\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\net45\System.Reactive.PlatformServices.dll</HintPath>
<Private>True</Private>
</Reference>
<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="TestTemplatedRoot.cs" />
<Compile Include="TestRoot.cs" />
<Compile Include="TestServices.cs" />
<Compile Include="UnitTestApplication.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MockWindowingPlatform.cs" />
</ItemGroup>
<ItemGroup>
<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.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.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>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="..\..\src\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<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>

36
tests/Perspex.UnitTests/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("Perspex.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[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("88060192-33d5-4932-b0f9-8bd2763e857d")]
// 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")]

37
tests/Perspex.Markup.UnitTests/TestRoot.cs → tests/Perspex.UnitTests/TestRoot.cs

@ -3,13 +3,14 @@
using System;
using Perspex.Controls;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
namespace Perspex.Markup.UnitTests
namespace Perspex.UnitTests
{
public class TestRoot : Decorator, IRenderRoot, INameScope, IStyleRoot
public class TestRoot : Decorator, ILayoutRoot, INameScope, IRenderRoot, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
@ -29,37 +30,31 @@ namespace Perspex.Markup.UnitTests
public int NameScopeUnregisteredSubscribers { get; private set; }
public IRenderTarget RenderTarget
{
get { throw new NotImplementedException(); }
}
public Size ClientSize => new Size(100, 100);
public IRenderQueueManager RenderQueueManager
{
get { throw new NotImplementedException(); }
}
public Size MaxClientSize => Size.Infinity;
public Point PointToClient(Point p)
{
throw new NotImplementedException();
}
public ILayoutManager LayoutManager => PerspexLocator.Current.GetService<ILayoutManager>();
public Point PointToScreen(Point p)
{
throw new NotImplementedException();
}
public IRenderTarget RenderTarget => null;
public IRenderQueueManager RenderQueueManager => null;
public Point PointToClient(Point p) => p;
public Point PointToScreen(Point p) => p;
public void Register(string name, object element)
void INameScope.Register(string name, object element)
{
_nameScope.Register(name, element);
}
public object Find(string name)
object INameScope.Find(string name)
{
return _nameScope.Find(name);
}
public void Unregister(string name)
void INameScope.Unregister(string name)
{
_nameScope.Unregister(name);
}

110
tests/Perspex.UnitTests/TestServices.cs

@ -0,0 +1,110 @@
// 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.Reflection;
using Moq;
using Perspex.Input;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Shared.PlatformSupport;
using Perspex.Styling;
using Perspex.Themes.Default;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
namespace Perspex.UnitTests
{
public class TestServices
{
private static IFixture s_fixture = new Fixture().Customize(new AutoMoqCustomization());
public static readonly TestServices StyledWindow = new TestServices(
assetLoader: new AssetLoader(),
layoutManager: new LayoutManager(),
platformWrapper: new PclPlatformWrapper(),
renderInterface: s_fixture.Create<IPlatformRenderInterface>(),
standardCursorFactory: Mock.Of<IStandardCursorFactory>(),
styler: new Styler(),
theme: () => new DefaultTheme(),
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true),
windowingPlatform: new MockWindowingPlatform());
public static readonly TestServices MockPlatformWrapper = new TestServices(
platformWrapper: Mock.Of<IPclPlatformWrapper>());
public static readonly TestServices MockStyler = new TestServices(
styler: Mock.Of<IStyler>());
public static readonly TestServices MockThreadingInterface = new TestServices(
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true));
public static readonly TestServices RealStyler = new TestServices(
styler: new Styler());
public TestServices(
IAssetLoader assetLoader = null,
IInputManager inputManager = null,
ILayoutManager layoutManager = null,
IPclPlatformWrapper platformWrapper = null,
IPlatformRenderInterface renderInterface = null,
IStandardCursorFactory standardCursorFactory = null,
IStyler styler = null,
Func<Styles> theme = null,
IPlatformThreadingInterface threadingInterface = null,
IWindowImpl windowImpl = null,
IWindowingPlatform windowingPlatform = null)
{
AssetLoader = assetLoader;
InputManager = inputManager;
LayoutManager = layoutManager;
PlatformWrapper = platformWrapper;
RenderInterface = renderInterface;
StandardCursorFactory = standardCursorFactory;
Styler = styler;
Theme = theme;
ThreadingInterface = threadingInterface;
WindowImpl = windowImpl;
WindowingPlatform = windowingPlatform;
}
public IAssetLoader AssetLoader { get; }
public IInputManager InputManager { get; }
public ILayoutManager LayoutManager { get; }
public IPclPlatformWrapper PlatformWrapper { get; }
public IPlatformRenderInterface RenderInterface { get; }
public IStandardCursorFactory StandardCursorFactory { get; }
public IStyler Styler { get; }
public Func<Styles> Theme { get; }
public IPlatformThreadingInterface ThreadingInterface { get; }
public IWindowImpl WindowImpl { get; }
public IWindowingPlatform WindowingPlatform { get; }
public TestServices With(
IAssetLoader assetLoader = null,
IInputManager inputManager = null,
ILayoutManager layoutManager = null,
IPclPlatformWrapper platformWrapper = null,
IPlatformRenderInterface renderInterface = null,
IStandardCursorFactory standardCursorFactory = null,
IStyler styler = null,
Func<Styles> theme = null,
IPlatformThreadingInterface threadingInterface = null,
IWindowImpl windowImpl = null,
IWindowingPlatform windowingPlatform = null)
{
return new TestServices(
assetLoader: assetLoader ?? AssetLoader,
inputManager: inputManager ?? InputManager,
layoutManager: layoutManager ?? LayoutManager,
platformWrapper: platformWrapper ?? PlatformWrapper,
renderInterface: renderInterface ?? RenderInterface,
standardCursorFactory: standardCursorFactory ?? StandardCursorFactory,
styler: styler ?? Styler,
theme: theme ?? Theme,
threadingInterface: threadingInterface ?? ThreadingInterface,
windowImpl: windowImpl ?? WindowImpl,
windowingPlatform: windowingPlatform ?? WindowingPlatform);
}
}
}

65
tests/Perspex.UnitTests/TestTemplatedRoot.cs

@ -0,0 +1,65 @@
// 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 Perspex.Controls;
using Perspex.Controls.Presenters;
using Perspex.Controls.Templates;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
namespace Perspex.UnitTests
{
public class TestTemplatedRoot : ContentControl, ILayoutRoot, INameScope, IRenderRoot, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
public TestTemplatedRoot()
{
Template = new FuncControlTemplate<TestTemplatedRoot>(x => new ContentPresenter());
}
public event EventHandler<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
public Size ClientSize => new Size(100, 100);
public Size MaxClientSize => Size.Infinity;
public ILayoutManager LayoutManager => PerspexLocator.Current.GetService<ILayoutManager>();
public IRenderTarget RenderTarget => null;
public IRenderQueueManager RenderQueueManager => null;
public Point PointToClient(Point p) => p;
public Point PointToScreen(Point p) => p;
void INameScope.Register(string name, object element)
{
_nameScope.Register(name, element);
}
object INameScope.Find(string name)
{
return _nameScope.Find(name);
}
void INameScope.Unregister(string name)
{
_nameScope.Unregister(name);
}
}
}

47
tests/Perspex.UnitTests/UnitTestApplication.cs

@ -0,0 +1,47 @@
// 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 Perspex.Input;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Styling;
namespace Perspex.UnitTests
{
public class UnitTestApplication : Application
{
public UnitTestApplication(TestServices services)
{
Services = services ?? new TestServices();
RegisterServices();
Styles = Services.Theme?.Invoke();
}
public static new UnitTestApplication Current => (UnitTestApplication)Application.Current;
public TestServices Services { get; }
public static IDisposable Start(TestServices services = null)
{
var scope = PerspexLocator.EnterScope();
var app = new UnitTestApplication(services);
return scope;
}
protected override void RegisterServices()
{
PerspexLocator.CurrentMutable
.Bind<IAssetLoader>().ToConstant(Services.AssetLoader)
.BindToSelf<IGlobalStyles>(this)
.Bind<IInputManager>().ToConstant(Services.InputManager)
.Bind<ILayoutManager>().ToConstant(Services.LayoutManager)
.Bind<IPclPlatformWrapper>().ToConstant(Services.PlatformWrapper)
.Bind<IPlatformRenderInterface>().ToConstant(Services.RenderInterface)
.Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface)
.Bind<IStandardCursorFactory>().ToConstant(Services.StandardCursorFactory)
.Bind<IStyler>().ToConstant(Services.Styler)
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform);
}
}
}

11
tests/Perspex.UnitTests/app.config

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

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

Loading…
Cancel
Save