Browse Source

Merge branch 'master' into pr/1131-defer-changes-to-dirty-visuals

pull/1131/head
Steven Kirk 9 years ago
parent
commit
23a966a365
  1. 6
      .gitignore
  2. 4
      .gitmodules
  3. 1
      .ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
  4. 9
      .ncrunch/Avalonia.Markup.UnitTests.netcoreapp1.1.v3.ncrunchproject
  5. 1
      .ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject
  6. 3
      .travis.yml
  7. 53
      Avalonia.sln
  8. 4
      appveyor.yml
  9. 4
      build.cake
  10. 5
      build/MonoMac.props
  11. 2
      build/Moq.props
  12. 5
      build/ReactiveUI.props
  13. 13
      build/Rx.props
  14. 19
      build/UnitTests.NetCore.targets
  15. 2
      build/XUnit.props
  16. 13
      docs/guidelines/build.md
  17. 11
      docs/tutorial/from-wpf.md
  18. 99
      packages.cake
  19. 1
      samples/BindingTest/App.xaml.cs
  20. 2
      samples/BindingTest/BindingTest.csproj
  21. 10
      samples/BindingTest/ViewModels/MainWindowViewModel.cs
  22. 2
      samples/BindingTest/ViewModels/NestedCommandViewModel.cs
  23. 2
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  24. 35
      samples/ControlCatalog.NetCore/Program.cs
  25. 14
      samples/ControlCatalog/ControlCatalog.csproj
  26. 33
      samples/ControlCatalog/DecoratedWindow.xaml
  27. 53
      samples/ControlCatalog/DecoratedWindow.xaml.cs
  28. 2
      samples/ControlCatalog/MainView.xaml
  29. 9
      samples/ControlCatalog/MainView.xaml.cs
  30. 5
      samples/ControlCatalog/MainWindow.xaml.cs
  31. 10
      samples/ControlCatalog/Pages/BorderPage.xaml
  32. 8
      samples/ControlCatalog/Pages/ButtonPage.xaml
  33. 2
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  34. 12
      samples/ControlCatalog/Pages/DialogsPage.xaml
  35. 46
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  36. 2
      samples/ControlCatalog/Pages/DropDownPage.xaml
  37. 8
      samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml
  38. 53
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  39. 4
      samples/ControlCatalog/SideBar.xaml
  40. 2
      samples/RenderTest/Pages/ClippingPage.xaml
  41. 8
      samples/RenderTest/Pages/DrawingPage.xaml
  42. 1
      samples/RenderTest/Program.cs
  43. 1
      samples/RenderTest/RenderTest.csproj
  44. 4
      samples/RenderTest/SideBar.xaml
  45. 10
      samples/RenderTest/ViewModels/MainWindowViewModel.cs
  46. 1
      samples/VirtualizationTest/Program.cs
  47. 25
      samples/VirtualizationTest/ViewModels/MainWindowViewModel.cs
  48. 1
      samples/VirtualizationTest/VirtualizationTest.csproj
  49. 2
      src/Avalonia.Animation/Avalonia.Animation.csproj
  50. 2
      src/Avalonia.Base/Avalonia.Base.csproj
  51. 3
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  52. 54
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  53. 66
      src/Avalonia.Controls/Application.cs
  54. 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  55. 70
      src/Avalonia.Controls/Button.cs
  56. 144
      src/Avalonia.Controls/Control.cs
  57. 2
      src/Avalonia.Controls/DropDown.cs
  58. 15
      src/Avalonia.Controls/IControl.cs
  59. 6
      src/Avalonia.Controls/IGlobalDataTemplates.cs
  60. 7
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  61. 2
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  62. 26
      src/Avalonia.Controls/Primitives/Popup.cs
  63. 24
      src/Avalonia.Controls/Primitives/RangeBase.cs
  64. 103
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  65. 4
      src/Avalonia.Controls/Primitives/ToggleButton.cs
  66. 102
      src/Avalonia.Controls/Primitives/Track.cs
  67. 82
      src/Avalonia.Controls/RepeatButton.cs
  68. 4
      src/Avalonia.Controls/ScrollViewer.cs
  69. 55
      src/Avalonia.Controls/Slider.cs
  70. 2
      src/Avalonia.Controls/SystemDialog.cs
  71. 24
      src/Avalonia.Controls/Templates/DataTemplateExtensions.cs
  72. 27
      src/Avalonia.Controls/Templates/IDataTemplateHost.cs
  73. 236
      src/Avalonia.Controls/ToolTip.cs
  74. 98
      src/Avalonia.Controls/ToolTipService.cs
  75. 24
      src/Avalonia.Controls/TopLevel.cs
  76. 24
      src/Avalonia.Controls/Window.cs
  77. 2
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  78. 2
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  79. 2
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  80. 2
      src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
  81. 6
      src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
  82. 3
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  83. 13
      src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
  84. 94
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  85. 15
      src/Avalonia.DotNetFrameworkRuntime/Properties/AssemblyInfo.cs
  86. 3
      src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
  87. 12
      src/Avalonia.HtmlRenderer/Compat/Api.cs
  88. 2
      src/Avalonia.Input/Avalonia.Input.csproj
  89. 2
      src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
  90. 20
      src/Avalonia.Interactivity/Interactive.cs
  91. 2
      src/Avalonia.Layout/Avalonia.Layout.csproj
  92. 2
      src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
  93. 24
      src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
  94. 76
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  95. 3
      src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs
  96. 23
      src/Avalonia.ReactiveUI/Registrations.cs
  97. 34
      src/Avalonia.ReactiveUI/Shims.cs
  98. 1
      src/Avalonia.ReactiveUI/src
  99. 3
      src/Avalonia.Styling/Avalonia.Styling.csproj
  100. 19
      src/Avalonia.Styling/Controls/IResourceDictionary.cs

6
.gitignore

@ -159,6 +159,12 @@ $RECYCLE.BIN/
*.userprefs *.userprefs
*.nugetreferenceswitcher *.nugetreferenceswitcher
#################
## Rider
#################
.idea
################# #################
## Cake ## Cake
################# #################

4
.gitmodules

@ -1,7 +1,3 @@
[submodule "src/Avalonia.ReactiveUI/src"]
path = src/Avalonia.ReactiveUI/src
url = https://github.com/AvaloniaUI/ReactiveUI.git
branch = avalonia-snapshot
[submodule "src/Avalonia.HtmlRenderer/external"] [submodule "src/Avalonia.HtmlRenderer/external"]
path = src/Avalonia.HtmlRenderer/external path = src/Avalonia.HtmlRenderer/external
url = https://github.com/AvaloniaUI/HTML-Renderer.git url = https://github.com/AvaloniaUI/HTML-Renderer.git

1
.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject

@ -1,6 +1,7 @@
<ProjectConfiguration> <ProjectConfiguration>
<Settings> <Settings>
<DefaultTestTimeout>1000</DefaultTestTimeout> <DefaultTestTimeout>1000</DefaultTestTimeout>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
<PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully> <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
</Settings> </Settings>
</ProjectConfiguration> </ProjectConfiguration>

9
.ncrunch/Avalonia.Markup.UnitTests.netcoreapp1.1.v3.ncrunchproject

@ -0,0 +1,9 @@
<ProjectConfiguration>
<Settings>
<IgnoredTests>
<NamedTestSelector>
<TestName>Avalonia.Markup.UnitTests.Data.Plugins.DataAnnotationsValidationPluginTests.Produces_Aggregate_BindingNotificationsx</TestName>
</NamedTestSelector>
</IgnoredTests>
</Settings>
</ProjectConfiguration>

1
.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject

@ -1,6 +1,7 @@
<ProjectConfiguration> <ProjectConfiguration>
<Settings> <Settings>
<DefaultTestTimeout>1000</DefaultTestTimeout> <DefaultTestTimeout>1000</DefaultTestTimeout>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
<PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully> <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
</Settings> </Settings>
</ProjectConfiguration> </ProjectConfiguration>

3
.travis.yml

@ -3,13 +3,14 @@ os:
- linux - linux
- osx - osx
dist: trusty dist: trusty
osx_image: xcode8.3
env: env:
global: global:
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
- DOTNET_CLI_TELEMETRY_OPTOUT=1 - DOTNET_CLI_TELEMETRY_OPTOUT=1
mono: mono:
- latest - latest
dotnet: 1.0.1 dotnet: 2.0.0
script: script:
- ./build.sh --target "Travis" --platform "Mono" --configuration "Release" - ./build.sh --target "Travis" --platform "Mono" --configuration "Release"
notifications: notifications:

