diff --git a/samples/AppWithoutLifetime/MainWindow.axaml.cs b/samples/AppWithoutLifetime/MainWindow.axaml.cs
index d27d5d5653..df3ed3cea0 100644
--- a/samples/AppWithoutLifetime/MainWindow.axaml.cs
+++ b/samples/AppWithoutLifetime/MainWindow.axaml.cs
@@ -17,10 +17,11 @@ public partial class MainWindow : Window
AvaloniaXamlLoader.Load(this);
}
- protected override void OnLoaded()
+ ///
+ protected override void OnLoaded(RoutedEventArgs e)
{
this.AttachDevTools();
- base.OnLoaded();
+ base.OnLoaded(e);
}
public void Open(object sender, RoutedEventArgs e)
diff --git a/samples/AppWithoutLifetime/Sub.axaml.cs b/samples/AppWithoutLifetime/Sub.axaml.cs
index 50c770b3a2..3a7ce787bc 100644
--- a/samples/AppWithoutLifetime/Sub.axaml.cs
+++ b/samples/AppWithoutLifetime/Sub.axaml.cs
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Controls;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace AppWithoutLifetime;
@@ -16,9 +17,10 @@ public partial class Sub : Window
AvaloniaXamlLoader.Load(this);
}
- protected override void OnLoaded()
+ ///
+ protected override void OnLoaded(RoutedEventArgs e)
{
this.AttachDevTools();
- base.OnLoaded();
+ base.OnLoaded(e);
}
}
diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
index a43ea4539a..f668067f80 100644
--- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
+++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
@@ -10,6 +10,11 @@
apk
true
+
+
+
+
+
Resources\drawable\Icon.png
@@ -37,6 +42,10 @@
+
+
+
+
diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs
index 486d14661e..9b5b06e5fb 100644
--- a/samples/ControlCatalog.Android/MainActivity.cs
+++ b/samples/ControlCatalog.Android/MainActivity.cs
@@ -5,8 +5,16 @@ using Avalonia.Android;
namespace ControlCatalog.Android
{
- [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
- public class MainActivity : AvaloniaMainActivity
+ [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
+ public class MainActivity : AvaloniaMainActivity
{
+ protected override Avalonia.AppBuilder CustomizeAppBuilder(Avalonia.AppBuilder builder)
+ {
+ return base.CustomizeAppBuilder(builder)
+ .AfterSetup(_ =>
+ {
+ Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
+ });
+ }
}
}
diff --git a/samples/ControlCatalog.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/ControlCatalog.Android/Resources/drawable-night-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..dde4b5a7dd
--- /dev/null
+++ b/samples/ControlCatalog.Android/Resources/drawable-night-v31/avalonia_anim.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/ControlCatalog.Android/Resources/drawable-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..94f27d9e63
--- /dev/null
+++ b/samples/ControlCatalog.Android/Resources/drawable-v31/avalonia_anim.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Android/Resources/values-v31/styles.xml b/samples/ControlCatalog.Android/Resources/values-v31/styles.xml
new file mode 100644
index 0000000000..d5ecec4391
--- /dev/null
+++ b/samples/ControlCatalog.Android/Resources/values-v31/styles.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Android/Resources/values/styles.xml b/samples/ControlCatalog.Android/Resources/values/styles.xml
index 3e1270256d..6e534de2f0 100644
--- a/samples/ControlCatalog.Android/Resources/values/styles.xml
+++ b/samples/ControlCatalog.Android/Resources/values/styles.xml
@@ -6,16 +6,7 @@
-
-
-
-
-
diff --git a/samples/ControlCatalog.Android/SplashActivity.cs b/samples/ControlCatalog.Android/SplashActivity.cs
deleted file mode 100644
index a0b68b129b..0000000000
--- a/samples/ControlCatalog.Android/SplashActivity.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using Android.App;
-using Android.Content;
-using Android.Content.PM;
-using Android.OS;
-using Avalonia.Android;
-
-namespace ControlCatalog.Android
-{
- [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : AvaloniaSplashActivity
- {
- protected override Avalonia.AppBuilder CustomizeAppBuilder(Avalonia.AppBuilder builder)
- {
- return base.CustomizeAppBuilder(builder)
- .AfterSetup(_ =>
- {
- Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
- });
- }
-
- protected override void OnCreate(Bundle? savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
- }
-
- protected override void OnResume()
- {
- base.OnResume();
-
- StartActivity(new Intent(Application.Context, typeof(MainActivity)));
-
- Finish();
- }
- }
-}
diff --git a/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs b/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs
index 47d368f7a4..bd0c1bf98e 100644
--- a/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs
+++ b/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs
@@ -39,7 +39,7 @@ internal unsafe class WinApi
[DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyWindow(IntPtr hwnd);
- [DllImport("kernel32.dll")]
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW", ExactSpelling = true)]
public static extern IntPtr LoadLibrary(string lib);
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index 5249a4fb41..5e3e301461 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -110,8 +110,7 @@ namespace ControlCatalog.NetCore
{
builder.With(new Win32PlatformOptions()
{
- UseLowLatencyDxgiSwapChain = true,
- UseWindowsUIComposition = false
+ CompositionMode = new [] { Win32CompositionMode.LowLatencyDxgiSwapChain }
});
return builder.StartWithClassicDesktopLifetime(args);
}
diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml
index 64bf3e53b3..02b1242471 100644
--- a/samples/ControlCatalog/App.xaml
+++ b/samples/ControlCatalog/App.xaml
@@ -28,6 +28,9 @@
+
+
+
diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index 246fe4385f..605254c995 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -30,8 +30,8 @@ namespace ControlCatalog
AvaloniaXamlLoader.Load(this);
- _fluentTheme = new FluentTheme();
- _simpleTheme = new SimpleTheme();
+ _fluentTheme = (FluentTheme)Resources["FluentTheme"]!;
+ _simpleTheme = (SimpleTheme)Resources["SimpleTheme"]!;
_colorPickerFluent = (IStyle)Resources["ColorPickerFluent"]!;
_colorPickerSimple = (IStyle)Resources["ColorPickerSimple"]!;
_dataGridFluent = (IStyle)Resources["DataGridFluent"]!;
diff --git a/samples/MobileSandbox.Android/MainActivity.cs b/samples/MobileSandbox.Android/MainActivity.cs
index d65f0dec92..807afb0bd0 100644
--- a/samples/MobileSandbox.Android/MainActivity.cs
+++ b/samples/MobileSandbox.Android/MainActivity.cs
@@ -1,12 +1,11 @@
using Android.App;
using Android.Content.PM;
-using Avalonia;
using Avalonia.Android;
namespace MobileSandbox.Android
{
- [Activity(Label = "MobileSandbox.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
- public class MainActivity : AvaloniaMainActivity
+ [Activity(Label = "MobileSandbox.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AvaloniaMainActivity
{
}
}
diff --git a/samples/MobileSandbox.Android/MobileSandbox.Android.csproj b/samples/MobileSandbox.Android/MobileSandbox.Android.csproj
index 94f0d31e4d..3b67d79f7b 100644
--- a/samples/MobileSandbox.Android/MobileSandbox.Android.csproj
+++ b/samples/MobileSandbox.Android/MobileSandbox.Android.csproj
@@ -10,6 +10,12 @@
apk
true
+
+
+
+
+
+
Resources\drawable\Icon.png
@@ -37,6 +43,10 @@
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/MobileSandbox.Android/Resources/drawable-night-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..dde4b5a7dd
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/drawable-night-v31/avalonia_anim.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/MobileSandbox.Android/Resources/drawable-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..94f27d9e63
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/drawable-v31/avalonia_anim.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/values-night/colors.xml b/samples/MobileSandbox.Android/Resources/values-night/colors.xml
new file mode 100644
index 0000000000..3d47b6fc58
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/values-night/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #212121
+
diff --git a/samples/MobileSandbox.Android/Resources/values-v31/styles.xml b/samples/MobileSandbox.Android/Resources/values-v31/styles.xml
new file mode 100644
index 0000000000..7518f078e5
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/values-v31/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/values/styles.xml b/samples/MobileSandbox.Android/Resources/values/styles.xml
index 2759d2904a..22085806da 100644
--- a/samples/MobileSandbox.Android/Resources/values/styles.xml
+++ b/samples/MobileSandbox.Android/Resources/values/styles.xml
@@ -6,12 +6,7 @@
-
-
-
diff --git a/samples/MobileSandbox.Android/SplashActivity.cs b/samples/MobileSandbox.Android/SplashActivity.cs
deleted file mode 100644
index ced092554d..0000000000
--- a/samples/MobileSandbox.Android/SplashActivity.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Android.App;
-using Android.Content;
-using Avalonia.Android;
-
-namespace MobileSandbox.Android
-{
- [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : AvaloniaSplashActivity
- {
- protected override void OnResume()
- {
- base.OnResume();
-
- StartActivity(new Intent(Application.Context, typeof(MainActivity)));
- }
- }
-}
diff --git a/samples/SafeAreaDemo.Android/MainActivity.cs b/samples/SafeAreaDemo.Android/MainActivity.cs
index b0f0a6e419..1df575eb4d 100644
--- a/samples/SafeAreaDemo.Android/MainActivity.cs
+++ b/samples/SafeAreaDemo.Android/MainActivity.cs
@@ -4,8 +4,8 @@ using Avalonia.Android;
namespace SafeAreaDemo.Android
{
- [Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
- public class MainActivity : AvaloniaMainActivity
+ [Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
+ public class MainActivity : AvaloniaMainActivity
{
}
}
diff --git a/samples/SafeAreaDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/SafeAreaDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..dde4b5a7dd
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/SafeAreaDemo.Android/Resources/drawable-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..94f27d9e63
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/drawable-v31/avalonia_anim.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values-night/colors.xml b/samples/SafeAreaDemo.Android/Resources/values-night/colors.xml
new file mode 100644
index 0000000000..3d47b6fc58
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/values-night/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #212121
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values-v31/styles.xml b/samples/SafeAreaDemo.Android/Resources/values-v31/styles.xml
new file mode 100644
index 0000000000..7518f078e5
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/values-v31/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values/styles.xml b/samples/SafeAreaDemo.Android/Resources/values/styles.xml
index 2759d2904a..22085806da 100644
--- a/samples/SafeAreaDemo.Android/Resources/values/styles.xml
+++ b/samples/SafeAreaDemo.Android/Resources/values/styles.xml
@@ -6,12 +6,7 @@
-
-
-
diff --git a/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj b/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
index f5d2af79d0..cc182b2b56 100644
--- a/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
+++ b/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
@@ -1,4 +1,4 @@
-
+
Exe
net7.0-android
@@ -12,13 +12,14 @@
-
- Resources\drawable\Icon.png
-
+
+
-
-
+
+ Resources\drawable\Icon.png
+
+
diff --git a/samples/SafeAreaDemo.Android/SplashActivity.cs b/samples/SafeAreaDemo.Android/SplashActivity.cs
deleted file mode 100644
index 621ad1c675..0000000000
--- a/samples/SafeAreaDemo.Android/SplashActivity.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Android.App;
-using Android.Content;
-using Android.OS;
-using Avalonia;
-using Avalonia.Android;
-using Application = Android.App.Application;
-
-namespace SafeAreaDemo.Android
-{
- [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : AvaloniaSplashActivity
- {
- protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
- {
- return base.CustomizeAppBuilder(builder);
- }
-
- protected override void OnCreate(Bundle? savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
- }
-
- protected override void OnResume()
- {
- base.OnResume();
-
- StartActivity(new Intent(Application.Context, typeof(MainActivity)));
- }
- }
-}
diff --git a/samples/SafeAreaDemo/Views/MainView.xaml.cs b/samples/SafeAreaDemo/Views/MainView.xaml.cs
index 2b651225e7..4b8c5e5f15 100644
--- a/samples/SafeAreaDemo/Views/MainView.xaml.cs
+++ b/samples/SafeAreaDemo/Views/MainView.xaml.cs
@@ -1,4 +1,5 @@
using Avalonia.Controls;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using SafeAreaDemo.ViewModels;
@@ -11,9 +12,10 @@ namespace SafeAreaDemo.Views
AvaloniaXamlLoader.Load(this);
}
- protected override void OnLoaded()
+ ///
+ protected override void OnLoaded(RoutedEventArgs e)
{
- base.OnLoaded();
+ base.OnLoaded(e);
var insetsManager = TopLevel.GetTopLevel(this)?.InsetsManager;
if (insetsManager != null && DataContext is MainViewModel viewModel)
diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs
index d5d5f211e9..144909db4b 100644
--- a/src/Android/Avalonia.Android/AndroidPlatform.cs
+++ b/src/Android/Avalonia.Android/AndroidPlatform.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using Avalonia.Controls;
using Avalonia.Android;
using Avalonia.Android.Platform;
@@ -22,6 +24,39 @@ namespace Avalonia
.UseSkia();
}
}
+
+ ///
+ /// Represents the rendering mode for platform graphics.
+ ///
+ public enum AndroidRenderingMode
+ {
+ ///
+ /// Avalonia is rendered into a framebuffer.
+ ///
+ Software = 1,
+
+ ///
+ /// Enables android EGL rendering.
+ ///
+ Egl = 2
+ }
+
+ public sealed class AndroidPlatformOptions
+ {
+ ///
+ /// Gets or sets Avalonia rendering modes with fallbacks.
+ /// The first element in the array has the highest priority.
+ /// The default value is: , .
+ ///
+ ///
+ /// If application should work on as wide range of devices as possible, at least add as a fallback value.
+ ///
+ /// Thrown if no values were matched.
+ public IReadOnlyList RenderingMode { get; set; } = new[]
+ {
+ AndroidRenderingMode.Egl, AndroidRenderingMode.Software
+ };
+ }
}
namespace Avalonia.Android
@@ -47,18 +82,39 @@ namespace Avalonia.Android
.Bind().ToConstant(new ChoreographerTimer())
.Bind().ToSingleton();
- if (Options.UseGpu)
+ var graphics = InitializeGraphics(Options);
+ if (graphics is not null)
{
- EglPlatformGraphics.TryInitialize();
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(graphics);
}
-
- Compositor = new Compositor(AvaloniaLocator.Current.GetService());
+
+ Compositor = new Compositor(graphics);
}
- }
+
+ private static IPlatformGraphics InitializeGraphics(AndroidPlatformOptions opts)
+ {
+ if (opts.RenderingMode is null || !opts.RenderingMode.Any())
+ {
+ throw new InvalidOperationException($"{nameof(AndroidPlatformOptions)}.{nameof(AndroidPlatformOptions.RenderingMode)} must not be empty or null");
+ }
- public sealed class AndroidPlatformOptions
- {
- public bool UseDeferredRendering { get; set; } = false;
- public bool UseGpu { get; set; } = true;
+ foreach (var renderingMode in opts.RenderingMode)
+ {
+ if (renderingMode == AndroidRenderingMode.Software)
+ {
+ return null;
+ }
+
+ if (renderingMode == AndroidRenderingMode.Egl)
+ {
+ if (EglPlatformGraphics.TryCreate() is { } egl)
+ {
+ return egl;
+ }
+ }
+ }
+
+ throw new InvalidOperationException($"{nameof(AndroidPlatformOptions)}.{nameof(AndroidPlatformOptions.RenderingMode)} has a value of \"{string.Join(", ", opts.RenderingMode)}\", but no options were applied.");
+ }
}
}
diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
new file mode 100644
index 0000000000..3fcfde3ee4
--- /dev/null
+++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Android
+{
+ partial class AvaloniaMainActivity where TApp : Application, new()
+ {
+ protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
+
+ private static AppBuilder? s_appBuilder;
+ internal static object ViewContent;
+
+ public object Content
+ {
+ get
+ {
+ return ViewContent;
+ }
+ set
+ {
+ ViewContent = value;
+ if (View != null)
+ View.Content = value;
+ }
+ }
+
+ protected AppBuilder CreateAppBuilder()
+ {
+ var builder = AppBuilder.Configure();
+
+ return CustomizeAppBuilder(builder);
+ }
+
+ private void InitializeApp()
+ {
+ if (s_appBuilder == null)
+ {
+ var builder = CreateAppBuilder();
+
+ builder.SetupWithLifetime(new SingleViewLifetime());
+
+ s_appBuilder = builder;
+ }
+
+ View = new AvaloniaView(this);
+ if (ViewContent != null)
+ {
+ View.Content = ViewContent;
+ }
+
+ if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime)
+ {
+ lifetime.View = View;
+ }
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
index b2cd150933..499924d8fb 100644
--- a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
+++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
@@ -11,27 +11,49 @@ using AndroidX.AppCompat.App;
namespace Avalonia.Android
{
- public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler, IActivityNavigationService
+ public class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler, IActivityNavigationService
{
- internal static object ViewContent;
-
public Action ActivityResult { get; set; }
public Action RequestPermissionsResult { get; set; }
+
+ public event EventHandler BackRequested;
+
+ public override void OnBackPressed()
+ {
+ var eventArgs = new AndroidBackRequestedEventArgs();
+
+ BackRequested?.Invoke(this, eventArgs);
+
+ if (!eventArgs.Handled)
+ {
+ base.OnBackPressed();
+ }
+ }
+
+ protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
+ {
+ base.OnActivityResult(requestCode, resultCode, data);
+
+ ActivityResult?.Invoke(requestCode, resultCode, data);
+ }
+
+ public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
+ {
+ base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+
+ RequestPermissionsResult?.Invoke(requestCode, permissions, grantResults);
+ }
+ }
+
+ public abstract partial class AvaloniaMainActivity : AvaloniaMainActivity where TApp : Application, new()
+ {
internal AvaloniaView View;
private GlobalLayoutListener _listener;
protected override void OnCreate(Bundle savedInstanceState)
{
- View = new AvaloniaView(this);
- if (ViewContent != null)
- {
- View.Content = ViewContent;
- }
+ InitializeApp();
- if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime)
- {
- lifetime.View = View;
- }
base.OnCreate(savedInstanceState);
SetContentView(View);
@@ -41,20 +63,6 @@ namespace Avalonia.Android
View.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener);
}
- public object Content
- {
- get
- {
- return ViewContent;
- }
- set
- {
- ViewContent = value;
- if (View != null)
- View.Content = value;
- }
- }
-
protected override void OnResume()
{
base.OnResume();
@@ -66,20 +74,6 @@ namespace Avalonia.Android
}
}
- public event EventHandler BackRequested;
-
- public override void OnBackPressed()
- {
- var eventArgs = new AndroidBackRequestedEventArgs();
-
- BackRequested?.Invoke(this, eventArgs);
-
- if (!eventArgs.Handled)
- {
- base.OnBackPressed();
- }
- }
-
protected override void OnDestroy()
{
View.Content = null;
@@ -89,20 +83,6 @@ namespace Avalonia.Android
base.OnDestroy();
}
- protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
- {
- base.OnActivityResult(requestCode, resultCode, data);
-
- ActivityResult?.Invoke(requestCode, resultCode, data);
- }
-
- public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
- {
- base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
-
- RequestPermissionsResult?.Invoke(requestCode, permissions, grantResults);
- }
-
class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
private AvaloniaView _view;
diff --git a/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs b/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
deleted file mode 100644
index 38038ef26c..0000000000
--- a/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Android.OS;
-using AndroidX.AppCompat.App;
-
-namespace Avalonia.Android
-{
- public abstract class AvaloniaSplashActivity : AppCompatActivity
- {
- protected abstract AppBuilder CreateAppBuilder();
-
- private static AppBuilder s_appBuilder;
-
- protected override void OnCreate(Bundle? savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
-
- if (s_appBuilder == null)
- {
- var builder = CreateAppBuilder();
-
- var lifetime = new SingleViewLifetime();
-
- builder.SetupWithLifetime(lifetime);
-
- s_appBuilder = builder;
- }
- }
- }
-
- public abstract class AvaloniaSplashActivity : AvaloniaSplashActivity where TApp : Application, new()
- {
- protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
-
- protected override AppBuilder CreateAppBuilder()
- {
- var builder = AppBuilder.Configure();
-
- return CustomizeAppBuilder(builder);
- }
- }
-}
diff --git a/src/Avalonia.Base/CombinedGeometry.cs b/src/Avalonia.Base/CombinedGeometry.cs
index 4b5866519b..a47e756c88 100644
--- a/src/Avalonia.Base/CombinedGeometry.cs
+++ b/src/Avalonia.Base/CombinedGeometry.cs
@@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Text;
using Avalonia.Platform;
-#nullable enable
-
namespace Avalonia.Media
{
public enum GeometryCombineMode
@@ -147,7 +145,7 @@ namespace Avalonia.Media
return new CombinedGeometry(GeometryCombineMode, Geometry1, Geometry2, Transform);
}
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
var g1 = Geometry1;
var g2 = Geometry2;
diff --git a/src/Avalonia.Base/Input/Pointer.cs b/src/Avalonia.Base/Input/Pointer.cs
index 91358712a0..5744ddf963 100644
--- a/src/Avalonia.Base/Input/Pointer.cs
+++ b/src/Avalonia.Base/Input/Pointer.cs
@@ -88,7 +88,6 @@ namespace Avalonia.Input
/// Captures pointer input to the specified gesture recognizer.
///
/// The gesture recognizer.
- ///
internal void CaptureGestureRecognizer(GestureRecognizer? gestureRecognizer)
{
if (CapturedGestureRecognizer != gestureRecognizer)
diff --git a/src/Avalonia.Base/Input/TextInputEventArgs.cs b/src/Avalonia.Base/Input/TextInputEventArgs.cs
index f4acd694a0..305b4d81f8 100644
--- a/src/Avalonia.Base/Input/TextInputEventArgs.cs
+++ b/src/Avalonia.Base/Input/TextInputEventArgs.cs
@@ -4,6 +4,6 @@ namespace Avalonia.Input
{
public class TextInputEventArgs : RoutedEventArgs
{
- public string? Text { get; init; }
+ public string? Text { get; set; }
}
}
diff --git a/src/Avalonia.Base/Media/EllipseGeometry.cs b/src/Avalonia.Base/Media/EllipseGeometry.cs
index 84d74e888e..bb1263d8d5 100644
--- a/src/Avalonia.Base/Media/EllipseGeometry.cs
+++ b/src/Avalonia.Base/Media/EllipseGeometry.cs
@@ -135,7 +135,7 @@ namespace Avalonia.Media
}
///
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetRequiredService();
diff --git a/src/Avalonia.Base/Media/Geometry.cs b/src/Avalonia.Base/Media/Geometry.cs
index 0d2311eafc..a66cd616a3 100644
--- a/src/Avalonia.Base/Media/Geometry.cs
+++ b/src/Avalonia.Base/Media/Geometry.cs
@@ -28,6 +28,11 @@ namespace Avalonia.Media
TransformProperty.Changed.AddClassHandler((x,e) => x.TransformChanged(e));
}
+ internal Geometry()
+ {
+
+ }
+
///
/// Raised when the geometry changes.
///
@@ -134,7 +139,7 @@ namespace Avalonia.Media
/// Creates the platform implementation of the geometry, without the transform applied.
///
///
- protected abstract IGeometryImpl? CreateDefiningGeometry();
+ private protected abstract IGeometryImpl? CreateDefiningGeometry();
///
/// Invalidates the platform implementation of the geometry.
diff --git a/src/Avalonia.Base/Media/GeometryGroup.cs b/src/Avalonia.Base/Media/GeometryGroup.cs
index 3e61413919..20bd297fc1 100644
--- a/src/Avalonia.Base/Media/GeometryGroup.cs
+++ b/src/Avalonia.Base/Media/GeometryGroup.cs
@@ -1,8 +1,6 @@
using Avalonia.Metadata;
using Avalonia.Platform;
-#nullable enable
-
namespace Avalonia.Media
{
///
@@ -72,7 +70,7 @@ namespace Avalonia.Media
newChildren.Parent = this;
}
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
if (_children.Count > 0)
{
diff --git a/src/Avalonia.Base/Media/LineGeometry.cs b/src/Avalonia.Base/Media/LineGeometry.cs
index 6ac92ea33b..ced208e30b 100644
--- a/src/Avalonia.Base/Media/LineGeometry.cs
+++ b/src/Avalonia.Base/Media/LineGeometry.cs
@@ -68,7 +68,7 @@ namespace Avalonia.Media
}
///
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetRequiredService();
diff --git a/src/Avalonia.Base/Media/MediaContext.cs b/src/Avalonia.Base/Media/MediaContext.cs
index 84a4a8c873..0a290052c7 100644
--- a/src/Avalonia.Base/Media/MediaContext.cs
+++ b/src/Avalonia.Base/Media/MediaContext.cs
@@ -213,10 +213,10 @@ internal partial class MediaContext : ICompositorScheduler
}
///
- /// Executes the callback in the next iteration of the current UI-thread
+ /// Executes the callback in the next iteration of the current UI-thread
/// render loop / layout pass that.
///
- /// Code to execute.
+ ///
public void BeginInvokeOnRender(Action callback)
{
if (_invokeOnRenderCallbacks == null)
diff --git a/src/Avalonia.Base/Media/PathGeometry.cs b/src/Avalonia.Base/Media/PathGeometry.cs
index 8292afde7e..bdfbfadce4 100644
--- a/src/Avalonia.Base/Media/PathGeometry.cs
+++ b/src/Avalonia.Base/Media/PathGeometry.cs
@@ -43,7 +43,7 @@ namespace Avalonia.Media
///
/// The s.
///
- public static new PathGeometry Parse(string pathData)
+ public new static PathGeometry Parse(string pathData)
{
var pathGeometry = new PathGeometry();
@@ -81,7 +81,7 @@ namespace Avalonia.Media
set { SetValue(FillRuleProperty, value); }
}
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
var figures = Figures;
diff --git a/src/Avalonia.Base/Media/PlatformGeometry.cs b/src/Avalonia.Base/Media/PlatformGeometry.cs
index f25a14540f..e1488a8229 100644
--- a/src/Avalonia.Base/Media/PlatformGeometry.cs
+++ b/src/Avalonia.Base/Media/PlatformGeometry.cs
@@ -2,7 +2,7 @@
namespace Avalonia.Media
{
- internal class PlatformGeometry : Geometry
+ internal sealed class PlatformGeometry : Geometry
{
private readonly IGeometryImpl _geometryImpl;
@@ -16,7 +16,7 @@ namespace Avalonia.Media
return new PlatformGeometry(_geometryImpl);
}
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected override IGeometryImpl? CreateDefiningGeometry()
{
return _geometryImpl;
}
diff --git a/src/Avalonia.Base/Media/PolylineGeometry.cs b/src/Avalonia.Base/Media/PolylineGeometry.cs
index b0229b6455..47cf2f48a4 100644
--- a/src/Avalonia.Base/Media/PolylineGeometry.cs
+++ b/src/Avalonia.Base/Media/PolylineGeometry.cs
@@ -74,7 +74,7 @@ namespace Avalonia.Media
return new PolylineGeometry(Points, IsFilled);
}
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetRequiredService();
var geometry = factory.CreateStreamGeometry();
diff --git a/src/Avalonia.Base/Media/RectangleGeometry.cs b/src/Avalonia.Base/Media/RectangleGeometry.cs
index 0bf9eb5664..01771242a7 100644
--- a/src/Avalonia.Base/Media/RectangleGeometry.cs
+++ b/src/Avalonia.Base/Media/RectangleGeometry.cs
@@ -47,7 +47,7 @@ namespace Avalonia.Media
///
public override Geometry Clone() => new RectangleGeometry(Rect);
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected sealed override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetRequiredService();
diff --git a/src/Avalonia.Base/Media/StreamGeometry.cs b/src/Avalonia.Base/Media/StreamGeometry.cs
index fb79488e0f..9969376896 100644
--- a/src/Avalonia.Base/Media/StreamGeometry.cs
+++ b/src/Avalonia.Base/Media/StreamGeometry.cs
@@ -31,7 +31,7 @@ namespace Avalonia.Media
///
/// The string.
/// A .
- public static new StreamGeometry Parse(string s)
+ public new static StreamGeometry Parse(string s)
{
var streamGeometry = new StreamGeometry();
@@ -62,7 +62,7 @@ namespace Avalonia.Media
}
///
- protected override IGeometryImpl? CreateDefiningGeometry()
+ private protected override IGeometryImpl? CreateDefiningGeometry()
{
if (_impl == null)
{
diff --git a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
index a0cd2a8dcd..df3c9ebfc5 100644
--- a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
+++ b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
@@ -161,7 +161,7 @@ namespace Avalonia.Platform
void PopGeometryClip();
///
-
+ /// Get Fetaure from type
///
/// Attempts to get an optional feature from the drawing context implementation
///
diff --git a/src/Avalonia.Base/Point.cs b/src/Avalonia.Base/Point.cs
index 331cce4a76..e3ea21d1eb 100644
--- a/src/Avalonia.Base/Point.cs
+++ b/src/Avalonia.Base/Point.cs
@@ -164,6 +164,19 @@ namespace Avalonia
/// The resulting point.
public static Point operator *(Point point, Matrix matrix) => matrix.Transform(point);
+ ///
+ /// Computes the Euclidean distance between the two given points.
+ ///
+ /// The first point.
+ /// The second point.
+ /// The Euclidean distance.
+ public static double Distance(Point value1, Point value2)
+ {
+ double distanceSquared = ((value2.X - value1.X) * (value2.X - value1.X)) +
+ ((value2.Y - value1.Y) * (value2.Y - value1.Y));
+ return Math.Sqrt(distanceSquared);
+ }
+
///
/// Parses a string.
///
diff --git a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
index 4518289335..a69d7b7094 100644
--- a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
+++ b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
@@ -216,7 +216,7 @@ namespace Avalonia.PropertyStore
valueChanged = !EqualityComparer.Default.Equals(Value, v);
Value = v;
Priority = priority;
- if (_uncommon is not null)
+ if (!isCoercedDefaultValue && _uncommon is not null)
_uncommon._uncoercedValue = value;
}
@@ -225,7 +225,7 @@ namespace Avalonia.PropertyStore
baseValueChanged = !EqualityComparer.Default.Equals(_baseValue, v);
_baseValue = v;
BasePriority = priority;
- if (_uncommon is not null)
+ if (!isCoercedDefaultValue && _uncommon is not null)
_uncommon._uncoercedBaseValue = value;
}
diff --git a/src/Avalonia.Base/Rendering/RenderLoop.cs b/src/Avalonia.Base/Rendering/RenderLoop.cs
index aaecf5deaf..80410ba181 100644
--- a/src/Avalonia.Base/Rendering/RenderLoop.cs
+++ b/src/Avalonia.Base/Rendering/RenderLoop.cs
@@ -42,7 +42,6 @@ namespace Avalonia.Rendering
/// Initializes a new instance of the class.
///
/// The render timer.
- /// The UI thread dispatcher.
public RenderLoop(IRenderTimer timer)
{
_timer = timer;
diff --git a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
index bb1663eac0..7d586e1cbd 100644
--- a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
+++ b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
@@ -581,11 +581,6 @@ public partial class Dispatcher
///
/// A Func<Task<TResult>> delegate to invoke through the dispatcher.
///
- ///
- /// The priority that determines in what order the specified
- /// callback is invoked relative to the other pending operations
- /// in the Dispatcher.
- ///
///
/// An task that completes after the task returned from callback finishes
///
diff --git a/src/Avalonia.Base/Vector.cs b/src/Avalonia.Base/Vector.cs
index 15722901a6..fffe206835 100644
--- a/src/Avalonia.Base/Vector.cs
+++ b/src/Avalonia.Base/Vector.cs
@@ -359,7 +359,7 @@ namespace Avalonia
internal Vector(Vector2 v) : this(v.X, v.Y)
{
-
+
}
///
@@ -379,21 +379,27 @@ namespace Avalonia
///
public static Vector Max(Vector left, Vector right) =>
new(Math.Max(left.X, right.X), Math.Max(left.Y, right.Y));
-
+
///
/// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors
///
public static Vector Min(Vector left, Vector right) =>
new(Math.Min(left.X, right.X), Math.Min(left.Y, right.Y));
-
+
///
/// Computes the Euclidean distance between the two given points.
///
+ /// The first point.
+ /// The second point.
+ /// The Euclidean distance.
public static double Distance(Vector value1, Vector value2) => Math.Sqrt(DistanceSquared(value1, value2));
-
+
///
/// Returns the Euclidean distance squared between two specified points
///
+ /// The first point.
+ /// The second point.
+ /// The Euclidean distance squared.
public static double DistanceSquared(Vector value1, Vector value2)
{
var difference = value1 - value2;
diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
index d28c0969c4..a5695afeb7 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
@@ -38,7 +38,7 @@ namespace Avalonia.Controls
private ICellEditBinding _editBinding;
private IBinding _clipboardContentBinding;
private ControlTheme _cellTheme;
- private readonly Classes _cellStyleClasses = new Classes();
+ private Classes _cellStyleClasses;
///
/// Initializes a new instance of the class.
@@ -393,17 +393,7 @@ namespace Avalonia.Controls
}
}
- public Classes CellStyleClasses
- {
- get => _cellStyleClasses;
- set
- {
- if(_cellStyleClasses != value)
- {
- _cellStyleClasses.Replace(value);
- }
- }
- }
+ public Classes CellStyleClasses => _cellStyleClasses ??= new();
///
/// Backing field for CellTheme property.
diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
index 082eac60be..0cc620dae9 100644
--- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
+++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
@@ -42,9 +42,10 @@
-
+
0.6
0.8
+ 32
M1875 1011l-787 787v-1798h-128v1798l-787 -787l-90 90l941 941l941 -941z
M1965 947l-941 -941l-941 941l90 90l787 -787v1798h128v-1798l787 787z
@@ -174,7 +175,7 @@
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
-
+
-
AppBuilder method or inherit Application type.");
}
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index ae7d4f3fb4..0851c14178 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -316,7 +316,8 @@ namespace Avalonia.Controls
((ILogical)this).IsAttachedToLogicalTree)
{
_isLoaded = true;
- OnLoaded();
+
+ OnLoaded(new RoutedEventArgs(LoadedEvent, this));
}
}
@@ -333,28 +334,36 @@ namespace Avalonia.Controls
_loadedQueue.Remove(this);
_isLoaded = false;
- OnUnloaded();
+
+ OnUnloaded(new RoutedEventArgs(UnloadedEvent, this));
}
}
///
/// Invoked just before the event.
///
- protected virtual void OnLoaded()
+ /// The event args.
+ protected virtual void OnLoaded(RoutedEventArgs e)
{
- var eventArgs = new RoutedEventArgs(LoadedEvent);
- eventArgs.Source = null;
- RaiseEvent(eventArgs);
+ RaiseEvent(e);
}
///
/// Invoked just before the event.
///
- protected virtual void OnUnloaded()
+ /// The event args.
+ protected virtual void OnUnloaded(RoutedEventArgs e)
{
- var eventArgs = new RoutedEventArgs(UnloadedEvent);
- eventArgs.Source = null;
- RaiseEvent(eventArgs);
+ RaiseEvent(e);
+ }
+
+ ///
+ /// Invoked just before the event.
+ ///
+ /// The event args.
+ protected virtual void OnSizeChanged(SizeChangedEventArgs e)
+ {
+ RaiseEvent(e);
}
///
@@ -435,6 +444,10 @@ namespace Avalonia.Controls
}
}
+ ///
+ /// Returns a new, type-specific implementation for the control.
+ ///
+ /// The type-specific implementation.
protected virtual AutomationPeer OnCreateAutomationPeer()
{
return new NoneAutomationPeer(this);
@@ -459,6 +472,7 @@ namespace Avalonia.Controls
return _automationPeer;
}
+ ///
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
@@ -473,6 +487,7 @@ namespace Avalonia.Controls
}
}
+ ///
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
@@ -531,7 +546,7 @@ namespace Avalonia.Controls
previousSize: new Size(oldValue.Width, oldValue.Height),
newSize: new Size(newValue.Width, newValue.Height));
- RaiseEvent(sizeChangedEventArgs);
+ OnSizeChanged(sizeChangedEventArgs);
}
}
}
diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
index bd694b200c..bd3d2b5171 100644
--- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
@@ -7,7 +7,7 @@ using Avalonia.Input.GestureRecognizers;
using Avalonia.Utilities;
using Avalonia.VisualTree;
using System.Linq;
-using Avalonia.Interactivity;
+using Avalonia.Layout;
namespace Avalonia.Controls.Presenters
{
@@ -473,7 +473,15 @@ namespace Avalonia.Controls.Presenters
}
Viewport = finalSize;
- Extent = Child!.Bounds.Size.Inflate(Child.Margin);
+
+ var childMargin = Child!.Margin;
+ if (Child.UseLayoutRounding)
+ {
+ var scale = LayoutHelper.GetLayoutScale(Child);
+ childMargin = LayoutHelper.RoundLayoutThickness(childMargin, scale, scale);
+ }
+
+ Extent = Child!.Bounds.Size.Inflate(childMargin);
_isAnchorElementDirty = true;
return finalSize;
diff --git a/src/Avalonia.Controls/ToggleSwitch.cs b/src/Avalonia.Controls/ToggleSwitch.cs
index 48b068d324..dc6b946381 100644
--- a/src/Avalonia.Controls/ToggleSwitch.cs
+++ b/src/Avalonia.Controls/ToggleSwitch.cs
@@ -3,6 +3,7 @@ using Avalonia.Controls.Metadata;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
+using Avalonia.Interactivity;
using Avalonia.LogicalTree;
namespace Avalonia.Controls
@@ -200,9 +201,10 @@ namespace Avalonia.Controls
}
}
- protected override void OnLoaded()
+ ///
+ protected override void OnLoaded(RoutedEventArgs e)
{
- base.OnLoaded();
+ base.OnLoaded(e);
UpdateKnobTransitions();
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs
index aec0cb37bc..f6e9842ac8 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs
@@ -265,7 +265,7 @@ namespace Avalonia.Diagnostics.Views
static bool IsValidNumeric(Type? type)
{
- if (type == null)
+ if (type == null || type.IsEnum == true)
{
return false;
}
diff --git a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml
index 22362fa5f5..b58df71ba2 100644
--- a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml
+++ b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml
@@ -6,106 +6,71 @@
MinWidth="430"
MinHeight="475"
Title="About Avalonia"
- Background="Purple"
FontFamily="/Assets/Roboto-Light.ttf#Roboto"
x:Class="Avalonia.Dialogs.AboutAvaloniaDialog"
x:DataType="dialogs:AboutAvaloniaDialog">
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs
index 2dc377a242..ba432337dc 100644
--- a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs
+++ b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Avalonia.Controls;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace Avalonia.Dialogs
@@ -11,35 +12,19 @@ namespace Avalonia.Dialogs
{
private static readonly Version s_version = typeof(AboutAvaloniaDialog).Assembly.GetName().Version;
- public static string Version { get; } = s_version.ToString(2);
+ public static string Version { get; } = $@"v{s_version.ToString(2)}";
public static bool IsDevelopmentBuild { get; } = s_version.Revision == 999;
+ public static string Copyright { get; } = $"© {DateTime.Now.Year} The Avalonia Project";
+
public AboutAvaloniaDialog()
{
AvaloniaXamlLoader.Load(this);
DataContext = this;
}
- public static void OpenBrowser(string url)
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- {
- // If no associated application/json MimeType is found xdg-open opens retrun error
- // but it tries to open it anyway using the console editor (nano, vim, other..)
- ShellExec($"xdg-open {url}", waitForExit: false);
- }
- else
- {
- using Process process = Process.Start(new ProcessStartInfo
- {
- FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? url : "open",
- Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? $"{url}" : "",
- CreateNoWindow = true,
- UseShellExecute = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
- });
- }
- }
+
private static void ShellExec(string cmd, bool waitForExit = true)
{
@@ -64,5 +49,26 @@ namespace Avalonia.Dialogs
}
}
}
+
+ private void Button_OnClick(object sender, RoutedEventArgs e)
+ {
+ var url = "https://www.avaloniaui.net/";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ // If no associated application/json MimeType is found xdg-open opens retrun error
+ // but it tries to open it anyway using the console editor (nano, vim, other..)
+ ShellExec($"xdg-open {url}", waitForExit: false);
+ }
+ else
+ {
+ using Process process = Process.Start(new ProcessStartInfo
+ {
+ FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? url : "open",
+ Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? $"{url}" : "",
+ CreateNoWindow = true,
+ UseShellExecute = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ });
+ }
+ }
}
}
diff --git a/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs b/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs
index 8389a25386..8e24da97a4 100644
--- a/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs
+++ b/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs
@@ -18,9 +18,9 @@ namespace Avalonia.Dialogs.Internal
return;
}
- _patterns = filter.Patterns?
- .Select(e => new Regex(Regex.Escape(e).Replace(@"\*", ".*").Replace(@"\?", "."), RegexOptions.Singleline | RegexOptions.IgnoreCase))
- .ToArray();
+ _patterns = filter.Patterns?
+ .Select(e => new Regex("^" + Regex.Escape(e).Replace("\\*", ".*") + "$", RegexOptions.Singleline | RegexOptions.IgnoreCase))
+ .ToArray();
}
public bool Match(string filename)
diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs
index 5d5e17839f..03f0129200 100644
--- a/src/Avalonia.Native/AvaloniaNativePlatform.cs
+++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs
@@ -123,20 +123,18 @@ namespace Avalonia.Native
hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers));
AvaloniaLocator.CurrentMutable.Bind().ToConstant(hotkeys);
-
- if (_options.UseGpu)
+
+ // TODO: add software and metal support via RenderingMode options param
+ try
+ {
+ _platformGl = new AvaloniaNativeGlPlatformGraphics(_factory.ObtainGlDisplay());
+ AvaloniaLocator.CurrentMutable
+ .Bind().ToConstant(_platformGl);
+
+ }
+ catch (Exception)
{
- try
- {
- _platformGl = new AvaloniaNativeGlPlatformGraphics(_factory.ObtainGlDisplay());
- AvaloniaLocator.CurrentMutable
- .Bind().ToConstant(_platformGl);
-
- }
- catch (Exception)
- {
- // ignored
- }
+ // ignored
}
Compositor = new Compositor(_platformGl, true);
diff --git a/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs b/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
index 2b989ce733..7e01e03c9c 100644
--- a/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
+++ b/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Native;
@@ -30,11 +31,6 @@ namespace Avalonia
///
public class AvaloniaNativePlatformOptions
{
- ///
- /// Determines whether to use GPU for rendering in your project. The default value is true.
- ///
- public bool UseGpu { get; set; } = true;
-
///
/// Embeds popups to the window when set to true. The default value is false.
///
diff --git a/src/Avalonia.Native/PopupImpl.cs b/src/Avalonia.Native/PopupImpl.cs
index 6b7f7e8883..6cef7ea578 100644
--- a/src/Avalonia.Native/PopupImpl.cs
+++ b/src/Avalonia.Native/PopupImpl.cs
@@ -15,7 +15,7 @@ namespace Avalonia.Native
public PopupImpl(IAvaloniaNativeFactory factory,
AvaloniaNativePlatformOptions opts,
AvaloniaNativeGlPlatformGraphics glFeature,
- IWindowBaseImpl parent) : base(factory, opts, glFeature)
+ IWindowBaseImpl parent) : base(factory, glFeature)
{
_opts = opts;
_glFeature = glFeature;
diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs
index 817fe3d080..ba96dd401a 100644
--- a/src/Avalonia.Native/WindowImpl.cs
+++ b/src/Avalonia.Native/WindowImpl.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Native
private bool _canResize = true;
internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
- AvaloniaNativeGlPlatformGraphics glFeature) : base(factory, opts, glFeature)
+ AvaloniaNativeGlPlatformGraphics glFeature) : base(factory, glFeature)
{
_opts = opts;
_glFeature = glFeature;
diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs
index 760816643e..053957f89f 100644
--- a/src/Avalonia.Native/WindowImplBase.cs
+++ b/src/Avalonia.Native/WindowImplBase.cs
@@ -67,11 +67,10 @@ namespace Avalonia.Native
private PlatformBehaviorInhibition _platformBehaviorInhibition;
private WindowTransparencyLevel _transparencyLevel = WindowTransparencyLevel.None;
- internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
- AvaloniaNativeGlPlatformGraphics glFeature)
+ internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativeGlPlatformGraphics glFeature)
{
_factory = factory;
- _gpu = opts.UseGpu && glFeature != null;
+ _gpu = glFeature != null;
_keyboard = AvaloniaLocator.Current.GetService();
_mouse = new MouseDevice();
diff --git a/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs b/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
index 07e304febe..cf81999095 100644
--- a/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
+++ b/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
@@ -16,13 +16,6 @@ namespace Avalonia.OpenGL.Egl
_display = display;
}
- public static void TryInitialize()
- {
- var feature = TryCreate();
- if (feature != null)
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(feature);
- }
-
public static EglPlatformGraphics? TryCreate() => TryCreate(() => new EglDisplay(new EglDisplayCreationOptions
{
Egl = new EglInterface(),
diff --git a/src/Avalonia.Themes.Fluent/ColorPaletteResourcesCollection.cs b/src/Avalonia.Themes.Fluent/ColorPaletteResourcesCollection.cs
index 261de5497d..6eb465d399 100644
--- a/src/Avalonia.Themes.Fluent/ColorPaletteResourcesCollection.cs
+++ b/src/Avalonia.Themes.Fluent/ColorPaletteResourcesCollection.cs
@@ -10,12 +10,18 @@ internal class ColorPaletteResourcesCollection : AvaloniaDictionary
+ (key, x) =>
{
if (Owner is not null)
{
x.PropertyChanged += Palette_PropertyChanged;
}
+
+ if (key != ThemeVariant.Dark && key != ThemeVariant.Light)
+ {
+ throw new InvalidOperationException(
+ $"{nameof(FluentTheme)}.{nameof(FluentTheme.Palettes)} only supports Light and Dark variants.");
+ }
},
(_, x) =>
{
@@ -30,9 +36,13 @@ internal class ColorPaletteResourcesCollection : AvaloniaDictionary Count > 0;
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
- theme ??= ThemeVariant.Default;
- if (base.TryGetValue(theme, out var paletteResources)
- && paletteResources.TryGetResource(key, theme, out value))
+ if (theme == null || theme == ThemeVariant.Default)
+ {
+ theme = ThemeVariant.Light;
+ }
+
+ if (base.TryGetValue(theme, out var themePaletteResources)
+ && themePaletteResources.TryGetResource(key, theme, out value))
{
return true;
}
diff --git a/src/Avalonia.Themes.Fluent/DensityStyles/Compact.xaml b/src/Avalonia.Themes.Fluent/DensityStyles/Compact.xaml
index d335e6f4b9..830198f6d1 100644
--- a/src/Avalonia.Themes.Fluent/DensityStyles/Compact.xaml
+++ b/src/Avalonia.Themes.Fluent/DensityStyles/Compact.xaml
@@ -1,22 +1,25 @@
-
-
-
- 14
- 14
- 24
- 2,2,6,1
- 32
- 24
- 0,1,0,2
- 0,1,0,2
- 9,0,0,1
- 10,0,30,0
- 24
- 12,1,0,3
- 32
-
-
+
+ 14
+ 14
+ 24
+ 32
+ 4, 2
+ 4,2
+ 24
+ 11,5,11,7
+ 4 4 8 4
+ 5, 2
+ 24
+ 0,1,0,2
+ 0,1,0,2
+ 9,0,0,1
+ 10,0,30,0
+ 24
+ 12,1,0,3
+ 32
+ 28
+ 6, 0
+ 6,4
+
diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml b/src/Avalonia.Themes.Fluent/FluentTheme.xaml
index c84772aa61..f4467e40ce 100644
--- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml
+++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs b/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs
index 5af22dbd1d..378041356a 100644
--- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs
+++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs
@@ -16,9 +16,10 @@ namespace Avalonia.Themes.Fluent
///
/// Includes the fluent theme in an application.
///
- public class FluentTheme : Styles
+ public class FluentTheme : Styles, IResourceNode
{
- private readonly Styles _compactStyles;
+ private readonly ResourceDictionary _compactStyles;
+ private DensityStyle _densityStyle;
///
/// Initializes a new instance of the class.
@@ -28,9 +29,7 @@ namespace Avalonia.Themes.Fluent
{
AvaloniaXamlLoader.Load(sp, this);
- _compactStyles = (Styles)GetAndRemove("CompactStyles");
-
- EnsureCompactStyles();
+ _compactStyles = (ResourceDictionary)GetAndRemove("CompactStyles");
Palettes = Resources.MergedDictionaries.OfType().FirstOrDefault()
?? throw new InvalidOperationException("FluentTheme was initialized with missing ColorPaletteResourcesCollection.");
@@ -43,17 +42,17 @@ namespace Avalonia.Themes.Fluent
return val;
}
}
-
- public static readonly StyledProperty DensityStyleProperty =
- AvaloniaProperty.Register(nameof(DensityStyle));
+
+ public static readonly DirectProperty DensityStyleProperty = AvaloniaProperty.RegisterDirect(
+ nameof(DensityStyle), o => o.DensityStyle, (o, v) => o.DensityStyle = v);
///
/// Gets or sets the density style of the fluent theme (normal, compact).
///
public DensityStyle DensityStyle
{
- get => GetValue(DensityStyleProperty);
- set => SetValue(DensityStyleProperty, value);
+ get => _densityStyle;
+ set => SetAndRaise(DensityStyleProperty, ref _densityStyle, value);
}
public IDictionary Palettes { get; }
@@ -64,20 +63,20 @@ namespace Avalonia.Themes.Fluent
if (change.Property == DensityStyleProperty)
{
- EnsureCompactStyles();
+ Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
}
- private void EnsureCompactStyles()
+ bool IResourceNode.TryGetResource(object key, ThemeVariant? theme, out object? value)
{
- if (DensityStyle == DensityStyle.Compact)
+ // DensityStyle dictionary should be checked first
+ if (_densityStyle == DensityStyle.Compact
+ && _compactStyles.TryGetResource(key, theme, out value))
{
- Add(_compactStyles);
- }
- else
- {
- Remove(_compactStyles);
+ return true;
}
+
+ return base.TryGetResource(key, theme, out value);
}
}
}
diff --git a/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml b/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml
index ceccdf56c7..5f532df848 100644
--- a/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml
@@ -13,11 +13,10 @@
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
ContentTemplate="{TemplateBinding ContentTemplate}"
- Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
- Display.CreateContext();
public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException();
-
- public static bool TryInitialize(X11Info x11, IList glProfiles)
- {
- var feature = TryCreate(x11, glProfiles);
- if (feature != null)
- {
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(feature);
- return true;
- }
-
- return false;
- }
public static GlxPlatformGraphics TryCreate(X11Info x11, IList glProfiles)
{
diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs
index 04d1aae194..6e18151fae 100644
--- a/src/Avalonia.X11/X11Clipboard.cs
+++ b/src/Avalonia.X11/X11Clipboard.cs
@@ -224,7 +224,7 @@ namespace Avalonia.X11
private Task