Browse Source

Merge branch 'master' into framework-path-override

pull/1148/head
Jeremy Koritzinsky 9 years ago
committed by GitHub
parent
commit
321fa38843
  1. 4
      .gitmodules
  2. 1
      .ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
  3. 9
      .ncrunch/Avalonia.Markup.UnitTests.netcoreapp1.1.v3.ncrunchproject
  4. 1
      .ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject
  5. 53
      Avalonia.sln
  6. 5
      build/MonoMac.props
  7. 5
      build/ReactiveUI.props
  8. 13
      build/Rx.props
  9. 11
      docs/tutorial/from-wpf.md
  10. 40
      packages.cake
  11. 1
      samples/BindingTest/App.xaml.cs
  12. 2
      samples/BindingTest/BindingTest.csproj
  13. 10
      samples/BindingTest/ViewModels/MainWindowViewModel.cs
  14. 2
      samples/BindingTest/ViewModels/NestedCommandViewModel.cs
  15. 35
      samples/ControlCatalog.NetCore/Program.cs
  16. 12
      samples/ControlCatalog/ControlCatalog.csproj
  17. 33
      samples/ControlCatalog/DecoratedWindow.xaml
  18. 53
      samples/ControlCatalog/DecoratedWindow.xaml.cs
  19. 2
      samples/ControlCatalog/MainView.xaml
  20. 9
      samples/ControlCatalog/MainView.xaml.cs
  21. 5
      samples/ControlCatalog/MainWindow.xaml.cs
  22. 10
      samples/ControlCatalog/Pages/BorderPage.xaml
  23. 8
      samples/ControlCatalog/Pages/ButtonPage.xaml
  24. 2
      samples/ControlCatalog/Pages/ContextMenuPage.xaml
  25. 12
      samples/ControlCatalog/Pages/DialogsPage.xaml
  26. 46
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  27. 2
      samples/ControlCatalog/Pages/DropDownPage.xaml
  28. 8
      samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml
  29. 4
      samples/ControlCatalog/SideBar.xaml
  30. 2
      samples/RenderTest/Pages/ClippingPage.xaml
  31. 8
      samples/RenderTest/Pages/DrawingPage.xaml
  32. 1
      samples/RenderTest/Program.cs
  33. 1
      samples/RenderTest/RenderTest.csproj
  34. 4
      samples/RenderTest/SideBar.xaml
  35. 10
      samples/RenderTest/ViewModels/MainWindowViewModel.cs
  36. 1
      samples/VirtualizationTest/Program.cs
  37. 25
      samples/VirtualizationTest/ViewModels/MainWindowViewModel.cs
  38. 1
      samples/VirtualizationTest/VirtualizationTest.csproj
  39. 3
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  40. 54
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  41. 51
      src/Avalonia.Controls/Application.cs
  42. 70
      src/Avalonia.Controls/Button.cs
  43. 134
      src/Avalonia.Controls/Control.cs
  44. 1
      src/Avalonia.Controls/IControl.cs
  45. 7
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  46. 2
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  47. 24
      src/Avalonia.Controls/Primitives/RangeBase.cs
  48. 103
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  49. 4
      src/Avalonia.Controls/Primitives/ToggleButton.cs
  50. 102
      src/Avalonia.Controls/Primitives/Track.cs
  51. 82
      src/Avalonia.Controls/RepeatButton.cs
  52. 4
      src/Avalonia.Controls/ScrollViewer.cs
  53. 55
      src/Avalonia.Controls/Slider.cs
  54. 2
      src/Avalonia.Controls/SystemDialog.cs
  55. 24
      src/Avalonia.Controls/TopLevel.cs
  56. 24
      src/Avalonia.Controls/Window.cs
  57. 6
      src/Avalonia.DotNetCoreRuntime/AppBuilder.cs
  58. 1
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  59. 24
      src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
  60. 74
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  61. 3
      src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs
  62. 23
      src/Avalonia.ReactiveUI/Registrations.cs
  63. 34
      src/Avalonia.ReactiveUI/Shims.cs
  64. 1
      src/Avalonia.ReactiveUI/src
  65. 1
      src/Avalonia.Styling/Avalonia.Styling.csproj
  66. 19
      src/Avalonia.Styling/Controls/IResourceDictionary.cs
  67. 15
      src/Avalonia.Styling/Controls/IResourceNode.cs
  68. 33
      src/Avalonia.Styling/Controls/IResourceProvider.cs
  69. 101
      src/Avalonia.Styling/Controls/ResourceDictionary.cs
  70. 65
      src/Avalonia.Styling/Controls/ResourceProviderExtensions.cs
  71. 11
      src/Avalonia.Styling/Controls/ResourcesChangedEventArgs.cs
  72. 11
      src/Avalonia.Styling/LogicalTree/ILogical.cs
  73. 2
      src/Avalonia.Styling/Properties/AssemblyInfo.cs
  74. 32
      src/Avalonia.Styling/Styling/ISetStyleParent.cs
  75. 13
      src/Avalonia.Styling/Styling/IStyle.cs
  76. 92
      src/Avalonia.Styling/Styling/Style.cs
  77. 42
      src/Avalonia.Styling/Styling/StyleExtensions.cs
  78. 90
      src/Avalonia.Styling/Styling/StyleResources.cs
  79. 149
      src/Avalonia.Styling/Styling/Styles.cs
  80. 14
      src/Avalonia.Themes.Default/Button.xaml
  81. 10
      src/Avalonia.Themes.Default/CheckBox.xaml
  82. 1
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  83. 10
      src/Avalonia.Themes.Default/DropDown.xaml
  84. 4
      src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml
  85. 8
      src/Avalonia.Themes.Default/GridSplitter.xaml
  86. 6
      src/Avalonia.Themes.Default/ListBox.xaml
  87. 18
      src/Avalonia.Themes.Default/MenuItem.xaml
  88. 2
      src/Avalonia.Themes.Default/PopupRoot.xaml
  89. 4
      src/Avalonia.Themes.Default/ProgressBar.xaml
  90. 10
      src/Avalonia.Themes.Default/RadioButton.xaml
  91. 44
      src/Avalonia.Themes.Default/RepeatButton.xaml
  92. 158
      src/Avalonia.Themes.Default/ScrollBar.xaml
  93. 2
      src/Avalonia.Themes.Default/ScrollViewer.xaml
  94. 4
      src/Avalonia.Themes.Default/Separator.xaml
  95. 32
      src/Avalonia.Themes.Default/Slider.xaml
  96. 6
      src/Avalonia.Themes.Default/TabStripItem.xaml
  97. 22
      src/Avalonia.Themes.Default/TextBox.xaml
  98. 18
      src/Avalonia.Themes.Default/ToggleButton.xaml
  99. 6
      src/Avalonia.Themes.Default/ToolTip.xaml
  100. 4
      src/Avalonia.Themes.Default/TreeView.xaml

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"]
path = src/Avalonia.HtmlRenderer/external
url = https://github.com/AvaloniaUI/HTML-Renderer.git

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

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