53
Avalonia.sln

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26228.4 VisualStudioVersion = 15.0.26730.3
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject EndProject
@ -129,7 +129,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInteropTest", "sampl
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkInteropDemo", "samples\interop\GtkInteropDemo\GtkInteropDemo.csproj", "{BD7F352C-6DC1-4740-BAF2-2D34A038728C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkInteropDemo", "samples\interop\GtkInteropDemo\GtkInteropDemo.csproj", "{BD7F352C-6DC1-4740-BAF2-2D34A038728C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DotNetFrameworkRuntime", "src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj", "{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.DotNetFrameworkRuntime", "src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj", "{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\RenderTest\RenderTest.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\RenderTest\RenderTest.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
EndProject EndProject
@ -159,6 +159,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
build\Moq.props = build\Moq.props build\Moq.props = build\Moq.props
build\NetCore.props = build\NetCore.props build\NetCore.props = build\NetCore.props
build\ReactiveUI.props = build\ReactiveUI.props
build\Rx.props = build\Rx.props build\Rx.props = build\Rx.props
build\Serilog.props = build\Serilog.props build\Serilog.props = build\Serilog.props
build\Serilog.Sinks.Trace.props = build\Serilog.Sinks.Trace.props build\Serilog.Sinks.Trace.props = build\Serilog.Sinks.Trace.props
@ -185,6 +186,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "s
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OSX", "OSX", "{A59C4C0A-64DF-4621-B450-2BA00D6F61E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MonoMac", "src\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj", "{CBFD5788-567D-401B-9DFA-74E4224025A0}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -2514,6 +2519,46 @@ Global
{E1582370-37B3-403C-917F-8209551B1634}.Release|Mono.Build.0 = Release|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Release|Mono.Build.0 = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.ActiveCfg = Release|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Release|x86.ActiveCfg = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.Build.0 = Release|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Release|x86.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhone.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Mono.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Mono.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|x86.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|x86.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhone.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Mono.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Mono.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|x86.ActiveCfg = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|x86.Build.0 = Debug|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Any CPU.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhone.ActiveCfg = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhone.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Mono.ActiveCfg = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Mono.Build.0 = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|x86.ActiveCfg = Release|Any CPU
{CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -2571,5 +2616,9 @@ Global
{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888} {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

4
appveyor.yml

@ -17,9 +17,9 @@ init:
- ps: if (Test-Path env:nuget_address) {[System.IO.File]::AppendAllText("C:\Windows\System32\drivers\etc\hosts", "`n$($env:nuget_address)`tapi.nuget.org")} - ps: if (Test-Path env:nuget_address) {[System.IO.File]::AppendAllText("C:\Windows\System32\drivers\etc\hosts", "`n$($env:nuget_address)`tapi.nuget.org")}
install: install:
- if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi - if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi
- if not exist dotnet-1.0.1.exe appveyor DownloadFile https://go.microsoft.com/fwlink/?linkid=843448 -FileName "dotnet-1.0.1.exe" - if not exist dotnet-2.0.0.exe appveyor DownloadFile https://download.microsoft.com/download/0/F/D/0FD852A4-7EA1-4E2A-983A-0484AC19B92C/dotnet-sdk-2.0.0-win-x64.exe -FileName "dotnet-2.0.0.exe"
- ps: Start-Process -FilePath "msiexec" -ArgumentList "/i gtk-sharp-2.12.26.msi /quiet /qn /norestart" -Wait - ps: Start-Process -FilePath "msiexec" -ArgumentList "/i gtk-sharp-2.12.26.msi /quiet /qn /norestart" -Wait
- ps: Start-Process -FilePath "dotnet-1.0.1.exe" -ArgumentList "/quiet" -Wait - ps: Start-Process -FilePath "dotnet-2.0.0.exe" -ArgumentList "/quiet" -Wait
- cmd: set PATH=%programfiles(x86)%\GtkSharp\2.12\bin\;%PATH% - cmd: set PATH=%programfiles(x86)%\GtkSharp\2.12\bin\;%PATH%
before_build: before_build:
- git submodule update --init - git submodule update --init

4
build.cake

@ -6,7 +6,7 @@
#addin "nuget:?package=NuGet.Core&version=2.12.0" #addin "nuget:?package=NuGet.Core&version=2.12.0"
#tool "nuget:?package=xunit.runner.console&version=2.2.0" #tool "nuget:?package=xunit.runner.console&version=2.2.0"
#tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease" #tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease"
#tool "JetBrains.ReSharper.CommandLineTools" #tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2017.1.20170613.162720"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// TOOLS // TOOLS
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -162,7 +162,7 @@ void RunCoreTest(string project, Parameters parameters, bool coreOnly = false)
project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj"); project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj");
Information("Running tests from " + project); Information("Running tests from " + project);
DotNetCoreRestore(project); DotNetCoreRestore(project);
var frameworks = new List<string>(){"netcoreapp1.1"}; var frameworks = new List<string>(){"netcoreapp2.0"};
if(parameters.IsRunningOnWindows) if(parameters.IsRunningOnWindows)
frameworks.Add("net461"); frameworks.Add("net461");
foreach(var fw in frameworks) foreach(var fw in frameworks)

5
build/MonoMac.props

@ -0,0 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="MonoMac.NetStandard" Version="0.0.3" />
</ItemGroup>
</Project>

2
build/Moq.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<PackageReference Include="Moq" Version="4.7.25" /> <PackageReference Include="Moq" Version="4.7.99" />
</ItemGroup> </ItemGroup>
</Project> </Project>

5
build/ReactiveUI.props

@ -0,0 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="reactiveui" Version="8.0.0-alpha0073" />
</ItemGroup>
</Project>

13
build/Rx.props

@ -1,11 +1,10 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Reactive" Version="3.0.0" /> <PackageReference Include="System.Reactive" Version="3.1.1" />
<PackageReference Include="System.Reactive.Core" Version="3.0.0" /> <PackageReference Include="System.Reactive.Core" Version="3.1.1" />
<PackageReference Include="System.Reactive.Interfaces" Version="3.0.0" /> <PackageReference Include="System.Reactive.Interfaces" Version="3.1.1" />
<PackageReference Include="System.Reactive.Linq" Version="3.0.0" /> <PackageReference Include="System.Reactive.Linq" Version="3.1.1" />
<PackageReference Include="System.Reactive.PlatformServices" Version="3.0.0" /> <PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
<PackageReference Condition="'$(TargetFramework)' == 'net45'" Include="System.Reactive.Windows.Threading" Version="3.0.0" /> <PackageReference Condition="$(TargetFramework.StartsWith('net4'))" Include="System.Reactive.Windows.Threading" Version="3.1.1" />
<PackageReference Condition="'$(TargetFramework)' == 'net461'" Include="System.Reactive.Windows.Threading" Version="3.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

19
build/UnitTests.NetCore.targets

@ -3,25 +3,6 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup> </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>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</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>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Threading.Thread" Version="4.3.0" /> <PackageReference Include="System.Threading.Thread" Version="4.3.0" />
</ItemGroup> </ItemGroup>

2
build/XUnit.props

@ -9,7 +9,7 @@
<PackageReference Include="xunit.runner.console" Version="2.2.0" /> <PackageReference Include="xunit.runner.console" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp1.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>

13
docs/guidelines/build.md

@ -80,10 +80,11 @@ mono ./samples/ControlCatalog.Desktop/bin/Debug/ControlCatalog.Desktop.exe
### Building Avalonia in MonoDevelop ### Building Avalonia in MonoDevelop
Unless you have a very current version of monodevelop (6.1.x or newer), it is necessary to manually Flatpak version will *NOT* work. Version from https://github.com/cra0zy/monodevelop-run-installer/ might work if you are very lucky. Make sure that you have the latest version of Mono (from alpha update channel) and .NET Core SDK. Make sure to follow `FrameworkPathOverride` workaround from https://github.com/dotnet/sdk/issues/335
restore the Nuget depdendencies as [mentioned above](#restore-nuget-packages). You must then
disable MonoDevelop's inbuilt NuGet package manager add-in by going to `Tools -> Add-in Manager` or ### Building and running Avalonia in Rider
it will complain that a newer version of NuGet is needed.
For Linux/OSX you'll probably need to apply workaround from https://github.com/dotnet/sdk/issues/335
Just add `export FrameworkPathOverride=/usr/lib/mono/4.6.1-api` (or `export FrameworkPathOverride=/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.6.1-api` for OSX)
Finally, select the `Debug | Mono` or `Release | Mono` build configuration and you should be good to
go!

11
docs/tutorial/from-wpf.md

@ -73,17 +73,6 @@ and includes `DirectProperty` for turning standard CLR properties into Avalonia
properties. The common base class of `StyledProperty` and `DirectProperty` properties. The common base class of `StyledProperty` and `DirectProperty`
is `AvaloniaProperty`. is `AvaloniaProperty`.
# Resources
There is no `Resources` collection on controls in Avalonia, however `Style`s
do have a `Resources` collection for style-related resources. These can be
referred to using the `{StyleResource}` markup extension both inside and outside
styles.
For non-style-related resources, we suggest defining them in code and referring
to them in markup using the `{Static}` markup extension. To read more about the reasoning for this,
see [this issue comment](https://github.com/AvaloniaUI/Avalonia/issues/462#issuecomment-191849723).
## Grid ## Grid
Column and row definitions can be specified in Avalonia using strings, avoiding Column and row definitions can be specified in Avalonia using strings, avoiding

99
packages.cake

@ -43,7 +43,6 @@ public class Packages
} }
} }
//new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp1.0", Version = "4.3.0" },
public Packages(ICakeContext context, Parameters parameters) public Packages(ICakeContext context, Parameters parameters)
{ {
// NUGET NUSPECS // NUGET NUSPECS
@ -111,6 +110,7 @@ public class Packages
var SplatVersion = packageVersions["Splat"].FirstOrDefault().Item1; var SplatVersion = packageVersions["Splat"].FirstOrDefault().Item1;
var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1; var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1; var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
var ReactiveUIVersion = packageVersions["reactiveui"].FirstOrDefault().Item1;
var SystemValueTupleVersion = packageVersions["System.ValueTuple"].FirstOrDefault().Item1; var SystemValueTupleVersion = packageVersions["System.ValueTuple"].FirstOrDefault().Item1;
SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1; SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
SkiaSharpLinuxVersion = packageVersions["Avalonia.Skia.Linux.Natives"].FirstOrDefault().Item1; SkiaSharpLinuxVersion = packageVersions["Avalonia.Skia.Linux.Natives"].FirstOrDefault().Item1;
@ -124,6 +124,7 @@ public class Packages
context.Information("Package: Splat, version: {0}", SplatVersion); context.Information("Package: Splat, version: {0}", SplatVersion);
context.Information("Package: Sprache, version: {0}", SpracheVersion); context.Information("Package: Sprache, version: {0}", SpracheVersion);
context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion); context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
context.Information("Package: reactiveui, version: {0}", ReactiveUIVersion);
context.Information("Package: System.ValueTuple, version: {0}", SystemValueTupleVersion); context.Information("Package: System.ValueTuple, version: {0}", SystemValueTupleVersion);
context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion); context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
context.Information("Package: Avalonia.Skia.Linux.Natives, version: {0}", SkiaSharpLinuxVersion); context.Information("Package: Avalonia.Skia.Linux.Natives, version: {0}", SkiaSharpLinuxVersion);
@ -176,7 +177,6 @@ public class Packages
new [] { "./src/", "Avalonia.Visuals", ".xml" }, new [] { "./src/", "Avalonia.Visuals", ".xml" },
new [] { "./src/", "Avalonia.Styling", ".dll" }, new [] { "./src/", "Avalonia.Styling", ".dll" },
new [] { "./src/", "Avalonia.Styling", ".xml" }, new [] { "./src/", "Avalonia.Styling", ".xml" },
new [] { "./src/", "Avalonia.ReactiveUI", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".dll" }, new [] { "./src/", "Avalonia.Themes.Default", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".xml" }, new [] { "./src/", "Avalonia.Themes.Default", ".xml" },
new [] { "./src/Markup/", "Avalonia.Markup", ".dll" }, new [] { "./src/Markup/", "Avalonia.Markup", ".dll" },
@ -186,12 +186,12 @@ public class Packages
}; };
var coreLibrariesFiles = coreLibraries.Select((lib) => { var coreLibrariesFiles = coreLibraries.Select((lib) => {
return (FilePath)context.File(lib[0] + lib[1] + "/bin/" + parameters.DirSuffix + "/netstandard1.3/" + lib[1] + lib[2]); return (FilePath)context.File(lib[0] + lib[1] + "/bin/" + parameters.DirSuffix + "/netstandard2.0/" + lib[1] + lib[2]);
}).ToList(); }).ToList();
var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => { var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent { return new NuSpecContent {
Source = file.FullPath, Target = "lib/netstandard1.3" Source = file.FullPath, Target = "lib/netstandard2.0"
}; };
}); });
@ -203,14 +203,14 @@ public class Packages
var netcoreappCoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => { var netcoreappCoreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent { return new NuSpecContent {
Source = file.FullPath, Target = "lib/netcoreapp1.0" Source = file.FullPath, Target = "lib/netcoreapp2.0"
}; };
}); });
var net45RuntimePlatformExtensions = new [] {".xml", ".dll"}; var net45RuntimePlatformExtensions = new [] {".xml", ".dll"};
var net45RuntimePlatform = net45RuntimePlatformExtensions.Select(libSuffix => { var net45RuntimePlatform = net45RuntimePlatformExtensions.Select(libSuffix => {
return new NuSpecContent { return new NuSpecContent {
Source = ((FilePath)context.File("./src/Avalonia.DotNetFrameworkRuntime/bin/" + parameters.DirSuffix + "/Avalonia.DotNetFrameworkRuntime" + libSuffix)).FullPath, Source = ((FilePath)context.File("./src/Avalonia.DotNetFrameworkRuntime/bin/" + parameters.DirSuffix + "/net461/Avalonia.DotNetFrameworkRuntime" + libSuffix)).FullPath,
Target = "lib/net45" Target = "lib/net45"
}; };
}); });
@ -218,8 +218,8 @@ public class Packages
var netCoreRuntimePlatformExtensions = new [] {".xml", ".dll"}; var netCoreRuntimePlatformExtensions = new [] {".xml", ".dll"};
var netCoreRuntimePlatform = netCoreRuntimePlatformExtensions.Select(libSuffix => { var netCoreRuntimePlatform = netCoreRuntimePlatformExtensions.Select(libSuffix => {
return new NuSpecContent { return new NuSpecContent {
Source = ((FilePath)context.File("./src/Avalonia.DotNetCoreRuntime/bin/" + parameters.DirSuffix + "/netcoreapp1.0/Avalonia.DotNetCoreRuntime" + libSuffix)).FullPath, Source = ((FilePath)context.File("./src/Avalonia.DotNetCoreRuntime/bin/" + parameters.DirSuffix + "/netcoreapp2.0/Avalonia.DotNetCoreRuntime" + libSuffix)).FullPath,
Target = "lib/netcoreapp1.0" Target = "lib/netcoreapp2.0"
}; };
}); });
@ -238,15 +238,15 @@ public class Packages
new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion }, new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion }, new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion },
//.NET Core //.NET Core
new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp1.0", Version = "4.3.0" }, new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp2.0", Version = "4.3.0" },
new NuSpecDependency() { Id = "Microsoft.Extensions.DependencyModel", TargetFramework = "netcoreapp1.0", Version = "1.1.0" }, new NuSpecDependency() { Id = "Microsoft.Extensions.DependencyModel", TargetFramework = "netcoreapp2.0", Version = "1.1.0" },
new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netcoreapp1.0", Version = "1.6.0" }, new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netcoreapp2.0", Version = "1.6.0" },
new NuSpecDependency() { Id = "Splat", TargetFramework = "netcoreapp1.0", Version = SplatVersion }, new NuSpecDependency() { Id = "Splat", TargetFramework = "netcoreapp2.0", Version = SplatVersion },
new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp1.0", Version = SerilogVersion }, new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp2.0", Version = SerilogVersion },
new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp1.0", Version = SpracheVersion }, new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp2.0", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp1.0", Version = SystemReactiveVersion }, new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp2.0", Version = SystemReactiveVersion },
} }
.Deps(new string[]{null, "netcoreapp1.0"}, .Deps(new string[]{null, "netcoreapp2.0"},
"System.ValueTuple", "System.ComponentModel.TypeConverter", "System.ComponentModel.Primitives", "System.ValueTuple", "System.ComponentModel.TypeConverter", "System.ComponentModel.Primitives",
"System.Runtime.Serialization.Primitives", "System.Xml.XmlDocument", "System.Xml.ReaderWriter") "System.Runtime.Serialization.Primitives", "System.Xml.XmlDocument", "System.Xml.ReaderWriter")
.ToArray(), .ToArray(),
@ -269,11 +269,28 @@ public class Packages
}, },
Files = new [] Files = new []
{ {
new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/netstandard1.3" } new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/netstandard2.0" }
}, },
BasePath = context.Directory("./src/Avalonia.HtmlRenderer/bin/" + parameters.DirSuffix + "/netstandard1.3"), BasePath = context.Directory("./src/Avalonia.HtmlRenderer/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot OutputDirectory = parameters.NugetRoot
} },
///////////////////////////////////////////////////////////////////////////////
// Avalonia.ReactiveUI
///////////////////////////////////////////////////////////////////////////////
new NuGetPackSettings()
{
Id = "Avalonia.ReactiveUI",
Dependencies = new DependencyBuilder(this)
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
}.Deps(new string[] {null}, "reactiveui"),
Files = new []
{
new NuSpecContent { Source = "Avalonia.ReactiveUI.dll", Target = "lib/netstandard2.0" }
},
BasePath = context.Directory("./src/Avalonia.ReactiveUI/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot
},
}; };
var nuspecNuGetSettingsMobile = new [] var nuspecNuGetSettingsMobile = new []
@ -331,7 +348,7 @@ public class Packages
Files = new [] Files = new []
{ {
new NuSpecContent { Source = "Avalonia.Win32/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/net45" }, new NuSpecContent { Source = "Avalonia.Win32/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/net45" },
new NuSpecContent { Source = "Avalonia.Win32.NetStandard/bin/" + parameters.DirSuffix + "/netstandard1.3/Avalonia.Win32.dll", Target = "lib/netstandard1.3" } new NuSpecContent { Source = "Avalonia.Win32.NetStandard/bin/" + parameters.DirSuffix + "/netstandard2.0/Avalonia.Win32.dll", Target = "lib/netstandard2.0" }
}, },
BasePath = context.Directory("./src/Windows"), BasePath = context.Directory("./src/Windows"),
OutputDirectory = parameters.NugetRoot OutputDirectory = parameters.NugetRoot
@ -352,9 +369,9 @@ public class Packages
}, },
Files = new [] Files = new []
{ {
new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/netstandard1.3" } new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/netstandard2.0" }
}, },
BasePath = context.Directory("./src/Windows/Avalonia.Direct2D1/bin/" + parameters.DirSuffix + "/netstandard1.3"), BasePath = context.Directory("./src/Windows/Avalonia.Direct2D1/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot OutputDirectory = parameters.NugetRoot
}, },
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -386,9 +403,9 @@ public class Packages
}, },
Files = new [] Files = new []
{ {
new NuSpecContent { Source = "Avalonia.Gtk3.dll", Target = "lib/netstandard1.3" } new NuSpecContent { Source = "Avalonia.Gtk3.dll", Target = "lib/netstandard2.0" }
}, },
BasePath = context.Directory("./src/Gtk/Avalonia.Gtk3/bin/" + parameters.DirSuffix + "/netstandard1.3"), BasePath = context.Directory("./src/Gtk/Avalonia.Gtk3/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot OutputDirectory = parameters.NugetRoot
}, },
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -418,18 +435,32 @@ public class Packages
{ {
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }, new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion },
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version, TargetFramework="netcoreapp1.1" }, new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version, TargetFramework="netcoreapp2.0" },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion, TargetFramework="netcoreapp1.1" }, new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion, TargetFramework="netcoreapp2.0" },
new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion, TargetFramework="netcoreapp1.1" }, new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion, TargetFramework="netcoreapp2.0" },
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version, TargetFramework="net461" }, new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version, TargetFramework="net461" },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion, TargetFramework="net461" }, new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion, TargetFramework="net461" },
new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion, TargetFramework="net461" } new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion, TargetFramework="net461" }
}, },
Files = new [] Files = new []
{ {
new NuSpecContent { Source = "Avalonia.Skia.dll", Target = "lib/netstandard1.3" } new NuSpecContent { Source = "Avalonia.Skia.dll", Target = "lib/netstandard2.0" }
},
BasePath = context.Directory("./src/Skia/Avalonia.Skia/bin/" + parameters.DirSuffix + "/netstandard2.0"),
OutputDirectory = parameters.NugetRoot
},
new NuGetPackSettings()
{
Id = "Avalonia.MonoMac",
Dependencies = new DependencyBuilder(this)
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }
}.Dep("MonoMac.NetStandard").ToArray(),
Files = new []
{
new NuSpecContent { Source = "netstandard2.0/Avalonia.MonoMac.dll", Target = "lib/netstandard2.0" },
}, },
BasePath = context.Directory("./src/Skia/Avalonia.Skia/bin/" + parameters.DirSuffix + "/netstandard1.3"), BasePath = context.Directory("./src/OSX/Avalonia.MonoMac/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot OutputDirectory = parameters.NugetRoot
}, },
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -447,10 +478,12 @@ public class Packages
new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="net45", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="net45", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="net45", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="net45", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="net45", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="net45", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.MonoMac", TargetFramework="net45", Version = parameters.Version },
//.NET Core //.NET Core
new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp1.0", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp2.0", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="netcoreapp1.0", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="netcoreapp2.0", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp1.0", Version = parameters.Version } new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp2.0", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.MonoMac", TargetFramework="netcoreapp2.0", Version = parameters.Version }
}, },
Files = new NuSpecContent[] Files = new NuSpecContent[]
{ {
@ -488,7 +521,7 @@ public class Packages
}, },
Files = new [] Files = new []
{ {
new NuSpecContent { Source = "Avalonia.LinuxFramebuffer/bin/" + parameters.DirSuffix + "/netstandard1.3/Avalonia.LinuxFramebuffer.dll", Target = "lib/netstandard1.3" } new NuSpecContent { Source = "Avalonia.LinuxFramebuffer/bin/" + parameters.DirSuffix + "/netstandard2.0/Avalonia.LinuxFramebuffer.dll", Target = "lib/netstandard2.0" }
}, },
BasePath = context.Directory("./src/Linux/"), BasePath = context.Directory("./src/Linux/"),
OutputDirectory = parameters.NugetRoot OutputDirectory = parameters.NugetRoot

1
samples/BindingTest/App.xaml.cs

@ -20,6 +20,7 @@ namespace BindingTest
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI()
.Start<MainWindow>(); .Start<MainWindow>();
} }

2
samples/BindingTest/BindingTest.csproj

@ -45,7 +45,6 @@
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -163,4 +162,5 @@
<Import Project="..\..\build\Serilog.Sinks.Trace.props" /> <Import Project="..\..\build\Serilog.Sinks.Trace.props" />
<Import Project="..\..\build\Splat.props" /> <Import Project="..\..\build\Splat.props" />
<Import Project="..\..\build\Rx.props" /> <Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
</Project> </Project>

10
samples/BindingTest/ViewModels/MainWindowViewModel.cs

