diff --git a/.gitignore b/.gitignore
index 44fe5e4ba4..84faae1806 100644
--- a/.gitignore
+++ b/.gitignore
@@ -212,3 +212,6 @@ coc-settings.json
*.map
src/Web/Avalonia.Web.Blazor/wwwroot/*.js
src/Web/Avalonia.Web.Blazor/Interop/Typescript/*.js
+node_modules
+src/Web/Avalonia.Web.Blazor/webapp/package-lock.json
+src/Web/Avalonia.Web.Blazor/wwwroot
diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props
index 85e7a1f34d..620ec58ff3 100644
--- a/build/HarfBuzzSharp.props
+++ b/build/HarfBuzzSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/ReactiveUI.props b/build/ReactiveUI.props
index c3b136d41d..1911c02677 100644
--- a/build/ReactiveUI.props
+++ b/build/ReactiveUI.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index 3d9548ab9d..1b60bb4df9 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
Avalonia
- 0.10.999
+ 11.0.999
Copyright 2022 © The AvaloniaUI Project
https://avaloniaui.net
https://github.com/AvaloniaUI/Avalonia/
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index d54cffba08..31619399f9 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index 9fcb9d6b7f..4bbb667154 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -36,25 +36,6 @@ partial class Build : NukeBuild
{
[Solution("Avalonia.sln")] readonly Solution Solution;
- static Lazy MsBuildExe = new Lazy(() =>
- {
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- return null;
-
- var msBuildDirectory = VSWhere("-latest -nologo -property installationPath -format value -prerelease").FirstOrDefault().Text;
-
- if (!string.IsNullOrWhiteSpace(msBuildDirectory))
- {
- string msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\Current\Bin\MSBuild.exe");
- if (!System.IO.File.Exists(msBuildExe))
- msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\15.0\Bin\MSBuild.exe");
-
- return msBuildExe;
- }
-
- return null;
- }, false);
-
BuildParameters Parameters { get; set; }
protected override void OnBuildInitialized()
{
@@ -89,25 +70,28 @@ partial class Build : NukeBuild
}
ExecWait("dotnet version:", "dotnet", "--info");
ExecWait("dotnet workloads:", "dotnet", "workload list");
+ Information("Processor count: " + Environment.ProcessorCount);
+ Information("Available RAM: " + GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 0x100000 + "MB");
}
- IReadOnlyCollection
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index 71cf5e4a70..9644063da7 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -464,41 +464,6 @@ namespace Avalonia
});
}
- ///
- /// Subscribes to a property changed notifications for changes that originate from a
- /// .
- ///
- /// The type of the property change sender.
- /// The property changed observable.
- /// Given a TTarget, returns the handler.
- /// A disposable that can be used to terminate the subscription.
- [Obsolete("Use overload taking Action.")]
- public static IDisposable AddClassHandler(
- this IObservable observable,
- Func> handler)
- where TTarget : class
- {
- return observable.Subscribe(e => SubscribeAdapter(e, handler));
- }
-
- ///
- /// Observer method for .
- ///
- /// The sender type to accept.
- /// The event args.
- /// Given a TTarget, returns the handler.
- private static void SubscribeAdapter(
- AvaloniaPropertyChangedEventArgs e,
- Func> handler)
- where TTarget : class
- {
- if (e.Sender is TTarget target)
- {
- handler(target)(e);
- }
- }
-
private class BindingAdaptor : IBinding
{
private IObservable _source;
diff --git a/src/Avalonia.Base/AvaloniaProperty`1.cs b/src/Avalonia.Base/AvaloniaProperty`1.cs
index 3937ee5658..14acc2c47f 100644
--- a/src/Avalonia.Base/AvaloniaProperty`1.cs
+++ b/src/Avalonia.Base/AvaloniaProperty`1.cs
@@ -30,21 +30,6 @@ namespace Avalonia
_changed = new Subject>();
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The property to copy.
- /// The new owner type.
- /// Optional overridden metadata.
- [Obsolete("Use constructor with AvaloniaProperty instead.", true)]
- protected AvaloniaProperty(
- AvaloniaProperty source,
- Type ownerType,
- AvaloniaPropertyMetadata? metadata)
- : this(source as AvaloniaProperty ?? throw new InvalidOperationException(), ownerType, metadata)
- {
- }
-
///
/// Initializes a new instance of the class.
///
diff --git a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
index fb70729cf8..c4684960d6 100644
--- a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
@@ -140,21 +140,6 @@ namespace Avalonia.Collections
}
}
- [Obsolete("Causes memory leaks. Use DynamicData or similar instead.")]
- public static IAvaloniaReadOnlyList CreateDerivedList(
- this IAvaloniaReadOnlyList collection,
- Func select)
- {
- var result = new AvaloniaList();
-
- collection.ForEachItem(
- (i, item) => result.Insert(i, select(item)),
- (i, item) => result.RemoveAt(i),
- () => result.Clear());
-
- return result;
- }
-
///
/// Listens for property changed events from all items in a collection.
///
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index 447e2425e6..0a8fe19885 100644
--- a/src/Avalonia.Base/DirectPropertyBase.cs
+++ b/src/Avalonia.Base/DirectPropertyBase.cs
@@ -30,21 +30,6 @@ namespace Avalonia
{
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The property to copy.
- /// The new owner type.
- /// Optional overridden metadata.
- [Obsolete("Use constructor with DirectPropertyBase instead.", true)]
- protected DirectPropertyBase(
- AvaloniaProperty source,
- Type ownerType,
- AvaloniaPropertyMetadata metadata)
- : this(source as DirectPropertyBase ?? throw new InvalidOperationException(), ownerType, metadata)
- {
- }
-
///
/// Initializes a new instance of the class.
///
diff --git a/src/Avalonia.Base/EnumExtensions.cs b/src/Avalonia.Base/EnumExtensions.cs
index 19eb42a700..9b74266b09 100644
--- a/src/Avalonia.Base/EnumExtensions.cs
+++ b/src/Avalonia.Base/EnumExtensions.cs
@@ -8,10 +8,6 @@ namespace Avalonia
///
public static class EnumExtensions
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [Obsolete("This method is obsolete. Use HasAllFlags instead.")]
- public static bool HasFlagCustom(this T value, T flag) where T : unmanaged, Enum
- => value.HasAllFlags(flag);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe bool HasAllFlags(this T value, T flags) where T : unmanaged, Enum
diff --git a/src/Avalonia.Base/Input/PointerOverPreProcessor.cs b/src/Avalonia.Base/Input/PointerOverPreProcessor.cs
index a95d66346a..2ebf01bcf6 100644
--- a/src/Avalonia.Base/Input/PointerOverPreProcessor.cs
+++ b/src/Avalonia.Base/Input/PointerOverPreProcessor.cs
@@ -158,6 +158,8 @@ namespace Avalonia.Input
ClearPointerOver(pointer, root, timestamp, position, properties, inputModifiers);
}
}
+
+ _lastPointer = (pointer, root.PointToScreen(position));
}
private void SetPointerOverToElement(IPointer pointer, IInputRoot root, IInputElement element,
@@ -195,7 +197,6 @@ namespace Avalonia.Input
}
el = root.PointerOverElement = element;
- _lastPointer = (pointer, root.PointToScreen(position));
e.RoutedEvent = InputElement.PointerEnteredEvent;
diff --git a/src/Avalonia.Base/Input/PointerPoint.cs b/src/Avalonia.Base/Input/PointerPoint.cs
index 71145b5cb0..c51f286053 100644
--- a/src/Avalonia.Base/Input/PointerPoint.cs
+++ b/src/Avalonia.Base/Input/PointerPoint.cs
@@ -5,7 +5,7 @@ namespace Avalonia.Input
///
/// Provides basic properties for the input pointer associated with a single mouse, pen/stylus, or touch contact.
///
- public sealed class PointerPoint
+ public struct PointerPoint
{
public PointerPoint(IPointer pointer, Point position, PointerPointProperties properties)
{
@@ -33,47 +33,47 @@ namespace Avalonia.Input
///
/// Provides extended properties for a PointerPoint object.
///
- public sealed class PointerPointProperties
+ public struct PointerPointProperties
{
///
/// Gets a value that indicates whether the pointer input was triggered by the primary action mode of an input device.
///
- public bool IsLeftButtonPressed { get; }
+ public bool IsLeftButtonPressed { get; } = false;
///
/// Gets a value that indicates whether the pointer input was triggered by the tertiary action mode of an input device.
///
- public bool IsMiddleButtonPressed { get; }
+ public bool IsMiddleButtonPressed { get; } = false;
///
/// Gets a value that indicates whether the pointer input was triggered by the secondary action mode (if supported) of an input device.
///
- public bool IsRightButtonPressed { get; }
+ public bool IsRightButtonPressed { get; } = false;
///
/// Gets a value that indicates whether the pointer input was triggered by the first extended mouse button (XButton1).
///
- public bool IsXButton1Pressed { get; }
+ public bool IsXButton1Pressed { get; } = false;
///
/// Gets a value that indicates whether the pointer input was triggered by the second extended mouse button (XButton2).
///
- public bool IsXButton2Pressed { get; }
+ public bool IsXButton2Pressed { get; } = false;
///
/// Gets a value that indicates whether the barrel button of the pen/stylus device is pressed.
///
- public bool IsBarrelButtonPressed { get; }
+ public bool IsBarrelButtonPressed { get; } = false;
///
/// Gets a value that indicates whether the input is from a pen eraser.
///
- public bool IsEraser { get; }
+ public bool IsEraser { get; } = false;
///
/// Gets a value that indicates whether the digitizer pen is inverted.
///
- public bool IsInverted { get; }
+ public bool IsInverted { get; } = false;
///
/// Gets the clockwise rotation in degrees of a pen device around its own major axis (such as when the user spins the pen in their fingers).
@@ -81,7 +81,7 @@ namespace Avalonia.Input
///
/// A value between 0.0 and 359.0 in degrees of rotation. The default value is 0.0.
///
- public float Twist { get; }
+ public float Twist { get; } = 0.0F;
///
/// Gets a value that indicates the force that the pointer device (typically a pen/stylus) exerts on the surface of the digitizer.
@@ -97,7 +97,7 @@ namespace Avalonia.Input
///
/// The value is 0.0 when the finger or pen is perpendicular to the digitizer surface, between 0.0 and 90.0 when tilted to the right of perpendicular, and between 0.0 and -90.0 when tilted to the left of perpendicular. The default value is 0.0.
///
- public float XTilt { get; }
+ public float XTilt { get; } = 0.0F;
///
/// Gets the plane angle between the X-Z plane and the plane that contains the X axis and the axis of the input device (typically a pen/stylus).
@@ -105,14 +105,14 @@ namespace Avalonia.Input
///
/// The value is 0.0 when the finger or pen is perpendicular to the digitizer surface, between 0.0 and 90.0 when tilted towards the user, and between 0.0 and -90.0 when tilted away from the user. The default value is 0.0.
///
- public float YTilt { get; }
+ public float YTilt { get; } = 0.0F;
///
/// Gets the kind of pointer state change.
///
- public PointerUpdateKind PointerUpdateKind { get; }
+ public PointerUpdateKind PointerUpdateKind { get; } = PointerUpdateKind.LeftButtonPressed;
- private PointerPointProperties()
+ public PointerPointProperties()
{
}
diff --git a/src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs b/src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs
index 0e4e0ed3e2..b8f6f99ae8 100644
--- a/src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs
+++ b/src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs
@@ -137,9 +137,13 @@ namespace Avalonia.Input.Raw
///
public Point Position { get; set; }
+ ///
public float Twist { get; set; }
+ ///
public float Pressure { get; set; }
+ ///
public float XTilt { get; set; }
+ ///
public float YTilt { get; set; }
diff --git a/src/Avalonia.Base/Interactivity/RoutedEvent.cs b/src/Avalonia.Base/Interactivity/RoutedEvent.cs
index a9b7dc8c89..37edb24cc1 100644
--- a/src/Avalonia.Base/Interactivity/RoutedEvent.cs
+++ b/src/Avalonia.Base/Interactivity/RoutedEvent.cs
@@ -113,24 +113,6 @@ namespace Avalonia.Interactivity
{
}
- [Obsolete("Use overload taking Action.")]
- public IDisposable AddClassHandler(
- Func> handler,
- RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
- bool handledEventsToo = false)
- where TTarget : class, IInteractive
- {
- void Adapter(object? sender, RoutedEventArgs e)
- {
- if (sender is TTarget target && e is TEventArgs args)
- {
- handler(target)(args);
- }
- }
-
- return AddClassHandler(typeof(TTarget), Adapter, routes, handledEventsToo);
- }
-
public IDisposable AddClassHandler(
Action handler,
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
diff --git a/src/Avalonia.Base/Layout/ILayoutManager.cs b/src/Avalonia.Base/Layout/ILayoutManager.cs
index 143ce13a1b..88d95c81fd 100644
--- a/src/Avalonia.Base/Layout/ILayoutManager.cs
+++ b/src/Avalonia.Base/Layout/ILayoutManager.cs
@@ -44,17 +44,6 @@ namespace Avalonia.Layout
///
void ExecuteInitialLayoutPass();
- ///
- /// Executes the initial layout pass on a layout root.
- ///
- /// The control to lay out.
- ///
- /// You should not usually need to call this method explictly, the layout root will call
- /// it to carry out the initial layout of the control.
- ///
- [Obsolete("Call ExecuteInitialLayoutPass without parameter")]
- void ExecuteInitialLayoutPass(ILayoutRoot root);
-
///
/// Registers a control as wanting to receive effective viewport notifications.
///
diff --git a/src/Avalonia.Base/Layout/LayoutManager.cs b/src/Avalonia.Base/Layout/LayoutManager.cs
index b9ca6bfbd7..826947c39a 100644
--- a/src/Avalonia.Base/Layout/LayoutManager.cs
+++ b/src/Avalonia.Base/Layout/LayoutManager.cs
@@ -196,17 +196,6 @@ namespace Avalonia.Layout
ExecuteLayoutPass();
}
- [Obsolete("Call ExecuteInitialLayoutPass without parameter")]
- public void ExecuteInitialLayoutPass(ILayoutRoot root)
- {
- if (root != _owner)
- {
- throw new ArgumentException("ExecuteInitialLayoutPass called with incorrect root.");
- }
-
- ExecuteInitialLayoutPass();
- }
-
public void Dispose()
{
_disposed = true;
diff --git a/src/Avalonia.Base/Layout/Layoutable.cs b/src/Avalonia.Base/Layout/Layoutable.cs
index 101e867d56..527b63292d 100644
--- a/src/Avalonia.Base/Layout/Layoutable.cs
+++ b/src/Avalonia.Base/Layout/Layoutable.cs
@@ -460,20 +460,6 @@ namespace Avalonia.Layout
_effectiveViewportChanged?.Invoke(this, e);
}
- ///
- /// Marks a property as affecting the control's measurement.
- ///
- /// The properties.
- ///
- /// After a call to this method in a control's static constructor, any change to the
- /// property will cause to be called on the element.
- ///
- [Obsolete("Use AffectsMeasure and specify the control type.")]
- protected static void AffectsMeasure(params AvaloniaProperty[] properties)
- {
- AffectsMeasure(properties);
- }
-
///
/// Marks a property as affecting the control's measurement.
///
@@ -497,20 +483,6 @@ namespace Avalonia.Layout
}
}
- ///
- /// Marks a property as affecting the control's arrangement.
- ///
- /// The properties.
- ///
- /// After a call to this method in a control's static constructor, any change to the
- /// property will cause to be called on the element.
- ///
- [Obsolete("Use AffectsArrange and specify the control type.")]
- protected static void AffectsArrange(params AvaloniaProperty[] properties)
- {
- AffectsArrange(properties);
- }
-
///
/// Marks a property as affecting the control's arrangement.
///
diff --git a/src/Avalonia.Base/Media/DashStyle.cs b/src/Avalonia.Base/Media/DashStyle.cs
index abee580020..3a30b2d32f 100644
--- a/src/Avalonia.Base/Media/DashStyle.cs
+++ b/src/Avalonia.Base/Media/DashStyle.cs
@@ -35,7 +35,6 @@ namespace Avalonia.Media
/// Initializes a new instance of the class.
///
public DashStyle()
- : this(null, 0)
{
}
diff --git a/src/Avalonia.Base/Media/Imaging/Bitmap.cs b/src/Avalonia.Base/Media/Imaging/Bitmap.cs
index 5f1617d778..cf8a31c3e9 100644
--- a/src/Avalonia.Base/Media/Imaging/Bitmap.cs
+++ b/src/Avalonia.Base/Media/Imaging/Bitmap.cs
@@ -89,22 +89,6 @@ namespace Avalonia.Media.Imaging
PlatformImpl.Dispose();
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The pixel format.
- /// The pointer to the source bytes.
- /// The size of the bitmap in device pixels.
- /// The DPI of the bitmap.
- /// The number of bytes per row.
- [Obsolete("Use overload taking an AlphaFormat.")]
- public Bitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
- {
- var ri = GetFactory();
- PlatformImpl = RefCountable.Create(ri
- .LoadBitmap(format, ri.DefaultAlphaFormat, data, size, dpi, stride));
- }
-
///
/// Initializes a new instance of the class.
///
diff --git a/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs b/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs
index 1f39b1344d..1aac8efac7 100644
--- a/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs
+++ b/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs
@@ -9,18 +9,6 @@ namespace Avalonia.Media.Imaging
///
public class WriteableBitmap : Bitmap
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The size of the bitmap in device pixels.
- /// The DPI of the bitmap.
- /// The pixel format (optional).
- /// An .
- [Obsolete("Use overload taking an AlphaFormat.")]
- public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null)
- : base(CreatePlatformImpl(size, dpi, format, null))
- {
- }
///
/// Initializes a new instance of the class.
@@ -30,7 +18,7 @@ namespace Avalonia.Media.Imaging
/// The pixel format (optional).
/// The alpha format (optional).
/// An .
- public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat format, AlphaFormat alphaFormat)
+ public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null, AlphaFormat? alphaFormat = null)
: base(CreatePlatformImpl(size, dpi, format, alphaFormat))
{
}
diff --git a/src/Avalonia.Base/Media/KnownColors.cs b/src/Avalonia.Base/Media/KnownColors.cs
index 8f07b5f8ac..ae2fca5a60 100644
--- a/src/Avalonia.Base/Media/KnownColors.cs
+++ b/src/Avalonia.Base/Media/KnownColors.cs
@@ -1,10 +1,11 @@
using System;
using System.Reflection;
using System.Collections.Generic;
+using Avalonia.SourceGenerator;
namespace Avalonia.Media
{
- internal static class KnownColors
+ internal static partial class KnownColors
{
private static readonly IReadOnlyDictionary _knownColorNames;
private static readonly IReadOnlyDictionary _knownColors;
@@ -12,23 +13,25 @@ namespace Avalonia.Media
private static readonly Dictionary _knownBrushes;
#endif
+ [GenerateEnumValueDictionary()]
+ private static partial Dictionary GetKnownColors();
+
static KnownColors()
{
var knownColorNames = new Dictionary(StringComparer.OrdinalIgnoreCase);
var knownColors = new Dictionary();
- foreach (var field in typeof(KnownColor).GetRuntimeFields())
+ foreach (var field in GetKnownColors())
{
- if (field.FieldType != typeof(KnownColor)) continue;
- var knownColor = (KnownColor)field.GetValue(null)!;
+ var knownColor = field.Value;
if (knownColor == KnownColor.None) continue;
- knownColorNames.Add(field.Name, knownColor);
+ knownColorNames.Add(field.Key, knownColor);
// some known colors have the same value, so use the first
if (!knownColors.ContainsKey((uint)knownColor))
{
- knownColors.Add((uint)knownColor, field.Name);
+ knownColors.Add((uint)knownColor, field.Key);
}
}
diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs
index cf21e9b8b5..cec20678cf 100644
--- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs
+++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFile.cs
@@ -12,6 +12,11 @@ public class BclStorageFile : IStorageBookmarkFile
{
private readonly FileInfo _fileInfo;
+ public BclStorageFile(string fileName)
+ {
+ _fileInfo = new FileInfo(fileName);
+ }
+
public BclStorageFile(FileInfo fileInfo)
{
_fileInfo = fileInfo ?? throw new ArgumentNullException(nameof(fileInfo));
@@ -27,15 +32,14 @@ public class BclStorageFile : IStorageBookmarkFile
public Task GetBasicPropertiesAsync()
{
- var props = new StorageItemProperties();
if (_fileInfo.Exists)
{
- props = new StorageItemProperties(
+ return Task.FromResult(new StorageItemProperties(
(ulong)_fileInfo.Length,
_fileInfo.CreationTimeUtc,
- _fileInfo.LastAccessTimeUtc);
+ _fileInfo.LastAccessTimeUtc));
}
- return Task.FromResult(props);
+ return Task.FromResult(new StorageItemProperties());
}
public Task GetParentAsync()
diff --git a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs
index cd6c8be1ae..b91e910777 100644
--- a/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs
+++ b/src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs
@@ -14,6 +14,15 @@ public class BclStorageFolder : IStorageBookmarkFolder
{
private readonly DirectoryInfo _directoryInfo;
+ public BclStorageFolder(string path)
+ {
+ _directoryInfo = new DirectoryInfo(path);
+ if (!_directoryInfo.Exists)
+ {
+ throw new ArgumentException("Directory must exist");
+ }
+ }
+
public BclStorageFolder(DirectoryInfo directoryInfo)
{
_directoryInfo = directoryInfo ?? throw new ArgumentNullException(nameof(directoryInfo));
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
index 9aa3c25425..e47c8e7e31 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
@@ -29,6 +29,7 @@ public class CompositingRenderer : IRendererWithCompositor
private bool _queuedUpdate;
private Action _update;
private Action _invalidateScene;
+ private bool _updating;
internal CompositionTarget CompositionTarget;
@@ -77,6 +78,8 @@ public class CompositingRenderer : IRendererWithCompositor
///
public void AddDirty(IVisual visual)
{
+ if (_updating)
+ throw new InvalidOperationException("Visual was invalidated during the render pass");
_dirty.Add((Visual)visual);
QueueUpdate();
}
@@ -84,7 +87,16 @@ public class CompositingRenderer : IRendererWithCompositor
///
public IEnumerable HitTest(Point p, IVisual root, Func? filter)
{
- var res = CompositionTarget.TryHitTest(p, filter);
+ Func? f = null;
+ if (filter != null)
+ f = v =>
+ {
+ if (v is CompositionDrawListVisual dlv)
+ return filter(dlv.Visual);
+ return true;
+ };
+
+ var res = CompositionTarget.TryHitTest(p, f);
if(res == null)
yield break;
foreach(var v in res)
@@ -107,6 +119,8 @@ public class CompositingRenderer : IRendererWithCompositor
///
public void RecalculateChildren(IVisual visual)
{
+ if (_updating)
+ throw new InvalidOperationException("Visual was invalidated during the render pass");
_recalculateChildren.Add((Visual)visual);
QueueUpdate();
}
@@ -191,7 +205,7 @@ public class CompositingRenderer : IRendererWithCompositor
private void InvalidateScene() =>
SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs(_root, new Rect(_root.ClientSize)));
- private void Update()
+ private void UpdateCore()
{
_queuedUpdate = false;
foreach (var visual in _dirty)
@@ -240,6 +254,21 @@ public class CompositingRenderer : IRendererWithCompositor
CompositionTarget.Scaling = _root.RenderScaling;
Compositor.InvokeOnNextCommit(_invalidateScene);
}
+
+ private void Update()
+ {
+ if(_updating)
+ return;
+ _updating = true;
+ try
+ {
+ UpdateCore();
+ }
+ finally
+ {
+ _updating = false;
+ }
+ }
public void Resized(Size size)
{
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
index 77b392eee5..b019d1792b 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
@@ -54,13 +54,11 @@ internal class CompositionDrawListVisual : CompositionContainerVisual
Visual = visual;
}
- internal override bool HitTest(Point pt, Func? filter)
+ internal override bool HitTest(Point pt)
{
var custom = Visual as ICustomHitTest;
if (DrawList == null && custom == null)
return false;
- if (filter != null && !filter(Visual))
- return false;
if (custom != null)
{
// Simulate the old behavior
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
index 4e53e163ec..eb499604e0 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
@@ -31,7 +31,7 @@ namespace Avalonia.Rendering.Composition
///
///
///
- public PooledList? TryHitTest(Point point, Func? filter)
+ public PooledList? TryHitTest(Point point, Func? filter)
{
Server.Readback.NextRead();
if (Root == null)
@@ -88,10 +88,14 @@ namespace Avalonia.Rendering.Composition
}
void HitTestCore(CompositionVisual visual, Point globalPoint, PooledList result,
- Func? filter)
+ Func? filter)
{
if (visual.Visible == false)
return;
+
+ if (filter != null && !filter(visual))
+ return;
+
if (!TryTransformTo(visual, globalPoint, out var point))
return;
@@ -111,7 +115,7 @@ namespace Avalonia.Rendering.Composition
}
// Hit-test the current node
- if (visual.HitTest(point, filter))
+ if (visual.HitTest(point))
result.Add(visual);
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Visual.cs b/src/Avalonia.Base/Rendering/Composition/Visual.cs
index 7356b7b9e8..6d6818256a 100644
--- a/src/Avalonia.Base/Rendering/Composition/Visual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Visual.cs
@@ -53,6 +53,6 @@ namespace Avalonia.Rendering.Composition
internal object? Tag { get; set; }
- internal virtual bool HitTest(Point point, Func? filter) => true;
+ internal virtual bool HitTest(Point point) => true;
}
}
diff --git a/src/Avalonia.Base/Rendering/DirtyVisuals.cs b/src/Avalonia.Base/Rendering/DirtyVisuals.cs
index 00bc236b9c..999b12e810 100644
--- a/src/Avalonia.Base/Rendering/DirtyVisuals.cs
+++ b/src/Avalonia.Base/Rendering/DirtyVisuals.cs
@@ -17,8 +17,7 @@ namespace Avalonia.Rendering
{
private SortedDictionary> _inner = new SortedDictionary>();
private Dictionary _index = new Dictionary();
- private List _deferredChanges = new List();
- private int _deferring;
+ private int _enumerating;
///
/// Gets the number of dirty visuals.
@@ -31,10 +30,9 @@ namespace Avalonia.Rendering
/// The dirty visual.
public void Add(IVisual visual)
{
- if (_deferring > 0)
+ if (_enumerating > 0)
{
- _deferredChanges.Add(visual);
- return;
+ throw new InvalidOperationException("Visual was invalidated during a render pass");
}
var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot);
@@ -65,7 +63,7 @@ namespace Avalonia.Rendering
///
public void Clear()
{
- if (_deferring > 0)
+ if (_enumerating > 0)
{
throw new InvalidOperationException("Cannot clear while enumerating");
}
@@ -80,7 +78,7 @@ namespace Avalonia.Rendering
/// A collection of visuals.
public IEnumerator GetEnumerator()
{
- BeginDefer();
+ _enumerating++;
try
{
foreach (var i in _inner)
@@ -93,27 +91,10 @@ namespace Avalonia.Rendering
}
finally
{
- EndDefer();
+ _enumerating--;
}
}
-
- private void BeginDefer()
- {
- ++_deferring;
- }
-
- private void EndDefer()
- {
- if (--_deferring > 0) return;
-
- foreach (var visual in _deferredChanges)
- {
- Add(visual);
- }
-
- _deferredChanges.Clear();
- }
-
+
///
/// Gets the dirty visuals, in ascending order of distance to their root.
///
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index d381979c1e..3c48c3469e 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -324,6 +324,41 @@ namespace Avalonia.Utilities
return angle * 2 * Math.PI;
}
+ ///
+ /// Calculates the point of an angle on an ellipse.
+ ///
+ /// The centre point of the ellipse.
+ /// The x radius of the ellipse.
+ /// The y radius of the ellipse.
+ /// The angle in radians.
+ /// A point on the ellipse.
+ public static Point GetEllipsePoint(Point centre, double radiusX, double radiusY, double angle)
+ {
+ return new Point(radiusX * Math.Cos(angle) + centre.X, radiusY * Math.Sin(angle) + centre.Y);
+ }
+
+ ///
+ /// Gets the minimum and maximum from the specified numbers.
+ ///
+ /// The first number.
+ /// The second number.
+ /// A tuple containing the minimum and maximum of the two specified numbers.
+ public static (double min, double max) GetMinMax(double a, double b)
+ {
+ return a < b ? (a, b) : (b, a);
+ }
+
+ ///
+ /// Gets the minimum and maximum from the specified number and the difference with that number.
+ ///
+ /// The initial value to use.
+ /// The difference for .
+ /// A tuple containing the minimum and maximum of the specified number and the difference with that number.
+ public static (double min, double max) GetMinMaxFromDelta(double initialValue, double delta)
+ {
+ return GetMinMax(initialValue, initialValue + delta);
+ }
+
private static void ThrowCannotBeGreaterThanException(T min, T max)
{
throw new ArgumentException($"{min} cannot be greater than {max}.");
diff --git a/src/Avalonia.Base/Utilities/WeakObservable.cs b/src/Avalonia.Base/Utilities/WeakObservable.cs
index 6bf1d4082f..e1c350d539 100644
--- a/src/Avalonia.Base/Utilities/WeakObservable.cs
+++ b/src/Avalonia.Base/Utilities/WeakObservable.cs
@@ -9,31 +9,6 @@ namespace Avalonia.Utilities
///
public static class WeakObservable
{
- ///
- /// Converts a .NET event conforming to the standard .NET event pattern into an observable
- /// sequence, subscribing weakly.
- ///
- /// The type of target.
- /// The type of the event args.
- /// Object instance that exposes the event to convert.
- /// Name of the event to convert.
- ///
- [Obsolete("Use WeakEvent-based overload")]
- public static IObservable> FromEventPattern(
- TTarget target,
- string eventName)
- where TEventArgs : EventArgs
- {
- _ = target ?? throw new ArgumentNullException(nameof(target));
- _ = eventName ?? throw new ArgumentNullException(nameof(eventName));
-
- return Observable.Create>(observer =>
- {
- var handler = new Handler(observer);
- WeakSubscriptionManager.Subscribe(target, eventName, handler);
- return () => WeakSubscriptionManager.Unsubscribe(target, eventName, handler);
- }).Publish().RefCount();
- }
private class Handler
: IWeakSubscriber,
diff --git a/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs b/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
deleted file mode 100644
index dc9e86cc32..0000000000
--- a/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
+++ /dev/null
@@ -1,193 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-namespace Avalonia.Utilities
-{
- ///
- /// Manages subscriptions to events using weak listeners.
- ///
- public static class WeakSubscriptionManager
- {
- ///
- /// Subscribes to an event on an object using a weak subscription.
- ///
- /// The type of the target.
- /// The type of the event arguments.
- /// The event source.
- /// The name of the event.
- /// The subscriber.
- [Obsolete("Use WeakEvent")]
- public static void Subscribe(TTarget target, string eventName, IWeakSubscriber subscriber)
- where TEventArgs : EventArgs
- {
- _ = target ?? throw new ArgumentNullException(nameof(target));
-
- var dic = SubscriptionTypeStorage.Subscribers.GetOrCreateValue(target);
-
- if (!dic.TryGetValue(eventName, out var sub))
- {
- dic[eventName] = sub = new Subscription(dic, typeof(TTarget), target, eventName);
- }
-
- sub.Add(new WeakReference>(subscriber));
- }
-
- ///
- /// Unsubscribes from an event.
- ///
- /// The type of the event arguments.
- /// The event source.
- /// The name of the event.
- /// The subscriber.
- public static void Unsubscribe(object target, string eventName, IWeakSubscriber subscriber)
- where T : EventArgs
- {
- if (SubscriptionTypeStorage.Subscribers.TryGetValue(target, out var dic))
- {
- if (dic.TryGetValue(eventName, out var sub))
- {
- sub.Remove(subscriber);
- }
- }
- }
-
- private static class SubscriptionTypeStorage
- where T : EventArgs
- {
- public static readonly ConditionalWeakTable> Subscribers
- = new ConditionalWeakTable>();
- }
-
- private class SubscriptionDic : Dictionary>
- where T : EventArgs
- {
- }
-
- private static readonly Dictionary> Accessors
- = new Dictionary>();
-
- private class Subscription where T : EventArgs
- {
- private readonly EventInfo _info;
- private readonly SubscriptionDic _sdic;
- private readonly object _target;
- private readonly string _eventName;
- private readonly Delegate _delegate;
-
- private WeakReference>?[] _data = new WeakReference>?[16];
- private int _count = 0;
-
- public Subscription(SubscriptionDic sdic, Type targetType, object target, string eventName)
- {
- _sdic = sdic;
- _target = target;
- _eventName = eventName;
- if (!Accessors.TryGetValue(targetType, out var evDic))
- Accessors[targetType] = evDic = new Dictionary();
-
- if (evDic.TryGetValue(eventName, out var info))
- {
- _info = info;
- }
- else
- {
- var ev = targetType.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
-
- if (ev == null)
- {
- throw new ArgumentException(
- $"The event {eventName} was not found on {target.GetType()}.");
- }
-
- evDic[eventName] = _info = ev;
- }
-
- var del = new Action(OnEvent);
- _delegate = del.GetMethodInfo().CreateDelegate(_info.EventHandlerType!, del.Target);
- _info.AddMethod!.Invoke(target, new[] { _delegate });
- }
-
- void Destroy()
- {
- _info.RemoveMethod!.Invoke(_target, new[] { _delegate });
- _sdic.Remove(_eventName);
- }
-
- public void Add(WeakReference> s)
- {
- if (_count == _data.Length)
- {
- //Extend capacity
- var ndata = new WeakReference>?[_data.Length*2];
- Array.Copy(_data, ndata, _data.Length);
- _data = ndata;
- }
- _data[_count] = s!;
- _count++;
- }
-
- public void Remove(IWeakSubscriber s)
- {
- var removed = false;
-
- for (int c = 0; c < _count; ++c)
- {
- var reference = _data[c];
- IWeakSubscriber? instance;
-
- if (reference != null && reference.TryGetTarget(out instance) && instance == s)
- {
- _data[c] = null;
- removed = true;
- }
- }
-
- if (removed)
- {
- Compact();
- }
- }
-
- void Compact()
- {
- int empty = -1;
- for (int c = 0; c < _count; c++)
- {
- var r = _data[c];
- //Mark current index as first empty
- if (r == null && empty == -1)
- empty = c;
- //If current element isn't null and we have an empty one
- if (r != null && empty != -1)
- {
- _data[c] = null;
- _data[empty] = r;
- empty++;
- }
- }
- if (empty != -1)
- _count = empty;
- if (_count == 0)
- Destroy();
- }
-
- void OnEvent(object sender, T eventArgs)
- {
- var needCompact = false;
- for(var c=0; c<_count; c++)
- {
- var r = _data[c];
- if (r?.TryGetTarget(out var sub) == true)
- sub!.OnEvent(sender, eventArgs);
- else
- needCompact = true;
- }
- if (needCompact)
- Compact();
- }
- }
- }
-}
diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs
index da3de890d8..29559a8618 100644
--- a/src/Avalonia.Base/Visual.cs
+++ b/src/Avalonia.Base/Visual.cs
@@ -338,22 +338,6 @@ namespace Avalonia
Contract.Requires(context != null);
}
- ///
- /// Indicates that a property change should cause to be
- /// called.
- ///
- /// The properties.
- ///
- /// This method should be called in a control's static constructor with each property
- /// on the control which when changed should cause a redraw. This is similar to WPF's
- /// FrameworkPropertyMetadata.AffectsRender flag.
- ///
- [Obsolete("Use AffectsRender and specify the control type.")]
- protected static void AffectsRender(params AvaloniaProperty[] properties)
- {
- AffectsRender(properties);
- }
-
///
/// Indicates that a property change should cause to be
/// called.
diff --git a/src/Avalonia.Base/VisualTree/IVisualTreeHost.cs b/src/Avalonia.Base/VisualTree/IVisualTreeHost.cs
deleted file mode 100644
index e47377063f..0000000000
--- a/src/Avalonia.Base/VisualTree/IVisualTreeHost.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace Avalonia.VisualTree
-{
- ///
- /// Interface for controls that host their own separate visual tree, such as popups.
- ///
- [Obsolete]
- public interface IVisualTreeHost
- {
- ///
- /// Gets the root of the hosted visual tree.
- ///
- ///
- /// The root of the hosted visual tree.
- ///
- IVisual? Root { get; }
- }
-}
diff --git a/src/Avalonia.Base/VisualTree/VisualExtensions.cs b/src/Avalonia.Base/VisualTree/VisualExtensions.cs
index 128a39c082..a1b8894604 100644
--- a/src/Avalonia.Base/VisualTree/VisualExtensions.cs
+++ b/src/Avalonia.Base/VisualTree/VisualExtensions.cs
@@ -413,7 +413,7 @@ namespace Avalonia.VisualTree
Index = index,
ZIndex = element.ZIndex,
})
- .OrderBy(x => x, null)
+ .OrderBy(x => x, ZOrderElement.Comparer)
.Select(x => x.Element!);
}
@@ -448,6 +448,19 @@ namespace Avalonia.VisualTree
public int Index { get; set; }
public int ZIndex { get; set; }
+ class ZOrderComparer : IComparer
+ {
+ public int Compare(ZOrderElement? x, ZOrderElement? y)
+ {
+ if (ReferenceEquals(x, y)) return 0;
+ if (ReferenceEquals(null, y)) return 1;
+ if (ReferenceEquals(null, x)) return -1;
+ return x.CompareTo(y);
+ }
+ }
+
+ public static IComparer Comparer { get; } = new ZOrderComparer();
+
public int CompareTo(ZOrderElement? other)
{
if (other is null)
diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
index dc9064b262..eef574d297 100644
--- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
+++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
@@ -108,4 +108,5 @@
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml
index a5a94a2322..0a1a9e60c6 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml
@@ -11,15 +11,20 @@
Stretch="Uniform"
DestinationRect="0,0,8,8">
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml
index 1e507a91fe..f21b03cee2 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Simple/Simple.xaml
@@ -11,15 +11,20 @@
Stretch="Uniform"
DestinationRect="0,0,8,8">
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
index ff222658db..ab73ed73c7 100644
--- a/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
+++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
@@ -12,9 +12,6 @@ namespace Avalonia.Collections
{
public virtual string PropertyPath => null;
- [Obsolete("Use Direction property to read or override sorting direction.")]
- public virtual bool Descending => Direction == ListSortDirection.Descending;
-
public virtual ListSortDirection Direction => ListSortDirection.Ascending;
public bool HasPropertyPath => !String.IsNullOrEmpty(PropertyPath);
public abstract IComparer Comparer { get; }
@@ -254,13 +251,6 @@ namespace Avalonia.Collections
return new DataGridPathSortDescription(propertyPath, direction, null, culture);
}
-
- [Obsolete("Use overload taking a ListSortDirection.")]
- public static DataGridSortDescription FromPath(string propertyPath, bool descending, CultureInfo culture = null)
- {
- return new DataGridPathSortDescription(propertyPath, descending ? ListSortDirection.Descending : ListSortDirection.Ascending, null, culture);
- }
-
public static DataGridSortDescription FromPath(string propertyPath, ListSortDirection direction, IComparer comparer)
{
return new DataGridPathSortDescription(propertyPath, direction, comparer, null);
diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs
index d42468f47e..cacd5c5a16 100644
--- a/src/Avalonia.Controls.DataGrid/DataGrid.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs
@@ -2167,7 +2167,23 @@ namespace Avalonia.Controls
return desiredSize;
}
+
+ ///
+ protected override void OnDataContextBeginUpdate()
+ {
+ base.OnDataContextBeginUpdate();
+ NotifyDataContextPropertyForAllRowCells(GetAllRows(), true);
+ }
+
+ ///
+ protected override void OnDataContextEndUpdate()
+ {
+ base.OnDataContextEndUpdate();
+
+ NotifyDataContextPropertyForAllRowCells(GetAllRows(), false);
+ }
+
///
/// Raises the BeginningEdit event.
///
@@ -3165,6 +3181,20 @@ namespace Avalonia.Controls
}
}
+ private static void NotifyDataContextPropertyForAllRowCells(IEnumerable rowSource, bool arg2)
+ {
+ foreach (DataGridRow row in rowSource)
+ {
+ foreach (DataGridCell cell in row.Cells)
+ {
+ if (cell.Content is StyledElement cellContent)
+ {
+ DataContextProperty.Notifying?.Invoke(cellContent, arg2);
+ }
+ }
+ }
+ }
+
private void UpdateRowDetailsVisibilityMode(DataGridRowDetailsVisibilityMode newDetailsMode)
{
int itemCount = DataConnection.Count;
diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
index 5ae83427b5..364a2a52e3 100644
--- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
+++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
@@ -53,7 +53,6 @@
-
diff --git a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
index bc47f3892e..e9c60570c7 100644
--- a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml
@@ -56,18 +56,11 @@
-
-
diff --git a/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml b/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml
index 55f4893057..b8ade96b6f 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ManagedFileChooser.xaml
@@ -138,7 +138,11 @@
-
+
+
+
+
+
@@ -231,7 +235,11 @@
-
+
+
+
+
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
index 0d1b416d7a..fb02071c3f 100644
--- a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
@@ -55,18 +55,11 @@
-
-
diff --git a/src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml
index 43fc8c7a34..724c317beb 100644
--- a/src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/CalendarDatePicker.xaml
@@ -118,7 +118,7 @@
+ IsLightDismissEnabled="False">
_namesToAtoms = new Dictionary();
private readonly Dictionary _atomsToNames = new Dictionary();
public X11Atoms(IntPtr display)
{
_display = display;
+ PopulateAtoms(display);
+ }
- // make sure this array stays in sync with the statements below
-
- var fields = typeof(X11Atoms).GetFields()
- .Where(f => f.FieldType == typeof(IntPtr) && (IntPtr)f.GetValue(this) == IntPtr.Zero).ToArray();
- var atomNames = fields.Select(f => f.Name).ToArray();
-
- IntPtr[] atoms = new IntPtr [atomNames.Length];
- ;
-
- XInternAtoms(display, atomNames, atomNames.Length, true, atoms);
-
- for (var c = 0; c < fields.Length; c++)
+ private void InitAtom(ref IntPtr field, string name, IntPtr value)
+ {
+ if (value != IntPtr.Zero)
{
- _namesToAtoms[fields[c].Name] = atoms[c];
- _atomsToNames[atoms[c]] = fields[c].Name;
- fields[c].SetValue(this, atoms[c]);
+ field = value;
+ _namesToAtoms[name] = value;
+ _atomsToNames[value] = name;
}
}
diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs
index 60f035cd7e..6041b53a62 100644
--- a/src/Avalonia.X11/X11CursorFactory.cs
+++ b/src/Avalonia.X11/X11CursorFactory.cs
@@ -5,13 +5,14 @@ using System.Runtime.InteropServices;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Input;
using Avalonia.Platform;
+using Avalonia.SourceGenerator;
using Avalonia.Utilities;
#nullable enable
namespace Avalonia.X11
{
- class X11CursorFactory : ICursorFactory
+ partial class X11CursorFactory : ICursorFactory
{
private static readonly byte[] NullCursorData = new byte[] { 0 };
@@ -48,11 +49,14 @@ namespace Avalonia.X11
{StandardCursorType.TopRightCorner, CursorFontShape.XC_top_right_corner},
};
+ [GenerateEnumValueList]
+ private static partial CursorFontShape[] GetAllCursorShapes();
+
public X11CursorFactory(IntPtr display)
{
_display = display;
_nullCursor = GetNullCursor(display);
- _cursors = Enum.GetValues(typeof(CursorFontShape)).Cast()
+ _cursors = GetAllCursorShapes()
.ToDictionary(id => id, id => XLib.XCreateFontCursor(_display, id));
}
diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs
index 0357fdd94e..ffac3c55e2 100644
--- a/src/Avalonia.X11/X11IconLoader.cs
+++ b/src/Avalonia.X11/X11IconLoader.cs
@@ -68,9 +68,7 @@ namespace Avalonia.X11
public void Save(Stream outputStream)
{
using (var wr =
-#pragma warning disable CS0618 // Type or member is obsolete
new WriteableBitmap(new PixelSize(_width, _height), new Vector(96, 96), PixelFormat.Bgra8888))
-#pragma warning restore CS0618 // Type or member is obsolete
{
using (var fb = wr.Lock())
{
diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs
index cc9737668d..81c2a69aac 100644
--- a/src/Avalonia.X11/X11Platform.cs
+++ b/src/Avalonia.X11/X11Platform.cs
@@ -278,7 +278,8 @@ namespace Avalonia
"llvmpipe"
};
- public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name;
+
+ public string WmClass { get; set; }
///
/// Enables multitouch support. The default value is true.
@@ -287,6 +288,18 @@ namespace Avalonia
/// Multitouch allows a surface (a touchpad or touchscreen) to recognize the presence of more than one point of contact with the surface at the same time.
///
public bool? EnableMultiTouch { get; set; } = true;
+
+ public X11PlatformOptions()
+ {
+ try
+ {
+ WmClass = Assembly.GetEntryAssembly()?.GetName()?.Name;
+ }
+ catch
+ {
+ //
+ }
+ }
}
public static class AvaloniaX11PlatformExtensions
{
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
index 8688671d3b..b64423ec10 100644
--- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
+++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
@@ -7,6 +7,7 @@ using Avalonia.LinuxFramebuffer.Input;
using Avalonia.LinuxFramebuffer.Output;
using Avalonia.Platform;
using Avalonia.Rendering;
+using Avalonia.Rendering.Composition;
namespace Avalonia.LinuxFramebuffer
{
@@ -32,7 +33,7 @@ namespace Avalonia.LinuxFramebuffer
{
var factory = AvaloniaLocator.Current.GetService();
var renderLoop = AvaloniaLocator.Current.GetService();
- return factory?.Create(root, renderLoop) ?? new DeferredRenderer(root, renderLoop);
+ return factory?.Create(root, renderLoop) ?? new CompositingRenderer(root, LinuxFramebufferPlatform.Compositor);
}
public void Dispose()
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
index a642766809..bf9452e191 100644
--- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
+++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
@@ -15,6 +15,7 @@ using Avalonia.LinuxFramebuffer.Output;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Rendering;
+using Avalonia.Rendering.Composition;
using Avalonia.Threading;
using JetBrains.Annotations;
@@ -26,6 +27,10 @@ namespace Avalonia.LinuxFramebuffer
private static readonly Stopwatch St = Stopwatch.StartNew();
internal static uint Timestamp => (uint)St.ElapsedTicks;
public static InternalPlatformThreadingInterface Threading;
+
+ internal static Compositor Compositor { get; private set; }
+
+
LinuxFramebufferPlatform(IOutputBackend backend)
{
_fb = backend;
@@ -48,6 +53,10 @@ namespace Avalonia.LinuxFramebuffer
.Bind().ToConstant(new KeyboardDevice())
.Bind().ToSingleton()
.Bind().ToSingleton();
+
+ Compositor = new Compositor(
+ AvaloniaLocator.Current.GetRequiredService(),
+ AvaloniaLocator.Current.GetService());
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
index a0e7fd7dcf..168b9835dd 100644
--- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
@@ -158,9 +158,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
string.Join(",", lst.Select(e => $"`{e.ClrAssemblyName}:{e.ClrNamespace}.{name}`")));
}
}
-
- [Obsolete("Don't use", true)]
- public static readonly IServiceProvider RootServiceProviderV1 = new RootServiceProvider(null);
// Don't emit debug symbols for this code so debugger will be forced to step into XAML instead
#line hidden
diff --git a/src/Shared/SourceGeneratorAttributes.cs b/src/Shared/SourceGeneratorAttributes.cs
index ac7c82c469..3f00fbef57 100644
--- a/src/Shared/SourceGeneratorAttributes.cs
+++ b/src/Shared/SourceGeneratorAttributes.cs
@@ -38,4 +38,12 @@ namespace Avalonia.SourceGenerator
}
}
+
+ internal class GenerateEnumValueDictionaryAttribute : Attribute
+ {
+ }
+
+ internal class GenerateEnumValueListAttribute : Attribute
+ {
+ }
}
diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs
index a4617bb4d5..d700d4848e 100644
--- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs
+++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/OpenGlBitmapImpl.cs
@@ -41,7 +41,7 @@ namespace Avalonia.Skia
new GRGlTextureInfo(
GlConsts.GL_TEXTURE_2D, (uint)_surface.GetTextureId(),
(uint)_surface.InternalFormat)))
- using (var surface = SKSurface.Create(context.GrContext, backendTexture, GRSurfaceOrigin.TopLeft,
+ using (var surface = SKSurface.Create(context.GrContext, backendTexture, GRSurfaceOrigin.BottomLeft,
SKColorType.Rgba8888))
{
// Again, silently ignore, if something went wrong it's not our fault
@@ -118,7 +118,7 @@ namespace Avalonia.Skia
{
var gl = _context.GlInterface;
- var textures = new int[2];
+ Span textures = stackalloc int[2];
fixed (int* ptex = textures)
gl.GenTextures(2, ptex);
_texture = textures[0];
@@ -139,7 +139,6 @@ namespace Avalonia.Skia
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
gl.BindTexture(GL_TEXTURE_2D, oldTexture);
-
}
}
}
@@ -161,15 +160,15 @@ namespace Avalonia.Skia
gl.GetIntegerv(GL_ACTIVE_TEXTURE, out var oldActive);
gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo);
- gl.BindTexture(GL_TEXTURE_2D, _frontBuffer);
gl.ActiveTexture(GL_TEXTURE0);
+ gl.BindTexture(GL_TEXTURE_2D, _frontBuffer);
gl.CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _bitmap.PixelSize.Width,
_bitmap.PixelSize.Height);
gl.BindFramebuffer(GL_FRAMEBUFFER, oldFbo);
- gl.BindTexture(GL_TEXTURE_2D, oldTexture);
gl.ActiveTexture(oldActive);
+ gl.BindTexture(GL_TEXTURE_2D, oldTexture);
gl.Finish();
}
@@ -192,9 +191,8 @@ namespace Avalonia.Skia
if(_disposed)
return;
_disposed = true;
- var tex = new[] { _texture, _frontBuffer };
- fixed (int* ptex = tex)
- gl.DeleteTextures(2, ptex);
+ var ptex = stackalloc[] { _texture, _frontBuffer };
+ gl.DeleteTextures(2, ptex);
}
}
diff --git a/src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs b/src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs
index a078c364a2..ec33770356 100644
--- a/src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs
+++ b/src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs
@@ -1,5 +1,4 @@
-using System;
-using Avalonia.Platform;
+using Avalonia.Platform;
using Avalonia.Rendering;
using SkiaSharp;
@@ -29,72 +28,5 @@ namespace Avalonia.Skia.Helpers
return new DrawingContextImpl(createInfo);
}
- ///
- /// Unsupported - Wraps a GPU Backed SkiaSurface in an Avalonia DrawingContext.
- ///
- [Obsolete]
- public static IDrawingContextImpl WrapSkiaSurface(this SKSurface surface, GRContext grContext, Vector dpi, params IDisposable[] disposables)
- {
- var createInfo = new DrawingContextImpl.CreateInfo
- {
- GrContext = grContext,
- Surface = surface,
- Dpi = dpi,
- DisableTextLcdRendering = false,
- };
-
- return new DrawingContextImpl(createInfo, disposables);
- }
-
- ///
- /// Unsupported - Wraps a non-GPU Backed SkiaSurface in an Avalonia DrawingContext.
- ///
- [Obsolete]
- public static IDrawingContextImpl WrapSkiaSurface(this SKSurface surface, Vector dpi, params IDisposable[] disposables)
- {
- var createInfo = new DrawingContextImpl.CreateInfo
- {
- Surface = surface,
- Dpi = dpi,
- DisableTextLcdRendering = false,
- };
-
- return new DrawingContextImpl(createInfo, disposables);
- }
-
- [Obsolete]
- public static IDrawingContextImpl CreateDrawingContext(Size size, Vector dpi, GRContext grContext = null)
- {
- if (grContext is null)
- {
- var surface = SKSurface.Create(
- new SKImageInfo(
- (int)Math.Ceiling(size.Width),
- (int)Math.Ceiling(size.Height),
- SKImageInfo.PlatformColorType,
- SKAlphaType.Premul));
-
- return WrapSkiaSurface(surface, dpi, surface);
- }
- else
- {
- var surface = SKSurface.Create(grContext, false,
- new SKImageInfo(
- (int)Math.Ceiling(size.Width),
- (int)Math.Ceiling(size.Height),
- SKImageInfo.PlatformColorType,
- SKAlphaType.Premul));
-
- return WrapSkiaSurface(surface, grContext, dpi, surface);
- }
- }
-
- [Obsolete]
- public static void DrawTo(this IDrawingContextImpl source, IDrawingContextImpl destination, SKPaint paint = null)
- {
- var src = (DrawingContextImpl)source;
- var dst = (DrawingContextImpl)destination;
- dst.Canvas.DrawSurface(src.Surface, new SKPoint(0, 0), paint);
- }
}
}
diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
index 1531c95830..3fcfaa1c9c 100644
--- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
+++ b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
@@ -8,31 +8,16 @@
false
true
-
+
-
- wwwroot
- true
- true
-
-
-
- false
- true
-
-
- true
- false
-
-
-
+
true
@@ -45,12 +30,26 @@
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
index b501db16d3..27a6acd0de 100644
--- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
+++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
@@ -1,7 +1,11 @@
-
+ oncut="return false;"
+ @onkeydown:preventDefault="true"
+ @onkeyup:preventDefault="true"
+ autocapitalize="none"/>