53
Avalonia.sln

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
VisualStudioVersion = 15.0.26730.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
@ -129,7 +129,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInteropTest", "sampl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkInteropDemo", "samples\interop\GtkInteropDemo\GtkInteropDemo.csproj", "{BD7F352C-6DC1-4740-BAF2-2D34A038728C}"
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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderTest", "samples\RenderTest\RenderTest.csproj", "{F1FDC5B0-4654-416F-AE69-E3E9BBD87801}"
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\Moq.props = build\Moq.props
build\NetCore.props = build\NetCore.props
build\ReactiveUI.props = build\ReactiveUI.props
build\Rx.props = build\Rx.props
build\Serilog.props = build\Serilog.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
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
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
GlobalSection(SharedMSBuildProjectFiles) = preSolution
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|x86.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2571,5 +2616,9 @@ Global
{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
EndGlobalSection
EndGlobal

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>

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">
<ItemGroup>
<PackageReference Include="System.Reactive" Version="3.0.0" />
<PackageReference Include="System.Reactive.Core" Version="3.0.0" />
<PackageReference Include="System.Reactive.Interfaces" Version="3.0.0" />
<PackageReference Include="System.Reactive.Linq" Version="3.0.0" />
<PackageReference Include="System.Reactive.PlatformServices" Version="3.0.0" />
<PackageReference Condition="'$(TargetFramework)' == 'net45'" Include="System.Reactive.Windows.Threading" Version="3.0.0" />
<PackageReference Condition="'$(TargetFramework)' == 'net461'" Include="System.Reactive.Windows.Threading" Version="3.0.0" />
<PackageReference Include="System.Reactive" Version="3.1.1" />
<PackageReference Include="System.Reactive.Core" Version="3.1.1" />
<PackageReference Include="System.Reactive.Interfaces" Version="3.1.1" />
<PackageReference Include="System.Reactive.Linq" Version="3.1.1" />
<PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
<PackageReference Condition="$(TargetFramework.StartsWith('net4'))" Include="System.Reactive.Windows.Threading" Version="3.1.1" />
</ItemGroup>
</Project>

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`
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
Column and row definitions can be specified in Avalonia using strings, avoiding

40
packages.cake

@ -110,6 +110,7 @@ public class Packages
var SplatVersion = packageVersions["Splat"].FirstOrDefault().Item1;
var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
var ReactiveUIVersion = packageVersions["reactiveui"].FirstOrDefault().Item1;
var SystemValueTupleVersion = packageVersions["System.ValueTuple"].FirstOrDefault().Item1;
SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
SkiaSharpLinuxVersion = packageVersions["Avalonia.Skia.Linux.Natives"].FirstOrDefault().Item1;
@ -123,6 +124,7 @@ public class Packages
context.Information("Package: Splat, version: {0}", SplatVersion);
context.Information("Package: Sprache, version: {0}", SpracheVersion);
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: SkiaSharp, version: {0}", SkiaSharpVersion);
context.Information("Package: Avalonia.Skia.Linux.Natives, version: {0}", SkiaSharpLinuxVersion);
@ -175,7 +177,6 @@ public class Packages
new [] { "./src/", "Avalonia.Visuals", ".xml" },
new [] { "./src/", "Avalonia.Styling", ".dll" },
new [] { "./src/", "Avalonia.Styling", ".xml" },
new [] { "./src/", "Avalonia.ReactiveUI", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".dll" },
new [] { "./src/", "Avalonia.Themes.Default", ".xml" },
new [] { "./src/Markup/", "Avalonia.Markup", ".dll" },
@ -272,7 +273,24 @@ public class Packages
},
BasePath = context.Directory("./src/Avalonia.HtmlRenderer/bin/" + parameters.DirSuffix + "/netstandard2.0"),
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 []
@ -431,6 +449,20 @@ public class Packages
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/OSX/Avalonia.MonoMac/bin/" + parameters.DirSuffix),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
// Avalonia.Desktop
///////////////////////////////////////////////////////////////////////////////
@ -446,10 +478,12 @@ public class Packages
new NuSpecDependency() { Id = "Avalonia.Win32", 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.MonoMac", TargetFramework="net45", Version = parameters.Version },
//.NET Core
new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp2.0", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Skia", TargetFramework="netcoreapp2.0", Version = parameters.Version },
new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp2.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[]
{

1
samples/BindingTest/App.xaml.cs

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

2
samples/BindingTest/BindingTest.csproj

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

10
samples/BindingTest/ViewModels/MainWindowViewModel.cs

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

2
samples/BindingTest/ViewModels/NestedCommandViewModel.cs

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

35
samples/ControlCatalog.NetCore/Program.cs

@ -1,24 +1,47 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia;
namespace ControlCatalog.NetCore
{
class Program
static class Program
{
static void Main(string[] args)
{
if (args.Contains("--fbdev")) AppBuilder.Configure<App>().InitializeWithLinuxFramebuffer(tl =>
if (args.Contains("--wait-for-attach"))
{
tl.Content = new MainView();
System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
});
Console.WriteLine("Attach debugger and use 'Set next statement'");
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
AppBuilder.Configure<App>()
.UsePlatformDetect()
.CustomPlatformDetect()
.UseReactiveUI()
.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()
{
Console.CursorVisible = false;

12
samples/ControlCatalog/ControlCatalog.csproj

@ -32,6 +32,12 @@
<EmbeddedResource Include="MainView.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="DecoratedWindow.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\DialogsPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\BorderPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
@ -83,9 +89,15 @@
<Compile Include="MainView.xaml.cs">
<DependentUpon>MainView.xaml</DependentUpon>
</Compile>
<Compile Include="DecoratedWindow.xaml.cs">
<DependentUpon>DecoratedWindow.xaml</DependentUpon>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\DialogsPage.xaml.cs">
<DependentUpon>DialogsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\BorderPage.xaml.cs">
<DependentUpon>BorderPage.xaml</DependentUpon>
</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"
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabControl Classes="sidebar">
<TabControl Classes="sidebar" Name="Sidebar">
<TabControl.Transition>
<CrossFade Duration="0.25"/>
</TabControl.Transition>

9
samples/ControlCatalog/MainView.xaml.cs

@ -1,6 +1,9 @@
using System.Collections;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using ControlCatalog.Pages;
namespace ControlCatalog
{
@ -9,6 +12,12 @@ namespace ControlCatalog
public MainView()
{
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()

5
samples/ControlCatalog/MainWindow.xaml.cs

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

10
samples/ControlCatalog/Pages/BorderPage.xaml

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

8
samples/ControlCatalog/Pages/ButtonPage.xaml

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

2
samples/ControlCatalog/Pages/ContextMenuPage.xaml

@ -7,7 +7,7 @@
Margin="0,16,0,0"
HorizontalAlignment="Center"
Gap="16">
<Border Background="{StyleResource ThemeAccentBrush}"
<Border Background="{DynamicResource ThemeAccentBrush}"
Padding="48,48,48,48">
<Border.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">
<DropDownItem>
<Panel>
<Rectangle Fill="{StyleResource ThemeAccentBrush}"/>
<Rectangle Fill="{DynamicResource ThemeAccentBrush}"/>
<TextBlock Margin="8">Control Items</TextBlock>
</Panel>
</DropDownItem>

8
samples/ControlCatalog/Pages/LayoutTransformControlPage.xaml

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

4
samples/ControlCatalog/SideBar.xaml

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

2
samples/RenderTest/Pages/ClippingPage.xaml

@ -5,7 +5,7 @@
Width="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 ">
<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 -->
<TextBox Text="Avalonia" Opacity="0.9" VerticalAlignment="Center"/>
</Border>

8
samples/RenderTest/Pages/DrawingPage.xaml

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

1
samples/RenderTest/Program.cs

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

1
samples/RenderTest/RenderTest.csproj

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

4
samples/RenderTest/SideBar.xaml

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

10
samples/RenderTest/ViewModels/MainWindowViewModel.cs

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

1
samples/VirtualizationTest/Program.cs

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

25
samples/VirtualizationTest/ViewModels/MainWindowViewModel.cs

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

1
samples/VirtualizationTest/VirtualizationTest.csproj

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

3
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -47,6 +47,9 @@ namespace Avalonia
{
Dictionary<int, AvaloniaProperty> inner;
// Ensure the type's static ctor has been run.
RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle);
if (_attached.TryGetValue(ownerType, out inner))
{
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="TValue">The type of the dictionary value.</typeparam>
public class AvaloniaDictionary<TKey, TValue> : IDictionary<TKey, TValue>,
IDictionary,
INotifyCollectionChanged,
INotifyPropertyChanged
{
@ -51,6 +52,16 @@ namespace Avalonia.Collections
/// <inheritdoc/>
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>
/// Gets or sets the named resource.
/// </summary>
@ -89,6 +100,8 @@ namespace Avalonia.Collections
}
}
object IDictionary.this[object key] { get => ((IDictionary)_inner)[key]; set => ((IDictionary)_inner)[key] = value; }
/// <inheritdoc/>
public void Add(TKey key, TValue value)
{
@ -118,10 +131,7 @@ namespace Avalonia.Collections
}
/// <inheritdoc/>
public bool ContainsKey(TKey key)
{
return _inner.ContainsKey(key);
}
public bool ContainsKey(TKey key) => _inner.ContainsKey(key);
/// <inheritdoc/>
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
@ -130,21 +140,16 @@ namespace Avalonia.Collections
}
/// <inheritdoc/>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _inner.GetEnumerator();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _inner.GetEnumerator();
/// <inheritdoc/>
public bool Remove(TKey key)
{
TValue value;
if (_inner.TryGetValue(key, out value))
if (_inner.TryGetValue(key, out TValue value))
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
if (CollectionChanged != null)
{
var e = new NotifyCollectionChangedEventArgs(
@ -163,16 +168,13 @@ namespace Avalonia.Collections
}
/// <inheritdoc/>
public bool TryGetValue(TKey key, out TValue value)
{
return _inner.TryGetValue(key, out value);
}
public bool TryGetValue(TKey key, out TValue value) => _inner.TryGetValue(key, out value);
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return _inner.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator();
/// <inheritdoc/>
void ICollection.CopyTo(Array array, int index) => ((ICollection)_inner).CopyTo(array, index);
/// <inheritdoc/>
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
@ -192,6 +194,18 @@ namespace Avalonia.Collections
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)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));

51
src/Avalonia.Controls/Application.cs

@ -29,7 +29,7 @@ namespace Avalonia
/// method.
/// - Tracks the lifetime of the application.
/// </remarks>
public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IApplicationLifecycle
public class Application : IApplicationLifecycle, IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IResourceNode
{
/// <summary>
/// The application-global data templates.
@ -40,6 +40,7 @@ namespace Avalonia
new Lazy<IClipboard>(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)));
private readonly Styler _styler = new Styler();
private Styles _styles;
private IResourceDictionary _resources;
/// <summary>
/// Initializes a new instance of the <see cref="Application"/> class.
@ -49,6 +50,9 @@ namespace Avalonia
OnExit += OnExiting;
}
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <summary>
/// Gets the current instance of the <see cref="Application"/> class.
/// </summary>
@ -97,6 +101,34 @@ namespace Avalonia
/// </summary>
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>
/// Gets the application's global styles.
/// </summary>
@ -119,6 +151,12 @@ namespace Avalonia
/// <inheritdoc/>
bool IStyleHost.IsStylesInitialized => _styles != null;
/// <inheritdoc/>
bool IResourceProvider.HasResources => _resources?.Count > 0;
/// <inheritdoc/>
IResourceNode IResourceNode.ResourceParent => null;
/// <summary>
/// Initializes the application by loading XAML etc.
/// </summary>
@ -145,13 +183,20 @@ namespace Avalonia
{
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>
/// Sent when the application is exiting.
/// </summary>
public event EventHandler OnExit;
/// <summary>
/// Called when the application is exiting.
/// </summary>

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

134
src/Avalonia.Controls/Control.cs

@ -97,8 +97,9 @@ namespace Avalonia.Controls
private bool _isAttachedToLogicalTree;
private IAvaloniaList<ILogical> _logicalChildren;
private INameScope _nameScope;
private bool _styled;
private IResourceDictionary _resources;
private Styles _styles;
private bool _styled;
private Subject<IStyleable> _styleDetach = new Subject<IStyleable>();
/// <summary>
@ -153,6 +154,11 @@ namespace Avalonia.Controls
/// </remarks>
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>
/// Gets or sets the name of the control.
/// </summary>
@ -262,7 +268,32 @@ namespace Avalonia.Controls
/// each control may in addition define its own styles which are applied to the control
/// itself and its children.
/// </remarks>
public Styles Styles => _styles ?? (_styles = new Styles());
public Styles Styles
{
get { return _styles ?? (Styles = new Styles()); }
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>
/// Gets the control's logical parent.
@ -278,6 +309,34 @@ namespace Avalonia.Controls
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>
/// Gets or sets a user-defined object attached to the control.
/// </summary>
@ -296,9 +355,35 @@ namespace Avalonia.Controls
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>
/// Gets a value indicating whether the element is attached to a rooted logical tree.
/// </summary>
@ -314,6 +399,12 @@ namespace Avalonia.Controls
/// </summary>
IAvaloniaReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren;
/// <inheritdoc/>
bool IResourceProvider.HasResources => _resources?.Count > 0 || Styles.HasResources;
/// <inheritdoc/>
IResourceNode IResourceNode.ResourceParent => ((IStyleHost)this).StylingParent as IResourceNode;
/// <inheritdoc/>
IAvaloniaReadOnlyList<string> IStyleable.Classes => Classes;
@ -390,31 +481,24 @@ namespace Avalonia.Controls
this.OnDetachedFromLogicalTreeCore(e);
}
/// <summary>
/// Gets the control's logical children.
/// </summary>
protected IAvaloniaList<ILogical> LogicalChildren
/// <inheritdoc/>
void ILogical.NotifyResourcesChanged(ResourcesChangedEventArgs e)
{
get
{
if (_logicalChildren == null)
{
var list = new AvaloniaList<ILogical>();
list.ResetBehavior = ResetBehavior.Remove;
list.Validate = ValidateLogicalChild;
list.CollectionChanged += LogicalChildrenCollectionChanged;
_logicalChildren = list;
}
ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
return _logicalChildren;
foreach (var child in LogicalChildren)
{
child.NotifyResourcesChanged(e);
}
}
/// <summary>
/// Gets the <see cref="Classes"/> collection in a form that allows adding and removing
/// pseudoclasses.
/// </summary>
protected IPseudoClasses PseudoClasses => Classes;
/// <inheritdoc/>
bool IResourceProvider.TryGetResource(string key, out object value)
{
value = null;
return (_resources?.TryGetResource(key, out value) ?? false) ||
(_styles?.TryGetResource(key, out value) ?? false);
}
/// <summary>
/// Sets the control's logical parent.
@ -450,6 +534,7 @@ namespace Avalonia.Controls
}
_parent = (IControl)parent;
((ILogical)this).NotifyResourcesChanged(new ResourcesChangedEventArgs());
if (_parent is IStyleRoot || _parent?.IsAttachedToLogicalTree == true || this is IStyleRoot)
{
@ -841,5 +926,10 @@ namespace Avalonia.Controls
}
}
}
private void ThisResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
((ILogical)this).NotifyResourcesChanged(e);
}
}
}

1
src/Avalonia.Controls/IControl.cs

@ -20,6 +20,7 @@ namespace Avalonia.Controls
ILayoutable,
IInputElement,
INamed,
IResourceNode,
IStyleable,
IStyleHost
{

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

@ -31,7 +31,7 @@ namespace Avalonia.Platform
IDisposable ShowDialog();
/// <summary>
/// Enables of disables system window decorations (title bar, buttons, etc)
/// Enables or disables system window decorations (title bar, buttons, etc)
/// </summary>
void SetSystemDecorations(bool enabled);
@ -39,5 +39,10 @@ namespace Avalonia.Platform
/// Sets the icon of this window.
/// </summary>
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)
{
_highlightBrush = (IBrush)this.FindStyleResource("HighlightBrush");
_highlightBrush = (IBrush)this.FindResource("HighlightBrush");
}
foreach (var rect in rects)

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

@ -38,6 +38,18 @@ namespace Avalonia.Controls.Primitives
o => o.Value,
(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 _maximum = 100.0;
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>
/// Throws an exception if the double valus is NaN or Inf.
/// </summary>

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

@ -5,6 +5,7 @@ using System;
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Data;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Primitives
{
@ -31,13 +32,18 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation));
private Button _lineUpButton;
private Button _lineDownButton;
private Button _pageUpButton;
private Button _pageDownButton;
/// <summary>
/// Initializes static members of the <see cref="ScrollBar"/> class.
/// </summary>
static ScrollBar()
{
PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Vertical, ":vertical");
PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal");
PseudoClass(OrientationProperty, o => o == Orientation.Vertical, ":vertical");
PseudoClass(OrientationProperty, o => o == Orientation.Horizontal, ":horizontal");
}
/// <summary>
@ -97,12 +103,101 @@ namespace Avalonia.Controls.Primitives
return false;
case ScrollBarVisibility.Auto:
var viewportSize = ViewportSize;
return double.IsNaN(viewportSize) || viewportSize < Maximum - Minimum;
return double.IsNaN(ViewportSize) || Maximum > 0;
default:
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); }
}
protected override void OnClick(RoutedEventArgs e)
protected override void OnClick()
{
Toggle();
base.OnClick(e);
base.OnClick();
}
protected virtual void Toggle()

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

@ -10,7 +10,7 @@ namespace Avalonia.Controls.Primitives
public class Track : Control
{
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 =
RangeBase.MaximumProperty.AddOwner<Track>(o => o.Maximum, (o, v) => o.Maximum = v);
@ -25,7 +25,13 @@ namespace Avalonia.Controls.Primitives
ScrollBar.OrientationProperty.AddOwner<Track>();
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 _maximum = 100.0;
@ -34,6 +40,8 @@ namespace Avalonia.Controls.Primitives
static Track()
{
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);
}
@ -74,6 +82,18 @@ namespace Avalonia.Controls.Primitives
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)
{
var thumb = Thumb;
@ -98,34 +118,54 @@ namespace Avalonia.Controls.Primitives
protected override Size ArrangeOverride(Size finalSize)
{
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 thumbFraction = ViewportSize / range;
var valueFraction = (Value - Minimum) / range;
var thumbWidth = double.IsNaN(viewportSize) ? thumb?.DesiredSize.Width ?? 0 : finalSize.Width * viewportSize / extent;
var remaining = finalSize.Width - thumbWidth;
var firstWidth = range <= 0 ? 0 : remaining * offset / range;
if (double.IsNaN(valueFraction) || double.IsInfinity(valueFraction))
if (decreaseButton != null)
{
valueFraction = 0;
thumbFraction = 1;
decreaseButton.Arrange(new Rect(0, 0, firstWidth, finalSize.Height));
}
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);
var x = (finalSize.Width - width) * valueFraction;
thumb.Arrange(new Rect(x, 0, width, finalSize.Height));
increaseButton.Arrange(new Rect(firstWidth + thumbWidth, 0, remaining - firstWidth, 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);
var y = (finalSize.Height - height) * valueFraction;
thumb.Arrange(new Rect(0, y, finalSize.Width, height));
decreaseButton.Arrange(new Rect(0, 0, finalSize.Width, firstHeight));
}
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)
{
oldThumb.DragDelta -= ThumbDragged;
}
LogicalChildren.Clear();
VisualChildren.Clear();
LogicalChildren.Remove(oldThumb);
VisualChildren.Remove(oldThumb);
}
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)
{
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>
protected double HorizontalScrollBarViewportSize
{
get { return Max((_viewport.Width / _extent.Width) * (_extent.Width - _viewport.Width), 0); }
get { return _viewport.Width; }
}
/// <summary>
@ -308,7 +308,7 @@ namespace Avalonia.Controls
/// </summary>
protected double VerticalScrollBarViewportSize
{
get { return Max((_viewport.Height / _extent.Height) * (_extent.Height - _viewport.Height), 0); }
get { return _viewport.Height; }
}
/// <summary>

55
src/Avalonia.Controls/Slider.cs

@ -33,6 +33,8 @@ namespace Avalonia.Controls
// Slider required parts
private Track _track;
private Button _decreaseButton;
private Button _increaseButton;
/// <summary>
/// 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.DragDeltaEvent.AddClassHandler<Slider>(x => x.OnThumbDragDelta, RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler<Slider>(x => x.OnThumbDragCompleted, RoutingStrategies.Bubble);
SmallChangeProperty.OverrideDefaultValue<Slider>(1);
LargeChangeProperty.OverrideDefaultValue<Slider>(10);
}
/// <summary>
@ -83,7 +87,54 @@ namespace Avalonia.Controls
/// <inheritdoc/>
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>
@ -101,7 +152,7 @@ namespace Avalonia.Controls
protected virtual void OnThumbDragDelta(VectorEventArgs e)
{
Thumb thumb = e.Source as Thumb;
if (thumb != null && _track.Thumb == thumb)
if (thumb != null && _track?.Thumb == thumb)
{
MoveToNextTick(_track.Value);
}

2
src/Avalonia.Controls/SystemDialog.cs

@ -20,7 +20,7 @@ namespace Avalonia.Controls
{
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)) ??
new string[0]).FirstOrDefault();

24
src/Avalonia.Controls/TopLevel.cs

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

24
src/Avalonia.Controls/Window.cs

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

6
src/Avalonia.DotNetCoreRuntime/AppBuilder.cs

@ -37,12 +37,15 @@ namespace Avalonia
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UsePlatformDetect()
{
var os = RuntimePlatform.GetRuntimeInfo().OperatingSystem;
//We don't have the ability to load every assembly right now, so we are
//stuck with manual configuration here
//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
if (RuntimePlatform.GetRuntimeInfo().OperatingSystem == OperatingSystemType.WinNT)
if (os == OperatingSystemType.WinNT)
LoadWin32();
else if(os==OperatingSystemType.OSX)
LoadMonoMac();
else
LoadGtk3();
this.UseSkia();
@ -50,6 +53,7 @@ namespace Avalonia
return this;
}
void LoadMonoMac() => this.UseMonoMac();
void LoadWin32() => this.UseWin32();
void LoadGtk3() => this.UseGtk3();
}

1
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@ -16,6 +16,7 @@
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.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="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj" />
</ItemGroup>

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;
});
}
}
}

74
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -1,83 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</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>
<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.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
@ -88,5 +15,6 @@
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
</ItemGroup>
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
<Import Project="..\..\build\Splat.props" />
</Project>

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

@ -3,7 +3,4 @@
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")]

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

1
src/Avalonia.Styling/Avalonia.Styling.csproj

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>Avalonia</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<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; }
}
}

15
src/Avalonia.Styling/Controls/IResourceNode.cs

@ -0,0 +1,15 @@
using System;
namespace Avalonia.Controls
{
/// <summary>
/// Represents resource provider in a tree.
/// </summary>
public interface IResourceNode : IResourceProvider
{
/// <summary>
/// Gets the parent resource node, if any.
/// </summary>
IResourceNode ResourceParent { get; }
}
}

33
src/Avalonia.Styling/Controls/IResourceProvider.cs

@ -0,0 +1,33 @@
using System;
namespace Avalonia.Controls
{
/// <summary>
/// Represents an object that can be queried for resources.
/// </summary>
public interface IResourceProvider
{
/// <summary>
/// Raised when resources in the provider are changed.
/// </summary>
event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <summary>
/// Gets a value indicating whether the element has resources.
/// </summary>
bool HasResources { get; }
/// <summary>
/// Tries to find a resource within the provider.
/// </summary>
/// <param name="key">The resource key.</param>
/// <param name="value">
/// When this method returns, contains the value associated with the specified key,
/// if the key is found; otherwise, null.
/// </param>
/// <returns>
/// True if the resource if found, otherwise false.
/// </returns>
bool TryGetResource(string key, out object value);
}
}

101
src/Avalonia.Styling/Controls/ResourceDictionary.cs

@ -0,0 +1,101 @@
// 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;
using System.Collections.Specialized;
using System.Linq;
using Avalonia.Collections;
namespace Avalonia.Controls
{
/// <summary>
/// An indexed dictionary of resources.
/// </summary>
public class ResourceDictionary : AvaloniaDictionary<object, object>, IResourceDictionary
{
private AvaloniaList<IResourceProvider> _mergedDictionaries;
/// <summary>
/// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
/// </summary>
public ResourceDictionary()
{
CollectionChanged += OnCollectionChanged;
}
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <inheritdoc/>
public IList<IResourceProvider> MergedDictionaries
{
get
{
if (_mergedDictionaries == null)
{
_mergedDictionaries = new AvaloniaList<IResourceProvider>();
_mergedDictionaries.ResetBehavior = ResetBehavior.Remove;
_mergedDictionaries.ForEachItem(
x =>
{
if (x.HasResources)
{
OnResourcesChanged();
}
x.ResourcesChanged += MergedDictionaryResourcesChanged;
},
x =>
{
if (x.HasResources)
{
OnResourcesChanged();
}
x.ResourcesChanged -= MergedDictionaryResourcesChanged;
},
() => { });
}
return _mergedDictionaries;
}
}
/// <inheritdoc/>
bool IResourceProvider.HasResources
{
get => Count > 0 || (_mergedDictionaries?.Any(x => x.HasResources) ?? false);
}
/// <inheritdoc/>
public bool TryGetResource(string key, out object value)
{
if (TryGetValue(key, out value))
{
return true;
}
if (_mergedDictionaries != null)
{
for (var i = _mergedDictionaries.Count - 1; i >= 0; --i)
{
if (_mergedDictionaries[i].TryGetResource(key, out value))
{
return true;
}
}
}
return false;
}
private void OnResourcesChanged()
{
ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => OnResourcesChanged();
private void MergedDictionaryResourcesChanged(object sender, ResourcesChangedEventArgs e) => OnResourcesChanged();
}
}

65
src/Avalonia.Styling/Controls/ResourceProviderExtensions.cs

@ -0,0 +1,65 @@
using System;
using System.Reactive;
using System.Reactive.Linq;
namespace Avalonia.Controls
{
public static class ResourceProviderExtensions
{
/// <summary>
/// Finds the specified resource by searching up the logical tree and then global styles.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="key">The resource key.</param>
/// <returns>The resource, or <see cref="AvaloniaProperty.UnsetValue"/> if not found.</returns>
public static object FindResource(this IResourceNode control, string key)
{
if (control.TryFindResource(key, out var value))
{
return value;
}
return AvaloniaProperty.UnsetValue;
}
/// <summary>
/// Tries to the specified resource by searching up the logical tree and then global styles.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="key">The resource key.</param>
/// <param name="value">On return, contains the resource if found, otherwise null.</param>
/// <returns>True if the resource was found; otherwise false.</returns>
public static bool TryFindResource(this IResourceNode control, string key, out object value)
{
Contract.Requires<ArgumentNullException>(control != null);
Contract.Requires<ArgumentNullException>(key != null);
var current = control;
while (current != null)
{
if (current is IResourceNode host)
{
if (host.TryGetResource(key, out value))
{
return true;
}
}
current = current.ResourceParent;
}
value = null;
return false;
}
public static IObservable<object> GetResourceObservable(this IResourceNode target, string key)
{
return Observable.FromEventPattern<ResourcesChangedEventArgs>(
x => target.ResourcesChanged += x,
x => target.ResourcesChanged -= x)
.StartWith((EventPattern<ResourcesChangedEventArgs>)null)
.Select(x => target.FindResource(key));
}
}
}

11
src/Avalonia.Styling/Controls/ResourcesChangedEventArgs.cs

@ -0,0 +1,11 @@
// 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
{
public class ResourcesChangedEventArgs : EventArgs
{
}
}

11
src/Avalonia.Styling/LogicalTree/ILogical.cs

@ -3,6 +3,7 @@
using System;
using Avalonia.Collections;
using Avalonia.Controls;
namespace Avalonia.LogicalTree
{
@ -55,5 +56,15 @@ namespace Avalonia.LogicalTree
/// this method yourself.
/// </remarks>
void NotifyDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e);
/// <summary>
/// Notifies the control that a change has been made to resources that apply to it.
/// </summary>
/// <param name="e">The event args.</param>
/// <remarks>
/// This method will be called automatically by the framework, you should not need to call
/// this method yourself.
/// </remarks>
void NotifyResourcesChanged(ResourcesChangedEventArgs e);
}
}

2
src/Avalonia.Styling/Properties/AssemblyInfo.cs

@ -6,5 +6,7 @@ using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: AssemblyTitle("Avalonia.Styling")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.LogicalTree")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")]
[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests")]

32
src/Avalonia.Styling/Styling/ISetStyleParent.cs

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Controls;
namespace Avalonia.Styling
{
/// <summary>
/// Defines an interface through which a <see cref="Style"/>'s parent can be set.
/// </summary>
/// <remarks>
/// You should not usually need to use this interface - it is for internal use only.
/// </remarks>
public interface ISetStyleParent : IStyle
{
/// <summary>
/// Sets the style parent.
/// </summary>
/// <param name="parent">The parent.</param>
void SetParent(IResourceNode parent);
/// <summary>
/// Notifies the style that a change has been made to resources that apply to it.
/// </summary>
/// <param name="e">The event args.</param>
/// <remarks>
/// This method will be called automatically by the framework, you should not need to call
/// this method yourself.
/// </remarks>
void NotifyResourcesChanged(ResourcesChangedEventArgs e);
}
}

13
src/Avalonia.Styling/Styling/IStyle.cs

@ -1,12 +1,14 @@
// 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;
namespace Avalonia.Styling
{
/// <summary>
/// Defines the interface for styles.
/// </summary>
public interface IStyle
public interface IStyle : IResourceNode
{
/// <summary>
/// Attaches the style to a control if the style's selector matches.
@ -16,14 +18,5 @@ namespace Avalonia.Styling
/// The control that contains this style. May be null.
/// </param>
void Attach(IStyleable control, IStyleHost container);
/// <summary>
/// Tries to find a named resource within the style.
/// </summary>
/// <param name="name">The resource name.</param>
/// <returns>
/// The resource if found, otherwise <see cref="AvaloniaProperty.UnsetValue"/>.
/// </returns>
object FindResource(string name);
}
}

92
src/Avalonia.Styling/Styling/Style.cs

@ -3,7 +3,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Metadata;
namespace Avalonia.Styling
@ -11,12 +13,12 @@ namespace Avalonia.Styling
/// <summary>
/// Defines a style.
/// </summary>
public class Style : IStyle
public class Style : IStyle, ISetStyleParent
{
private static Dictionary<IStyleable, List<IDisposable>> _applied =
new Dictionary<IStyleable, List<IDisposable>>();
private StyleResources _resources;
private IResourceNode _parent;
private IResourceDictionary _resources;
/// <summary>
/// Initializes a new instance of the <see cref="Style"/> class.
@ -34,33 +36,33 @@ namespace Avalonia.Styling
Selector = selector(null);
}
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <summary>
/// Gets or sets a dictionary of style resources.
/// </summary>
public StyleResources Resources
public IResourceDictionary Resources
{
get
get => _resources ?? (Resources = new ResourceDictionary());
set
{
if (_resources == null)
Contract.Requires<ArgumentNullException>(value != null);
var hadResources = false;
if (_resources != null)
{
_resources = new StyleResources();
hadResources = _resources.Count > 0;
_resources.ResourcesChanged -= ResourceDictionaryChanged;
}
return _resources;
}
_resources = value;
_resources.ResourcesChanged += ResourceDictionaryChanged;
set
{
var resources = Resources;
if (!Equals(resources, value))
if (hadResources || _resources.Count > 0)
{
foreach (var i in value)
{
resources[i.Key] = i.Value;
//resources.Add(i.Key, i.Value);
//(resources as IDictionary<string,object>).Add(i);
}
((ISetStyleParent)this).NotifyResourcesChanged(new ResourcesChangedEventArgs());
}
}
}
@ -76,6 +78,12 @@ namespace Avalonia.Styling
[Content]
public IList<ISetter> Setters { get; set; } = new List<ISetter>();
/// <inheritdoc/>
IResourceNode IResourceNode.ResourceParent => _parent;
/// <inheritdoc/>
bool IResourceProvider.HasResources => _resources?.Count > 0;
/// <summary>
/// Attaches the style to a control if the style's selector matches.
/// </summary>
@ -112,25 +120,11 @@ namespace Avalonia.Styling
}
}
/// <summary>
/// Tries to find a named resource within the style.
/// </summary>
/// <param name="name">The resource name.</param>
/// <returns>
/// The resource if found, otherwise <see cref="AvaloniaProperty.UnsetValue"/>.
/// </returns>
public object FindResource(string name)
/// <inheritdoc/>
public bool TryGetResource(string key, out object result)
{
object result = null;
if (_resources?.TryGetValue(name, out result) == true)
{
return result;
}
else
{
return AvaloniaProperty.UnsetValue;
}
result = null;
return _resources?.TryGetResource(key, out result) ?? false;
}
/// <summary>
@ -149,6 +143,23 @@ namespace Avalonia.Styling
}
}
/// <inheritdoc/>
void ISetStyleParent.NotifyResourcesChanged(ResourcesChangedEventArgs e)
{
ResourcesChanged?.Invoke(this, e);
}
/// <inheritdoc/>
void ISetStyleParent.SetParent(IResourceNode parent)
{
if (_parent != null && parent != null)
{
throw new InvalidOperationException("The Style already has a parent.");
}
_parent = parent;
}
private static List<IDisposable> GetSubscriptions(IStyleable control)
{
List<IDisposable> subscriptions;
@ -179,5 +190,10 @@ namespace Avalonia.Styling
_applied.Remove(control);
}
private void ResourceDictionaryChanged(object sender, ResourcesChangedEventArgs e)
{
ResourcesChanged?.Invoke(this, e);
}
}
}

42
src/Avalonia.Styling/Styling/StyleExtensions.cs

@ -1,42 +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;
namespace Avalonia.Styling
{
public static class StyleExtensions
{
/// <summary>
/// Tries to find a named style resource.
/// </summary>
/// <param name="control">The control from which to find the resource.</param>
/// <param name="name">The resource name.</param>
/// <returns>
/// The resource if found, otherwise <see cref="AvaloniaProperty.UnsetValue"/>.
/// </returns>
public static object FindStyleResource(this IStyleHost control, string name)
{
Contract.Requires<ArgumentNullException>(control != null);
Contract.Requires<ArgumentNullException>(name != null);
Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(name));
while (control != null)
{
if (control.IsStylesInitialized)
{
var result = control.Styles.FindResource(name);
if (result != AvaloniaProperty.UnsetValue)
{
return result;
}
}
control = control.StylingParent;
}
return AvaloniaProperty.UnsetValue;
}
}
}

90
src/Avalonia.Styling/Styling/StyleResources.cs

@ -1,90 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Avalonia.Styling
{
/// <summary>
/// Holds resources for a <see cref="Style"/>.
/// </summary>
public class StyleResources : IDictionary<string, object>, IDictionary
{
private Dictionary<string, object> _inner = new Dictionary<string, object>();
public object this[string key]
{
get { return _inner[key]; }
set { _inner[key] = value; }
}
public int Count => _inner.Count;
ICollection<string> IDictionary<string, object>.Keys => _inner.Keys;
ICollection<object> IDictionary<string, object>.Values => _inner.Values;
bool ICollection<KeyValuePair<string, object>>.IsReadOnly => false;
object IDictionary.this[object key]
{
get { return ((IDictionary)_inner)[key]; }
set { ((IDictionary)_inner)[key] = value; }
}
ICollection IDictionary.Keys => _inner.Keys;
ICollection IDictionary.Values => _inner.Values;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => ((IDictionary)_inner).SyncRoot;
bool IDictionary.IsFixedSize => false;
bool IDictionary.IsReadOnly => false;
public void Add(string key, object value) => _inner.Add(key, value);
public void Clear() => _inner.Clear();
public bool ContainsKey(string key) => _inner.ContainsKey(key);
public bool Remove(string key) => _inner.Remove(key);
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => _inner.GetEnumerator();
public bool TryGetValue(string key, out object value) => _inner.TryGetValue(key, out value);
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
{
return ((IDictionary<string, object>)_inner).Contains(item);
}
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
{
((IDictionary<string, object>)_inner).Add(item);
}
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
((IDictionary<string, object>)_inner).CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
{
return ((IDictionary<string, object>)_inner).Remove(item);
}
void ICollection.CopyTo(Array array, int index) => ((IDictionary)_inner).CopyTo(array, index);
IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator();
IDictionaryEnumerator IDictionary.GetEnumerator() => ((IDictionary)_inner).GetEnumerator();
void IDictionary.Add(object key, object value) => ((IDictionary)_inner).Add(key, value);
bool IDictionary.Contains(object key) => ((IDictionary)_inner).Contains(key);
void IDictionary.Remove(object key) => ((IDictionary)_inner).Remove(key);
}
}

149
src/Avalonia.Styling/Styling/Styles.cs

@ -1,16 +1,95 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
namespace Avalonia.Styling
{
/// <summary>
/// A style that consists of a number of child styles.
/// </summary>
public class Styles : AvaloniaList<IStyle>, IStyle
public class Styles : AvaloniaList<IStyle>, IStyle, ISetStyleParent
{
private IResourceNode _parent;
private IResourceDictionary _resources;
public Styles()
{
ResetBehavior = ResetBehavior.Remove;
this.ForEachItem(
x =>
{
if (x.ResourceParent == null && x is ISetStyleParent setParent)
{
setParent.SetParent(this);
setParent.NotifyResourcesChanged(new ResourcesChangedEventArgs());
}
if (x.HasResources)
{
ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
}
x.ResourcesChanged += SubResourceChanged;
},
x =>
{
if (x.ResourceParent == this && x is ISetStyleParent setParent)
{
setParent.SetParent(null);
setParent.NotifyResourcesChanged(new ResourcesChangedEventArgs());
}
if (x.HasResources)
{
ResourcesChanged?.Invoke(this, new ResourcesChangedEventArgs());
}
x.ResourcesChanged -= SubResourceChanged;
},
() => { });
}
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged;
/// <inheritdoc/>
public bool HasResources => _resources?.Count > 0 || this.Any(x => x.HasResources);
/// <summary>
/// Gets or sets a dictionary of style resources.
/// </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 -= ResourceDictionaryChanged;
}
_resources = value;
_resources.ResourcesChanged += ResourceDictionaryChanged;
if (hadResources || _resources.Count > 0)
{
((ISetStyleParent)this).NotifyResourcesChanged(new ResourcesChangedEventArgs());
}
}
}
/// <inheritdoc/>
IResourceNode IResourceNode.ResourceParent => _parent;
/// <summary>
/// Attaches the style to a control if the style's selector matches.
/// </summary>
@ -26,26 +105,68 @@ namespace Avalonia.Styling
}
}
/// <summary>
/// Tries to find a named resource within the style.
/// </summary>
/// <param name="name">The resource name.</param>
/// <returns>
/// The resource if found, otherwise <see cref="AvaloniaProperty.UnsetValue"/>.
/// </returns>
public object FindResource(string name)
/// <inheritdoc/>
public bool TryGetResource(string key, out object value)
{
if (_resources != null && _resources.TryGetValue(key, out value))
{
return true;
}
for (var i = Count - 1; i >= 0; --i)
{
if (this[i].TryGetResource(key, out value))
{
return true;
}
}
value = null;
return false;
}
/// <inheritdoc/>
void ISetStyleParent.SetParent(IResourceNode parent)
{
if (_parent != null && parent != null)
{
throw new InvalidOperationException("The Style already has a parent.");
}
_parent = parent;
}
/// <inheritdoc/>
void ISetStyleParent.NotifyResourcesChanged(ResourcesChangedEventArgs e)
{
ResourcesChanged?.Invoke(this, e);
}
private void ResourceDictionaryChanged(object sender, ResourcesChangedEventArgs e)
{
foreach (var style in this.Reverse())
foreach (var child in this)
{
var result = style.FindResource(name);
(child as ISetStyleParent)?.NotifyResourcesChanged(e);
}
ResourcesChanged?.Invoke(this, e);
}
if (result != AvaloniaProperty.UnsetValue)
private void SubResourceChanged(object sender, ResourcesChangedEventArgs e)
{
var foundSource = false;
foreach (var child in this)
{
if (foundSource)
{
return result;
(child as ISetStyleParent)?.NotifyResourcesChanged(e);
}
foundSource |= child == sender;
}
return AvaloniaProperty.UnsetValue;
ResourcesChanged?.Invoke(this, e);
}
}
}

14
src/Avalonia.Themes.Default/Button.xaml

@ -1,9 +1,9 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="Button">
<Setter Property="Background" Value="{StyleResource ThemeControlMidBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderLightBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{StyleResource ThemeForegroundBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLightBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="4"/>
@ -23,12 +23,12 @@
</Setter>
</Style>
<Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="Button:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{StyleResource ThemeControlDarkBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlDarkBrush}"/>
</Style>
<Style Selector="Button:disabled">
<Setter Property="Opacity" Value="{StyleResource ThemeDisabledOpacity}"/>
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
</Styles>

10
src/Avalonia.Themes.Default/CheckBox.xaml

@ -1,8 +1,8 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="CheckBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="Auto,*" Background="{TemplateBinding Background}">
@ -13,7 +13,7 @@
Height="18"
VerticalAlignment="Center">
<Path Name="checkMark"
Fill="{StyleResource HighlightBrush}"
Fill="{DynamicResource HighlightBrush}"
Width="11"
Height="10"
Stretch="Uniform"
@ -32,7 +32,7 @@
</Setter>
</Style>
<Style Selector="CheckBox:pointerover /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderDarkBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderDarkBrush}"/>
</Style>
<Style Selector="CheckBox /template/ Path#checkMark">
<Setter Property="IsVisible" Value="False"/>
@ -41,6 +41,6 @@
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="CheckBox:disabled /template/ Border#border">
<Setter Property="Opacity" Value="{StyleResource ThemeDisabledOpacity}"/>
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
</Styles>

1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -20,6 +20,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.PopupRoot.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ProgressBar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.RadioButton.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.RepeatButton.xaml?assembly=Avalonia.Themes.Default" />
<StyleInclude Source="resm:Avalonia.Themes.Default.Separator.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Slider.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ScrollBar.xaml?assembly=Avalonia.Themes.Default"/>

10
src/Avalonia.Themes.Default/DropDown.xaml

@ -1,7 +1,7 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="DropDown">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<ControlTemplate>
@ -21,7 +21,7 @@
Focusable="False"
IsChecked="{TemplateBinding IsDropDownOpen, Mode=TwoWay}"
Grid.Column="1">
<Path Fill="{StyleResource ThemeForegroundBrush}"
<Path Fill="{DynamicResource ThemeForegroundBrush}"
Width="8"
Height="4"
Stretch="Uniform"
@ -35,7 +35,7 @@
MaxHeight="{TemplateBinding MaxDropDownHeight}"
PlacementTarget="{TemplateBinding}"
StaysOpen="False">
<Border BorderBrush="{StyleResource ThemeBorderMidBrush}"
<Border BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="1">
<ScrollViewer>
<ItemsPresenter Name="PART_ItemsPresenter"
@ -51,6 +51,6 @@
</Setter>
</Style>
<Style Selector="DropDown:pointerover /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderDarkBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderDarkBrush}"/>
</Style>
</Styles>

4
src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml

@ -1,7 +1,7 @@
<Style xmlns="https://github.com/avaloniaui" Selector="EmbeddableControlRoot">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="{StyleResource FontSizeNormal}"/>
<Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}">

8
src/Avalonia.Themes.Default/GridSplitter.xaml

@ -1,7 +1,7 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="GridSplitter:vertical">
<Setter Property="Width" Value="6"/>
<Setter Property="Background" Value="{StyleResource ThemeControlLightBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlLightBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}">
@ -11,7 +11,7 @@
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Width" Value="4"/>
<Setter Property="Height" Value="4"/>
<Setter Property="Fill" Value="{StyleResource ThemeControlMidBrush}"/>
<Setter Property="Fill" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="Margin" Value="1"/>
</Style>
</StackPanel.Styles>
@ -25,7 +25,7 @@
</Style>
<Style Selector="GridSplitter:horizontal">
<Setter Property="Height" Value="6"/>
<Setter Property="Background" Value="{StyleResource ThemeControlLightBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlLightBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}">
@ -35,7 +35,7 @@
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Width" Value="4"/>
<Setter Property="Height" Value="4"/>
<Setter Property="Fill" Value="{StyleResource ThemeControlMidBrush}"/>
<Setter Property="Fill" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="Margin" Value="1"/>
</Style>
</StackPanel.Styles>

6
src/Avalonia.Themes.Default/ListBox.xaml

@ -1,7 +1,7 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ListBox">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<ControlTemplate>

18
src/Avalonia.Themes.Default/MenuItem.xaml

@ -38,7 +38,7 @@
</ContentPresenter>
<Path Name="rightArrow"
Data="M0,0L4,3.5 0,7z"
Fill="{StyleResource ThemeForegroundBrush}"
Fill="{DynamicResource ThemeForegroundBrush}"
Margin="10,0,0,0"
VerticalAlignment="Center"
Grid.Column="3"/>
@ -47,7 +47,7 @@
StaysOpen="True"
IsOpen="{TemplateBinding Path=IsSubMenuOpen, Mode=TwoWay}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{StyleResource ThemeBorderMidBrush}"
BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="1">
<ScrollViewer>
<Panel>
@ -58,7 +58,7 @@
Margin="2"
MemberSelector="{TemplateBinding MemberSelector}"/>
<Rectangle Name="iconSeparator"
Fill="{StyleResource ThemeControlMidBrush}"
Fill="{DynamicResource ThemeControlMidBrush}"
HorizontalAlignment="Left"
IsHitTestVisible="False"
Margin="29,2,0,2"
@ -94,7 +94,7 @@
IsOpen="{TemplateBinding Path=IsSubMenuOpen, Mode=TwoWay}"
StaysOpen="True">
<Border Background="{TemplateBinding Background}"
BorderBrush="{StyleResource ThemeBorderMidBrush}"
BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="1">
<ScrollViewer>
<Panel>
@ -105,7 +105,7 @@
Margin="2"
MemberSelector="{TemplateBinding MemberSelector}"/>
<Rectangle Name="iconSeparator"
Fill="{StyleResource ThemeControlMidBrush}"
Fill="{DynamicResource ThemeControlMidBrush}"
HorizontalAlignment="Left"
IsHitTestVisible="False"
Margin="29,2,0,2"
@ -121,13 +121,13 @@
</Style>
<Style Selector="MenuItem:selected /template/ Border#root">
<Setter Property="Background" Value="{StyleResource ThemeAccentBrush4}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeAccentBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentBrush}"/>
</Style>
<Style Selector="MenuItem:pointerover /template/ Border#root">
<Setter Property="Background" Value="{StyleResource ThemeAccentBrush4}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeAccentBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentBrush}"/>
</Style>
<Style Selector="MenuItem:empty /template/ Path#rightArrow">

2
src/Avalonia.Themes.Default/PopupRoot.xaml

@ -1,5 +1,5 @@
<Style xmlns="https://github.com/avaloniaui" Selector="PopupRoot">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"

4
src/Avalonia.Themes.Default/ProgressBar.xaml

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ProgressBar">
<Setter Property="Background" Value="{StyleResource ThemeAccentBrush4}"/>
<Setter Property="Foreground" Value="{StyleResource ThemeAccentBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeAccentBrush}"/>
<Setter Property="MinHeight" Value="14"/>
<Setter Property="MinWidth" Value="200"/>
<Setter Property="Template">

10
src/Avalonia.Themes.Default/RadioButton.xaml

@ -1,8 +1,8 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="RadioButton">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="Auto,*" Background="{TemplateBinding Background}">
@ -13,7 +13,7 @@
Height="18"
VerticalAlignment="Center"/>
<Ellipse Name="checkMark"
Fill="{StyleResource HighlightBrush}"
Fill="{DynamicResource HighlightBrush}"
Width="10"
Height="10"
Stretch="Uniform"
@ -31,7 +31,7 @@
</Setter>
</Style>
<Style Selector="RadioButton:pointerover /template/ Ellipse#border">
<Setter Property="Stroke" Value="{StyleResource ThemeBorderDarkBrush}"/>
<Setter Property="Stroke" Value="{DynamicResource ThemeBorderDarkBrush}"/>
</Style>
<Style Selector="RadioButton /template/ Ellipse#checkMark">
<Setter Property="IsVisible" Value="False"/>
@ -40,6 +40,6 @@
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="RadioButton:disabled /template/ Ellipse#border">
<Setter Property="Opacity" Value="{StyleResource ThemeDisabledOpacity}"/>
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
</Styles>

44
src/Avalonia.Themes.Default/RepeatButton.xaml

@ -0,0 +1,44 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="RepeatButton">
<Setter Property="Background"
Value="{StyleResource ThemeControlMidBrush}" />
<Setter Property="BorderBrush"
Value="{StyleResource ThemeBorderLightBrush}" />
<Setter Property="BorderThickness"
Value="{StyleResource ThemeBorderThickness}" />
<Setter Property="Foreground"
Value="{StyleResource ThemeForegroundBrush}" />
<Setter Property="HorizontalContentAlignment"
Value="Center" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="Padding"
Value="4" />
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="RepeatButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush"
Value="{StyleResource ThemeBorderMidBrush}" />
</Style>
<Style Selector="RepeatButton:pressed /template/ ContentPresenter">
<Setter Property="Background"
Value="{StyleResource ThemeControlDarkBrush}" />
</Style>
<Style Selector="RepeatButton:disabled">
<Setter Property="Opacity"
Value="{StyleResource ThemeDisabledOpacity}" />
</Style>
</Styles>

158
src/Avalonia.Themes.Default/ScrollBar.xaml

@ -1,35 +1,127 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="ScrollBar">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{StyleResource ThemeControlMidBrush}">
<Track Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Path=Value, Mode=TwoWay}"
ViewportSize="{TemplateBinding ViewportSize}"
Orientation="{TemplateBinding Orientation}">
<Thumb Name="thumb">
<Thumb.Template>
<ControlTemplate>
<Border Background="{StyleResource ThemeControlDarkBrush}"/>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal">
<Setter Property="Height" Value="10"/>
</Style>
<Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
<Setter Property="MinWidth" Value="10"/>
</Style>
<Style Selector="ScrollBar:vertical">
<Setter Property="Width" Value="10"/>
</Style>
<Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
<Setter Property="MinHeight" Value="10"/>
</Style>
<Style Selector="ScrollBar">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{DynamicResource ThemeControlMidBrush}">
<Grid RowDefinitions="10,*,10">
<RepeatButton Name="PART_LineUpButton"
Classes="repeat"
Grid.Row="0"
Grid.Column="0">
<Path Data="M 0,4 C0,4 0,6 0,6 0,6 3.5,2.5 3.5,2.5 3.5,2.5 7,6 7,6 7,6 7,4 7,4 7,4 3.5,0.5 3.5,0.5 3.5,0.5 0,4 0,4 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
<Track Grid.Row="1"
Grid.Column="1"
Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Path=Value, Mode=TwoWay}"
ViewportSize="{TemplateBinding ViewportSize}"
Orientation="{TemplateBinding Orientation}">
<Track.DecreaseButton>
<RepeatButton Name="PART_PageUpButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_PageDownButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb Name="thumb">
<Thumb.Template>
<ControlTemplate>
<Border Background="{DynamicResource ThemeControlDarkBrush}" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
<RepeatButton Name="PART_LineDownButton"
Classes="repeat"
Grid.Row="2"
Grid.Column="2">
<Path Data="M 0,2.5 C0,2.5 0,0.5 0,0.5 0,0.5 3.5,4 3.5,4 3.5,4 7,0.5 7,0.5 7,0.5 7,2.5 7,2.5 7,2.5 3.5,6 3.5,6 3.5,6 0,2.5 0,2.5 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal">
<Setter Property="Height"
Value="10" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{DynamicResource ThemeControlMidBrush}">
<Grid ColumnDefinitions="10,*,10">
<RepeatButton Name="PART_LineUpButton"
Classes="repeat"
Grid.Row="0"
Grid.Column="0">
<Path Data="M 3.18,7 C3.18,7 5,7 5,7 5,7 1.81,3.5 1.81,3.5 1.81,3.5 5,0 5,0 5,0 3.18,0 3.18,0 3.18,0 0,3.5 0,3.5 0,3.5 3.18,7 3.18,7 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
<Track Grid.Row="1"
Grid.Column="1"
Minimum="{TemplateBinding Minimum}"
Maximum="{TemplateBinding Maximum}"
Value="{TemplateBinding Path=Value, Mode=TwoWay}"
ViewportSize="{TemplateBinding ViewportSize}"
Orientation="{TemplateBinding Orientation}">
<Track.DecreaseButton>
<RepeatButton Name="PART_PageUpButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_PageDownButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb Name="thumb">
<Thumb.Template>
<ControlTemplate>
<Border Background="{DynamicResource ThemeControlDarkBrush}" />
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
<RepeatButton Name="PART_LineDownButton"
Classes="repeat"
Grid.Row="2"
Grid.Column="2">
<Path Data="M 1.81,7 C1.81,7 0,7 0,7 0,7 3.18,3.5 3.18,3.5 3.18,3.5 0,0 0,0 0,0 1.81,0 1.81,0 1.81,0 5,3.5 5,3.5 5,3.5 1.81,7 1.81,7 z"
Stretch="Uniform"
Fill="Gray" />
</RepeatButton>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollBar:horizontal /template/ Thumb#thumb">
<Setter Property="MinWidth"
Value="10" />
</Style>
<Style Selector="ScrollBar:vertical">
<Setter Property="Width"
Value="10" />
</Style>
<Style Selector="ScrollBar:vertical /template/ Thumb#thumb">
<Setter Property="MinHeight"
Value="10" />
</Style>
<Style Selector="ScrollBar /template/ RepeatButton.repeat">
<Setter Property="Padding"
Value="2" />
<Setter Property="BorderThickness"
Value="0" />
</Style>
<Style Selector="ScrollBar /template/ RepeatButton.repeattrack">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter>
</Style>
</Styles>

2
src/Avalonia.Themes.Default/ScrollViewer.xaml

@ -1,4 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ScrollViewer">
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<ControlTemplate>
<Grid ColumnDefinitions="*,Auto" RowDefinitions="*,Auto">

4
src/Avalonia.Themes.Default/Separator.xaml

@ -11,13 +11,13 @@
</Style>
<Style Selector="MenuItem > Separator">
<Setter Property="Background" Value="{StyleResource ThemeControlMidBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="Margin" Value="29,1,0,1"/>
<Setter Property="Height" Value="1"/>
</Style>
<Style Selector="ContextMenu > Separator">
<Setter Property="Background" Value="{StyleResource ThemeControlMidBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="Margin" Value="29,1,0,1"/>
<Setter Property="Height" Value="1"/>
</Style>

32
src/Avalonia.Themes.Default/Slider.xaml

@ -12,11 +12,19 @@
</Grid.RowDefinitions>
<Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
<Track Name="PART_Track" Grid.Row="1">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb MinWidth="20" MinHeight="20">
<Thumb.Template>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12" Fill="{StyleResource ThemeAccentBrush}"/>
<Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/>
</Grid>
</ControlTemplate>
</Thumb.Template>
@ -39,11 +47,19 @@
</Grid.ColumnDefinitions>
<Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
<Track Name="PART_Track" Grid.Column="1">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb MinWidth="20" MinHeight="20">
<Thumb.Template>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12" Fill="{StyleResource ThemeAccentBrush}"/>
<Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/>
</Grid>
</ControlTemplate>
</Thumb.Template>
@ -61,6 +77,14 @@
</Style>
<Style Selector="Slider /template/ Border#TrackBackground">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderLightBrush}"/>
</Style>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLightBrush}"/>
</Style>
<Style Selector="Slider /template/ RepeatButton.repeattrack">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter>
</Style>
</Styles>

6
src/Avalonia.Themes.Default/TabStripItem.xaml

@ -1,8 +1,8 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="TabStripItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FontSize" Value="{StyleResource FontSizeLarge}"/>
<Setter Property="Foreground" Value="{StyleResource ThemeForegroundLightBrush}"/>
<Setter Property="FontSize" Value="{DynamicResource FontSizeLarge}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLightBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
@ -16,6 +16,6 @@
</Setter>
</Style>
<Style Selector="TabStripItem:selected">
<Setter Property="Foreground" Value="{StyleResource ThemeForegroundBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
</Styles>

22
src/Avalonia.Themes.Default/TextBox.xaml

@ -1,8 +1,8 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="TextBox">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<ControlTemplate>
@ -13,8 +13,8 @@
<DockPanel Margin="{TemplateBinding Padding}">
<TextBlock Name="floatingWatermark"
Foreground="{StyleResource ThemeAccentBrush}"
FontSize="{StyleResource FontSizeSmall}"
Foreground="{DynamicResource ThemeAccentBrush}"
FontSize="{DynamicResource FontSizeSmall}"
Text="{TemplateBinding Watermark}"
DockPanel.Dock="Top">
<TextBlock.IsVisible>
@ -33,7 +33,7 @@
<ToolTip.Tip>
<ItemsControl Items="{TemplateBinding DataValidationErrors}" MemberSelector="Message"/>
</ToolTip.Tip>
<Path Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2" Stroke="{StyleResource ErrorBrush}" StrokeThickness="2"/>
<Path Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2" Stroke="{DynamicResource ErrorBrush}" StrokeThickness="2"/>
</Canvas>
<ScrollViewer CanScrollHorizontally="{TemplateBinding CanScrollHorizontally}"
@ -62,13 +62,13 @@
</Setter>
</Style>
<Style Selector="TextBox:pointerover /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderDarkBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderDarkBrush}"/>
</Style>
<Style Selector="TextBox:focus /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderDarkBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderDarkBrush}"/>
</Style>
<Style Selector="TextBox:error /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ErrorBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/>
</Style>
<Style Selector="TextBox /template/ Canvas#error">
<Setter Property="IsVisible" Value="False"/>
@ -77,7 +77,7 @@
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="TextBox /template/ ToolTip">
<Setter Property="Background" Value="{StyleResource ErrorBrushLight}"/>
<Setter Property="BorderBrush" Value="{StyleResource ErrorBrush}"/>
<Setter Property="Background" Value="{DynamicResource ErrorBrushLight}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/>
</Style>
</Styles>

18
src/Avalonia.Themes.Default/ToggleButton.xaml

@ -1,9 +1,9 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="ToggleButton">
<Setter Property="Background" Value="{StyleResource ThemeControlMidBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderLightBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{StyleResource ThemeForegroundBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLightBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
@ -23,16 +23,16 @@
</Setter>
</Style>
<Style Selector="ToggleButton:checked /template/ ContentPresenter">
<Setter Property="Background" Value="{StyleResource ThemeControlDarkBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlDarkBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="ToggleButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="ToggleButton:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{StyleResource ThemeControlDarkBrush}"/>
<Setter Property="Background" Value="{DynamicResource ThemeControlDarkBrush}"/>
</Style>
<Style Selector="ToggleButton:disabled">
<Setter Property="Opacity" Value="{StyleResource ThemeDisabledOpacity}"/>
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
</Styles>

6
src/Avalonia.Themes.Default/ToolTip.xaml

@ -1,7 +1,7 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ToolTip">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<ControlTemplate>

4
src/Avalonia.Themes.Default/TreeView.xaml

@ -1,7 +1,7 @@
<Style xmlns="https://github.com/avaloniaui" Selector="TreeView">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<ControlTemplate>

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

Loading…
Cancel
Save