@ -28,15 +28,13 @@ namespace BindingTest.ViewModels
SelectedItems = new ObservableCollection<TestItem>(); SelectedItems = new ObservableCollection<TestItem>();
ShuffleItems = ReactiveCommand.Create(); ShuffleItems = ReactiveCommand.Create(() =>
ShuffleItems.Subscribe(_ =>
{ {
var r = new Random(); var r = new Random();
Items.Move(r.Next(Items.Count), 1); Items.Move(r.Next(Items.Count), 1);
}); });
StringValueCommand = ReactiveCommand.Create(); StringValueCommand = ReactiveCommand.Create<object>(param =>
StringValueCommand.Subscribe(param =>
{ {
BooleanFlag = !BooleanFlag; BooleanFlag = !BooleanFlag;
StringValue = param.ToString(); StringValue = param.ToString();
@ -58,7 +56,7 @@ namespace BindingTest.ViewModels
public ObservableCollection<TestItem> Items { get; } public ObservableCollection<TestItem> Items { get; }
public ObservableCollection<TestItem> SelectedItems { get; } public ObservableCollection<TestItem> SelectedItems { get; }
public ReactiveCommand<object> ShuffleItems { get; } public ReactiveCommand ShuffleItems { get; }
public string BooleanString public string BooleanString
{ {
@ -91,7 +89,7 @@ namespace BindingTest.ViewModels
} }
public IObservable<string> CurrentTimeObservable { get; } public IObservable<string> CurrentTimeObservable { get; }
public ReactiveCommand<object> StringValueCommand { get; } public ReactiveCommand StringValueCommand { get; }
public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel(); public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel();
public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel(); public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel();

2
samples/BindingTest/ViewModels/NestedCommandViewModel.cs

@ -12,7 +12,7 @@ namespace BindingTest.ViewModels
{ {
public NestedCommandViewModel() public NestedCommandViewModel()
{ {
Command = ReactiveCommand.Create(); Command = ReactiveCommand.Create(() => { });
} }
public ICommand Command { get; } public ICommand Command { get; }

2
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

35
samples/ControlCatalog.NetCore/Program.cs

@ -1,24 +1,47 @@
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia; using Avalonia;
namespace ControlCatalog.NetCore namespace ControlCatalog.NetCore
{ {
class Program static class Program
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
if (args.Contains("--fbdev")) AppBuilder.Configure<App>().InitializeWithLinuxFramebuffer(tl => if (args.Contains("--wait-for-attach"))
{ {
tl.Content = new MainView(); Console.WriteLine("Attach debugger and use 'Set next statement'");
System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer()); while (true)
}); {
Thread.Sleep(100);
if (Debugger.IsAttached)
break;
}
}
if (args.Contains("--fbdev"))
AppBuilder.Configure<App>().InitializeWithLinuxFramebuffer(tl =>
{
tl.Content = new MainView();
System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
});
else else
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .CustomPlatformDetect()
.UseReactiveUI()
.Start<MainWindow>(); .Start<MainWindow>();
} }
static AppBuilder CustomPlatformDetect(this AppBuilder builder)
{
//This is needed because we still aren't ready to have MonoMac backend as default one
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return builder.UseSkia().UseMonoMac();
return builder.UsePlatformDetect();
}
static void ConsoleSilencer() static void ConsoleSilencer()
{ {
Console.CursorVisible = false; Console.CursorVisible = false;

14
samples/ControlCatalog/ControlCatalog.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems> <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
@ -32,6 +32,12 @@
<EmbeddedResource Include="MainView.xaml"> <EmbeddedResource Include="MainView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="DecoratedWindow.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\DialogsPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\BorderPage.xaml"> <EmbeddedResource Include="Pages\BorderPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
@ -83,9 +89,15 @@
<Compile Include="MainView.xaml.cs"> <Compile Include="MainView.xaml.cs">
<DependentUpon>MainView.xaml</DependentUpon> <DependentUpon>MainView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="DecoratedWindow.xaml.cs">
<DependentUpon>DecoratedWindow.xaml</DependentUpon>
</Compile>
<Compile Include="MainWindow.xaml.cs"> <Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon> <DependentUpon>MainWindow.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\DialogsPage.xaml.cs">
<DependentUpon>DialogsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\BorderPage.xaml.cs"> <Compile Include="Pages\BorderPage.xaml.cs">
<DependentUpon>BorderPage.xaml</DependentUpon> <DependentUpon>BorderPage.xaml</DependentUpon>
</Compile> </Compile>

33
samples/ControlCatalog/DecoratedWindow.xaml

@ -0,0 +1,33 @@
<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
Title="Avalonia Control Gallery"
Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog"
xmlns:local="clr-namespace:ControlCatalog;assembly=ControlCatalog" HasSystemDecorations="False">
<Grid RowDefinitions="5,*,5" ColumnDefinitions="5,*,5">
<DockPanel Grid.Column="1" Grid.Row="1" >
<Grid Name="TitleBar" Background="LightBlue" DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto">
<TextBlock VerticalAlignment="Center" Margin="5,0,0,0">Title</TextBlock>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<StackPanel.Styles>
<Style Selector="Button">
<Setter Property="Margin" Value="2"/>
</Style>
</StackPanel.Styles>
<Button Name="MinimizeButton">_</Button>
<Button Name="MaximizeButton">[ ]</Button>
<Button Name="CloseButton">X</Button>
</StackPanel>
</Grid>
<Border Background="White" Margin="5">
<TextBlock>Hello world!</TextBlock>
</Border>
</DockPanel>
<Border Name="TopLeft" Background="Red"/>
<Border Name="TopRight" Background="Red" Grid.Column="2" />
<Border Name="BottomLeft" Background="Red" Grid.Row="2" />
<Border Name="BottomRight" Background="Red" Grid.Row="2" Grid.Column="2"/>
<Border Name="Top" Background="Blue" Grid.Column="1" />
<Border Name="Right" Background="Blue" Grid.Row="1" Grid.Column="2" />
<Border Name="Bottom" Background="Blue" Grid.Row="2" Grid.Column="1" />
<Border Name="Left" Background="Blue" Grid.Row="1" />
</Grid>
</Window>

53
samples/ControlCatalog/DecoratedWindow.xaml.cs

@ -0,0 +1,53 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using System;
using Avalonia.Input;
namespace ControlCatalog
{
public class DecoratedWindow : Window
{
public DecoratedWindow()
{
this.InitializeComponent();
this.AttachDevTools();
}
void SetupSide(string name, StandardCursorType cursor, WindowEdge edge)
{
var ctl = this.FindControl<Control>(name);
ctl.Cursor = new Cursor(cursor);
ctl.PointerPressed += delegate
{
PlatformImpl.BeginResizeDrag(edge);
};
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
this.FindControl<Control>("TitleBar").PointerPressed += delegate
{
PlatformImpl.BeginMoveDrag();
};
SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West);
SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East);
SetupSide("Top", StandardCursorType.TopSide, WindowEdge.North);
SetupSide("Bottom", StandardCursorType.BottomSize, WindowEdge.South);
SetupSide("TopLeft", StandardCursorType.TopLeftCorner, WindowEdge.NorthWest);
SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast);
SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest);
SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast);
this.FindControl<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; };
this.FindControl<Button>("MaximizeButton").Click += delegate
{
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
};
this.FindControl<Button>("CloseButton").Click += delegate
{
Close();
};
}
}
}

2
samples/ControlCatalog/MainView.xaml

@ -1,7 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog" xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabControl Classes="sidebar"> <TabControl Classes="sidebar" Name="Sidebar">
<TabControl.Transition> <TabControl.Transition>
<CrossFade Duration="0.25"/> <CrossFade Duration="0.25"/>
</TabControl.Transition> </TabControl.Transition>

9
samples/ControlCatalog/MainView.xaml.cs

@ -1,6 +1,9 @@
using System.Collections;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using ControlCatalog.Pages;
namespace ControlCatalog namespace ControlCatalog
{ {
@ -9,6 +12,12 @@ namespace ControlCatalog
public MainView() public MainView()
{ {
this.InitializeComponent(); this.InitializeComponent();
if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsDesktop)
((IList) this.FindControl<TabControl>("Sidebar").Items).Add(new TabItem()
{
Header = "Dialogs",
Content = new DialogsPage()
});
} }
private void InitializeComponent() private void InitializeComponent()

5
samples/ControlCatalog/MainWindow.xaml.cs

@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using System;
namespace ControlCatalog namespace ControlCatalog
{ {
@ -10,7 +11,7 @@ namespace ControlCatalog
{ {
this.InitializeComponent(); this.InitializeComponent();
this.AttachDevTools(); this.AttachDevTools();
Renderer.DrawDirtyRects = Renderer.DrawFps = true; //Renderer.DrawDirtyRects = Renderer.DrawFps = true;
} }
private void InitializeComponent() private void InitializeComponent()
@ -19,7 +20,7 @@ namespace ControlCatalog
// so we must refer to this resource DLL statically. For // so we must refer to this resource DLL statically. For
// now I am doing that here. But we need a better solution!! // now I am doing that here. But we need a better solution!!
var theme = new Avalonia.Themes.Default.DefaultTheme(); var theme = new Avalonia.Themes.Default.DefaultTheme();
theme.FindResource("Button"); theme.TryGetResource("Button", out _);
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }

10
samples/ControlCatalog/Pages/BorderPage.xaml

@ -7,22 +7,22 @@
Margin="0,16,0,0" Margin="0,16,0,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Gap="16"> Gap="16">
<Border BorderBrush="{StyleResource ThemeAccentBrush}" BorderThickness="2" Padding="16"> <Border BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="2" Padding="16">
<TextBlock>Border</TextBlock> <TextBlock>Border</TextBlock>
</Border> </Border>
<Border Background="{StyleResource ThemeAccentBrush2}" <Border Background="{DynamicResource ThemeAccentBrush2}"
BorderBrush="{StyleResource ThemeAccentBrush}" BorderBrush="{DynamicResource ThemeAccentBrush}"
BorderThickness="4" BorderThickness="4"
Padding="16"> Padding="16">
<TextBlock>Border and Background</TextBlock> <TextBlock>Border and Background</TextBlock>
</Border> </Border>
<Border BorderBrush="{StyleResource ThemeAccentBrush}" <Border BorderBrush="{DynamicResource ThemeAccentBrush}"
BorderThickness="4" BorderThickness="4"
CornerRadius="8" CornerRadius="8"
Padding="16"> Padding="16">
<TextBlock>Rounded Corners</TextBlock> <TextBlock>Rounded Corners</TextBlock>
</Border> </Border>
<Border Background="{StyleResource ThemeAccentBrush2}" <Border Background="{DynamicResource ThemeAccentBrush2}"
CornerRadius="8" CornerRadius="8"
Padding="16"> Padding="16">
<TextBlock>Rounded Corners</TextBlock> <TextBlock>Rounded Corners</TextBlock>

8
samples/ControlCatalog/Pages/ButtonPage.xaml

@ -11,7 +11,7 @@
<StackPanel Orientation="Vertical" Gap="8" Width="150"> <StackPanel Orientation="Vertical" Gap="8" Width="150">
<Button>Button</Button> <Button>Button</Button>
<Button Foreground="White">Foreground</Button> <Button Foreground="White">Foreground</Button>
<Button Background="{StyleResource ThemeAccentBrush}">Background</Button> <Button Background="{DynamicResource ThemeAccentBrush}">Background</Button>
<Button IsEnabled="False">Disabled</Button> <Button IsEnabled="False">Disabled</Button>
<Button Content="Re-themed"> <Button Content="Re-themed">
<Button.Styles> <Button.Styles>
@ -27,9 +27,9 @@
<StackPanel Orientation="Vertical" Gap="8" Width="150"> <StackPanel Orientation="Vertical" Gap="8" Width="150">
<Button BorderThickness="0">No Border</Button> <Button BorderThickness="0">No Border</Button>
<Button BorderBrush="{StyleResource ThemeAccentBrush}">Border Color</Button> <Button BorderBrush="{DynamicResource ThemeAccentBrush}">Border Color</Button>
<Button BorderBrush="{StyleResource ThemeAccentBrush}" BorderThickness="4">Thick Border</Button> <Button BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="4">Thick Border</Button>
<Button BorderBrush="{StyleResource ThemeAccentBrush}" BorderThickness="4" IsEnabled="False">Disabled</Button> <Button BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="4" IsEnabled="False">Disabled</Button>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>

2
samples/ControlCatalog/Pages/ContextMenuPage.xaml

@ -7,7 +7,7 @@
Margin="0,16,0,0" Margin="0,16,0,0"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Gap="16"> Gap="16">
<Border Background="{StyleResource ThemeAccentBrush}" <Border Background="{DynamicResource ThemeAccentBrush}"
Padding="48,48,48,48"> Padding="48,48,48,48">
<Border.ContextMenu> <Border.ContextMenu>
<ContextMenu> <ContextMenu>

12
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -0,0 +1,12 @@
<UserControl xmlns="https://github.com/avaloniaui">
<StackPanel Orientation="Vertical" Gap="4" Margin="4">
<Button Name="OpenFile">Open File</Button>
<Button Name="SaveFile">Save File</Button>
<Button Name="SelectFolder">Select Folder</Button>
<StackPanel Orientation="Horizontal">
<CheckBox Name="IsModal" IsChecked="True"/>
<TextBlock>Modal to window</TextBlock>
</StackPanel>
<Button Name="DecoratedWindow">Decorated window</Button>
</StackPanel>
</UserControl>

46
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -0,0 +1,46 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
#pragma warning disable 4014
namespace ControlCatalog.Pages
{
public class DialogsPage : UserControl
{
public DialogsPage()
{
this.InitializeComponent();
this.FindControl<Button>("OpenFile").Click += delegate
{
new OpenFileDialog()
{
Title = "Open file"
}.ShowAsync(GetWindow());
};
this.FindControl<Button>("SaveFile").Click += delegate
{
new SaveFileDialog()
{
Title = "Save file"
}.ShowAsync(GetWindow());
};
this.FindControl<Button>("SelectFolder").Click += delegate
{
new OpenFolderDialog()
{
Title = "Select folder"
}.ShowAsync(GetWindow());
};
this.FindControl<Button>("DecoratedWindow").Click += delegate
{
new DecoratedWindow().Show();
};
}
Window GetWindow() => this.FindControl<CheckBox>("IsModal").IsChecked ? (Window)this.VisualRoot : null;
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

2
samples/ControlCatalog/Pages/DropDownPage.xaml

@ -14,7 +14,7 @@
<DropDown SelectedIndex="0"> <DropDown SelectedIndex="0">
<DropDownItem> <DropDownItem>
<Panel> <Panel>
<Rectangle Fill="{StyleResource ThemeAccentBrush}"/> <Rectangle Fill="{DynamicResource ThemeAccentBrush}"/>
<TextBlock Margin="8">Control Items</TextBlock> <TextBlock Margin="8">Control Items</TextBlock>
</Panel> </Panel>
</DropDownItem> </DropDownItem>

8
samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml

@ -10,10 +10,10 @@
RowDefinitions="24,Auto,24" RowDefinitions="24,Auto,24"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center"> VerticalAlignment="Center">
<Border Background="{StyleResource ThemeAccentBrush}" Grid.Column="1" Grid.Row="0"/> <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="1" Grid.Row="0"/>
<Border Background="{StyleResource ThemeAccentBrush}" Grid.Column="0" Grid.Row="1"/> <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="0" Grid.Row="1"/>
<Border Background="{StyleResource ThemeAccentBrush}" Grid.Column="2" Grid.Row="1"/> <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="2" Grid.Row="1"/>
<Border Background="{StyleResource ThemeAccentBrush}" Grid.Column="1" Grid.Row="2"/> <Border Background="{DynamicResource ThemeAccentBrush}" Grid.Column="1" Grid.Row="2"/>
<LayoutTransformControl Name="layoutTransform" Grid.Column="1" Grid.Row="1"> <LayoutTransformControl Name="layoutTransform" Grid.Column="1" Grid.Row="1">
<LayoutTransformControl.LayoutTransform> <LayoutTransformControl.LayoutTransform>

53
samples/ControlCatalog/Pages/ToolTipPage.xaml

@ -1,22 +1,41 @@
<UserControl xmlns="https://github.com/avaloniaui"> <UserControl xmlns="https://github.com/avaloniaui">
<StackPanel Orientation="Vertical" Gap="4"> <StackPanel Orientation="Vertical"
<TextBlock Classes="h1">ToolTip</TextBlock> Gap="4">
<TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock> <TextBlock Classes="h1">ToolTip</TextBlock>
<TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
<StackPanel Orientation="Horizontal" <Grid RowDefinitions="Auto,Auto"
ColumnDefinitions="Auto,Auto"
Margin="0,16,0,0" Margin="0,16,0,0"
HorizontalAlignment="Center" HorizontalAlignment="Center">
Gap="16"> <Border Grid.Column="0"
<Border Background="{StyleResource ThemeAccentBrush}" Grid.Row="1"
Padding="48,48,48,48"> Background="{StyleResource ThemeAccentBrush}"
<ToolTip.Tip> Margin="5"
<StackPanel> Padding="50"
<TextBlock Classes="h1">ToolTip</TextBlock> ToolTip.Tip="This is a ToolTip">
<TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock> <TextBlock>Hover Here</TextBlock>
</StackPanel> </Border>
</ToolTip.Tip> <CheckBox Grid.Column="1"
<TextBlock>Hover Here</TextBlock> Margin="5"
</Border> Grid.Row="0"
IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"
Content="ToolTip Open" />
<Border Name="Border"
Grid.Column="1"
Grid.Row="1"
Background="{StyleResource ThemeAccentBrush}"
Margin="5"
Padding="50"
ToolTip.Placement="Bottom">
<ToolTip.Tip>
<StackPanel>
<TextBlock Classes="h1">ToolTip</TextBlock>
<TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
</StackPanel>
</ToolTip.Tip>
<TextBlock>ToolTip bottom placement</TextBlock>
</Border>
</Grid>
</StackPanel> </StackPanel>
</StackPanel>
</UserControl> </UserControl>

4
samples/ControlCatalog/SideBar.xaml

@ -3,7 +3,7 @@
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<DockPanel> <DockPanel>
<ScrollViewer MinWidth="190" Background="{StyleResource ThemeAccentBrush}" DockPanel.Dock="Left"> <ScrollViewer MinWidth="190" Background="{DynamicResource ThemeAccentBrush}" DockPanel.Dock="Left">
<TabStrip Name="PART_TabStrip" <TabStrip Name="PART_TabStrip"
MemberSelector="{Static TabControl.HeaderSelector}" MemberSelector="{Static TabControl.HeaderSelector}"
Items="{TemplateBinding Items}" Items="{TemplateBinding Items}"
@ -35,6 +35,6 @@
</Style> </Style>
<Style Selector="TabControl.sidebar TabStripItem:selected"> <Style Selector="TabControl.sidebar TabStripItem:selected">
<Setter Property="Background" Value="{StyleResource ThemeAccentBrush2}"/> <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
</Style> </Style>
</Styles> </Styles>

2
samples/RenderTest/Pages/ClippingPage.xaml

@ -5,7 +5,7 @@
Width="100" Width="100"
Height="100" Height="100"
Clip="M 58.625 0.07421875 C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703 C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594 C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312 C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875 C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422 C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125 C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172 C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438 C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953 C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078 C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594 C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859 C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766 C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359 C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531 C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609 C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344 C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812 C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z "> Clip="M 58.625 0.07421875 C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703 C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594 C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312 C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875 C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422 C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125 C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172 C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438 C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953 C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078 C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594 C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859 C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766 C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359 C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531 C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609 C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344 C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812 C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z ">
<Border Name="clipChild" Background="{StyleResource ThemeAccentBrush}" Margin="4"> <Border Name="clipChild" Background="{DynamicResource ThemeAccentBrush}" Margin="4">
<!-- Setting opacity puts the TextBox on a new layer --> <!-- Setting opacity puts the TextBox on a new layer -->
<TextBox Text="Avalonia" Opacity="0.9" VerticalAlignment="Center"/> <TextBox Text="Avalonia" Opacity="0.9" VerticalAlignment="Center"/>
</Border> </Border>

8
samples/RenderTest/Pages/DrawingPage.xaml

@ -49,7 +49,7 @@
BorderThickness="1" BorderThickness="1"
BorderBrush="Gray" BorderBrush="Gray"
Margin="5"> Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}" /> <DrawingPresenter Drawing="{DynamicResource Bulb}" />
</Border> </Border>
<TextBlock Text="Fill" <TextBlock Text="Fill"
Margin="3" Margin="3"
@ -61,7 +61,7 @@
BorderThickness="1" BorderThickness="1"
BorderBrush="Gray" BorderBrush="Gray"
Margin="5"> Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}" <DrawingPresenter Drawing="{DynamicResource Bulb}"
Width="100" Width="100"
Height="50" Height="50"
Stretch="Fill" /> Stretch="Fill" />
@ -76,7 +76,7 @@
BorderThickness="1" BorderThickness="1"
BorderBrush="Gray" BorderBrush="Gray"
Margin="5"> Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}" <DrawingPresenter Drawing="{DynamicResource Bulb}"
Width="100" Width="100"
Height="50" Height="50"
Stretch="Uniform" /> Stretch="Uniform" />
@ -91,7 +91,7 @@
BorderThickness="1" BorderThickness="1"
BorderBrush="Gray" BorderBrush="Gray"
Margin="5"> Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}" <DrawingPresenter Drawing="{DynamicResource Bulb}"
Width="100" Width="100"
Height="50" Height="50"
Stretch="UniformToFill" /> Stretch="UniformToFill" />

1
samples/RenderTest/Program.cs

@ -18,6 +18,7 @@ namespace RenderTest
// again. // again.
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI()
.Start<MainWindow>(); .Start<MainWindow>();
} }

