diff --git a/.editorconfig b/.editorconfig
index 9ae52b8bbd..ff7ac5d69e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -64,7 +64,7 @@ dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_style.static_prefix_style.required_prefix = s_
-dotnet_naming_style.static_prefix_style.capitalization = camel_case
+dotnet_naming_style.static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
@@ -137,14 +137,36 @@ space_within_single_line_array_initializer_braces = true
#Net Analyzer
dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed.
+# CS1591: Missing XML comment for publicly visible type or member
+dotnet_diagnostic.CS1591.severity = suggestion
+
+# CS0162: Remove unreachable code
+dotnet_diagnostic.CS0162.severity = error
+# CA1304: Specify CultureInfo
+dotnet_diagnostic.CA1304.severity = warning
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
+# CA1815: Override equals and operator equals on value types
+dotnet_diagnostic.CA1815.severity = warning
# CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers
dotnet_diagnostic.CA1821.severity = warning
+# CA1822: Mark members as static
+dotnet_diagnostic.CA1822.severity = suggestion
+# CA1823: Avoid unused private fields
+dotnet_diagnostic.CA1823.severity = warning
+dotnet_code_quality.CA1822.api_surface = private, internal
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
+# CA1826: Use property instead of Linq Enumerable method
+dotnet_diagnostic.CA1826.severity = suggestion
+# CA1827: Do not use Count/LongCount when Any can be used
+dotnet_diagnostic.CA1827.severity = warning
+# CA1828: Do not use CountAsync/LongCountAsync when AnyAsync can be used
+dotnet_diagnostic.CA1828.severity = warning
+# CA1829: Use Length/Count property instead of Enumerable.Count method
+dotnet_diagnostic.CA1829.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning
diff --git a/.ncrunch/ReactiveUIDemo.v3.ncrunchproject b/.ncrunch/ReactiveUIDemo.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/ReactiveUIDemo.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/Avalonia.Desktop.slnf b/Avalonia.Desktop.slnf
index 6ba05332be..3fa8e969c8 100644
--- a/Avalonia.Desktop.slnf
+++ b/Avalonia.Desktop.slnf
@@ -9,6 +9,7 @@
"samples\\MiniMvvm\\MiniMvvm.csproj",
"samples\\SampleControls\\ControlSamples.csproj",
"samples\\Sandbox\\Sandbox.csproj",
+ "samples\\ReactiveUIDemo\\ReactiveUIDemo.csproj",
"src\\Avalonia.Base\\Avalonia.Base.csproj",
"src\\Avalonia.Build.Tasks\\Avalonia.Build.Tasks.csproj",
"src\\Avalonia.Controls.ColorPicker\\Avalonia.Controls.ColorPicker.csproj",
diff --git a/Avalonia.sln b/Avalonia.sln
index 34b5596119..e6898131b0 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -40,6 +40,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
.editorconfig = .editorconfig
src\Shared\IsExternalInit.cs = src\Shared\IsExternalInit.cs
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
+ src\Shared\NullableAttributes.cs = src\Shared\NullableAttributes.cs
src\Shared\SourceGeneratorAttributes.cs = src\Shared\SourceGeneratorAttributes.cs
src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs = src\Avalonia.Base\Compatibility\StringCompatibilityExtensions.cs
EndProjectSection
@@ -119,6 +120,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\SourceLink.props = build\SourceLink.props
build\System.Drawing.Common.props = build\System.Drawing.Common.props
build\System.Memory.props = build\System.Memory.props
+ build\TrimmingEnable.props = build\TrimmingEnable.props
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\XUnit.props = build\XUnit.props
EndProjectSection
@@ -134,8 +136,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct3DInteropSample", "samples\interop\Direct3DInteropSample\Direct3DInteropSample.csproj", "{638580B0-7910-40EF-B674-DCB34DA308CD}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
@@ -222,13 +222,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.iOS", "sample
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MobileSandbox.Desktop", "samples\MobileSandbox.Desktop\MobileSandbox.Desktop.csproj", "{62D392C9-81CF-487F-92E8-598B2AF3FDCE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser.Blazor", "samples\ControlCatalog.Browser.Blazor\ControlCatalog.Browser.Blazor.csproj", "{90B08091-9BBD-4362-B712-E9F2CC62B218}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Browser.Blazor", "samples\ControlCatalog.Browser.Blazor\ControlCatalog.Browser.Blazor.csproj", "{90B08091-9BBD-4362-B712-E9F2CC62B218}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\ReactiveUIDemo\ReactiveUIDemo.csproj", "{75C47156-C5D8-44BC-A5A7-E8657C2248D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -362,10 +364,6 @@ Global
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.Build.0 = Release|Any CPU
- {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.Build.0 = Release|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -541,6 +539,10 @@ Global
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.Build.0 = Release|Any CPU
+ {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -572,7 +574,6 @@ Global
{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
- {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}
{E2999E4A-9086-401F-898C-AEB0AD38E676} = {9B9E3891-2366-4253-A952-D08BCEB71098}
@@ -605,6 +606,7 @@ Global
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{15B93A4C-1B46-43F6-B534-7B25B6E99932} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index 5838519596..e9c3d65b41 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -7,7 +7,7 @@
https://avaloniaui.net
https://github.com/AvaloniaUI/Avalonia/
true
- CS1591
+ $(NoWarn);CS1591
preview
MIT
Icon.png
diff --git a/build/TrimmingEnable.props b/build/TrimmingEnable.props
new file mode 100644
index 0000000000..3f873e3345
--- /dev/null
+++ b/build/TrimmingEnable.props
@@ -0,0 +1,16 @@
+
+
+ false
+ true
+ false
+ true
+
+
+
+ true
+
+ $(WarningsAsErrors);IL2000;IL2001;IL2002;IL2003;IL2004;IL2005;IL2006;IL2007;IL2008;IL2009;IL2010;IL2011;IL2012;IL2013;IL2014;IL2015;IL2016;IL2017;IL2018;IL2019;IL2020;IL2021;IL2022;IL2023;IL2024;IL2025;IL2026;IL2027;IL2028;IL2029;IL2030;IL2031;IL2032;IL2033;IL2034;IL2035;IL2036;IL2037;IL2038;IL2039;IL2040;IL2041;IL2042;IL2043;IL2044;IL2045;IL2046;IL2047;IL2048;IL2049;IL2050;IL2051;IL2052;IL2053;IL2054;IL2055;IL2056;IL2057;IL2058;IL2059;IL2060;IL2061;IL2062;IL2063;IL2064;IL2065;IL2066;IL2067;IL2068;IL2069;IL2070;IL2071;IL2072;IL2073;IL2074;IL2075;IL2076;IL2077;IL2078;IL2079;IL2080;IL2081;IL2082;IL2083;IL2084;IL2085;IL2086;IL2087;IL2088;IL2089;IL2090;IL2091;IL2092;IL2093;IL2094;IL2095;IL2096;IL2097;IL2098;IL2099;IL2100;IL2101;IL2102;IL2103;IL2104;IL2105;IL2106;IL2107;IL2108;IL2109;IL2110;IL2111;IL2112;IL2113;IL2114;IL2115;IL2116;IL2117;IL2118;IL2119;IL2120;IL2121;IL2122;IL2123;IL2124;IL2125;IL2126;IL2127;IL2128;IL2129;IL2130;IL2131;IL2132;IL2133;IL2134;IL2135;IL2136;IL2137;IL2138;IL2139;IL2140;IL2141;IL2142;IL2143;IL2144;IL2145;IL2146;IL2147;IL2148;IL2149;IL2150;IL2151;IL2152;IL2153;IL2154;IL2155;IL2156;IL2157
+
+ $(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056
+
+
diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm
index 2443965957..b6dacb6ce4 100644
--- a/native/Avalonia.Native/src/OSX/WindowImpl.mm
+++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm
@@ -137,7 +137,11 @@ void WindowImpl::BringToFront()
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
- (*iterator)->BringToFront();
+ auto window = (*iterator)->Window;
+
+ // #9565: Only bring window to front if it's on the currently active space
+ if ([window isOnActiveSpace])
+ (*iterator)->BringToFront();
}
}
}
@@ -161,6 +165,9 @@ void WindowImpl::StartStateTransition() {
void WindowImpl::EndStateTransition() {
_transitioningWindowState = false;
+
+ // Ensure correct order of child windows after fullscreen transition.
+ BringToFront();
}
SystemDecorations WindowImpl::Decorations() {
diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index 2295c0beda..3704cee890 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -80,7 +80,6 @@ partial class Build : NukeBuild
if (Parameters.IsRunningOnAzure)
c.AddProperty("JavaSdkDirectory", GetVariable("JAVA_HOME_11_X64"));
c.AddProperty("PackageVersion", Parameters.Version)
- .AddProperty("iOSRoslynPathHackRequired", true)
.SetConfiguration(Parameters.Configuration)
.SetVerbosity(DotNetVerbosity.Minimal);
return c;
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index 92d9732e91..13bac4b7db 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -4,7 +4,7 @@
false
False
- CS0649;CS0169;SYSLIB0011
+ $(NoWarn);CS0649;CS0169;SYSLIB0011
1
net7.0
diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index 1b822c14cf..ca2d4b66ed 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -30,7 +30,9 @@
/>
-
+
$(IntermediateOutputPath)/Avalonia/resources
@@ -62,7 +64,9 @@
BeforeTargets="CoreCompile;CoreResGen"
Inputs="@(AvaloniaResource);@(AvaloniaXaml);@(CustomAdditionalGenerateAvaloniaResourcesInputs);$(MSBuildAllProjects)"
Outputs="$(AvaloniaResourcesTemporaryFilePath)"
- DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)">
+ DependsOnTargets="$(BuildAvaloniaResourcesDependsOn)"
+ Condition="('@(AvaloniaResource->Count())' > 0) or ('@(AvaloniaXaml->Count())' > 0)"
+ >
@@ -81,7 +85,12 @@
$(IntermediateOutputPath)/Avalonia/references
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index b1bacc6483..d5e5cb14dc 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -99,6 +99,15 @@ namespace ControlCatalog.NetCore
SilenceConsole();
return builder.StartLinuxDrm(args, scaling: GetScaling());
}
+ else if (args.Contains("--dxgi"))
+ {
+ builder.With(new Win32PlatformOptions()
+ {
+ UseLowLatencyDxgiSwapChain = true,
+ UseWindowsUIComposition = false
+ });
+ return builder.StartWithClassicDesktopLifetime(args);
+ }
else
return builder.StartWithClassicDesktopLifetime(args);
}
diff --git a/samples/ControlCatalog.NetCore/Properties/launchSettings.json b/samples/ControlCatalog.NetCore/Properties/launchSettings.json
new file mode 100644
index 0000000000..5964ca320e
--- /dev/null
+++ b/samples/ControlCatalog.NetCore/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "ControlCatalog.NetCore": {
+ "commandName": "Project"
+ },
+ "Dxgi": {
+ "commandName": "Project",
+ "commandLineArgs": "--dxgi"
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index 6b550a30be..18f0dd16ba 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -33,4 +33,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Converter/DegToRadConverter.cs b/samples/ControlCatalog/Converter/DegToRadConverter.cs
new file mode 100644
index 0000000000..b062bcb64a
--- /dev/null
+++ b/samples/ControlCatalog/Converter/DegToRadConverter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using Avalonia.Data.Converters;
+
+namespace ControlCatalog.Converter
+{
+ public class DegToRadConverter : IValueConverter
+ {
+ public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is double rad)
+ {
+ return rad * 180.0d / Math.PI;
+ }
+ return 0.0d;
+ }
+
+ public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is double deg)
+ {
+ return deg / 180.0d * Math.PI;
+ }
+ return 0.0d;
+ }
+ }
+}
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index b5a09b5fbd..4a5f5bc96c 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -66,6 +66,9 @@
+
+
+
@@ -132,6 +135,9 @@
+
+
+
diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
index 8d9cd74ea7..ae7e43f511 100644
--- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
@@ -14,7 +14,26 @@ namespace ControlCatalog.Pages
{
public class AutoCompleteBoxPage : UserControl
{
- private StateData[] BuildAllStates()
+ public class StateData
+ {
+ public string Name { get; private set; }
+ public string Abbreviation { get; private set; }
+ public string Capital { get; private set; }
+
+ public StateData(string name, string abbreviatoin, string capital)
+ {
+ Name = name;
+ Abbreviation = abbreviatoin;
+ Capital = capital;
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+
+ private static StateData[] BuildAllStates()
{
return new StateData[]
{
@@ -72,7 +91,7 @@ namespace ControlCatalog.Pages
}
public StateData[] States { get; private set; }
- private LinkedList[] BuildAllSentences()
+ private static LinkedList[] BuildAllSentences()
{
return new string[]
{
@@ -124,7 +143,7 @@ namespace ControlCatalog.Pages
.OfType();
}
- private bool StringContains(string str, string? query)
+ private static bool StringContains(string str, string? query)
{
if (query == null) return false;
return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
diff --git a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
index 61e0ed5acb..c70675b606 100644
--- a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
+++ b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
@@ -25,7 +25,7 @@ public partial class CompositionPage : UserControl
this.Get("Items").Items = CreateColorItems();
}
- private List CreateColorItems()
+ private static List CreateColorItems()
{
var list = new List();
diff --git a/samples/ControlCatalog/Pages/CustomDrawing.xaml b/samples/ControlCatalog/Pages/CustomDrawing.xaml
new file mode 100644
index 0000000000..04b7fcfea5
--- /dev/null
+++ b/samples/ControlCatalog/Pages/CustomDrawing.xaml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs b/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
new file mode 100644
index 0000000000..0416e587b9
--- /dev/null
+++ b/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
@@ -0,0 +1,67 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public partial class CustomDrawing : UserControl
+ {
+ public CustomDrawing()
+ {
+ InitializeComponent();
+ }
+
+ private CustomDrawingExampleControl? _customControl;
+ public CustomDrawingExampleControl CustomDrawingControl
+ {
+ get
+ {
+ if (_customControl is not null)
+ return _customControl;
+ throw new System.Exception("Control did not get initialized");
+ }
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ var cntrl = this.FindControl("CustomDrawingControl");
+ if (cntrl != null)
+ {
+ _customControl = cntrl;
+ }
+ else
+ {
+ // be sad about it
+ }
+ }
+
+ private void RotateMinus (object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null) return;
+ _customControl.Rotation -= Math.PI / 20.0d;
+ }
+
+ private void RotatePlus(object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null)
+ return;
+ _customControl.Rotation += Math.PI / 20.0d;
+ }
+
+ private void ZoomIn(object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null)
+ return;
+ _customControl.Scale *= 1.2d;
+ }
+
+ private void ZoomOut(object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null)
+ return;
+ _customControl.Scale /= 1.2d;
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs b/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
new file mode 100644
index 0000000000..11e5e32cf1
--- /dev/null
+++ b/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Input;
+using Avalonia.Threading;
+using Avalonia.Controls.Shapes;
+
+namespace ControlCatalog.Pages
+{
+ public class CustomDrawingExampleControl : Control
+ {
+ private Point _cursorPoint;
+
+
+ public StyledProperty ScaleProperty = AvaloniaProperty.Register(nameof(Scale), 1.0d);
+ public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
+
+ public StyledProperty RotationProperty = AvaloniaProperty.Register(nameof(Rotation));
+ ///
+ /// Rotation, measured in Radians!
+ ///
+ public double Rotation
+ {
+ get => GetValue(RotationProperty);
+ set
+ {
+ double valueToUse = value % (Math.PI * 2);
+ SetValue(RotationProperty, valueToUse);
+ }
+ }
+
+ public StyledProperty ViewportCenterYProperty = AvaloniaProperty.Register(nameof(ViewportCenterY), 0.0d);
+ public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); }
+
+ public StyledProperty ViewportCenterXProperty = AvaloniaProperty.Register(nameof(ViewportCenterX), 0.0d);
+ public double ViewportCenterX { get => GetValue(ViewportCenterXProperty); set => SetValue(ViewportCenterXProperty, value); }
+
+ private IPen _pen;
+
+ private System.Diagnostics.Stopwatch _timeKeeper = System.Diagnostics.Stopwatch.StartNew();
+
+ private bool _isPointerCaptured = false;
+
+ public CustomDrawingExampleControl()
+ {
+ _pen = new Pen(new SolidColorBrush(Colors.Black), lineCap: PenLineCap.Round);
+
+ var _arc = new ArcSegment()
+ {
+ IsLargeArc = false,
+ Point = new Point(0, 0),
+ RotationAngle = 0,
+ Size = new Size(25, 25),
+ SweepDirection = SweepDirection.Clockwise,
+
+ };
+ StreamGeometry sg = new StreamGeometry();
+ var cntx = sg.Open();
+ cntx.BeginFigure(new Point(-25.0d, -10.0d), false);
+ cntx.ArcTo(new Point(25.0d, -10.0d), new Size(10.0d, 10.0d), 0.0d, false, SweepDirection.Clockwise);
+ cntx.EndFigure(true);
+ _smileGeometry = sg.Clone();
+ }
+
+ private Geometry _smileGeometry;
+
+ protected override void OnPointerMoved(PointerEventArgs e)
+ {
+ base.OnPointerMoved(e);
+
+ Point previousPoint = _cursorPoint;
+
+ _cursorPoint = e.GetPosition(this);
+
+ if (_isPointerCaptured)
+ {
+ Point oldWorldPoint = UIPointToWorldPoint(previousPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+ Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+
+ Vector diff = newWorldPoint - oldWorldPoint;
+
+ ViewportCenterX -= diff.X;
+ ViewportCenterY -= diff.Y;
+ }
+ }
+
+ protected override void OnPointerPressed(PointerPressedEventArgs e)
+ {
+ e.Handled = true;
+ e.Pointer.Capture(this);
+ _isPointerCaptured = true;
+ base.OnPointerPressed(e);
+ }
+
+ protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
+ {
+ base.OnPointerWheelChanged(e);
+ var oldScale = Scale;
+ Scale *= (1.0d + e.Delta.Y / 12.0d);
+
+ Point oldWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, oldScale, Rotation);
+ Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+
+ Vector diff = newWorldPoint - oldWorldPoint;
+
+ ViewportCenterX -= diff.X;
+ ViewportCenterY -= diff.Y;
+ }
+
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
+ {
+ e.Pointer.Capture(null);
+ _isPointerCaptured = false;
+ base.OnPointerReleased(e);
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ var localBounds = new Rect(new Size(this.Bounds.Width, this.Bounds.Height));
+ var clip = context.PushClip(this.Bounds);
+ context.DrawRectangle(Brushes.White, _pen, localBounds, 1.0d);
+
+ var halfMax = Math.Max(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) * Math.Sqrt(2.0d);
+ var halfMin = Math.Min(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) / 1.3d;
+ var halfWidth = this.Bounds.Width / 2.0d;
+ var halfHeight = this.Bounds.Height / 2.0d;
+
+ // 0,0 refers to the top-left of the control now. It is not prime time to draw gui stuff because it'll be under the world
+
+ var translateModifier = context.PushPreTransform(Avalonia.Matrix.CreateTranslation(new Avalonia.Vector(halfWidth, halfHeight)));
+
+ // now 0,0 refers to the ViewportCenter(X,Y).
+ var rotationMatrix = Avalonia.Matrix.CreateRotation(Rotation);
+ var rotationModifier = context.PushPreTransform(rotationMatrix);
+
+ // everything is rotated but not scaled
+
+ var scaleModifier = context.PushPreTransform(Avalonia.Matrix.CreateScale(Scale, -Scale));
+
+ var mapPositionModifier = context.PushPreTransform(Matrix.CreateTranslation(new Vector(-ViewportCenterX, -ViewportCenterY)));
+
+ // now everything is rotated and scaled, and at the right position, now we're drawing strictly in world coordinates
+
+ context.DrawEllipse(Brushes.White, _pen, new Point(0.0d, 0.0d), 50.0d, 50.0d);
+ context.DrawLine(_pen, new Point(-25.0d, -5.0d), new Point(-25.0d, 15.0d));
+ context.DrawLine(_pen, new Point(25.0d, -5.0d), new Point(25.0d, 15.0d));
+ context.DrawGeometry(null, _pen, _smileGeometry);
+
+ Point cursorInWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+ context.DrawEllipse(Brushes.Gray, _pen, cursorInWorldPoint, 20.0d, 20.0d);
+
+
+ for (int i = 0; i < 10; i++)
+ {
+ double orbitRadius = i * 100 + 200;
+ var orbitInput = ((_timeKeeper.Elapsed.TotalMilliseconds + 987654d) / orbitRadius) / 10.0d;
+ if (i % 3 == 0)
+ orbitInput *= -1;
+ Point orbitPosition = new Point(Math.Sin(orbitInput) * orbitRadius, Math.Cos(orbitInput) * orbitRadius);
+ context.DrawEllipse(Brushes.Gray, _pen, orbitPosition, 20.0d, 20.0d);
+ }
+
+
+ // end drawing the world
+
+ mapPositionModifier.Dispose();
+
+ scaleModifier.Dispose();
+
+ rotationModifier.Dispose();
+ translateModifier.Dispose();
+
+ // this is prime time to draw gui stuff
+
+ context.DrawLine(_pen, _cursorPoint + new Vector(-20, 0), _cursorPoint + new Vector(20, 0));
+ context.DrawLine(_pen, _cursorPoint + new Vector(0, -20), _cursorPoint + new Vector(0, 20));
+
+ clip.Dispose();
+
+ // oh and draw again when you can, no rush, right?
+ Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
+ }
+
+ private Point UIPointToWorldPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
+ {
+ Point workingPoint = new Point(inPoint.X, -inPoint.Y);
+ workingPoint += new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
+ workingPoint /= scale;
+
+ workingPoint = Matrix.CreateRotation(rotation).Transform(workingPoint);
+
+ workingPoint += new Vector(viewportCenterX, viewportCenterY);
+
+ return workingPoint;
+ }
+
+ private Point WorldPointToUIPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
+ {
+ Point workingPoint = new Point(inPoint.X, inPoint.Y);
+
+ workingPoint -= new Vector(viewportCenterX, viewportCenterY);
+ // undo rotation
+ workingPoint = Matrix.CreateRotation(-rotation).Transform(workingPoint);
+ workingPoint *= scale;
+ workingPoint -= new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
+ workingPoint = new Point(workingPoint.X, -workingPoint.Y);
+
+ return workingPoint;
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/ImagePage.xaml.cs b/samples/ControlCatalog/Pages/ImagePage.xaml.cs
index 45043aa5af..5b3169a1b0 100644
--- a/samples/ControlCatalog/Pages/ImagePage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ImagePage.xaml.cs
@@ -58,7 +58,7 @@ namespace ControlCatalog.Pages
}
}
- private PixelRect GetCropRect(int index)
+ private static PixelRect GetCropRect(int index)
{
var bitmapWidth = 640;
var bitmapHeight = 426;
@@ -70,7 +70,7 @@ namespace ControlCatalog.Pages
3 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, 0), cropSize),
4 => new PixelRect(new PixelPoint(0, bitmapHeight - cropSize.Height), cropSize),
5 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, bitmapHeight - cropSize.Height), cropSize),
- _ => PixelRect.Empty
+ _ => default
};
}
diff --git a/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs b/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
index a126fbefe5..ded02330d5 100644
--- a/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
@@ -247,7 +247,7 @@ namespace ControlCatalog.Pages
}
- private void CheckError(GlInterface gl)
+ private static void CheckError(GlInterface gl)
{
int err;
while ((err = gl.GetError()) != GL_NO_ERROR)
diff --git a/samples/ControlCatalog/Pages/RefreshContainerPage.axaml b/samples/ControlCatalog/Pages/RefreshContainerPage.axaml
new file mode 100644
index 0000000000..f3bf1724b4
--- /dev/null
+++ b/samples/ControlCatalog/Pages/RefreshContainerPage.axaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/RefreshContainerPage.axaml.cs b/samples/ControlCatalog/Pages/RefreshContainerPage.axaml.cs
new file mode 100644
index 0000000000..f9d0328d9a
--- /dev/null
+++ b/samples/ControlCatalog/Pages/RefreshContainerPage.axaml.cs
@@ -0,0 +1,36 @@
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using ControlCatalog.ViewModels;
+
+namespace ControlCatalog.Pages
+{
+ public class RefreshContainerPage : UserControl
+ {
+ private RefreshContainerViewModel _viewModel;
+
+ public RefreshContainerPage()
+ {
+ this.InitializeComponent();
+
+ _viewModel = new RefreshContainerViewModel();
+
+ DataContext = _viewModel;
+ }
+
+ private async void RefreshContainerPage_RefreshRequested(object? sender, RefreshRequestedEventArgs e)
+ {
+ var deferral = e.GetDeferral();
+
+ await _viewModel.AddToTop();
+
+ deferral.Complete();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs
index ff62b834c4..6af4cf353e 100644
--- a/samples/ControlCatalog/Pages/ScreenPage.cs
+++ b/samples/ControlCatalog/Pages/ScreenPage.cs
@@ -66,6 +66,7 @@ namespace ControlCatalog.Pages
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}");
+
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText =
@@ -77,7 +78,7 @@ namespace ControlCatalog.Pages
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10));
}
- private FormattedText CreateFormattedText(string textToFormat)
+ private static FormattedText CreateFormattedText(string textToFormat)
{
return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
Typeface.Default, 12, Brushes.Green);
diff --git a/samples/ControlCatalog/Pages/TabControlPage.xaml.cs b/samples/ControlCatalog/Pages/TabControlPage.xaml.cs
index 74e9928b24..413b6e1c75 100644
--- a/samples/ControlCatalog/Pages/TabControlPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/TabControlPage.xaml.cs
@@ -49,7 +49,7 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
- private IBitmap LoadBitmap(string uri)
+ private static IBitmap LoadBitmap(string uri)
{
var assets = AvaloniaLocator.Current!.GetService()!;
return new Bitmap(assets.Open(new Uri(uri)));
diff --git a/samples/ControlCatalog/ViewModels/RefreshContainerViewModel.cs b/samples/ControlCatalog/ViewModels/RefreshContainerViewModel.cs
new file mode 100644
index 0000000000..d4b43043be
--- /dev/null
+++ b/samples/ControlCatalog/ViewModels/RefreshContainerViewModel.cs
@@ -0,0 +1,26 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive;
+using System.Threading.Tasks;
+using Avalonia.Controls.Notifications;
+using ControlCatalog.Pages;
+using MiniMvvm;
+
+namespace ControlCatalog.ViewModels
+{
+ public class RefreshContainerViewModel : ViewModelBase
+ {
+ public ObservableCollection Items { get; }
+
+ public RefreshContainerViewModel()
+ {
+ Items = new ObservableCollection(Enumerable.Range(1, 200).Select(i => $"Item {i}"));
+ }
+
+ public async Task AddToTop()
+ {
+ await Task.Delay(3000);
+ Items.Insert(0, $"Item {200 - Items.Count}");
+ }
+ }
+}
diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props
index 8fc91aca14..471c42ec07 100644
--- a/samples/Directory.Build.props
+++ b/samples/Directory.Build.props
@@ -4,4 +4,7 @@
$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\netcoreapp2.0\Avalonia.Designer.HostApp.dll
+
+ false
+
diff --git a/samples/IntegrationTestApp/MainWindow.axaml b/samples/IntegrationTestApp/MainWindow.axaml
index 038ced4e5c..54c0cb0655 100644
--- a/samples/IntegrationTestApp/MainWindow.axaml
+++ b/samples/IntegrationTestApp/MainWindow.axaml
@@ -17,11 +17,15 @@
-
+
+
+ WindowState:
+
+
@@ -129,13 +133,14 @@
CenterOwner
- Normal
- Minimized
- Maximized
- FullScreen
+ Normal
+ Minimized
+ Maximized
+ FullScreen
+
diff --git a/samples/IntegrationTestApp/MainWindow.axaml.cs b/samples/IntegrationTestApp/MainWindow.axaml.cs
index c1acc7ca88..841947673a 100644
--- a/samples/IntegrationTestApp/MainWindow.axaml.cs
+++ b/samples/IntegrationTestApp/MainWindow.axaml.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia;
@@ -178,6 +179,8 @@ namespace IntegrationTestApp
ShowWindow();
if (source?.Name == "SendToBack")
SendToBack();
+ if (source?.Name == "EnterFullscreen")
+ WindowState = WindowState.FullScreen;
if (source?.Name == "ExitFullscreen")
WindowState = WindowState.Normal;
if (source?.Name == "RestoreAll")
diff --git a/samples/IntegrationTestApp/ShowWindowTest.axaml b/samples/IntegrationTestApp/ShowWindowTest.axaml
index c3a0d8d2e2..00987429d0 100644
--- a/samples/IntegrationTestApp/ShowWindowTest.axaml
+++ b/samples/IntegrationTestApp/ShowWindowTest.axaml
@@ -27,10 +27,10 @@
- Normal
- Minimized
- Maximized
- FullScreen
+ Normal
+ Minimized
+ Maximized
+ FullScreen
diff --git a/samples/ReactiveUIDemo/App.axaml b/samples/ReactiveUIDemo/App.axaml
new file mode 100644
index 0000000000..dd3a39f6ac
--- /dev/null
+++ b/samples/ReactiveUIDemo/App.axaml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/samples/ReactiveUIDemo/App.axaml.cs b/samples/ReactiveUIDemo/App.axaml.cs
new file mode 100644
index 0000000000..4578566427
--- /dev/null
+++ b/samples/ReactiveUIDemo/App.axaml.cs
@@ -0,0 +1,37 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using Avalonia.ReactiveUI;
+using ReactiveUI;
+using ReactiveUIDemo.ViewModels;
+using ReactiveUIDemo.Views;
+using Splat;
+
+namespace ReactiveUIDemo
+{
+ public class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ Locator.CurrentMutable.Register(() => new FooView(), typeof(IViewFor));
+ Locator.CurrentMutable.Register(() => new BarView(), typeof(IViewFor));
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ desktop.MainWindow = new MainWindow();
+ base.OnFrameworkInitializationCompleted();
+ }
+
+ public static int Main(string[] args)
+ => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
+
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .UseReactiveUI()
+ .LogToTrace();
+ }
+}
diff --git a/samples/ReactiveUIDemo/MainWindow.axaml b/samples/ReactiveUIDemo/MainWindow.axaml
new file mode 100644
index 0000000000..7775fc5a79
--- /dev/null
+++ b/samples/ReactiveUIDemo/MainWindow.axaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ReactiveUIDemo/MainWindow.axaml.cs b/samples/ReactiveUIDemo/MainWindow.axaml.cs
new file mode 100644
index 0000000000..5bf2d476fd
--- /dev/null
+++ b/samples/ReactiveUIDemo/MainWindow.axaml.cs
@@ -0,0 +1,22 @@
+using ReactiveUIDemo.ViewModels;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ReactiveUIDemo
+{
+ public class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ this.InitializeComponent();
+ this.DataContext = new MainWindowViewModel();
+ this.AttachDevTools();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/ReactiveUIDemo/ReactiveUIDemo.csproj b/samples/ReactiveUIDemo/ReactiveUIDemo.csproj
new file mode 100644
index 0000000000..94ca4ee809
--- /dev/null
+++ b/samples/ReactiveUIDemo/ReactiveUIDemo.csproj
@@ -0,0 +1,28 @@
+
+
+ Exe
+ net6.0
+ enable
+
+
+
+
+
+
+
+
+
+
+ BarView.axaml
+
+
+ FooView.axaml
+
+
+
+
+
+
+
+
+
diff --git a/samples/ReactiveUIDemo/ViewModels/BarViewModel.cs b/samples/ReactiveUIDemo/ViewModels/BarViewModel.cs
new file mode 100644
index 0000000000..3448453d81
--- /dev/null
+++ b/samples/ReactiveUIDemo/ViewModels/BarViewModel.cs
@@ -0,0 +1,11 @@
+using ReactiveUI;
+
+namespace ReactiveUIDemo.ViewModels
+{
+ internal class BarViewModel : ReactiveObject, IRoutableViewModel
+ {
+ public BarViewModel(IScreen screen) => HostScreen = screen;
+ public string UrlPathSegment => "Bar";
+ public IScreen HostScreen { get; }
+ }
+}
diff --git a/samples/ReactiveUIDemo/ViewModels/FooViewModel.cs b/samples/ReactiveUIDemo/ViewModels/FooViewModel.cs
new file mode 100644
index 0000000000..1a363e18dc
--- /dev/null
+++ b/samples/ReactiveUIDemo/ViewModels/FooViewModel.cs
@@ -0,0 +1,11 @@
+using ReactiveUI;
+
+namespace ReactiveUIDemo.ViewModels
+{
+ internal class FooViewModel : ReactiveObject, IRoutableViewModel
+ {
+ public FooViewModel(IScreen screen) => HostScreen = screen;
+ public string UrlPathSegment => "Foo";
+ public IScreen HostScreen { get; }
+ }
+}
diff --git a/samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs b/samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs
new file mode 100644
index 0000000000..2222137d38
--- /dev/null
+++ b/samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs
@@ -0,0 +1,9 @@
+using ReactiveUI;
+
+namespace ReactiveUIDemo.ViewModels
+{
+ internal class MainWindowViewModel : ReactiveObject
+ {
+ public RoutedViewHostPageViewModel RoutedViewHost { get; } = new();
+ }
+}
diff --git a/samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs b/samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs
new file mode 100644
index 0000000000..701447cfe8
--- /dev/null
+++ b/samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs
@@ -0,0 +1,21 @@
+using ReactiveUI;
+
+namespace ReactiveUIDemo.ViewModels
+{
+ internal class RoutedViewHostPageViewModel : ReactiveObject, IScreen
+ {
+ public RoutedViewHostPageViewModel()
+ {
+ Foo = new(this);
+ Bar = new(this);
+ Router.Navigate.Execute(Foo);
+ }
+
+ public RoutingState Router { get; } = new();
+ public FooViewModel Foo { get; }
+ public BarViewModel Bar { get; }
+
+ public void ShowFoo() => Router.Navigate.Execute(Foo);
+ public void ShowBar() => Router.Navigate.Execute(Bar);
+ }
+}
diff --git a/samples/ReactiveUIDemo/Views/BarView.axaml b/samples/ReactiveUIDemo/Views/BarView.axaml
new file mode 100644
index 0000000000..2622245997
--- /dev/null
+++ b/samples/ReactiveUIDemo/Views/BarView.axaml
@@ -0,0 +1,16 @@
+
+
+
+ Bar!
+
+
+
diff --git a/samples/ReactiveUIDemo/Views/BarView.axaml.cs b/samples/ReactiveUIDemo/Views/BarView.axaml.cs
new file mode 100644
index 0000000000..2fbea6de91
--- /dev/null
+++ b/samples/ReactiveUIDemo/Views/BarView.axaml.cs
@@ -0,0 +1,28 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using ReactiveUI;
+using ReactiveUIDemo.ViewModels;
+
+namespace ReactiveUIDemo.Views
+{
+ internal partial class BarView : UserControl, IViewFor
+ {
+ public BarView()
+ {
+ InitializeComponent();
+ }
+
+ public BarViewModel? ViewModel { get; set; }
+
+ object? IViewFor.ViewModel
+ {
+ get => ViewModel;
+ set => ViewModel = (BarViewModel?)value;
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/ReactiveUIDemo/Views/FooView.axaml b/samples/ReactiveUIDemo/Views/FooView.axaml
new file mode 100644
index 0000000000..8f73250d3b
--- /dev/null
+++ b/samples/ReactiveUIDemo/Views/FooView.axaml
@@ -0,0 +1,16 @@
+
+
+
+ Foo!
+
+
+
diff --git a/samples/ReactiveUIDemo/Views/FooView.axaml.cs b/samples/ReactiveUIDemo/Views/FooView.axaml.cs
new file mode 100644
index 0000000000..313a71044c
--- /dev/null
+++ b/samples/ReactiveUIDemo/Views/FooView.axaml.cs
@@ -0,0 +1,28 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using ReactiveUI;
+using ReactiveUIDemo.ViewModels;
+
+namespace ReactiveUIDemo.Views
+{
+ internal partial class FooView : UserControl, IViewFor
+ {
+ public FooView()
+ {
+ InitializeComponent();
+ }
+
+ public FooViewModel? ViewModel { get; set; }
+
+ object? IViewFor.ViewModel
+ {
+ get => ViewModel;
+ set => ViewModel = (FooViewModel?)value;
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/RenderDemo/Pages/TextFormatterPage.axaml.cs b/samples/RenderDemo/Pages/TextFormatterPage.axaml.cs
index 57a5c7101f..8fbfa854b1 100644
--- a/samples/RenderDemo/Pages/TextFormatterPage.axaml.cs
+++ b/samples/RenderDemo/Pages/TextFormatterPage.axaml.cs
@@ -90,7 +90,7 @@ namespace RenderDemo.Pages
return new ControlRun(_control, _defaultProperties);
}
- return new TextCharacters(_text.AsMemory(), _defaultProperties);
+ return new TextCharacters(_text, _defaultProperties);
}
}
diff --git a/samples/interop/Direct3DInteropSample/App.paml b/samples/interop/Direct3DInteropSample/App.paml
deleted file mode 100644
index e6d77dfaf4..0000000000
--- a/samples/interop/Direct3DInteropSample/App.paml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/samples/interop/Direct3DInteropSample/App.paml.cs b/samples/interop/Direct3DInteropSample/App.paml.cs
deleted file mode 100644
index 29365decfe..0000000000
--- a/samples/interop/Direct3DInteropSample/App.paml.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Avalonia;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Markup.Xaml;
-
-namespace Direct3DInteropSample
-{
- public class App : Application
- {
- public override void Initialize()
- {
- AvaloniaXamlLoader.Load(this);
- }
-
- public override void OnFrameworkInitializationCompleted()
- {
- if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- desktop.MainWindow = new MainWindow();
- base.OnFrameworkInitializationCompleted();
- }
- }
-}
diff --git a/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj b/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
deleted file mode 100644
index f9ef4693d5..0000000000
--- a/samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
- Exe
- net461
-
-
-
-
-
- %(Filename)
-
-
- Designer
-
-
-
-
-
-
-
- PreserveNewest
-
-
-
-
-
-
-
-
-
-
-
diff --git a/samples/interop/Direct3DInteropSample/MainWindow.cs b/samples/interop/Direct3DInteropSample/MainWindow.cs
deleted file mode 100644
index 6cc3cb9116..0000000000
--- a/samples/interop/Direct3DInteropSample/MainWindow.cs
+++ /dev/null
@@ -1,283 +0,0 @@
-using System;
-
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Direct2D1;
-using Avalonia.Direct2D1.Media;
-using Avalonia.Markup.Xaml;
-using Avalonia.Platform;
-using Avalonia.Rendering;
-
-using SharpDX;
-using SharpDX.D3DCompiler;
-using SharpDX.Direct2D1;
-using SharpDX.Direct3D;
-using SharpDX.Direct3D11;
-using SharpDX.DXGI;
-
-using AlphaMode = SharpDX.Direct2D1.AlphaMode;
-using Buffer = SharpDX.Direct3D11.Buffer;
-using DeviceContext = SharpDX.Direct2D1.DeviceContext;
-using Factory2 = SharpDX.DXGI.Factory2;
-using InputElement = SharpDX.Direct3D11.InputElement;
-using Matrix = SharpDX.Matrix;
-using PixelFormat = SharpDX.Direct2D1.PixelFormat;
-using Resource = SharpDX.Direct3D11.Resource;
-
-namespace Direct3DInteropSample
-{
- public class MainWindow : Window
- {
- Texture2D _backBuffer;
- RenderTargetView _renderView;
- Texture2D _depthBuffer;
- DepthStencilView _depthView;
- private readonly SwapChain _swapChain;
- private SwapChainDescription1 _desc;
- private Matrix _proj = Matrix.Identity;
- private readonly Matrix _view;
- private Buffer _contantBuffer;
- private DeviceContext _deviceContext;
- private readonly MainWindowViewModel _model;
-
- public MainWindow()
- {
- DataContext = _model = new MainWindowViewModel();
-
- _desc = new SwapChainDescription1()
- {
- BufferCount = 1,
- Width = (int)ClientSize.Width,
- Height = (int)ClientSize.Height,
- Format = Format.R8G8B8A8_UNorm,
- SampleDescription = new SampleDescription(1, 0),
- SwapEffect = SwapEffect.Discard,
- Usage = Usage.RenderTargetOutput
- };
-
- using (var factory = Direct2D1Platform.DxgiDevice.Adapter.GetParent())
- {
- _swapChain = new SwapChain1(factory, Direct2D1Platform.DxgiDevice, PlatformImpl?.Handle.Handle ?? IntPtr.Zero, ref _desc);
- }
-
- _deviceContext = new DeviceContext(Direct2D1Platform.Direct2D1Device, DeviceContextOptions.None)
- {
- DotsPerInch = new Size2F(96, 96)
- };
-
- CreateMesh();
-
- _view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
-
- this.GetObservable(ClientSizeProperty).Subscribe(Resize);
-
- Resize(ClientSize);
-
- AvaloniaXamlLoader.Load(this);
-
- Background = Avalonia.Media.Brushes.Transparent;
- }
-
-
- protected override void HandlePaint(Rect rect)
- {
- var viewProj = Matrix.Multiply(_view, _proj);
- var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
-
- // Clear views
- context.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
- context.ClearRenderTargetView(_renderView, Color.White);
-
- // Update WorldViewProj Matrix
- var worldViewProj = Matrix.RotationX((float)_model.RotationX) * Matrix.RotationY((float)_model.RotationY)
- * Matrix.RotationZ((float)_model.RotationZ)
- * Matrix.Scaling((float)_model.Zoom)
- * viewProj;
- worldViewProj.Transpose();
- context.UpdateSubresource(ref worldViewProj, _contantBuffer);
-
- // Draw the cube
- context.Draw(36, 0);
- base.HandlePaint(rect);
-
- // Present!
- _swapChain.Present(0, PresentFlags.None);
- }
-
- private void CreateMesh()
- {
- var device = Direct2D1Platform.Direct3D11Device;
-
- // Compile Vertex and Pixel shaders
- var vertexShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "VS", "vs_4_0");
- var vertexShader = new VertexShader(device, vertexShaderByteCode);
-
- var pixelShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "PS", "ps_4_0");
- var pixelShader = new PixelShader(device, pixelShaderByteCode);
-
- var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
-
- var inputElements = new[]
- {
- new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
- new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
- };
-
- // Layout from VertexShader input signature
- var layout = new InputLayout(
- device,
- signature,
- inputElements);
-
- // Instantiate Vertex buffer from vertex data
- var vertices = Buffer.Create(
- device,
- BindFlags.VertexBuffer,
- new[]
- {
- new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
- new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
- new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
-
- new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
- new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
- new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
- new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
-
- new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
- new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
- new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
-
- new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
- new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
- new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
- new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
- new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
-
- new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
- new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
- new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
- new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
- new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
- new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
-
- new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
- new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
- new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
- });
-
- // Create Constant Buffer
- _contantBuffer = new Buffer(device, Utilities.SizeOf(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
-
- var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
-
- // Prepare All the stages
- context.InputAssembler.InputLayout = layout;
- context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
- context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, Utilities.SizeOf() * 2, 0));
- context.VertexShader.SetConstantBuffer(0, _contantBuffer);
- context.VertexShader.Set(vertexShader);
- context.PixelShader.Set(pixelShader);
- }
-
- private void Resize(Size size)
- {
- Utilities.Dispose(ref _deviceContext);
- Utilities.Dispose(ref _backBuffer);
- Utilities.Dispose(ref _renderView);
- Utilities.Dispose(ref _depthBuffer);
- Utilities.Dispose(ref _depthView);
- var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
-
- // Resize the backbuffer
- _swapChain.ResizeBuffers(0, 0, 0, Format.Unknown, SwapChainFlags.None);
-
- // Get the backbuffer from the swapchain
- _backBuffer = Resource.FromSwapChain(_swapChain, 0);
-
- // Renderview on the backbuffer
- _renderView = new RenderTargetView(Direct2D1Platform.Direct3D11Device, _backBuffer);
-
- // Create the depth buffer
- _depthBuffer = new Texture2D(
- Direct2D1Platform.Direct3D11Device,
- new Texture2DDescription()
- {
- Format = Format.D32_Float_S8X24_UInt,
- ArraySize = 1,
- MipLevels = 1,
- Width = (int)size.Width,
- Height = (int)size.Height,
- SampleDescription = new SampleDescription(1, 0),
- Usage = ResourceUsage.Default,
- BindFlags = BindFlags.DepthStencil,
- CpuAccessFlags = CpuAccessFlags.None,
- OptionFlags = ResourceOptionFlags.None
- });
-
- // Create the depth buffer view
- _depthView = new DepthStencilView(Direct2D1Platform.Direct3D11Device, _depthBuffer);
-
- // Setup targets and viewport for rendering
- context.Rasterizer.SetViewport(new Viewport(0, 0, (int)size.Width, (int)size.Height, 0.0f, 1.0f));
- context.OutputMerger.SetTargets(_depthView, _renderView);
-
- // Setup new projection matrix with correct aspect ratio
- _proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)(size.Width / size.Height), 0.1f, 100.0f);
-
- using (var dxgiBackBuffer = _swapChain.GetBackBuffer(0))
- {
- var renderTarget = new SharpDX.Direct2D1.RenderTarget(
- Direct2D1Platform.Direct2D1Factory,
- dxgiBackBuffer,
- new RenderTargetProperties
- {
- DpiX = 96,
- DpiY = 96,
- Type = RenderTargetType.Default,
- PixelFormat = new PixelFormat(
- Format.Unknown,
- AlphaMode.Premultiplied)
- });
-
- _deviceContext = renderTarget.QueryInterface();
-
- renderTarget.Dispose();
- }
- }
-
- private class D3DRenderTarget : IRenderTarget
- {
- private readonly MainWindow _window;
-
- public D3DRenderTarget(MainWindow window)
- {
- _window = window;
- }
-
- public void Dispose()
- {
- }
-
- public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
- {
- return new DrawingContextImpl(visualBrushRenderer, null, _window._deviceContext);
- }
- }
-
-
- protected override IRenderTarget CreateRenderTarget() => new D3DRenderTarget(this);
- }
-}
diff --git a/samples/interop/Direct3DInteropSample/MainWindow.paml b/samples/interop/Direct3DInteropSample/MainWindow.paml
deleted file mode 100644
index 37c6265836..0000000000
--- a/samples/interop/Direct3DInteropSample/MainWindow.paml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- Rotation X
-
- Rotation Y
-
- Rotation Z
-
- Zoom
-
-
-
-
\ No newline at end of file
diff --git a/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs b/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
deleted file mode 100644
index 21679a99c5..0000000000
--- a/samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MiniMvvm;
-
-namespace Direct3DInteropSample
-{
- public class MainWindowViewModel : ViewModelBase
- {
- private double _rotationX;
-
- public double RotationX
- {
- get { return _rotationX; }
- set { this.RaiseAndSetIfChanged(ref _rotationX, value); }
- }
-
- private double _rotationY = 1;
-
- public double RotationY
- {
- get { return _rotationY; }
- set { this.RaiseAndSetIfChanged(ref _rotationY, value); }
- }
-
- private double _rotationZ = 2;
-
- public double RotationZ
- {
- get { return _rotationZ; }
- set { this.RaiseAndSetIfChanged(ref _rotationZ, value); }
- }
-
-
- private double _zoom = 1;
-
- public double Zoom
- {
- get { return _zoom; }
- set { this.RaiseAndSetIfChanged(ref _zoom, value); }
- }
- }
-}
diff --git a/samples/interop/Direct3DInteropSample/MiniCube.fx b/samples/interop/Direct3DInteropSample/MiniCube.fx
deleted file mode 100644
index f246421f2d..0000000000
--- a/samples/interop/Direct3DInteropSample/MiniCube.fx
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-struct VS_IN
-{
- float4 pos : POSITION;
- float4 col : COLOR;
-};
-
-struct PS_IN
-{
- float4 pos : SV_POSITION;
- float4 col : COLOR;
-};
-
-float4x4 worldViewProj;
-
-PS_IN VS( VS_IN input )
-{
- PS_IN output = (PS_IN)0;
-
- output.pos = mul(input.pos, worldViewProj);
- output.col = input.col;
-
- return output;
-}
-
-float4 PS( PS_IN input ) : SV_Target
-{
- return input.col;
-}
\ No newline at end of file
diff --git a/samples/interop/Direct3DInteropSample/Program.cs b/samples/interop/Direct3DInteropSample/Program.cs
deleted file mode 100644
index bf8e76d7e4..0000000000
--- a/samples/interop/Direct3DInteropSample/Program.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Avalonia;
-
-namespace Direct3DInteropSample
-{
- class Program
- {
- public static AppBuilder BuildAvaloniaApp()
- => AppBuilder.Configure()
- .With(new Win32PlatformOptions { UseDeferredRendering = false })
- .UseWin32()
- .UseDirect2D1();
-
- public static int Main(string[] args)
- => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
- }
-}
diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs
index 8d56086470..c885a7768c 100644
--- a/src/Android/Avalonia.Android/AndroidInputMethod.cs
+++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs
@@ -167,7 +167,7 @@ namespace Avalonia.Android
}
}
- public readonly struct ComposingRegion
+ public readonly record struct ComposingRegion
{
private readonly int _start = -1;
private readonly int _end = -1;
diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs
index 2b6d29e7c5..75856e4b52 100644
--- a/src/Android/Avalonia.Android/AndroidPlatform.cs
+++ b/src/Android/Avalonia.Android/AndroidPlatform.cs
@@ -32,6 +32,7 @@ namespace Avalonia.Android
public static AndroidPlatformOptions Options { get; private set; }
internal static Compositor Compositor { get; private set; }
+ internal static PlatformRenderInterfaceContextManager RenderInterface { get; private set; }
public static void Initialize()
{
@@ -51,15 +52,19 @@ namespace Avalonia.Android
if (Options.UseGpu)
{
- EglPlatformOpenGlInterface.TryInitialize();
+ EglPlatformGraphics.TryInitialize();
}
if (Options.UseCompositor)
{
Compositor = new Compositor(
AvaloniaLocator.Current.GetRequiredService(),
- AvaloniaLocator.Current.GetService());
+ AvaloniaLocator.Current.GetService());
}
+ else
+ RenderInterface =
+ new PlatformRenderInterfaceContextManager(AvaloniaLocator.Current
+ .GetService());
}
}
diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj
index 6688dde8f5..66557418dd 100644
--- a/src/Android/Avalonia.Android/Avalonia.Android.csproj
+++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj
@@ -16,4 +16,5 @@
+
diff --git a/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs b/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
deleted file mode 100644
index e85ed11028..0000000000
--- a/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Avalonia.OpenGL;
-using Avalonia.OpenGL.Egl;
-using Avalonia.OpenGL.Surfaces;
-
-namespace Avalonia.Android.OpenGL
-{
- internal sealed class GlPlatformSurface : EglGlPlatformSurfaceBase
- {
- private readonly EglPlatformOpenGlInterface _egl;
- private readonly IEglWindowGlPlatformSurfaceInfo _info;
-
- private GlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info)
- {
- _egl = egl;
- _info = info;
- }
-
- public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() =>
- new GlRenderTarget(_egl, _info, _egl.CreateWindowSurface(_info.Handle), _info.Handle);
-
- public static GlPlatformSurface TryCreate(IEglWindowGlPlatformSurfaceInfo info)
- {
- var feature = AvaloniaLocator.Current.GetService();
- if (feature is EglPlatformOpenGlInterface egl)
- {
- return new GlPlatformSurface(egl, info);
- }
-
- return null;
- }
- }
-}
diff --git a/src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs b/src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs
deleted file mode 100644
index f9071d9b27..0000000000
--- a/src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-
-using Avalonia.OpenGL.Egl;
-using Avalonia.OpenGL.Surfaces;
-
-namespace Avalonia.Android.OpenGL
-{
- internal sealed class GlRenderTarget : EglPlatformSurfaceRenderTargetBase, IGlPlatformSurfaceRenderTargetWithCorruptionInfo
- {
- private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info;
- private readonly EglSurface _surface;
- private readonly IntPtr _handle;
-
- public GlRenderTarget(
- EglPlatformOpenGlInterface egl,
- EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info,
- EglSurface surface,
- IntPtr handle)
- : base(egl)
- {
- _info = info;
- _surface = surface;
- _handle = handle;
- }
-
- public bool IsCorrupted => _handle != _info.Handle;
-
- public override IGlPlatformSurfaceRenderingSession BeginDraw() => BeginDraw(_surface, _info);
- }
-}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
index aabf8160f8..94e5f4bd01 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
@@ -96,12 +96,14 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IntPtr bits;
// Do not touch.
+#pragma warning disable CA1823 // Avoid unused private fields
uint reserved1;
uint reserved2;
uint reserved3;
uint reserved4;
uint reserved5;
uint reserved6;
+#pragma warning restore CA1823 // Avoid unused private fields
}
}
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 4150b52946..56dbadca03 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -8,7 +8,6 @@ using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
-using Avalonia.Android.OpenGL;
using Avalonia.Android.Platform.Specific;
using Avalonia.Android.Platform.Specific.Helpers;
using Avalonia.Android.Platform.Storage;
@@ -30,7 +29,7 @@ using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android.Platform.SkiaPlatform
{
- class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo,
+ class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo,
ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider
{
private readonly IGlPlatformSurface _gl;
@@ -47,7 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_textInputMethod = new AndroidInputMethod(_view);
_keyboardHelper = new AndroidKeyboardEventsHelper(this);
_pointerHelper = new AndroidMotionEventsHelper(this);
- _gl = GlPlatformSurface.TryCreate(this);
+ _gl = new EglGlPlatformSurface(this);
_framebuffer = new FramebufferManager(this);
RenderScaling = _view.Scaling;
@@ -106,10 +105,15 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IRenderer CreateRenderer(IRenderRoot root) =>
AndroidPlatform.Options.UseCompositor
- ? new CompositingRenderer(root, AndroidPlatform.Compositor)
+ ? new CompositingRenderer(root, AndroidPlatform.Compositor, () => Surfaces)
: AndroidPlatform.Options.UseDeferredRendering
- ? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService()) { RenderOnlyOnRenderThread = true }
- : new ImmediateRenderer((Visual)root);
+ ? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService(),
+ () => AndroidPlatform.RenderInterface.CreateRenderTarget(Surfaces),
+ AndroidPlatform.RenderInterface)
+ { RenderOnlyOnRenderThread = true }
+ : new ImmediateRenderer((Visual)root,
+ () => AndroidPlatform.RenderInterface.CreateRenderTarget(Surfaces),
+ AndroidPlatform.RenderInterface);
public virtual void Hide()
{
@@ -283,7 +287,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1);
- IntPtr EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo.Handle => ((IPlatformHandle)_view).Handle;
+ IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => ((IPlatformHandle)_view).Handle;
public PixelSize Size => _view.Size;
diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
index 57f6469a42..bc24a16e56 100644
--- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
+++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return DispatchKeyEventInternal(e, out callBase);
}
- string UnicodeTextInput(KeyEvent keyEvent)
+ static string UnicodeTextInput(KeyEvent keyEvent)
{
return keyEvent.Action == KeyEventActions.Multiple
&& keyEvent.RepeatCount == 0
diff --git a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
index a9b2e16d43..078f70db60 100644
--- a/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
+++ b/src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
@@ -178,7 +178,7 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
return false;
}
- private Stream? GetVirtualFileStream(Context context, AndroidUri uri, bool isOutput)
+ private static Stream? GetVirtualFileStream(Context context, AndroidUri uri, bool isOutput)
{
var mimeTypes = context.ContentResolver?.GetStreamTypes(uri, FilePickerFileTypes.All.MimeTypes![0]);
if (mimeTypes?.Length >= 1)
diff --git a/src/Avalonia.Base/Animation/Animation.cs b/src/Avalonia.Base/Animation/Animation.cs
index e0883901fd..06087cdd6a 100644
--- a/src/Avalonia.Base/Animation/Animation.cs
+++ b/src/Avalonia.Base/Animation/Animation.cs
@@ -202,9 +202,7 @@ namespace Avalonia.Animation
/// The animation setter.
/// The property animator value.
public static void SetAnimator(IAnimationSetter setter,
-#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
-#endif
Type value)
{
s_animators[setter] = (value, () => (IAnimator)Activator.CreateInstance(value)!);
diff --git a/src/Avalonia.Base/Animation/AnimatorKeyFrame.cs b/src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
index 0356723f00..3168a67d79 100644
--- a/src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
+++ b/src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
using Avalonia.Animation.Animators;
using Avalonia.Data;
using Avalonia.Reactive;
@@ -66,7 +67,8 @@ namespace Avalonia.Animation
}
}
- public T GetTypedValue()
+ [RequiresUnreferencedCode(TrimmingMessages.TypeConvertionRequiresUnreferencedCodeMessage)]
+ public T GetTypedValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
{
var typeConv = TypeDescriptor.GetConverter(typeof(T));
diff --git a/src/Avalonia.Base/Animation/Animators/Animator`1.cs b/src/Avalonia.Base/Animation/Animators/Animator`1.cs
index 8765cfb4c9..b5d1feb4a7 100644
--- a/src/Avalonia.Base/Animation/Animators/Animator`1.cs
+++ b/src/Avalonia.Base/Animation/Animators/Animator`1.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Animation.Utils;
using Avalonia.Collections;
@@ -39,7 +40,7 @@ namespace Avalonia.Animation.Animators
VerifyConvertKeyFrames();
var subject = new DisposeAnimationInstanceSubject(this, animation, control, clock, onComplete);
- return match.Subscribe(subject);
+ return new CompositeDisposable(match.Subscribe(subject), subject);
}
protected T InterpolationHandler(double animationTime, T neutralValue)
diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
index 4727ea1bfb..068c190fa1 100644
--- a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
+++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
@@ -72,7 +72,7 @@ namespace Avalonia.Animation.Animators
return control.Bind((AvaloniaProperty)Property, instance, BindingPriority.Animation);
}
- private IReadOnlyList InterpolateStops(double progress, IReadOnlyList oldValue, IReadOnlyList newValue)
+ private static IReadOnlyList InterpolateStops(double progress, IReadOnlyList oldValue, IReadOnlyList newValue)
{
var resultCount = Math.Max(oldValue.Count, newValue.Count);
var stops = new ImmutableGradientStop[resultCount];
diff --git a/src/Avalonia.Base/Animation/CrossFade.cs b/src/Avalonia.Base/Animation/CrossFade.cs
index 608a0880ec..a229bc7ce6 100644
--- a/src/Avalonia.Base/Animation/CrossFade.cs
+++ b/src/Avalonia.Base/Animation/CrossFade.cs
@@ -10,7 +10,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Animation
{
///
- /// Defines a cross-fade animation between two s.
+ /// Defines a cross-fade animation between two s.
///
public class CrossFade : IPageTransition
{
diff --git a/src/Avalonia.Base/Animation/Cue.cs b/src/Avalonia.Base/Animation/Cue.cs
index 6578148b07..c48f2ab6b0 100644
--- a/src/Avalonia.Base/Animation/Cue.cs
+++ b/src/Avalonia.Base/Animation/Cue.cs
@@ -8,7 +8,7 @@ namespace Avalonia.Animation
/// Determines the time index for a .
///
[TypeConverter(typeof(CueTypeConverter))]
- public readonly struct Cue : IEquatable, IEquatable
+ public readonly record struct Cue : IEquatable, IEquatable
{
///
/// The normalized percent value, ranging from 0.0 to 1.0
@@ -49,15 +49,6 @@ namespace Avalonia.Animation
}
}
- ///
- /// Checks for equality between two s.
- ///
- /// The second cue.
- public bool Equals(Cue other)
- {
- return CueValue == other.CueValue;
- }
-
///
/// Checks for equality between a
/// and a value.
diff --git a/src/Avalonia.Base/Animation/KeySpline.cs b/src/Avalonia.Base/Animation/KeySpline.cs
index a6e9769186..6ca5b2e759 100644
--- a/src/Avalonia.Base/Animation/KeySpline.cs
+++ b/src/Avalonia.Base/Animation/KeySpline.cs
@@ -196,7 +196,7 @@ namespace Avalonia.Animation
///
///
///
- private bool IsValidXValue(double value)
+ private static bool IsValidXValue(double value)
{
return value >= 0.0 && value <= 1.0;
}
diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj
index 21bdb794b3..0d3da66f7a 100644
--- a/src/Avalonia.Base/Avalonia.Base.csproj
+++ b/src/Avalonia.Base/Avalonia.Base.csproj
@@ -19,6 +19,7 @@
+
@@ -30,6 +31,8 @@
+
+
@@ -41,6 +44,7 @@
+
@@ -48,14 +52,10 @@
-
+
-
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 2c89062e51..e0782c51a2 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.PropertyStore;
@@ -442,6 +443,7 @@ namespace Avalonia
///
/// The value.
/// True if the value is valid, otherwise false.
+ [RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
public bool IsValidValue(object? value)
{
return TypeUtilities.TryConvertImplicit(PropertyType, value, out _);
diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
index 6106c58880..fc0ca2323e 100644
--- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Avalonia
@@ -42,6 +43,7 @@ namespace Avalonia
///
/// The type.
/// A collection of definitions.
+ [UnconditionalSuppressMessage("Trimming", "IL2059", Justification = "If type was trimmed out, no properties were referenced")]
public IReadOnlyList GetRegistered(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));
diff --git a/src/Avalonia.Base/AvaloniaProperty`1.cs b/src/Avalonia.Base/AvaloniaProperty`1.cs
index 5a0d69f3bf..53444ee475 100644
--- a/src/Avalonia.Base/AvaloniaProperty`1.cs
+++ b/src/Avalonia.Base/AvaloniaProperty`1.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reactive.Subjects;
using Avalonia.Data;
using Avalonia.Utilities;
@@ -67,6 +68,7 @@ namespace Avalonia
protected override IObservable GetChanged() => Changed;
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
protected BindingValue