1
samples/RenderTest/RenderTest.csproj

@ -191,4 +191,5 @@
<Import Project="..\..\build\Serilog.Sinks.Trace.props" /> <Import Project="..\..\build\Serilog.Sinks.Trace.props" />
<Import Project="..\..\build\Splat.props" /> <Import Project="..\..\build\Splat.props" />
<Import Project="..\..\build\Rx.props" /> <Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
</Project> </Project>

4
samples/RenderTest/SideBar.xaml

@ -3,7 +3,7 @@
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<DockPanel> <DockPanel>
<ScrollViewer MinWidth="190" Background="{StyleResource ThemeAccentBrush}" DockPanel.Dock="Left"> <ScrollViewer MinWidth="190" Background="{DynamicResource ThemeAccentBrush}" DockPanel.Dock="Left">
<TabStrip Name="PART_TabStrip" <TabStrip Name="PART_TabStrip"
MemberSelector="{Static TabControl.HeaderSelector}" MemberSelector="{Static TabControl.HeaderSelector}"
Items="{TemplateBinding Items}" Items="{TemplateBinding Items}"
@ -35,6 +35,6 @@
</Style> </Style>
<Style Selector="TabControl.sidebar TabStripItem:selected"> <Style Selector="TabControl.sidebar TabStripItem:selected">
<Setter Property="Background" Value="{StyleResource ThemeAccentBrush2}"/> <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
</Style> </Style>
</Styles> </Styles>

10
samples/RenderTest/ViewModels/MainWindowViewModel.cs

@ -10,10 +10,8 @@ namespace RenderTest.ViewModels
public MainWindowViewModel() public MainWindowViewModel()
{ {
ToggleDrawDirtyRects = ReactiveCommand.Create(); ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawDirtyRects.Subscribe(_ => DrawDirtyRects = !DrawDirtyRects); ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps);
ToggleDrawFps = ReactiveCommand.Create();
ToggleDrawFps.Subscribe(_ => DrawFps = !DrawFps);
} }
public bool DrawDirtyRects public bool DrawDirtyRects
@ -28,7 +26,7 @@ namespace RenderTest.ViewModels
set { this.RaiseAndSetIfChanged(ref drawFps, value); } set { this.RaiseAndSetIfChanged(ref drawFps, value); }
} }
public ReactiveCommand<object> ToggleDrawDirtyRects { get; } public ReactiveCommand ToggleDrawDirtyRects { get; }
public ReactiveCommand<object> ToggleDrawFps { get; } public ReactiveCommand ToggleDrawFps { get; }
} }
} }

1
samples/VirtualizationTest/Program.cs

@ -17,6 +17,7 @@ namespace VirtualizationTest
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI()
.Start<MainWindow>(); .Start<MainWindow>();
} }

25
samples/VirtualizationTest/ViewModels/MainWindowViewModel.cs

@ -23,20 +23,15 @@ namespace VirtualizationTest.ViewModels
public MainWindowViewModel() public MainWindowViewModel()
{ {
this.WhenAnyValue(x => x.ItemCount).Subscribe(ResizeItems); this.WhenAnyValue(x => x.ItemCount).Subscribe(ResizeItems);
RecreateCommand = ReactiveCommand.Create(); RecreateCommand = ReactiveCommand.Create(() => Recreate());
RecreateCommand.Subscribe(_ => Recreate());
AddItemCommand = ReactiveCommand.Create(); AddItemCommand = ReactiveCommand.Create(() => AddItem());
AddItemCommand.Subscribe(_ => AddItem());
RemoveItemCommand = ReactiveCommand.Create(); RemoveItemCommand = ReactiveCommand.Create(() => Remove());
RemoveItemCommand.Subscribe(_ => Remove());
SelectFirstCommand = ReactiveCommand.Create(); SelectFirstCommand = ReactiveCommand.Create(() => SelectItem(0));
SelectFirstCommand.Subscribe(_ => SelectItem(0));
SelectLastCommand = ReactiveCommand.Create(); SelectLastCommand = ReactiveCommand.Create(() => SelectItem(Items.Count - 1));
SelectLastCommand.Subscribe(_ => SelectItem(Items.Count - 1));
} }
public string NewItemString public string NewItemString
@ -78,11 +73,11 @@ namespace VirtualizationTest.ViewModels
public IEnumerable<ItemVirtualizationMode> VirtualizationModes => public IEnumerable<ItemVirtualizationMode> VirtualizationModes =>
Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>(); Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>();
public ReactiveCommand<object> AddItemCommand { get; private set; } public ReactiveCommand AddItemCommand { get; private set; }
public ReactiveCommand<object> RecreateCommand { get; private set; } public ReactiveCommand RecreateCommand { get; private set; }
public ReactiveCommand<object> RemoveItemCommand { get; private set; } public ReactiveCommand RemoveItemCommand { get; private set; }
public ReactiveCommand<object> SelectFirstCommand { get; private set; } public ReactiveCommand SelectFirstCommand { get; private set; }
public ReactiveCommand<object> SelectLastCommand { get; private set; } public ReactiveCommand SelectLastCommand { get; private set; }
private void ResizeItems(int count) private void ResizeItems(int count)
{ {

1
samples/VirtualizationTest/VirtualizationTest.csproj

@ -158,4 +158,5 @@
<Import Project="..\..\build\Serilog.Sinks.Trace.props" /> <Import Project="..\..\build\Serilog.Sinks.Trace.props" />
<Import Project="..\..\build\Splat.props" /> <Import Project="..\..\build\Splat.props" />
<Import Project="..\..\build\Rx.props" /> <Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
</Project> </Project>

2
src/Avalonia.Animation/Avalonia.Animation.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

2
src/Avalonia.Base/Avalonia.Base.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
</PropertyGroup> </PropertyGroup>

3
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -47,6 +47,9 @@ namespace Avalonia
{ {
Dictionary<int, AvaloniaProperty> inner; Dictionary<int, AvaloniaProperty> inner;
// Ensure the type's static ctor has been run.
RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle);
if (_attached.TryGetValue(ownerType, out inner)) if (_attached.TryGetValue(ownerType, out inner))
{ {
return inner.Values; return inner.Values;

54
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@ -16,6 +16,7 @@ namespace Avalonia.Collections
/// <typeparam name="TKey">The type of the dictionary key.</typeparam> /// <typeparam name="TKey">The type of the dictionary key.</typeparam>
/// <typeparam name="TValue">The type of the dictionary value.</typeparam> /// <typeparam name="TValue">The type of the dictionary value.</typeparam>
public class AvaloniaDictionary<TKey, TValue> : IDictionary<TKey, TValue>, public class AvaloniaDictionary<TKey, TValue> : IDictionary<TKey, TValue>,
IDictionary,
INotifyCollectionChanged, INotifyCollectionChanged,
INotifyPropertyChanged INotifyPropertyChanged
{ {
@ -51,6 +52,16 @@ namespace Avalonia.Collections
/// <inheritdoc/> /// <inheritdoc/>
public ICollection<TValue> Values => _inner.Values; public ICollection<TValue> Values => _inner.Values;
bool IDictionary.IsFixedSize => ((IDictionary)_inner).IsFixedSize;
ICollection IDictionary.Keys => ((IDictionary)_inner).Keys;
ICollection IDictionary.Values => ((IDictionary)_inner).Values;
bool ICollection.IsSynchronized => ((IDictionary)_inner).IsSynchronized;
object ICollection.SyncRoot => ((IDictionary)_inner).SyncRoot;
/// <summary> /// <summary>
/// Gets or sets the named resource. /// Gets or sets the named resource.
/// </summary> /// </summary>
@ -89,6 +100,8 @@ namespace Avalonia.Collections
} }
} }
object IDictionary.this[object key] { get => ((IDictionary)_inner)[key]; set => ((IDictionary)_inner)[key] = value; }
/// <inheritdoc/> /// <inheritdoc/>
public void Add(TKey key, TValue value) public void Add(TKey key, TValue value)
{ {
@ -118,10 +131,7 @@ namespace Avalonia.Collections
} }
/// <inheritdoc/> /// <inheritdoc/>
public bool ContainsKey(TKey key) public bool ContainsKey(TKey key) => _inner.ContainsKey(key);
{
return _inner.ContainsKey(key);
}
/// <inheritdoc/> /// <inheritdoc/>
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
@ -130,21 +140,16 @@ namespace Avalonia.Collections
} }
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _inner.GetEnumerator();
{
return _inner.GetEnumerator();
}
/// <inheritdoc/> /// <inheritdoc/>
public bool Remove(TKey key) public bool Remove(TKey key)
{ {
TValue value; if (_inner.TryGetValue(key, out TValue value))
if (_inner.TryGetValue(key, out value))
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
if (CollectionChanged != null) if (CollectionChanged != null)
{ {
var e = new NotifyCollectionChangedEventArgs( var e = new NotifyCollectionChangedEventArgs(
@ -163,16 +168,13 @@ namespace Avalonia.Collections
} }
/// <inheritdoc/> /// <inheritdoc/>
public bool TryGetValue(TKey key, out TValue value) public bool TryGetValue(TKey key, out TValue value) => _inner.TryGetValue(key, out value);
{
return _inner.TryGetValue(key, out value);
}
/// <inheritdoc/> /// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator();
{
return _inner.GetEnumerator(); /// <inheritdoc/>
} void ICollection.CopyTo(Array array, int index) => ((ICollection)_inner).CopyTo(array, index);
/// <inheritdoc/> /// <inheritdoc/>
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
@ -192,6 +194,18 @@ namespace Avalonia.Collections
return Remove(item.Key); return Remove(item.Key);
} }
/// <inheritdoc/>
void IDictionary.Add(object key, object value) => Add((TKey)key, (TValue)value);
/// <inheritdoc/>
bool IDictionary.Contains(object key) => ((IDictionary) _inner).Contains(key);
/// <inheritdoc/>
IDictionaryEnumerator IDictionary.GetEnumerator() => ((IDictionary)_inner).GetEnumerator();
/// <inheritdoc/>
void IDictionary.Remove(object key) => Remove((TKey)key);
private void NotifyAdd(TKey key, TValue value) private void NotifyAdd(TKey key, TValue value)
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));

66
src/Avalonia.Controls/Application.cs

@ -29,7 +29,7 @@ namespace Avalonia
/// method. /// method.
/// - Tracks the lifetime of the application. /// - Tracks the lifetime of the application.
/// </remarks> /// </remarks>
public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IApplicationLifecycle public class Application : IApplicationLifecycle, IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IResourceNode
{ {
/// <summary> /// <summary>
/// The application-global data templates. /// The application-global data templates.
@ -39,6 +39,8 @@ namespace Avalonia
private readonly Lazy<IClipboard> _clipboard = private readonly Lazy<IClipboard> _clipboard =
new Lazy<IClipboard>(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))); new Lazy<IClipboard>(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)));
private readonly Styler _styler = new Styler(); private readonly Styler _styler = new Styler();
private Styles _styles;
private IResourceDictionary _resources;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Application"/> class. /// Initializes a new instance of the <see cref="Application"/> class.
@ -48,6 +50,9 @@ namespace Avalonia
OnExit += OnExiting; OnExit += OnExiting;
} }
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <summary> /// <summary>
/// Gets the current instance of the <see cref="Application"/> class. /// Gets the current instance of the <see cref="Application"/> class.
/// </summary> /// </summary>
@ -65,11 +70,7 @@ namespace Avalonia
/// <value> /// <value>
/// The application's global data templates. /// The application's global data templates.
/// </value> /// </value>
public DataTemplates DataTemplates public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates());
{
get { return _dataTemplates ?? (_dataTemplates = new DataTemplates()); }
set { _dataTemplates = value; }
}
/// <summary> /// <summary>
/// Gets the application's focus manager. /// Gets the application's focus manager.
@ -100,6 +101,34 @@ namespace Avalonia
/// </summary> /// </summary>
public IClipboard Clipboard => _clipboard.Value; public IClipboard Clipboard => _clipboard.Value;
/// <summary>
/// Gets the application's global resource dictionary.
/// </summary>
public IResourceDictionary Resources
{
get => _resources ?? (Resources = new ResourceDictionary());
set
{
Contract.Requires<ArgumentNullException>(value != null);
var hadResources = false;
if (_resources != null)
{
hadResources = _resources.Count > 0;
_resources.ResourcesChanged -= ResourcesChanged;
}
_resources = value;
_resources.ResourcesChanged += ResourcesChanged;
if (hadResources || _resources.Count > 0)
{
ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
}
}
}
/// <summary> /// <summary>
/// Gets the application's global styles. /// Gets the application's global styles.
/// </summary> /// </summary>
@ -109,13 +138,25 @@ namespace Avalonia
/// <remarks> /// <remarks>
/// Global styles apply to all windows in the application. /// Global styles apply to all windows in the application.
/// </remarks> /// </remarks>
public Styles Styles { get; } = new Styles(); public Styles Styles => _styles ?? (_styles = new Styles());
/// <inheritdoc/>
bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;
/// <summary> /// <summary>
/// Gets the styling parent of the application, which is null. /// Gets the styling parent of the application, which is null.
/// </summary> /// </summary>
IStyleHost IStyleHost.StylingParent => null; IStyleHost IStyleHost.StylingParent => null;
/// <inheritdoc/>
bool IStyleHost.IsStylesInitialized => _styles != null;
/// <inheritdoc/>
bool IResourceProvider.HasResources => _resources?.Count > 0;
/// <inheritdoc/>
IResourceNode IResourceNode.ResourceParent => null;
/// <summary> /// <summary>
/// Initializes the application by loading XAML etc. /// Initializes the application by loading XAML etc.
/// </summary> /// </summary>
@ -142,13 +183,20 @@ namespace Avalonia
{ {
OnExit?.Invoke(this, EventArgs.Empty); OnExit?.Invoke(this, EventArgs.Empty);
} }
/// <inheritdoc/>
bool IResourceProvider.TryGetResource(string key, out object value)
{
value = null;
return (_resources?.TryGetResource(key, out value) ?? false) ||
Styles.TryGetResource(key, out value);
}
/// <summary> /// <summary>
/// Sent when the application is exiting. /// Sent when the application is exiting.
/// </summary> /// </summary>
public event EventHandler OnExit; public event EventHandler OnExit;
/// <summary> /// <summary>
/// Called when the application is exiting. /// Called when the application is exiting.
/// </summary> /// </summary>

2
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

70
src/Avalonia.Controls/Button.cs

@ -2,13 +2,10 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Linq;
using System.Windows.Input; using System.Windows.Input;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Rendering;
using Avalonia.VisualTree;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -68,19 +65,22 @@ namespace Avalonia.Controls
/// Defines the <see cref="Click"/> event. /// Defines the <see cref="Click"/> event.
/// </summary> /// </summary>
public static readonly RoutedEvent<RoutedEventArgs> ClickEvent = public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
RoutedEvent.Register<Button, RoutedEventArgs>("Click", RoutingStrategies.Bubble); RoutedEvent.Register<Button, RoutedEventArgs>(nameof(Click), RoutingStrategies.Bubble);
private ICommand _command; private ICommand _command;
public static readonly StyledProperty<bool> IsPressedProperty =
AvaloniaProperty.Register<Button, bool>(nameof(IsPressed));
/// <summary> /// <summary>
/// Initializes static members of the <see cref="Button"/> class. /// Initializes static members of the <see cref="Button"/> class.
/// </summary> /// </summary>
static Button() static Button()
{ {
FocusableProperty.OverrideDefaultValue(typeof(Button), true); FocusableProperty.OverrideDefaultValue(typeof(Button), true);
ClickEvent.AddClassHandler<Button>(x => x.OnClick);
CommandProperty.Changed.Subscribe(CommandChanged); CommandProperty.Changed.Subscribe(CommandChanged);
IsDefaultProperty.Changed.Subscribe(IsDefaultChanged); IsDefaultProperty.Changed.Subscribe(IsDefaultChanged);
PseudoClass(IsPressedProperty, ":pressed");
} }
/// <summary> /// <summary>
@ -138,6 +138,12 @@ namespace Avalonia.Controls
set { SetValue(IsDefaultProperty, value); } set { SetValue(IsDefaultProperty, value); }
} }
public bool IsPressed
{
get { return GetValue(IsPressedProperty); }
private set { SetValue(IsPressedProperty, value); }
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
@ -145,9 +151,7 @@ namespace Avalonia.Controls
if (IsDefault) if (IsDefault)
{ {
var inputElement = e.Root as IInputElement; if (e.Root is IInputElement inputElement)
if (inputElement != null)
{ {
ListenForDefault(inputElement); ListenForDefault(inputElement);
} }
@ -159,16 +163,16 @@ namespace Avalonia.Controls
{ {
if (e.Key == Key.Enter) if (e.Key == Key.Enter)
{ {
RaiseClickEvent(); OnClick();
e.Handled = true; e.Handled = true;
} }
else if (e.Key == Key.Space) else if (e.Key == Key.Space)
{ {
if (ClickMode == ClickMode.Press) if (ClickMode == ClickMode.Press)
{ {
RaiseClickEvent(); OnClick();
} }
IsPressed = true;
e.Handled = true; e.Handled = true;
} }
@ -182,9 +186,9 @@ namespace Avalonia.Controls
{ {
if (ClickMode == ClickMode.Release) if (ClickMode == ClickMode.Release)
{ {
RaiseClickEvent(); OnClick();
} }
IsPressed = false;
e.Handled = true; e.Handled = true;
} }
} }
@ -196,9 +200,7 @@ namespace Avalonia.Controls
if (IsDefault) if (IsDefault)
{ {
var inputElement = e.Root as IInputElement; if (e.Root is IInputElement inputElement)
if (inputElement != null)
{ {
StopListeningForDefault(inputElement); StopListeningForDefault(inputElement);
} }
@ -208,9 +210,11 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Invokes the <see cref="Click"/> event. /// Invokes the <see cref="Click"/> event.
/// </summary> /// </summary>
/// <param name="e">The event args.</param> protected virtual void OnClick()
protected virtual void OnClick(RoutedEventArgs e)
{ {
var e = new RoutedEventArgs(ClickEvent);
RaiseEvent(e);
if (Command != null) if (Command != null)
{ {
Command.Execute(CommandParameter); Command.Execute(CommandParameter);
@ -225,13 +229,13 @@ namespace Avalonia.Controls
if (e.MouseButton == MouseButton.Left) if (e.MouseButton == MouseButton.Left)
{ {
PseudoClasses.Add(":pressed");
e.Device.Capture(this); e.Device.Capture(this);
IsPressed = true;
e.Handled = true; e.Handled = true;
if (ClickMode == ClickMode.Press) if (ClickMode == ClickMode.Press)
{ {
RaiseClickEvent(); OnClick();
} }
} }
} }
@ -244,12 +248,12 @@ namespace Avalonia.Controls
if (e.MouseButton == MouseButton.Left) if (e.MouseButton == MouseButton.Left)
{ {
e.Device.Capture(null); e.Device.Capture(null);
PseudoClasses.Remove(":pressed"); IsPressed = false;
e.Handled = true; e.Handled = true;
if (ClickMode == ClickMode.Release && new Rect(Bounds.Size).Contains(e.GetPosition(this))) if (ClickMode == ClickMode.Release && new Rect(Bounds.Size).Contains(e.GetPosition(this)))
{ {
RaiseClickEvent(); OnClick();
} }
} }
} }
@ -272,9 +276,7 @@ namespace Avalonia.Controls
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private static void CommandChanged(AvaloniaPropertyChangedEventArgs e) private static void CommandChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var button = e.Sender as Button; if (e.Sender is Button button)
if (button != null)
{ {
var oldCommand = e.OldValue as ICommand; var oldCommand = e.OldValue as ICommand;
var newCommand = e.NewValue as ICommand; var newCommand = e.NewValue as ICommand;
@ -301,9 +303,8 @@ namespace Avalonia.Controls
{ {
var button = e.Sender as Button; var button = e.Sender as Button;
var isDefault = (bool)e.NewValue; var isDefault = (bool)e.NewValue;
var inputRoot = button?.VisualRoot as IInputElement;
if (inputRoot != null) if (button?.VisualRoot is IInputElement inputRoot)
{ {
if (isDefault) if (isDefault)
{ {
@ -346,19 +347,6 @@ namespace Avalonia.Controls
root.RemoveHandler(KeyDownEvent, RootKeyDown); root.RemoveHandler(KeyDownEvent, RootKeyDown);
} }
/// <summary>
/// Raises the <see cref="Click"/> event.
/// </summary>
private void RaiseClickEvent()
{
RoutedEventArgs click = new RoutedEventArgs
{
RoutedEvent = ClickEvent,
};
RaiseEvent(click);
}
/// <summary> /// <summary>
/// Called when a key is pressed on the input root and the button <see cref="IsDefault"/>. /// Called when a key is pressed on the input root and the button <see cref="IsDefault"/>.
/// </summary> /// </summary>
@ -368,7 +356,7 @@ namespace Avalonia.Controls
{ {
if (e.Key == Key.Enter && IsVisible && IsEnabled) if (e.Key == Key.Enter && IsVisible && IsEnabled)
{ {
RaiseClickEvent(); OnClick();
} }
} }
} }

144
src/Avalonia.Controls/Control.cs

@ -97,6 +97,7 @@ namespace Avalonia.Controls
private bool _isAttachedToLogicalTree; private bool _isAttachedToLogicalTree;
private IAvaloniaList<ILogical> _logicalChildren; private IAvaloniaList<ILogical> _logicalChildren;
private INameScope _nameScope; private INameScope _nameScope;
private IResourceDictionary _resources;
private Styles _styles; private Styles _styles;
private bool _styled; private bool _styled;
private Subject<IStyleable> _styleDetach = new Subject<IStyleable>(); private Subject<IStyleable> _styleDetach = new Subject<IStyleable>();
@ -153,6 +154,11 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
public event EventHandler Initialized; public event EventHandler Initialized;
/// <summary>
/// Occurs when a resource in this control or a parent control has changed.
/// </summary>
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <summary> /// <summary>
/// Gets or sets the name of the control. /// Gets or sets the name of the control.
/// </summary> /// </summary>
@ -243,11 +249,7 @@ namespace Avalonia.Controls
/// Each control may define data templates which are applied to the control itself and its /// Each control may define data templates which are applied to the control itself and its
/// children. /// children.
/// </remarks> /// </remarks>
public DataTemplates DataTemplates public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates());
{
get { return _dataTemplates ?? (_dataTemplates = new DataTemplates()); }
set { _dataTemplates = value; }
}
/// <summary> /// <summary>
/// Gets a value that indicates whether the element has finished initialization. /// Gets a value that indicates whether the element has finished initialization.
@ -259,7 +261,7 @@ namespace Avalonia.Controls
public bool IsInitialized { get; private set; } public bool IsInitialized { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the styles for the control. /// Gets the styles for the control.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Styles for the entire application are added to the Application.Styles collection, but /// Styles for the entire application are added to the Application.Styles collection, but
@ -268,8 +270,29 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
public Styles Styles public Styles Styles
{ {
get { return _styles ?? (_styles = new Styles()); } get { return _styles ?? (Styles = new Styles()); }
set { _styles = value; } set
{
Contract.Requires<ArgumentNullException>(value != null);
if (_styles != value)
{
if (_styles != null)
{
(_styles as ISetStyleParent)?.SetParent(null);
_styles.ResourcesChanged -= ThisResourcesChanged;
}
_styles = value;
if (value is ISetStyleParent setParent && setParent.ResourceParent == null)
{
setParent.SetParent(this);
}
_styles.ResourcesChanged += ThisResourcesChanged;
}
}
} }
/// <summary> /// <summary>
@ -286,6 +309,34 @@ namespace Avalonia.Controls
set { SetValue(ContextMenuProperty, value); } set { SetValue(ContextMenuProperty, value); }
} }
/// <summary>
/// Gets or sets the control's resource dictionary.
/// </summary>
public IResourceDictionary Resources
{
get => _resources ?? (Resources = new ResourceDictionary());
set
{
Contract.Requires<ArgumentNullException>(value != null);
var hadResources = false;
if (_resources != null)
{
hadResources = _resources.Count > 0;
_resources.ResourcesChanged -= ThisResourcesChanged;
}
_resources = value;
_resources.ResourcesChanged += ThisResourcesChanged;
if (hadResources || _resources.Count > 0)
{
((ILogical)this).NotifyResourcesChanged(new ResourcesChangedEventArgs());
}
}
}
/// <summary> /// <summary>
/// Gets or sets a user-defined object attached to the control. /// Gets or sets a user-defined object attached to the control.
/// </summary> /// </summary>
@ -304,6 +355,35 @@ namespace Avalonia.Controls
internal set { SetValue(TemplatedParentProperty, value); } internal set { SetValue(TemplatedParentProperty, value); }
} }
/// <summary>
/// Gets the control's logical children.
/// </summary>
protected IAvaloniaList<ILogical> LogicalChildren
{
get
{
if (_logicalChildren == null)
{
var list = new AvaloniaList<ILogical>();
list.ResetBehavior = ResetBehavior.Remove;
list.Validate = ValidateLogicalChild;
list.CollectionChanged += LogicalChildrenCollectionChanged;
_logicalChildren = list;
}
return _logicalChildren;
}
}
/// <inheritdoc/>
bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;
/// <summary>
/// Gets the <see cref="Classes"/> collection in a form that allows adding and removing
/// pseudoclasses.
/// </summary>
protected IPseudoClasses PseudoClasses => Classes;
/// <summary> /// <summary>
/// Gets a value indicating whether the element is attached to a rooted logical tree. /// Gets a value indicating whether the element is attached to a rooted logical tree.
/// </summary> /// </summary>
@ -319,6 +399,12 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
IAvaloniaReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren; IAvaloniaReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren;
/// <inheritdoc/>
bool IResourceProvider.HasResources => _resources?.Count > 0 || Styles.HasResources;
/// <inheritdoc/>
IResourceNode IResourceNode.ResourceParent => ((IStyleHost)this).StylingParent as IResourceNode;
/// <inheritdoc/> /// <inheritdoc/>
IAvaloniaReadOnlyList<string> IStyleable.Classes => Classes; IAvaloniaReadOnlyList<string> IStyleable.Classes => Classes;
@ -336,6 +422,9 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
IObservable<IStyleable> IStyleable.StyleDetach => _styleDetach; IObservable<IStyleable> IStyleable.StyleDetach => _styleDetach;
/// <inheritdoc/>
bool IStyleHost.IsStylesInitialized => _styles != null;
/// <inheritdoc/> /// <inheritdoc/>
IStyleHost IStyleHost.StylingParent => (IStyleHost)InheritanceParent; IStyleHost IStyleHost.StylingParent => (IStyleHost)InheritanceParent;
@ -392,31 +481,24 @@ namespace Avalonia.Controls
this.OnDetachedFromLogicalTreeCore(e); this.OnDetachedFromLogicalTreeCore(e);
} }
/// <summary> /// <inheritdoc/>
/// Gets the control's logical children. void ILogical.NotifyResourcesChanged(ResourcesChangedEventArgs e)
/// </summary>
protected IAvaloniaList<ILogical> LogicalChildren
{ {
get ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
{
if (_logicalChildren == null)
{
var list = new AvaloniaList<ILogical>();
list.ResetBehavior = ResetBehavior.Remove;
list.Validate = ValidateLogicalChild;
list.CollectionChanged += LogicalChildrenCollectionChanged;
_logicalChildren = list;
}
return _logicalChildren; foreach (var child in LogicalChildren)
{
child.NotifyResourcesChanged(e);
} }
} }
/// <summary> /// <inheritdoc/>
/// Gets the <see cref="Classes"/> collection in a form that allows adding and removing bool IResourceProvider.TryGetResource(string key, out object value)
/// pseudoclasses. {
/// </summary> value = null;
protected IPseudoClasses PseudoClasses => Classes; return (_resources?.TryGetResource(key, out value) ?? false) ||
(_styles?.TryGetResource(key, out value) ?? false);
}
/// <summary> /// <summary>
/// Sets the control's logical parent. /// Sets the control's logical parent.
@ -452,6 +534,7 @@ namespace Avalonia.Controls
} }
_parent = (IControl)parent; _parent = (IControl)parent;
((ILogical)this).NotifyResourcesChanged(new ResourcesChangedEventArgs());
if (_parent is IStyleRoot || _parent?.IsAttachedToLogicalTree == true || this is IStyleRoot) if (_parent is IStyleRoot || _parent?.IsAttachedToLogicalTree == true || this is IStyleRoot)
{ {
@ -843,5 +926,10 @@ namespace Avalonia.Controls
} }
} }
} }
private void ThisResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
((ILogical)this).NotifyResourcesChanged(e);
}
} }
} }

2
src/Avalonia.Controls/DropDown.cs

@ -120,7 +120,7 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerPressed(PointerPressedEventArgs e)
{ {
if (!IsDropDownOpen && ((IVisual)e.Source).GetVisualRoot() != typeof(PopupRoot)) if (!IsDropDownOpen && ((IVisual)e.Source).GetVisualRoot() is PopupRoot)
{ {
IsDropDownOpen = true; IsDropDownOpen = true;
e.Handled = true; e.Handled = true;

15
src/Avalonia.Controls/IControl.cs

@ -14,7 +14,15 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Interface for Avalonia controls. /// Interface for Avalonia controls.
/// </summary> /// </summary>
public interface IControl : IVisual, ILogical, ILayoutable, IInputElement, INamed, IStyleable, IStyleHost public interface IControl : IVisual,
IDataTemplateHost,
ILogical,
ILayoutable,
IInputElement,
INamed,
IResourceNode,
IStyleable,
IStyleHost
{ {
/// <summary> /// <summary>
/// Occurs when the control has finished initialization. /// Occurs when the control has finished initialization.
@ -31,11 +39,6 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
object DataContext { get; set; } object DataContext { get; set; }
/// <summary>
/// Gets the data templates for the control.
/// </summary>
DataTemplates DataTemplates { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether the element has finished initialization. /// Gets a value that indicates whether the element has finished initialization.
/// </summary> /// </summary>

6
src/Avalonia.Controls/IGlobalDataTemplates.cs

@ -8,11 +8,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the application-global data templates. /// Defines the application-global data templates.
/// </summary> /// </summary>
public interface IGlobalDataTemplates public interface IGlobalDataTemplates : IDataTemplateHost
{ {
/// <summary>
/// Gets the application-global data templates.
/// </summary>
DataTemplates DataTemplates { get; }
} }
} }

7
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -31,7 +31,7 @@ namespace Avalonia.Platform
IDisposable ShowDialog(); IDisposable ShowDialog();
/// <summary> /// <summary>
/// Enables of disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary> /// </summary>
void SetSystemDecorations(bool enabled); void SetSystemDecorations(bool enabled);
@ -39,5 +39,10 @@ namespace Avalonia.Platform
/// Sets the icon of this window. /// Sets the icon of this window.
/// </summary> /// </summary>
void SetIcon(IWindowIconImpl icon); void SetIcon(IWindowIconImpl icon);
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
void ShowTaskbarIcon(bool value);
} }
} }

2
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -115,7 +115,7 @@ namespace Avalonia.Controls.Presenters
if (_highlightBrush == null) if (_highlightBrush == null)
{ {
_highlightBrush = (IBrush)this.FindStyleResource("HighlightBrush"); _highlightBrush = (IBrush)this.FindResource("HighlightBrush");
} }
foreach (var rect in rects) foreach (var rect in rects)

26
src/Avalonia.Controls/Primitives/Popup.cs

@ -277,7 +277,7 @@ namespace Avalonia.Controls.Primitives
{ {
base.OnDetachedFromLogicalTree(e); base.OnDetachedFromLogicalTree(e);
_topLevel = null; _topLevel = null;
if (_popupRoot != null) if (_popupRoot != null)
{ {
((ISetLogicalParent)_popupRoot).SetParent(null); ((ISetLogicalParent)_popupRoot).SetParent(null);
@ -327,34 +327,40 @@ namespace Avalonia.Controls.Primitives
/// </summary> /// </summary>
/// <returns>The popup's position in screen coordinates.</returns> /// <returns>The popup's position in screen coordinates.</returns>
protected virtual Point GetPosition() protected virtual Point GetPosition()
{
return GetPosition(PlacementTarget ?? this.GetVisualParent<Control>(), PlacementMode, PopupRoot,
HorizontalOffset, VerticalOffset);
}
internal static Point GetPosition(Control target, PlacementMode placement, PopupRoot popupRoot, double horizontalOffset, double verticalOffset)
{ {
var zero = default(Point); var zero = default(Point);
var mode = PlacementMode; var mode = placement;
var target = PlacementTarget ?? this.GetVisualParent<Control>();
if (target?.GetVisualRoot() == null) if (target?.GetVisualRoot() == null)
{ {
mode = PlacementMode.Pointer; mode = PlacementMode.Pointer;
} }
switch (mode) switch (mode)
{ {
case PlacementMode.Pointer: case PlacementMode.Pointer:
if(PopupRoot != null) if (popupRoot != null)
{ {
// Scales the Horizontal and Vertical offset to screen co-ordinates. // Scales the Horizontal and Vertical offset to screen co-ordinates.
var screenOffset = new Point(HorizontalOffset * (PopupRoot as ILayoutRoot).LayoutScaling, VerticalOffset * (PopupRoot as ILayoutRoot).LayoutScaling); var screenOffset = new Point(horizontalOffset * (popupRoot as ILayoutRoot).LayoutScaling,
return (((IInputRoot)PopupRoot)?.MouseDevice?.Position ?? default(Point)) + screenOffset; verticalOffset * (popupRoot as ILayoutRoot).LayoutScaling);
return (((IInputRoot)popupRoot)?.MouseDevice?.Position ?? default(Point)) + screenOffset;
} }
return default(Point); return default(Point);
case PlacementMode.Bottom: case PlacementMode.Bottom:
return target?.PointToScreen(new Point(0 + horizontalOffset, target.Bounds.Height + verticalOffset)) ??
return target?.PointToScreen(new Point(0 + HorizontalOffset, target.Bounds.Height + VerticalOffset)) ?? zero; zero;
case PlacementMode.Right: case PlacementMode.Right:
return target?.PointToScreen(new Point(target.Bounds.Width + HorizontalOffset, 0 + VerticalOffset)) ?? zero; return target?.PointToScreen(new Point(target.Bounds.Width + horizontalOffset, 0 + verticalOffset)) ?? zero;
default: default:
throw new InvalidOperationException("Invalid value for Popup.PlacementMode"); throw new InvalidOperationException("Invalid value for Popup.PlacementMode");

24
src/Avalonia.Controls/Primitives/RangeBase.cs

@ -38,6 +38,18 @@ namespace Avalonia.Controls.Primitives
o => o.Value, o => o.Value,
(o, v) => o.Value = v); (o, v) => o.Value = v);
/// <summary>
/// Defines the <see cref="SmallChange"/> property.
/// </summary>
public static readonly StyledProperty<double> SmallChangeProperty =
AvaloniaProperty.Register<RangeBase, double>(nameof(SmallChange), 0.1);
/// <summary>
/// Defines the <see cref="LargeChange"/> property.
/// </summary>
public static readonly StyledProperty<double> LargeChangeProperty =
AvaloniaProperty.Register<RangeBase, double>(nameof(LargeChange), 1);
private double _minimum; private double _minimum;
private double _maximum = 100.0; private double _maximum = 100.0;
private double _value; private double _value;
@ -103,6 +115,18 @@ namespace Avalonia.Controls.Primitives
} }
} }
public double SmallChange
{
get => GetValue(SmallChangeProperty);
set => SetValue(SmallChangeProperty, value);
}
public double LargeChange
{
get => GetValue(LargeChangeProperty);
set => SetValue(LargeChangeProperty, value);
}
/// <summary> /// <summary>
/// Throws an exception if the double valus is NaN or Inf. /// Throws an exception if the double valus is NaN or Inf.
/// </summary> /// </summary>

103
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -5,6 +5,7 @@ using System;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
@ -31,13 +32,18 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<Orientation> OrientationProperty = public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation)); AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation));
private Button _lineUpButton;
private Button _lineDownButton;
private Button _pageUpButton;
private Button _pageDownButton;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ScrollBar"/> class. /// Initializes static members of the <see cref="ScrollBar"/> class.
/// </summary> /// </summary>
static ScrollBar() static ScrollBar()
{ {
PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Vertical, ":vertical"); PseudoClass(OrientationProperty, o => o == Orientation.Vertical, ":vertical");
PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal"); PseudoClass(OrientationProperty, o => o == Orientation.Horizontal, ":horizontal");
} }
/// <summary> /// <summary>
@ -97,12 +103,101 @@ namespace Avalonia.Controls.Primitives
return false; return false;
case ScrollBarVisibility.Auto: case ScrollBarVisibility.Auto:
var viewportSize = ViewportSize; return double.IsNaN(ViewportSize) || Maximum > 0;
return double.IsNaN(viewportSize) || viewportSize < Maximum - Minimum;
default: default:
throw new InvalidOperationException("Invalid value for ScrollBar.Visibility."); throw new InvalidOperationException("Invalid value for ScrollBar.Visibility.");
} }
} }
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
if (_lineUpButton != null)
{
_lineUpButton.Click -= LineUpClick;
}
if (_lineDownButton != null)
{
_lineDownButton.Click -= LineDownClick;
}
if (_pageUpButton != null)
{
_pageUpButton.Click -= PageUpClick;
}
if (_pageDownButton != null)
{
_pageDownButton.Click -= PageDownClick;
}
_lineUpButton = e.NameScope.Find<Button>("PART_LineUpButton");
_lineDownButton = e.NameScope.Find<Button>("PART_LineDownButton");
_pageUpButton = e.NameScope.Find<Button>("PART_PageUpButton");
_pageDownButton = e.NameScope.Find<Button>("PART_PageDownButton");
if (_lineUpButton != null)
{
_lineUpButton.Click += LineUpClick;
}
if (_lineDownButton != null)
{
_lineDownButton.Click += LineDownClick;
}
if (_pageUpButton != null)
{
_pageUpButton.Click += PageUpClick;
}
if (_pageDownButton != null)
{
_pageDownButton.Click += PageDownClick;
}
}
private void LineUpClick(object sender, RoutedEventArgs e)
{
SmallDecrement();
}
private void LineDownClick(object sender, RoutedEventArgs e)
{
SmallIncrement();
}
private void PageUpClick(object sender, RoutedEventArgs e)
{
LargeDecrement();
}
private void PageDownClick(object sender, RoutedEventArgs e)
{
LargeIncrement();
}
private void SmallDecrement()
{
Value = Math.Max(Value - SmallChange * ViewportSize, Minimum);
}
private void SmallIncrement()
{
Value = Math.Min(Value + SmallChange * ViewportSize, Maximum);
}
private void LargeDecrement()
{
Value = Math.Max(Value - LargeChange * ViewportSize, Minimum);
}
private void LargeIncrement()
{
Value = Math.Min(Value + LargeChange * ViewportSize, Maximum);
}
} }
} }

4
src/Avalonia.Controls/Primitives/ToggleButton.cs

@ -29,10 +29,10 @@ namespace Avalonia.Controls.Primitives
set { SetAndRaise(IsCheckedProperty, ref _isChecked, value); } set { SetAndRaise(IsCheckedProperty, ref _isChecked, value); }
} }
protected override void OnClick(RoutedEventArgs e) protected override void OnClick()
{ {
Toggle(); Toggle();
base.OnClick(e); base.OnClick();
} }
protected virtual void Toggle() protected virtual void Toggle()

102
src/Avalonia.Controls/Primitives/Track.cs

@ -10,7 +10,7 @@ namespace Avalonia.Controls.Primitives
public class Track : Control public class Track : Control
{ {
public static readonly DirectProperty<Track, double> MinimumProperty = public static readonly DirectProperty<Track, double> MinimumProperty =
RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o,v) => o.Minimum = v); RangeBase.MinimumProperty.AddOwner<Track>(o => o.Minimum, (o, v) => o.Minimum = v);
public static readonly DirectProperty<Track, double> MaximumProperty = public static readonly DirectProperty<Track, double> MaximumProperty =
RangeBase.MaximumProperty.AddOwner<Track>(o => o.Maximum, (o, v) => o.Maximum = v); RangeBase.MaximumProperty.AddOwner<Track>(o => o.Maximum, (o, v) => o.Maximum = v);
@ -25,7 +25,13 @@ namespace Avalonia.Controls.Primitives
ScrollBar.OrientationProperty.AddOwner<Track>(); ScrollBar.OrientationProperty.AddOwner<Track>();
public static readonly StyledProperty<Thumb> ThumbProperty = public static readonly StyledProperty<Thumb> ThumbProperty =
AvaloniaProperty.Register<Track, Thumb>("Thumb"); AvaloniaProperty.Register<Track, Thumb>(nameof(Thumb));
public static readonly StyledProperty<Button> IncreaseButtonProperty =
AvaloniaProperty.Register<Track, Button>(nameof(IncreaseButton));
public static readonly StyledProperty<Button> DecreaseButtonProperty =
AvaloniaProperty.Register<Track, Button>(nameof(DecreaseButton));
private double _minimum; private double _minimum;
private double _maximum = 100.0; private double _maximum = 100.0;
@ -34,6 +40,8 @@ namespace Avalonia.Controls.Primitives
static Track() static Track()
{ {
ThumbProperty.Changed.AddClassHandler<Track>(x => x.ThumbChanged); ThumbProperty.Changed.AddClassHandler<Track>(x => x.ThumbChanged);
IncreaseButtonProperty.Changed.AddClassHandler<Track>(x => x.ButtonChanged);
DecreaseButtonProperty.Changed.AddClassHandler<Track>(x => x.ButtonChanged);
AffectsArrange(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty); AffectsArrange(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
} }
@ -74,6 +82,18 @@ namespace Avalonia.Controls.Primitives
set { SetValue(ThumbProperty, value); } set { SetValue(ThumbProperty, value); }
} }
public Button IncreaseButton
{
get { return GetValue(IncreaseButtonProperty); }
set { SetValue(IncreaseButtonProperty, value); }
}
public Button DecreaseButton
{
get { return GetValue(DecreaseButtonProperty); }
set { SetValue(DecreaseButtonProperty, value); }
}
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var thumb = Thumb; var thumb = Thumb;
@ -98,34 +118,54 @@ namespace Avalonia.Controls.Primitives
protected override Size ArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize)
{ {
var thumb = Thumb; var thumb = Thumb;
var increaseButton = IncreaseButton;
var decreaseButton = DecreaseButton;
if (thumb != null) var range = Maximum - Minimum;
var offset = Math.Min(Value - Minimum, range);
var viewportSize = ViewportSize;
var extent = range + viewportSize;
if (Orientation == Orientation.Horizontal)
{ {
var range = Maximum - Minimum; var thumbWidth = double.IsNaN(viewportSize) ? thumb?.DesiredSize.Width ?? 0 : finalSize.Width * viewportSize / extent;
var thumbFraction = ViewportSize / range; var remaining = finalSize.Width - thumbWidth;
var valueFraction = (Value - Minimum) / range; var firstWidth = range <= 0 ? 0 : remaining * offset / range;
if (double.IsNaN(valueFraction) || double.IsInfinity(valueFraction)) if (decreaseButton != null)
{ {
valueFraction = 0; decreaseButton.Arrange(new Rect(0, 0, firstWidth, finalSize.Height));
thumbFraction = 1;
} }
else if (double.IsNaN(thumbFraction) || double.IsInfinity(thumbFraction))
if (thumb != null)
{ {
thumbFraction = 0; thumb.Arrange(new Rect(firstWidth, 0, thumbWidth, finalSize.Height));
} }
if (Orientation == Orientation.Horizontal) if (increaseButton != null)
{ {
var width = Math.Max(finalSize.Width * thumbFraction, thumb.MinWidth); increaseButton.Arrange(new Rect(firstWidth + thumbWidth, 0, remaining - firstWidth, finalSize.Height));
var x = (finalSize.Width - width) * valueFraction;
thumb.Arrange(new Rect(x, 0, width, finalSize.Height));
} }
else }
else
{
var thumbHeight = double.IsNaN(viewportSize) ? thumb?.DesiredSize.Height ?? 0 : finalSize.Height * viewportSize / extent;
var remaining = finalSize.Height - thumbHeight;
var firstHeight = range <= 0 ? 0 : remaining * offset / range;
if (decreaseButton != null)
{ {
var height = Math.Max(finalSize.Height * thumbFraction, thumb.MinHeight); decreaseButton.Arrange(new Rect(0, 0, finalSize.Width, firstHeight));
var y = (finalSize.Height - height) * valueFraction; }
thumb.Arrange(new Rect(0, y, finalSize.Width, height));
if (thumb != null)
{
thumb.Arrange(new Rect(0, firstHeight, finalSize.Width, thumbHeight));
}
if (increaseButton != null)
{
increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, remaining - firstHeight));
} }
} }
@ -140,10 +180,10 @@ namespace Avalonia.Controls.Primitives
if (oldThumb != null) if (oldThumb != null)
{ {
oldThumb.DragDelta -= ThumbDragged; oldThumb.DragDelta -= ThumbDragged;
}
LogicalChildren.Clear(); LogicalChildren.Remove(oldThumb);
VisualChildren.Clear(); VisualChildren.Remove(oldThumb);
}
if (newThumb != null) if (newThumb != null)
{ {
@ -153,6 +193,24 @@ namespace Avalonia.Controls.Primitives
} }
} }
private void ButtonChanged(AvaloniaPropertyChangedEventArgs e)
{
var oldButton = (Button)e.OldValue;
var newButton = (Button)e.NewValue;
if (oldButton != null)
{
LogicalChildren.Remove(oldButton);
VisualChildren.Remove(oldButton);
}
if (newButton != null)
{
LogicalChildren.Add(newButton);
VisualChildren.Add(newButton);
}
}
private void ThumbDragged(object sender, VectorEventArgs e) private void ThumbDragged(object sender, VectorEventArgs e)
{ {
double range = Maximum - Minimum; double range = Maximum - Minimum;

82
src/Avalonia.Controls/RepeatButton.cs

@ -0,0 +1,82 @@
using System;
using Avalonia.Input;
using Avalonia.Threading;
namespace Avalonia.Controls
{
public class RepeatButton : Button
{
/// <summary>
/// Defines the <see cref="Delay"/> property.
/// </summary>
public static readonly StyledProperty<int> DelayProperty =
AvaloniaProperty.Register<Button, int>(nameof(Delay), 100);
private DispatcherTimer _repeatTimer;
/// <summary>
/// Gets or sets the amount of time, in milliseconds, of repeating clicks.
/// </summary>
public int Delay
{
get { return GetValue(DelayProperty); }
set { SetValue(DelayProperty, value); }
}
private void StartTimer()
{
if (_repeatTimer == null)
{
_repeatTimer = new DispatcherTimer();
_repeatTimer.Tick += (o, e) => OnClick();
}
if (_repeatTimer.IsEnabled) return;
_repeatTimer.Interval = TimeSpan.FromMilliseconds(Delay);
_repeatTimer.Start();
}
private void StopTimer()
{
_repeatTimer?.Stop();
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Space)
{
StartTimer();
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
StopTimer();
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
if (e.MouseButton == MouseButton.Left)
{
StartTimer();
}
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
if (e.MouseButton == MouseButton.Left)
{
StopTimer();
}
}
}
}

4
src/Avalonia.Controls/ScrollViewer.cs

@ -275,7 +275,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
protected double HorizontalScrollBarViewportSize protected double HorizontalScrollBarViewportSize
{ {
get { return Max((_viewport.Width / _extent.Width) * (_extent.Width - _viewport.Width), 0); } get { return _viewport.Width; }
} }
/// <summary> /// <summary>
@ -308,7 +308,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
protected double VerticalScrollBarViewportSize protected double VerticalScrollBarViewportSize
{ {
get { return Max((_viewport.Height / _extent.Height) * (_extent.Height - _viewport.Height), 0); } get { return _viewport.Height; }
} }
/// <summary> /// <summary>

55
src/Avalonia.Controls/Slider.cs

@ -33,6 +33,8 @@ namespace Avalonia.Controls
// Slider required parts // Slider required parts
private Track _track; private Track _track;
private Button _decreaseButton;
private Button _increaseButton;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="Slider"/> class. /// Initializes static members of the <see cref="Slider"/> class.
@ -44,6 +46,8 @@ namespace Avalonia.Controls
Thumb.DragStartedEvent.AddClassHandler<Slider>(x => x.OnThumbDragStarted, RoutingStrategies.Bubble); Thumb.DragStartedEvent.AddClassHandler<Slider>(x => x.OnThumbDragStarted, RoutingStrategies.Bubble);
Thumb.DragDeltaEvent.AddClassHandler<Slider>(x => x.OnThumbDragDelta, RoutingStrategies.Bubble); Thumb.DragDeltaEvent.AddClassHandler<Slider>(x => x.OnThumbDragDelta, RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler<Slider>(x => x.OnThumbDragCompleted, RoutingStrategies.Bubble); Thumb.DragCompletedEvent.AddClassHandler<Slider>(x => x.OnThumbDragCompleted, RoutingStrategies.Bubble);
SmallChangeProperty.OverrideDefaultValue<Slider>(1);
LargeChangeProperty.OverrideDefaultValue<Slider>(10);
} }
/// <summary> /// <summary>
@ -83,7 +87,54 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnTemplateApplied(TemplateAppliedEventArgs e) protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{ {
_track = e.NameScope.Get<Track>("PART_Track"); if (_decreaseButton != null)
{
_decreaseButton.Click -= DecreaseClick;
}
if (_increaseButton != null)
{
_increaseButton.Click -= IncreaseClick;
}
_decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
_track = e.NameScope.Find<Track>("PART_Track");
_increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
if (_decreaseButton != null)
{
_decreaseButton.Click += DecreaseClick;
}
if (_increaseButton != null)
{
_increaseButton.Click += IncreaseClick;
}
}
private void DecreaseClick(object sender, RoutedEventArgs e)
{
ChangeValueBy(-LargeChange);
}
private void IncreaseClick(object sender, RoutedEventArgs e)
{
ChangeValueBy(LargeChange);
}
private void ChangeValueBy(double by)
{
if (IsSnapToTickEnabled)
{
by = by < 0 ? Math.Min(-TickFrequency, by) : Math.Max(TickFrequency, by);
}
var value = Value;
var next = SnapToTick(Math.Max(Math.Min(value + by, Maximum), Minimum));
if (next != value)
{
Value = next;
}
} }
/// <summary> /// <summary>
@ -101,7 +152,7 @@ namespace Avalonia.Controls
protected virtual void OnThumbDragDelta(VectorEventArgs e) protected virtual void OnThumbDragDelta(VectorEventArgs e)
{ {
Thumb thumb = e.Source as Thumb; Thumb thumb = e.Source as Thumb;
if (thumb != null && _track.Thumb == thumb) if (thumb != null && _track?.Thumb == thumb)
{ {
MoveToNextTick(_track.Value); MoveToNextTick(_track.Value);
} }

2
src/Avalonia.Controls/SystemDialog.cs

@ -20,7 +20,7 @@ namespace Avalonia.Controls
{ {
public string DefaultExtension { get; set; } public string DefaultExtension { get; set; }
public async Task<string> ShowAsync(Window window = null) public async Task<string> ShowAsync(Window window)
=> =>
((await AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFileDialogAsync(this, window?.PlatformImpl)) ?? ((await AvaloniaLocator.Current.GetService<ISystemDialogImpl>().ShowFileDialogAsync(this, window?.PlatformImpl)) ??
new string[0]).FirstOrDefault(); new string[0]).FirstOrDefault();

24
src/Avalonia.Controls/Templates/DataTemplateExtensions.cs

@ -17,8 +17,8 @@ namespace Avalonia.Controls.Templates
/// <param name="control">The control searching for the data template.</param> /// <param name="control">The control searching for the data template.</param>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <param name="primary"> /// <param name="primary">
/// An optional primary template that can will be tried before the /// An optional primary template that can will be tried before the DataTemplates in the
/// <see cref="IControl.DataTemplates"/> in the tree are searched. /// tree are searched.
/// </param> /// </param>
/// <returns>The data template or null if no matching data template was found.</returns> /// <returns>The data template or null if no matching data template was found.</returns>
public static IDataTemplate FindDataTemplate( public static IDataTemplate FindDataTemplate(
@ -31,13 +31,16 @@ namespace Avalonia.Controls.Templates
return primary; return primary;
} }
foreach (var i in control.GetSelfAndLogicalAncestors().OfType<IControl>()) foreach (var i in control.GetSelfAndLogicalAncestors().OfType<IDataTemplateHost>())
{ {
foreach (IDataTemplate dt in i.DataTemplates) if (i.IsDataTemplatesInitialized)
{ {
if (dt.Match(data)) foreach (IDataTemplate dt in i.DataTemplates)
{ {
return dt; if (dt.Match(data))
{
return dt;
}
} }
} }
} }
@ -46,11 +49,14 @@ namespace Avalonia.Controls.Templates
if (global != null) if (global != null)
{ {
foreach (IDataTemplate dt in global.DataTemplates) if (global.IsDataTemplatesInitialized)
{ {
if (dt.Match(data)) foreach (IDataTemplate dt in global.DataTemplates)
{ {
return dt; if (dt.Match(data))
{
return dt;
}
} }
} }
} }

27
src/Avalonia.Controls/Templates/IDataTemplateHost.cs

@ -0,0 +1,27 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Controls.Templates
{
/// <summary>
/// Defines an element that has a <see cref="DataTemplates"/> collection.
/// </summary>
public interface IDataTemplateHost
{
/// <summary>
/// Gets the data templates for the element.
/// </summary>
DataTemplates DataTemplates { get; }
/// <summary>
/// Gets a value indicating whether <see cref="DataTemplates"/> is initialized.
/// </summary>
/// <remarks>
/// The <see cref="DataTemplates"/> property may be lazily initialized, if so this property
/// indicates whether it has been initialized.
/// </remarks>
bool IsDataTemplatesInitialized { get; }
}
}

236
src/Avalonia.Controls/ToolTip.cs

@ -3,11 +3,7 @@
using System; using System;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Subjects;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -29,29 +25,50 @@ namespace Avalonia.Controls
AvaloniaProperty.RegisterAttached<ToolTip, Control, object>("Tip"); AvaloniaProperty.RegisterAttached<ToolTip, Control, object>("Tip");
/// <summary> /// <summary>
/// The popup window used to display the active tooltip. /// Defines the ToolTip.IsOpen attached property.
/// </summary> /// </summary>
private static PopupRoot s_popup; public static readonly AttachedProperty<bool> IsOpenProperty =
AvaloniaProperty.RegisterAttached<ToolTip, Control, bool>("IsOpen");
/// <summary> /// <summary>
/// The control that the currently visible tooltip is attached to. /// Defines the ToolTip.Placement property.
/// </summary> /// </summary>
private static Control s_current; public static readonly AttachedProperty<PlacementMode> PlacementProperty =
AvaloniaProperty.RegisterAttached<Popup, Control, PlacementMode>("Placement", defaultValue: PlacementMode.Pointer);
/// <summary> /// <summary>
/// Observable fired when a tooltip should be displayed for a control. The output from this /// Defines the ToolTip.HorizontalOffset property.
/// observable is throttled and calls <see cref="ShowToolTip(Control)"/> when the time
/// period expires.
/// </summary> /// </summary>
private static readonly Subject<Control> s_show = new Subject<Control>(); public static readonly AttachedProperty<double> HorizontalOffsetProperty =
AvaloniaProperty.RegisterAttached<Popup, Control, double>("HorizontalOffset");
/// <summary>
/// Defines the ToolTip.VerticalOffset property.
/// </summary>
public static readonly AttachedProperty<double> VerticalOffsetProperty =
AvaloniaProperty.RegisterAttached<Popup, Control, double>("VerticalOffset", 20);
/// <summary>
/// Defines the ToolTip.ShowDelay property.
/// </summary>
public static readonly AttachedProperty<int> ShowDelayProperty =
AvaloniaProperty.RegisterAttached<Popup, Control, int>("ShowDelay", 400);
/// <summary>
/// Stores the curernt <see cref="ToolTip"/> instance in the control.
/// </summary>
private static readonly AttachedProperty<ToolTip> ToolTipProperty =
AvaloniaProperty.RegisterAttached<ToolTip, Control, ToolTip>("ToolTip");
private PopupRoot _popup;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ToolTip"/> class. /// Initializes static members of the <see cref="ToolTip"/> class.
/// </summary> /// </summary>
static ToolTip() static ToolTip()
{ {
TipProperty.Changed.Subscribe(TipChanged); TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged);
s_show.Throttle(TimeSpan.FromSeconds(0.5), AvaloniaScheduler.Instance).Subscribe(ShowToolTip); IsOpenProperty.Changed.Subscribe(IsOpenChanged);
} }
/// <summary> /// <summary>
@ -77,101 +94,160 @@ namespace Avalonia.Controls
} }
/// <summary> /// <summary>
/// called when the <see cref="TipProperty"/> property changes on a control. /// Gets the value of the ToolTip.IsOpen attached property.
/// </summary> /// </summary>
/// <param name="e">The event args.</param> /// <param name="element">The control to get the property from.</param>
private static void TipChanged(AvaloniaPropertyChangedEventArgs e) /// <returns>
/// A value indicating whether the tool tip is visible.
/// </returns>
public static bool GetIsOpen(Control element)
{ {
var control = (Control)e.Sender; return element.GetValue(IsOpenProperty);
}
if (e.OldValue != null) /// <summary>
{ /// Sets the value of the ToolTip.IsOpen attached property.
control.PointerEnter -= ControlPointerEnter; /// </summary>
control.PointerLeave -= ControlPointerLeave; /// <param name="element">The control to get the property from.</param>
} /// <param name="value">A value indicating whether the tool tip is visible.</param>
public static void SetIsOpen(Control element, bool value)
{
element.SetValue(IsOpenProperty, value);
}
if (e.NewValue != null) /// <summary>
{ /// Gets the value of the ToolTip.Placement attached property.
control.PointerEnter += ControlPointerEnter; /// </summary>
control.PointerLeave += ControlPointerLeave; /// <param name="element">The control to get the property from.</param>
} /// <returns>
/// A value indicating how the tool tip is positioned.
/// </returns>
public static PlacementMode GetPlacement(Control element)
{
return element.GetValue(PlacementProperty);
} }
/// <summary> /// <summary>
/// Shows a tooltip for the specified control. /// Sets the value of the ToolTip.Placement attached property.
/// </summary> /// </summary>
/// <param name="control">The control.</param> /// <param name="element">The control to get the property from.</param>
private static void ShowToolTip(Control control) /// <param name="value">A value indicating how the tool tip is positioned.</param>
public static void SetPlacement(Control element, PlacementMode value)
{ {
if (control != null && control.IsVisible && control.GetVisualRoot() != null) element.SetValue(PlacementProperty, value);
{ }
var cp = (control.GetVisualRoot() as IInputRoot)?.MouseDevice?.GetPosition(control);
if (cp.HasValue && control.IsVisible && new Rect(control.Bounds.Size).Contains(cp.Value)) /// <summary>
{ /// Gets the value of the ToolTip.HorizontalOffset attached property.
var position = control.PointToScreen(cp.Value) + new Vector(0, 22); /// </summary>
/// <param name="element">The control to get the property from.</param>
if (s_popup == null) /// <returns>
{ /// A value indicating how the tool tip is positioned.
s_popup = new PopupRoot(); /// </returns>
s_popup.Content = new ToolTip(); public static double GetHorizontalOffset(Control element)
} {
else return element.GetValue(HorizontalOffsetProperty);
{ }
((ISetLogicalParent)s_popup).SetParent(null);
} /// <summary>
/// Sets the value of the ToolTip.HorizontalOffset attached property.
((ISetLogicalParent)s_popup).SetParent(control); /// </summary>
((ToolTip)s_popup.Content).Content = GetTip(control); /// <param name="element">The control to get the property from.</param>
s_popup.Position = position; /// <param name="value">A value indicating how the tool tip is positioned.</param>
s_popup.Show(); public static void SetHorizontalOffset(Control element, double value)
{
s_current = control; element.SetValue(HorizontalOffsetProperty, value);
} }
}
/// <summary>
/// Gets the value of the ToolTip.VerticalOffset attached property.
/// </summary>
/// <param name="element">The control to get the property from.</param>
/// <returns>
/// A value indicating how the tool tip is positioned.
/// </returns>
public static double GetVerticalOffset(Control element)
{
return element.GetValue(VerticalOffsetProperty);
}
/// <summary>
/// Sets the value of the ToolTip.VerticalOffset attached property.
/// </summary>
/// <param name="element">The control to get the property from.</param>
/// <param name="value">A value indicating how the tool tip is positioned.</param>
public static void SetVerticalOffset(Control element, double value)
{
element.SetValue(VerticalOffsetProperty, value);
} }
/// <summary> /// <summary>
/// Called when the pointer enters a control with an attached tooltip. /// Gets the value of the ToolTip.ShowDelay attached property.
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="element">The control to get the property from.</param>
/// <param name="e">The event args.</param> /// <returns>
private static void ControlPointerEnter(object sender, PointerEventArgs e) /// A value indicating the time, in milliseconds, before a tool tip opens.
/// </returns>
public static int GetShowDelay(Control element)
{ {
s_current = (Control)sender; return element.GetValue(ShowDelayProperty);
s_show.OnNext(s_current);
} }
/// <summary> /// <summary>
/// Called when the pointer leaves a control with an attached tooltip. /// Sets the value of the ToolTip.ShowDelay attached property.
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="element">The control to get the property from.</param>
/// <param name="e">The event args.</param> /// <param name="value">A value indicating the time, in milliseconds, before a tool tip opens.</param>
private static void ControlPointerLeave(object sender, PointerEventArgs e) public static void SetShowDelay(Control element, int value)
{ {
var control = (Control)sender; element.SetValue(ShowDelayProperty, value);
}
private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
{
var control = (Control)e.Sender;
if (control == s_current) if ((bool)e.NewValue)
{ {
if (s_popup != null) var tip = GetTip(control);
if (tip == null) return;
var toolTip = control.GetValue(ToolTipProperty);
if (toolTip == null || (tip != toolTip && tip != toolTip.Content))
{ {
DisposeTooltip(); toolTip?.Close();
s_show.OnNext(null);
toolTip = tip as ToolTip ?? new ToolTip { Content = tip };
control.SetValue(ToolTipProperty, toolTip);
} }
toolTip.Open(control);
}
else
{
var toolTip = control.GetValue(ToolTipProperty);
toolTip?.Close();
} }
} }
private static void DisposeTooltip() private void Open(Control control)
{ {
if (s_popup != null) Close();
{
// Clear the ToolTip's Content in case it has control content: this will _popup = new PopupRoot { Content = this };
// reset its visual parent allowing it to be used again. ((ISetLogicalParent)_popup).SetParent(control);
((ToolTip)s_popup.Content).Content = null; _popup.Position = Popup.GetPosition(control, GetPlacement(control), _popup,
GetHorizontalOffset(control), GetVerticalOffset(control));
_popup.Show();
}
// Dispose of the popup. private void Close()
s_popup.Dispose(); {
s_popup = null; if (_popup != null)
{
_popup.Content = null;
_popup.Hide();
_popup = null;
} }
} }
} }

98
src/Avalonia.Controls/ToolTipService.cs

@ -0,0 +1,98 @@
using System;
using Avalonia.Input;
using Avalonia.Threading;
namespace Avalonia.Controls
{
/// <summary>
/// Handeles <see cref="ToolTip"/> interaction with controls.
/// </summary>
internal sealed class ToolTipService
{
public static ToolTipService Instance { get; } = new ToolTipService();
private DispatcherTimer _timer;
private ToolTipService() { }
/// <summary>
/// called when the <see cref="ToolTip.TipProperty"/> property changes on a control.
/// </summary>
/// <param name="e">The event args.</param>
internal void TipChanged(AvaloniaPropertyChangedEventArgs e)
{
var control = (Control)e.Sender;
if (e.OldValue != null)
{
control.PointerEnter -= ControlPointerEnter;
control.PointerLeave -= ControlPointerLeave;
}
if (e.NewValue != null)
{
control.PointerEnter += ControlPointerEnter;
control.PointerLeave += ControlPointerLeave;
}
}
/// <summary>
/// Called when the pointer enters a control with an attached tooltip.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void ControlPointerEnter(object sender, PointerEventArgs e)
{
StopTimer();
var control = (Control)sender;
var showDelay = ToolTip.GetShowDelay(control);
if (showDelay == 0)
{
Open(control);
}
else
{
StartShowTimer(showDelay, control);
}
}
/// <summary>
/// Called when the pointer leaves a control with an attached tooltip.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void ControlPointerLeave(object sender, PointerEventArgs e)
{
var control = (Control)sender;
Close(control);
}
private void StartShowTimer(int showDelay, Control control)
{
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(showDelay) };
_timer.Tick += (o, e) => Open(control);
_timer.Start();
}
private void Open(Control control)
{
StopTimer();
ToolTip.SetIsOpen(control, true);
}
private void Close(Control control)
{
StopTimer();
ToolTip.SetIsOpen(control, false);
}
private void StopTimer()
{
_timer?.Stop();
_timer = null;
}
}
}

24
src/Avalonia.Controls/TopLevel.cs

@ -10,9 +10,11 @@ using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.LogicalTree;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Utilities;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using JetBrains.Annotations; using JetBrains.Annotations;
@ -26,7 +28,13 @@ namespace Avalonia.Controls
/// It handles scheduling layout, styling and rendering as well as /// It handles scheduling layout, styling and rendering as well as
/// tracking the widget's <see cref="ClientSize"/>. /// tracking the widget's <see cref="ClientSize"/>.
/// </remarks> /// </remarks>
public abstract class TopLevel : ContentControl, IInputRoot, ILayoutRoot, IRenderRoot, ICloseable, IStyleRoot public abstract class TopLevel : ContentControl,
IInputRoot,
ILayoutRoot,
IRenderRoot,
ICloseable,
IStyleRoot,
IWeakSubscriber<ResourcesChangedEventArgs>
{ {
/// <summary> /// <summary>
/// Defines the <see cref="ClientSize"/> property. /// Defines the <see cref="ClientSize"/> property.
@ -100,7 +108,6 @@ namespace Avalonia.Controls
impl.Resized = HandleResized; impl.Resized = HandleResized;
impl.ScalingChanged = HandleScalingChanged; impl.ScalingChanged = HandleScalingChanged;
_keyboardNavigationHandler?.SetOwner(this); _keyboardNavigationHandler?.SetOwner(this);
_accessKeyHandler?.SetOwner(this); _accessKeyHandler?.SetOwner(this);
styler?.ApplyStyles(this); styler?.ApplyStyles(this);
@ -116,6 +123,14 @@ namespace Avalonia.Controls
{ {
_applicationLifecycle.OnExit += OnApplicationExiting; _applicationLifecycle.OnExit += OnApplicationExiting;
} }
if (((IStyleHost)this).StylingParent is IResourceProvider applicationResources)
{
WeakSubscriptionManager.Subscribe(
applicationResources,
nameof(IResourceProvider.ResourcesChanged),
this);
}
} }
/// <summary> /// <summary>
@ -165,6 +180,11 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
IMouseDevice IInputRoot.MouseDevice => PlatformImpl?.MouseDevice; IMouseDevice IInputRoot.MouseDevice => PlatformImpl?.MouseDevice;
void IWeakSubscriber<ResourcesChangedEventArgs>.OnEvent(object sender, ResourcesChangedEventArgs e)
{
((ILogical)this).NotifyResourcesChanged(e);
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether access keys are shown in the window. /// Gets or sets a value indicating whether access keys are shown in the window.
/// </summary> /// </summary>

24
src/Avalonia.Controls/Window.cs

@ -61,11 +61,17 @@ namespace Avalonia.Controls
AvaloniaProperty.Register<Window, SizeToContent>(nameof(SizeToContent)); AvaloniaProperty.Register<Window, SizeToContent>(nameof(SizeToContent));
/// <summary> /// <summary>
/// Enables of disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary> /// </summary>
public static readonly StyledProperty<bool> HasSystemDecorationsProperty = public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true); AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
public static readonly StyledProperty<bool> ShowInTaskbarProperty =
AvaloniaProperty.Register<Window, bool>(nameof(ShowInTaskbar), true);
/// <summary> /// <summary>
/// Defines the <see cref="Title"/> property. /// Defines the <see cref="Title"/> property.
/// </summary> /// </summary>
@ -92,6 +98,8 @@ namespace Avalonia.Controls
HasSystemDecorationsProperty.Changed.AddClassHandler<Window>( HasSystemDecorationsProperty.Changed.AddClassHandler<Window>(
(s, e) => s.PlatformImpl?.SetSystemDecorations((bool) e.NewValue)); (s, e) => s.PlatformImpl?.SetSystemDecorations((bool) e.NewValue));
ShowInTaskbarProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
} }
@ -152,7 +160,7 @@ namespace Avalonia.Controls
} }
/// <summary> /// <summary>
/// Enables of disables system window decorations (title bar, buttons, etc) /// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary> /// </summary>
/// ///
public bool HasSystemDecorations public bool HasSystemDecorations
@ -160,6 +168,16 @@ namespace Avalonia.Controls
get { return GetValue(HasSystemDecorationsProperty); } get { return GetValue(HasSystemDecorationsProperty); }
set { SetValue(HasSystemDecorationsProperty, value); } set { SetValue(HasSystemDecorationsProperty, value); }
} }
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
///
public bool ShowInTaskbar
{
get { return GetValue(ShowInTaskbarProperty); }
set { SetValue(ShowInTaskbarProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets the minimized/maximized state of the window. /// Gets or sets the minimized/maximized state of the window.

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

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

2
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

2
src/Avalonia.Diagnostics/DevTools.xaml.cs

@ -71,7 +71,7 @@ namespace Avalonia.Diagnostics
Width = 1024, Width = 1024,
Height = 512, Height = 512,
Content = devTools, Content = devTools,
DataTemplates = new DataTemplates DataTemplates =
{ {
new ViewLocator<ViewModelBase>(), new ViewLocator<ViewModelBase>(),
} }

2
src/Avalonia.Diagnostics/Views/ControlDetailsView.cs

@ -42,7 +42,7 @@ namespace Avalonia.Diagnostics.Views
{ {
Content = _grid = new SimpleGrid Content = _grid = new SimpleGrid
{ {
Styles = new Styles Styles =
{ {
new Style(x => x.Is<Control>()) new Style(x => x.Is<Control>())
{ {

6
src/Avalonia.DotNetCoreRuntime/AppBuilder.cs

@ -37,12 +37,15 @@ namespace Avalonia
/// <returns>An <see cref="AppBuilder"/> instance.</returns> /// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UsePlatformDetect() public AppBuilder UsePlatformDetect()
{ {
var os = RuntimePlatform.GetRuntimeInfo().OperatingSystem;
//We don't have the ability to load every assembly right now, so we are //We don't have the ability to load every assembly right now, so we are
//stuck with manual configuration here //stuck with manual configuration here
//Helpers are extracted to separate methods to take the advantage of the fact //Helpers are extracted to separate methods to take the advantage of the fact
//that CLR doesn't try to load dependencies before referencing method is jitted //that CLR doesn't try to load dependencies before referencing method is jitted
if (RuntimePlatform.GetRuntimeInfo().OperatingSystem == OperatingSystemType.WinNT) if (os == OperatingSystemType.WinNT)
LoadWin32(); LoadWin32();
else if(os==OperatingSystemType.OSX)
LoadMonoMac();
else else
LoadGtk3(); LoadGtk3();
this.UseSkia(); this.UseSkia();
@ -50,6 +53,7 @@ namespace Avalonia
return this; return this;
} }
void LoadMonoMac() => this.UseMonoMac();
void LoadWin32() => this.UseWin32(); void LoadWin32() => this.UseWin32();
void LoadGtk3() => this.UseGtk3(); void LoadGtk3() => this.UseGtk3();
} }

3
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -16,6 +16,7 @@
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" /> <ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" /> <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj" /> <ProjectReference Include="..\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj" />
<ProjectReference Include="..\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj" />
<ProjectReference Include="..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" /> <ProjectReference Include="..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj" /> <ProjectReference Include="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj" />
</ItemGroup> </ItemGroup>

13
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@ -59,7 +59,11 @@ namespace Avalonia
from attribute in assembly.GetCustomAttributes<ExportWindowingSubsystemAttribute>() from attribute in assembly.GetCustomAttributes<ExportWindowingSubsystemAttribute>()
where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker) where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker)
orderby attribute.Priority ascending orderby attribute.Priority ascending
select attribute).First(); select attribute).FirstOrDefault();
if (windowingSubsystemAttribute == null)
{
throw new InvalidOperationException("No windowing subsystem found. Are you missing assembly references?");
}
var renderingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies() var renderingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies()
from attribute in assembly.GetCustomAttributes<ExportRenderingSubsystemAttribute>() from attribute in assembly.GetCustomAttributes<ExportRenderingSubsystemAttribute>()
@ -67,7 +71,12 @@ namespace Avalonia
where attribute.RequiresWindowingSubsystem == null where attribute.RequiresWindowingSubsystem == null
|| attribute.RequiresWindowingSubsystem == windowingSubsystemAttribute.Name || attribute.RequiresWindowingSubsystem == windowingSubsystemAttribute.Name
orderby attribute.Priority ascending orderby attribute.Priority ascending
select attribute).First(); select attribute).FirstOrDefault();
if (renderingSubsystemAttribute == null)
{
throw new InvalidOperationException("No rendering subsystem found. Are you missing assembly references?");
}
UseWindowingSubsystem(() => windowingSubsystemAttribute.InitializationType UseWindowingSubsystem(() => windowingSubsystemAttribute.InitializationType
.GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null), .GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null),

94
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@ -1,75 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <TargetFramework>net461</TargetFramework>
<PropertyGroup> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <DocumentationFile>bin\$(Configuration)\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <DefineConstants>$(DefineConstants);FULLDOTNET</DefineConstants>
<ProjectGuid>{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}</ProjectGuid> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<OutputType>Library</OutputType> </PropertyGroup>
<AppDesignerFolder>Properties</AppDesignerFolder> <ItemGroup>
<RootNamespace>Avalonia.DotNetFrameworkRuntime</RootNamespace> <Compile Include="..\Shared\SharedAssemblyInfo.cs">
<AssemblyName>Avalonia.DotNetFrameworkRuntime</AssemblyName> <Link>Properties\SharedAssemblyInfo.cs</Link>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> </Compile>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
</PropertyGroup> <ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<DebugSymbols>true</DebugSymbols> <ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
<DebugType>full</DebugType> </ItemGroup>
<Optimize>false</Optimize> <Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<OutputPath>bin\Debug\</OutputPath> <Import Project="..\..\build\Rx.props" />
<DefineConstants>TRACE;DEBUG;FULLDOTNET</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;FULLDOTNET</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AppBuilder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RuntimeInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>
</ProjectReference>
<ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Avalonia.Styling</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\build\Rx.props" />
</Project> </Project>

15
src/Avalonia.DotNetFrameworkRuntime/Properties/AssemblyInfo.cs

@ -1,15 +0,0 @@
using System.Reflection;
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("Avalonia.DotNetFrameworkRuntime")]
// 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("4a1abb09-9047-4bd5-a4ad-a055e52c5ee0")]

3
src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems> <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<EnableDefaultItems>False</EnableDefaultItems> <EnableDefaultItems>False</EnableDefaultItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<NoWarn>CS0436</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>

12
src/Avalonia.HtmlRenderer/Compat/Api.cs

@ -4,18 +4,6 @@ using System.Text;
namespace System.Net namespace System.Net
{ {
internal class AsyncCompletedEventArgs
{
public object UserState { get; set; }
public Exception Error { get; set; }
public bool Cancelled { get; set; }
public AsyncCompletedEventArgs(Exception error, bool cancelled, object userState)
{
}
}
class WebException : Exception class WebException : Exception
{ {
public object Response { get; set; } public object Response { get; set; }

2
src/Avalonia.Input/Avalonia.Input.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

2
src/Avalonia.Interactivity/Avalonia.Interactivity.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

20
src/Avalonia.Interactivity/Interactive.cs

@ -16,14 +16,18 @@ namespace Avalonia.Interactivity
/// </summary> /// </summary>
public class Interactive : Layoutable, IInteractive public class Interactive : Layoutable, IInteractive
{ {
private readonly Dictionary<RoutedEvent, List<EventSubscription>> _eventHandlers = private Dictionary<RoutedEvent, List<EventSubscription>> _eventHandlers;
new Dictionary<RoutedEvent, List<EventSubscription>>();
/// <summary> /// <summary>
/// Gets the interactive parent of the object for bubbling and tunnelling events. /// Gets the interactive parent of the object for bubbling and tunnelling events.
/// </summary> /// </summary>
IInteractive IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive; IInteractive IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive;
private Dictionary<RoutedEvent, List<EventSubscription>> EventHandlers
{
get { return _eventHandlers ?? (_eventHandlers = new Dictionary<RoutedEvent, List<EventSubscription>>()); }
}
/// <summary> /// <summary>
/// Adds a handler for the specified routed event. /// Adds a handler for the specified routed event.
/// </summary> /// </summary>
@ -43,10 +47,10 @@ namespace Avalonia.Interactivity
List<EventSubscription> subscriptions; List<EventSubscription> subscriptions;
if (!_eventHandlers.TryGetValue(routedEvent, out subscriptions)) if (!EventHandlers.TryGetValue(routedEvent, out subscriptions))
{ {
subscriptions = new List<EventSubscription>(); subscriptions = new List<EventSubscription>();
_eventHandlers.Add(routedEvent, subscriptions); EventHandlers.Add(routedEvent, subscriptions);
} }
var sub = new EventSubscription var sub = new EventSubscription
@ -89,9 +93,9 @@ namespace Avalonia.Interactivity
Contract.Requires<ArgumentNullException>(routedEvent != null); Contract.Requires<ArgumentNullException>(routedEvent != null);
Contract.Requires<ArgumentNullException>(handler != null); Contract.Requires<ArgumentNullException>(handler != null);
List<EventSubscription> subscriptions; List<EventSubscription> subscriptions = null;
if (_eventHandlers.TryGetValue(routedEvent, out subscriptions)) if (_eventHandlers?.TryGetValue(routedEvent, out subscriptions) == true)
{ {
subscriptions.RemoveAll(x => x.Handler == handler); subscriptions.RemoveAll(x => x.Handler == handler);
} }
@ -181,9 +185,9 @@ namespace Avalonia.Interactivity
e.RoutedEvent.InvokeRaised(this, e); e.RoutedEvent.InvokeRaised(this, e);
List<EventSubscription> subscriptions; List<EventSubscription> subscriptions = null;
if (_eventHandlers.TryGetValue(e.RoutedEvent, out subscriptions)) if (_eventHandlers?.TryGetValue(e.RoutedEvent, out subscriptions) == true)
{ {
foreach (var sub in subscriptions.ToList()) foreach (var sub in subscriptions.ToList())
{ {

2
src/Avalonia.Layout/Avalonia.Layout.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

2
src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

24
src/Avalonia.ReactiveUI/AppBuilderExtensions.cs

@ -0,0 +1,24 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Controls;
using Avalonia.Threading;
using ReactiveUI;
using System;
using System.Reactive.Concurrency;
using System.Threading;
namespace Avalonia
{
public static class AppBuilderExtensions
{
public static TAppBuilder UseReactiveUI<TAppBuilder>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
{
return builder.AfterSetup(_ =>
{
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
});
}
}
}

76
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -1,83 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;MONO PORTABLE;NETSTANDARD1_1</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;MONO PORTABLE;RELEASE;NETSTANDARD1_1</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<None Remove="Shims.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" /> <Compile Include="..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Registrations.cs" />
<Compile Include="Shims.cs" />
<Compile Include="src\ReactiveUI\ExpressionMixins.cs" />
<Compile Include="src\ReactiveUI\ExpressionRewriter.cs" />
<Compile Include="src\ReactiveUI\Activation.cs" />
<Compile Include="src\ReactiveUI\ReactiveBinding.cs" />
<Compile Include="src\ReactiveUI\AutoPersistHelper.cs" />
<Compile Include="src\ReactiveUI\BindingTypeConverters.cs" />
<Compile Include="src\ReactiveUI\CollectionDebugView.cs" />
<Compile Include="src\ReactiveUI\CommandBinding.cs" />
<Compile Include="src\ReactiveUI\CompatMixins.cs" />
<Compile Include="src\ReactiveUI\ContractStubs.cs" />
<Compile Include="src\ReactiveUI\CreatesCommandBinding.cs" />
<Compile Include="src\ReactiveUI\DefaultPropertyBinding.cs" />
<Compile Include="src\ReactiveUI\Errors.cs" />
<Compile Include="src\ReactiveUI\IDependencyResolver.cs" />
<Compile Include="src\ReactiveUI\INPCObservableForProperty.cs" />
<Compile Include="src\ReactiveUI\Interfaces.cs" />
<Compile Include="src\ReactiveUI\IROObservableForProperty.cs" />
<Compile Include="src\ReactiveUI\MessageBus.cs" />
<Compile Include="src\ReactiveUI\MobileLifecycle.cs" />
<Compile Include="src\ReactiveUI\NullDefaultPropertyBindingProvider.cs" />
<Compile Include="src\ReactiveUI\ObservableAsPropertyHelper.cs" />
<Compile Include="src\ReactiveUI\ObservedChangedMixin.cs" />
<Compile Include="src\ReactiveUI\OrderedComparer.cs" />
<Compile Include="src\ReactiveUI\POCOObservableForProperty.cs" />
<Compile Include="src\ReactiveUI\PropertyBinding.cs" />
<Compile Include="src\ReactiveUI\ReactiveList.cs" />
<Compile Include="src\ReactiveUI\ReactiveCollectionMixins.cs" />
<Compile Include="src\ReactiveUI\ReactiveCommand.cs" />
<Compile Include="src\ReactiveUI\ReactiveNotifyPropertyChangedMixin.cs" />
<Compile Include="src\ReactiveUI\ReactiveObject.cs" />
<Compile Include="src\ReactiveUI\RefcountDisposeWrapper.cs" />
<Compile Include="src\ReactiveUI\Reflection.cs" />
<Compile Include="src\ReactiveUI\RegisterableInterfaces.cs" />
<Compile Include="src\ReactiveUI\Registrations.cs" />
<Compile Include="src\ReactiveUI\RoutableViewModelMixin.cs" />
<Compile Include="src\ReactiveUI\RoutingState.cs" />
<Compile Include="src\ReactiveUI\RxApp.cs" />
<Compile Include="src\ReactiveUI\ViewLocator.cs" />
<Compile Include="src\ReactiveUI\ScheduledSubject.cs" />
<Compile Include="src\ReactiveUI\VariadicTemplates.cs" />
<Compile Include="src\ReactiveUI\WaitForDispatcherScheduler.cs" />
<Compile Include="src\ReactiveUI\LoggingMixins.cs" />
<Compile Include="src\ReactiveUI\IReactiveObject.cs" />
<Compile Include="src\ReactiveUI\WeakEventManager.cs" />
<Compile Include="src\ReactiveUI\Legacy\ReactiveCommand.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" /> <ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" /> <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" /> <ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
@ -88,5 +15,6 @@
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" /> <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\Rx.props" /> <Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
<Import Project="..\..\build\Splat.props" /> <Import Project="..\..\build\Splat.props" />
</Project> </Project>

3
src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs

@ -3,7 +3,4 @@
using System.Reflection; using System.Reflection;
// 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("Avalonia.ReactiveUI")] [assembly: AssemblyTitle("Avalonia.ReactiveUI")]

23
src/Avalonia.ReactiveUI/Registrations.cs

@ -1,23 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Concurrency;
using System.Threading;
namespace ReactiveUI
{
/// <summary>
/// Ignore me. This class is a secret handshake between RxUI and RxUI.Xaml
/// in order to register certain classes on startup that would be difficult
/// to register otherwise.
/// </summary>
public class PlatformRegistrations : IWantsToRegisterStuff
{
public void Register(Action<Func<object>, Type> registerFunction)
{
RxApp.MainThreadScheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);
}
}
}

34
src/Avalonia.ReactiveUI/Shims.cs

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Runtime.Serialization
{
class IgnoreDataMemberAttribute : Attribute
{
}
class DataMemberAttribute : Attribute
{
}
class OnDeserializedAttribute : Attribute
{
}
class DataContractAttribute : Attribute
{
}
class StreamingContext { }
}
namespace System.Diagnostics.Contracts
{
static class Contract
{
public static void Requires(bool condition)
{
}
}
}

1
src/Avalonia.ReactiveUI/src

@ -1 +0,0 @@
Subproject commit 3f725c808b1d4c8457f0d3204e0a071aa462cd75

3
src/Avalonia.Styling/Avalonia.Styling.csproj

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>Avalonia</RootNamespace>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>

19
src/Avalonia.Styling/Controls/IResourceDictionary.cs

@ -0,0 +1,19 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
namespace Avalonia.Controls
{
/// <summary>
/// An indexed dictionary of resources.
/// </summary>
public interface IResourceDictionary : IResourceProvider, IDictionary<object, object>
{
/// <summary>
/// Gets a collection of child resource dictionaries.
/// </summary>
IList<IResourceProvider> MergedDictionaries { get; }
}
}

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

Loading…
Cancel
Save