diff --git a/.editorconfig b/.editorconfig
index e6ae266849..a144ec8843 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -55,16 +55,17 @@ dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
-# static fields should have s_ prefix
-dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
-dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
-dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
+# private static fields should have s_ prefix
+dotnet_naming_rule.private_static_fields_should_have_prefix.severity = suggestion
+dotnet_naming_rule.private_static_fields_should_have_prefix.symbols = private_static_fields
+dotnet_naming_rule.private_static_fields_should_have_prefix.style = private_static_prefix_style
-dotnet_naming_symbols.static_fields.applicable_kinds = field
-dotnet_naming_symbols.static_fields.required_modifiers = static
+dotnet_naming_symbols.private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields.required_modifiers = static
+dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private
-dotnet_naming_style.static_prefix_style.required_prefix = s_
-dotnet_naming_style.static_prefix_style.capitalization = camel_case
+dotnet_naming_style.private_static_prefix_style.required_prefix = s_
+dotnet_naming_style.private_static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
@@ -117,7 +118,7 @@ csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
-csharp_space_around_declaration_statements = do_not_ignore
+csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
@@ -211,5 +212,5 @@ indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
-[*.{cmd, bat}]
+[*.{cmd,bat}]
end_of_line = crlf
diff --git a/Avalonia.Desktop.slnf b/Avalonia.Desktop.slnf
index 3acd4bf9f2..741570061b 100644
--- a/Avalonia.Desktop.slnf
+++ b/Avalonia.Desktop.slnf
@@ -45,6 +45,7 @@
"tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
"tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
"tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",
+ "tests\\Avalonia.Controls.ItemsRepeater.UnitTests\\Avalonia.Controls.ItemsRepeater.UnitTests.csproj",
"tests\\Avalonia.Controls.UnitTests\\Avalonia.Controls.UnitTests.csproj",
"tests\\Avalonia.DesignerSupport.TestApp\\Avalonia.DesignerSupport.TestApp.csproj",
"tests\\Avalonia.DesignerSupport.Tests\\Avalonia.DesignerSupport.Tests.csproj",
diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props
index 620ec58ff3..75d317be1a 100644
--- a/build/HarfBuzzSharp.props
+++ b/build/HarfBuzzSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/ImageSharp.props b/build/ImageSharp.props
index 178c274ac9..66e6580070 100644
--- a/build/ImageSharp.props
+++ b/build/ImageSharp.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/Moq.props b/build/Moq.props
index 9e2fd1db5d..357f0c9a5f 100644
--- a/build/Moq.props
+++ b/build/Moq.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index eca3ba37b0..2849262591 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -3,6 +3,7 @@
Avalonia
11.0.999
+ Avalonia Team
Copyright 2022 © The AvaloniaUI Project
https://avaloniaui.net
https://github.com/AvaloniaUI/Avalonia/
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index 31619399f9..f45addaa2a 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/XUnit.props b/build/XUnit.props
index 17ead91aa3..3c89c8b52b 100644
--- a/build/XUnit.props
+++ b/build/XUnit.props
@@ -1,13 +1,12 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
index 41d1534f8d..c49290314d 100644
--- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
+++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
@@ -43,6 +43,7 @@
523484CA26EA688F00EA0C2C /* trayicon.mm in Sources */ = {isa = PBXBuildFile; fileRef = 523484C926EA688F00EA0C2C /* trayicon.mm */; };
5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
+ 855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; };
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
@@ -95,6 +96,7 @@
5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = ""; };
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = ""; };
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = ""; };
+ 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformBehaviorInhibition.mm; sourceTree = ""; };
AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; };
AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
@@ -140,6 +142,7 @@
AB7A61E62147C814003C5833 = {
isa = PBXGroup;
children = (
+ 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */,
BC11A5BC2608D58F0017BAD0 /* automation.h */,
BC11A5BD2608D58F0017BAD0 /* automation.mm */,
1A1852DB23E05814008F0DED /* deadlock.mm */,
@@ -288,6 +291,7 @@
1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */,
BC11A5BF2608D58F0017BAD0 /* automation.mm in Sources */,
37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */,
+ 855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */,
520624B322973F4100C4DCEF /* menu.mm in Sources */,
37A517B32159597E00FBA241 /* Screens.mm in Sources */,
1AFD334123E03C4F0042899B /* controlhost.mm in Sources */,
diff --git a/native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm b/native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm
new file mode 100644
index 0000000000..db054d82ef
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm
@@ -0,0 +1,39 @@
+#include "common.h"
+
+namespace
+{
+ id s_inhibitAppSleepHandle{};
+}
+
+class PlatformBehaviorInhibition : public ComSingleObject
+{
+public:
+ FORWARD_IUNKNOWN()
+
+ virtual void SetInhibitAppSleep(bool inhibitAppSleep, char* reason) override
+ {
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if (inhibitAppSleep && s_inhibitAppSleepHandle == nullptr)
+ {
+ NSActivityOptions options = NSActivityUserInitiatedAllowingIdleSystemSleep;
+ s_inhibitAppSleepHandle = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:[NSString stringWithUTF8String: reason]];
+ }
+
+ if (!inhibitAppSleep)
+ {
+ s_inhibitAppSleepHandle = nullptr;
+ }
+ }
+ }
+};
+
+extern IAvnPlatformBehaviorInhibition* CreatePlatformBehaviorInhibition()
+{
+ @autoreleasepool
+ {
+ return new PlatformBehaviorInhibition();
+ }
+}
diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h
index 972927b99d..4353737dc8 100644
--- a/native/Avalonia.Native/src/OSX/common.h
+++ b/native/Avalonia.Native/src/OSX/common.h
@@ -26,6 +26,7 @@ extern IAvnTrayIcon* CreateTrayIcon();
extern IAvnMenuItem* CreateAppMenuItem();
extern IAvnMenuItem* CreateAppMenuItemSeparator();
extern IAvnApplicationCommands* CreateApplicationCommands();
+extern IAvnPlatformBehaviorInhibition* CreatePlatformBehaviorInhibition();
extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent);
extern IAvnPlatformSettings* CreatePlatformSettings();
extern void SetAppMenu(IAvnMenu *menu);
diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm
index 99063e600e..4bfda4b531 100644
--- a/native/Avalonia.Native/src/OSX/main.mm
+++ b/native/Avalonia.Native/src/OSX/main.mm
@@ -408,6 +408,17 @@ public:
return S_OK;
}
}
+
+ virtual HRESULT CreatePlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition** ppv) override
+ {
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreatePlatformBehaviorInhibition();
+ return S_OK;
+ }
+ }
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()
diff --git a/readme.md b/readme.md
index c2be487af3..2600cf83cc 100644
--- a/readme.md
+++ b/readme.md
@@ -1,3 +1,5 @@
+[](https://avaloniaui.net/xpf)
+
[](https://t.me/Avalonia)
[](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) []( https://aka.ms/dotnet-discord) [](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [](#backers) [](#sponsors) 
diff --git a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj
index d0fb614840..733a4b7194 100644
--- a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj
+++ b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs b/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
index 11e5e32cf1..938c45a4e2 100644
--- a/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
+++ b/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
@@ -59,10 +59,12 @@ namespace ControlCatalog.Pages
};
StreamGeometry sg = new StreamGeometry();
- var cntx = sg.Open();
- cntx.BeginFigure(new Point(-25.0d, -10.0d), false);
- cntx.ArcTo(new Point(25.0d, -10.0d), new Size(10.0d, 10.0d), 0.0d, false, SweepDirection.Clockwise);
- cntx.EndFigure(true);
+ using (var cntx = sg.Open())
+ {
+ cntx.BeginFigure(new Point(-25.0d, -10.0d), false);
+ cntx.ArcTo(new Point(25.0d, -10.0d), new Size(10.0d, 10.0d), 0.0d, false, SweepDirection.Clockwise);
+ cntx.EndFigure(true);
+ }
_smileGeometry = sg.Clone();
}
diff --git a/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs b/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
index a0b7d32d3b..ac09c48ccd 100644
--- a/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
+++ b/samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
@@ -47,7 +47,7 @@ public class D3DMemoryHelper
MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default,
- OptionFlags = ResourceOptionFlags.SharedKeyedmutex,
+ OptionFlags = ResourceOptionFlags.SharedKeyedmutex|ResourceOptionFlags.SharedNthandle,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
});
}
diff --git a/samples/GpuInterop/VulkanDemo/VulkanContext.cs b/samples/GpuInterop/VulkanDemo/VulkanContext.cs
index 3fdd9695f2..1d44549089 100644
--- a/samples/GpuInterop/VulkanDemo/VulkanContext.cs
+++ b/samples/GpuInterop/VulkanDemo/VulkanContext.cs
@@ -173,7 +173,7 @@ public unsafe class VulkanContext : IDisposable
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, familyProperties);
for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
{
- var family = familyProperties[c];
+ var family = familyProperties[queueFamilyIndex];
if (!family.QueueFlags.HasAllFlags(QueueFlags.GraphicsBit))
continue;
diff --git a/samples/GpuInterop/VulkanDemo/VulkanImage.cs b/samples/GpuInterop/VulkanDemo/VulkanImage.cs
index 59b2ef7e30..c1865a817d 100644
--- a/samples/GpuInterop/VulkanDemo/VulkanImage.cs
+++ b/samples/GpuInterop/VulkanDemo/VulkanImage.cs
@@ -4,10 +4,13 @@ using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Vulkan;
+using SharpDX.DXGI;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
+using Device = Silk.NET.Vulkan.Device;
+using Format = Silk.NET.Vulkan.Format;
namespace GpuInterop.VulkanDemo;
@@ -24,7 +27,6 @@ public unsafe class VulkanImage : IDisposable
private ImageView? _imageView { get; set; }
private DeviceMemory _imageMemory { get; set; }
private SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
- private IntPtr _win32ShareHandle;
internal Image? InternalHandle { get; private set; }
internal Format Format { get; }
@@ -60,7 +62,7 @@ public unsafe class VulkanImage : IDisposable
//MipLevels = MipLevels != 0 ? MipLevels : (uint)Math.Floor(Math.Log(Math.Max(Size.Width, Size.Height), 2));
var handleType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
- ExternalMemoryHandleTypeFlags.D3D11TextureKmtBit :
+ ExternalMemoryHandleTypeFlags.D3D11TextureBit :
ExternalMemoryHandleTypeFlags.OpaqueFDBit;
var externalMemoryCreateInfo = new ExternalMemoryImageCreateInfo
{
@@ -108,14 +110,14 @@ public unsafe class VulkanImage : IDisposable
if (exportable && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
- using var dxgi = _d3dTexture2D.QueryInterface();
- _win32ShareHandle = dxgi.SharedHandle;
+ using var dxgi = _d3dTexture2D.QueryInterface();
+
handleImport = new ImportMemoryWin32HandleInfoKHR
{
PNext = &dedicatedAllocation,
SType = StructureType.ImportMemoryWin32HandleInfoKhr,
- HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureKmtBit,
- Handle = _win32ShareHandle,
+ HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
+ Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
};
}
@@ -185,11 +187,19 @@ public unsafe class VulkanImage : IDisposable
return fd;
}
- public IPlatformHandle Export() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
- new PlatformHandle(_win32ShareHandle,
- KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle) :
- new PlatformHandle(new IntPtr(ExportFd()),
- KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
+ public IPlatformHandle Export()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ using var dxgi = _d3dTexture2D!.QueryInterface();
+ return new PlatformHandle(
+ dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
+ KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
+ }
+ else
+ return new PlatformHandle(new IntPtr(ExportFd()),
+ KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
+ }
public ImageTiling Tiling => ImageTiling.Optimal;
diff --git a/samples/IntegrationTestApp/MainWindow.axaml b/samples/IntegrationTestApp/MainWindow.axaml
index 7b1f0eddce..a6f463fdcb 100644
--- a/samples/IntegrationTestApp/MainWindow.axaml
+++ b/samples/IntegrationTestApp/MainWindow.axaml
@@ -70,6 +70,7 @@
Item 0
Item 1
+ Wrap Selection
diff --git a/samples/MobileSandbox/MainView.xaml b/samples/MobileSandbox/MainView.xaml
index 1eab13aa75..5d35ec3fec 100644
--- a/samples/MobileSandbox/MainView.xaml
+++ b/samples/MobileSandbox/MainView.xaml
@@ -5,8 +5,8 @@
x:DataType="mobileSandbox:MainView">
-
-
+
+
diff --git a/samples/interop/WindowsInteropTest/Program.cs b/samples/interop/WindowsInteropTest/Program.cs
index fac06d74b0..c2d30c67bb 100644
--- a/samples/interop/WindowsInteropTest/Program.cs
+++ b/samples/interop/WindowsInteropTest/Program.cs
@@ -1,5 +1,4 @@
using System;
-using Avalonia.Controls;
using ControlCatalog;
using Avalonia;
@@ -15,7 +14,15 @@ namespace WindowsInteropTest
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
- AppBuilder.Configure().UseWin32().UseDirect2D1().SetupWithoutStarting();
+ AppBuilder.Configure()
+ .UseWin32()
+ .UseDirect2D1()
+ .With(new Win32PlatformOptions
+ {
+ UseWindowsUIComposition = false,
+ ShouldRenderOnUIThread = true // necessary for WPF
+ })
+ .SetupWithoutStarting();
System.Windows.Forms.Application.Run(new SelectorForm());
}
}
diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
index 1643ca3ee2..95f77f6df9 100644
--- a/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
+++ b/samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
@@ -2,7 +2,7 @@
WinExe
net461
-
+ x64
true
true
@@ -10,9 +10,6 @@
-
- {d0a739b9-3c68-4ba6-a328-41606954b6bd}
- ControlCatalog
-
+
diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs
index c885a7768c..27dcfe8645 100644
--- a/src/Android/Avalonia.Android/AndroidInputMethod.cs
+++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs
@@ -5,8 +5,10 @@ using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.Platform.SkiaPlatform;
+using Avalonia.Controls.Presenters;
using Avalonia.Input;
using Avalonia.Input.TextInput;
+using Avalonia.Reactive;
namespace Avalonia.Android
{
@@ -32,7 +34,7 @@ namespace Avalonia.Android
ActionPrevious = 0x00000007,
}
- class AndroidInputMethod : ITextInputMethodImpl, IAndroidInputMethod
+ internal class AndroidInputMethod : ITextInputMethodImpl, IAndroidInputMethod
where TView : View, IInitEditorInfo
{
private readonly TView _host;
@@ -68,23 +70,10 @@ namespace Avalonia.Android
public void SetClient(ITextInputMethodClient client)
{
- if (_client != null)
- {
- _client.SurroundingTextChanged -= SurroundingTextChanged;
- }
-
- if(_inputConnection != null)
- {
- _inputConnection.ComposingText = null;
- _inputConnection.ComposingRegion = default;
- }
-
_client = client;
if (IsActive)
{
- _client.SurroundingTextChanged += SurroundingTextChanged;
-
_host.RequestFocus();
_imm.RestartInput(View);
@@ -101,24 +90,6 @@ namespace Avalonia.Android
}
}
- private void SurroundingTextChanged(object sender, EventArgs e)
- {
- if (IsActive && _inputConnection != null)
- {
- var surroundingText = Client.SurroundingText;
-
- _inputConnection.SurroundingText = surroundingText;
-
- _imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset);
-
- if (_inputConnection.ComposingText != null && !_inputConnection.IsCommiting && surroundingText.AnchorOffset == surroundingText.CursorOffset)
- {
- _inputConnection.CommitText(_inputConnection.ComposingText, 0);
- _inputConnection.SetSelection(surroundingText.AnchorOffset, surroundingText.CursorOffset);
- }
- }
- }
-
public void SetCursorRect(Rect rect)
{
@@ -157,17 +128,20 @@ namespace Avalonia.Android
TextInputReturnKeyType.Search => (ImeFlags)CustomImeFlags.ActionSearch,
TextInputReturnKeyType.Next => (ImeFlags)CustomImeFlags.ActionNext,
TextInputReturnKeyType.Previous => (ImeFlags)CustomImeFlags.ActionPrevious,
- _ => (ImeFlags)CustomImeFlags.ActionDone
+ TextInputReturnKeyType.Done => (ImeFlags)CustomImeFlags.ActionDone,
+ _ => options.Multiline ? ImeFlags.NoEnterAction : (ImeFlags)CustomImeFlags.ActionDone
};
outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi;
+ _client.TextEditable = _inputConnection.InputEditable;
+
return _inputConnection;
});
}
}
- public readonly record struct ComposingRegion
+ internal readonly record struct ComposingRegion
{
private readonly int _start = -1;
private readonly int _end = -1;
diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj
index 66557418dd..2533016e9f 100644
--- a/src/Android/Avalonia.Android/Avalonia.Android.csproj
+++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj
@@ -5,6 +5,7 @@
true
true
portable
+ Avalonia.Android.Internal
diff --git a/src/Android/Avalonia.Android/InputEditable.cs b/src/Android/Avalonia.Android/InputEditable.cs
new file mode 100644
index 0000000000..c5b68d2652
--- /dev/null
+++ b/src/Android/Avalonia.Android/InputEditable.cs
@@ -0,0 +1,127 @@
+using System;
+using Android.Runtime;
+using Android.Text;
+using Android.Views;
+using Android.Views.InputMethods;
+using Avalonia.Android.Platform.SkiaPlatform;
+using Avalonia.Controls.Presenters;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Input.TextInput;
+using Java.Lang;
+using static System.Net.Mime.MediaTypeNames;
+
+namespace Avalonia.Android
+{
+ internal class InputEditable : SpannableStringBuilder, ITextEditable
+ {
+ private readonly TopLevelImpl _topLevel;
+ private readonly IAndroidInputMethod _inputMethod;
+ private readonly AvaloniaInputConnection _avaloniaInputConnection;
+ private int _currentBatchLevel;
+ private string _previousText;
+ private int _previousSelectionStart;
+ private int _previousSelectionEnd;
+
+ public event EventHandler TextChanged;
+ public event EventHandler SelectionChanged;
+ public event EventHandler CompositionChanged;
+
+ public InputEditable(TopLevelImpl topLevel, IAndroidInputMethod inputMethod, AvaloniaInputConnection avaloniaInputConnection)
+ {
+ _topLevel = topLevel;
+ _inputMethod = inputMethod;
+ _avaloniaInputConnection = avaloniaInputConnection;
+ }
+
+ public InputEditable(ICharSequence text) : base(text)
+ {
+ }
+
+ public InputEditable(string text) : base(text)
+ {
+ }
+
+ public InputEditable(ICharSequence text, int start, int end) : base(text, start, end)
+ {
+ }
+
+ public InputEditable(string text, int start, int end) : base(text, start, end)
+ {
+ }
+
+ protected InputEditable(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
+ {
+ }
+
+ public int SelectionStart
+ {
+ get => Selection.GetSelectionStart(this); set
+ {
+ var end = SelectionEnd < 0 ? 0 : SelectionEnd;
+ _avaloniaInputConnection.SetSelection(value, end);
+ _inputMethod.IMM.UpdateSelection(_topLevel.View, value, end, value, end);
+ }
+ }
+ public int SelectionEnd
+ {
+ get => Selection.GetSelectionEnd(this); set
+ {
+ var start = SelectionStart < 0 ? 0 : SelectionStart;
+ _avaloniaInputConnection.SetSelection(start, value);
+ _inputMethod.IMM.UpdateSelection(_topLevel.View, start, value, start, value);
+ }
+ }
+
+ public string? Text
+ {
+ get => ToString(); set
+ {
+ if (Text != value)
+ {
+ Clear();
+ Insert(0, value ?? "");
+ }
+ }
+ }
+
+ public int CompositionStart => BaseInputConnection.GetComposingSpanStart(this);
+
+ public int CompositionEnd => BaseInputConnection.GetComposingSpanEnd(this);
+
+ public void BeginBatchEdit()
+ {
+ _currentBatchLevel++;
+
+ if (_currentBatchLevel == 1)
+ {
+ _previousText = ToString();
+ _previousSelectionStart = SelectionStart;
+ _previousSelectionEnd = SelectionEnd;
+ }
+ }
+
+ public void EndBatchEdit()
+ {
+ if (_currentBatchLevel == 1)
+ {
+ if(_previousText != Text)
+ {
+ TextChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ if (_previousSelectionStart != SelectionStart || _previousSelectionEnd != SelectionEnd)
+ {
+ SelectionChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ _currentBatchLevel--;
+ }
+
+ public void RaiseCompositionChanged()
+ {
+ CompositionChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs b/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs
index 726ccdbbdd..ab84801e57 100644
--- a/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs
+++ b/src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs
@@ -5,7 +5,7 @@ using Avalonia.Input;
namespace Avalonia.Android.Platform.Input
{
- public class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
+ internal class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
private static readonly Dictionary KeyDic = new Dictionary
{
// { Keycode.Cancel?, Key.Cancel },
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
index f205458f0e..47297a4f76 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
@@ -10,7 +10,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
- public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
+ internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
{
bool _invalidateQueued;
readonly object _lock = new object();
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 693a26f3bd..e511ed9a8b 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -28,6 +28,7 @@ using Math = System.Math;
using AndroidRect = Android.Graphics.Rect;
using Window = Android.Views.Window;
using Android.Graphics.Drawables;
+using Java.Util;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@@ -410,159 +411,73 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
private readonly TopLevelImpl _topLevel;
private readonly IAndroidInputMethod _inputMethod;
+ private readonly InputEditable _editable;
public AvaloniaInputConnection(TopLevelImpl topLevel, IAndroidInputMethod inputMethod) : base(inputMethod.View, true)
{
_topLevel = topLevel;
_inputMethod = inputMethod;
+ _editable = new InputEditable(_topLevel, _inputMethod, this);
}
- public TextInputMethodSurroundingText SurroundingText { get; set; }
+ public override IEditable Editable => _editable;
- public string ComposingText { get; internal set; }
-
- public ComposingRegion? ComposingRegion { get; internal set; }
-
- public bool IsComposing => !string.IsNullOrEmpty(ComposingText);
- public bool IsCommiting { get; private set; }
+ internal InputEditable InputEditable => _editable;
public override bool SetComposingRegion(int start, int end)
{
- //System.Diagnostics.Debug.WriteLine($"Composing Region: [{start}|{end}] {SurroundingText.Text?.Substring(start, end - start)}");
+ var ret = base.SetComposingRegion(start, end);
- ComposingRegion = new ComposingRegion(start, end);
+ InputEditable.RaiseCompositionChanged();
- return base.SetComposingRegion(start, end);
+ return ret;
}
public override bool SetComposingText(ICharSequence text, int newCursorPosition)
{
var composingText = text.ToString();
- ComposingText = composingText;
-
- _inputMethod.Client?.SetPreeditText(ComposingText);
-
- return base.SetComposingText(text, newCursorPosition);
- }
-
- public override bool FinishComposingText()
- {
- if (!string.IsNullOrEmpty(ComposingText))
+ if (string.IsNullOrEmpty(composingText))
{
- CommitText(ComposingText, ComposingText.Length);
+ return CommitText(text, newCursorPosition);
}
else
{
- ComposingRegion = new ComposingRegion(SurroundingText.CursorOffset, SurroundingText.CursorOffset);
- }
-
- return base.FinishComposingText();
- }
-
- public override ICharSequence GetTextBeforeCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
- {
- if (!string.IsNullOrEmpty(SurroundingText.Text) && length > 0)
- {
- var start = System.Math.Max(SurroundingText.CursorOffset - length, 0);
+ var ret = base.SetComposingText(text, newCursorPosition);
- var end = System.Math.Min(start + length - 1, SurroundingText.CursorOffset);
+ InputEditable.RaiseCompositionChanged();
- var text = SurroundingText.Text.Substring(start, end - start);
-
- //System.Diagnostics.Debug.WriteLine($"Text Before: {text}");
-
- return new Java.Lang.String(text);
+ return ret;
}
-
- return null;
}
- public override ICharSequence GetTextAfterCursorFormatted(int length, [GeneratedEnum] GetTextFlags flags)
+ public override bool BeginBatchEdit()
{
- if (!string.IsNullOrEmpty(SurroundingText.Text))
- {
- var start = SurroundingText.CursorOffset;
-
- var end = System.Math.Min(start + length, SurroundingText.Text.Length);
-
- var text = SurroundingText.Text.Substring(start, end - start);
+ _editable.BeginBatchEdit();
- //System.Diagnostics.Debug.WriteLine($"Text After: {text}");
-
- return new Java.Lang.String(text);
- }
-
- return null;
+ return base.BeginBatchEdit();
}
- public override bool CommitText(ICharSequence text, int newCursorPosition)
+ public override bool EndBatchEdit()
{
- IsCommiting = true;
- var committedText = text.ToString();
-
- _inputMethod.Client.SetPreeditText(null);
+ var ret = base.EndBatchEdit();
+ _editable.EndBatchEdit();
- int? start, end;
-
- if(SurroundingText.CursorOffset != SurroundingText.AnchorOffset)
- {
- start = Math.Min(SurroundingText.CursorOffset, SurroundingText.AnchorOffset);
- end = Math.Max(SurroundingText.CursorOffset, SurroundingText.AnchorOffset);
- }
- else if (ComposingRegion != null)
- {
- start = ComposingRegion?.Start;
- end = ComposingRegion?.End;
-
- ComposingRegion = null;
- }
- else
- {
- start = end = _inputMethod.Client.SurroundingText.CursorOffset;
- }
-
- _inputMethod.Client.SelectInSurroundingText((int)start, (int)end);
-
- var time = DateTime.Now.TimeOfDay;
-
- var rawTextEvent = new RawTextInputEventArgs(KeyboardDevice.Instance, (ulong)time.Ticks, _topLevel.InputRoot, committedText);
-
- _topLevel.Input(rawTextEvent);
-
- ComposingText = null;
-
- ComposingRegion = new ComposingRegion(newCursorPosition, newCursorPosition);
-
- return base.CommitText(text, newCursorPosition);
+ return ret;
}
- public override bool DeleteSurroundingText(int beforeLength, int afterLength)
+ public override bool FinishComposingText()
{
- var surroundingText = _inputMethod.Client.SurroundingText;
-
- var selectionStart = surroundingText.CursorOffset;
-
- _inputMethod.Client.SelectInSurroundingText(selectionStart - beforeLength, selectionStart + afterLength);
-
- _inputMethod.View.DispatchKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.ForwardDel));
-
- surroundingText = _inputMethod.Client.SurroundingText;
-
- selectionStart = surroundingText.CursorOffset;
-
- ComposingRegion = new ComposingRegion(selectionStart, selectionStart);
-
- return base.DeleteSurroundingText(beforeLength, afterLength);
+ var ret = base.FinishComposingText();
+ InputEditable.RaiseCompositionChanged();
+ return ret;
}
- public override bool SetSelection(int start, int end)
+ public override bool CommitText(ICharSequence text, int newCursorPosition)
{
- _inputMethod.Client.SelectInSurroundingText(start, end);
-
- ComposingRegion = new ComposingRegion(start, end);
-
- return base.SetSelection(start, end);
+ var ret = base.CommitText(text, newCursorPosition);
+ InputEditable.RaiseCompositionChanged();
+ return ret;
}
public override bool PerformEditorAction([GeneratedEnum] ImeAction actionCode)
diff --git a/src/Android/Avalonia.Android/PlatformIconLoader.cs b/src/Android/Avalonia.Android/PlatformIconLoader.cs
index 88677a9375..f557685dd2 100644
--- a/src/Android/Avalonia.Android/PlatformIconLoader.cs
+++ b/src/Android/Avalonia.Android/PlatformIconLoader.cs
@@ -3,7 +3,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
- class PlatformIconLoader : IPlatformIconLoader
+ internal class PlatformIconLoader : IPlatformIconLoader
{
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
{
@@ -29,7 +29,7 @@ namespace Avalonia.Android
}
// Stores the icon created as a stream to support saving even though an icon is never shown
- public class FakeIcon : IWindowIconImpl
+ internal class FakeIcon : IWindowIconImpl
{
private Stream stream = new MemoryStream();
diff --git a/src/Android/Avalonia.Android/Stubs.cs b/src/Android/Avalonia.Android/Stubs.cs
index f36c01dbc8..05638cdf88 100644
--- a/src/Android/Avalonia.Android/Stubs.cs
+++ b/src/Android/Avalonia.Android/Stubs.cs
@@ -4,7 +4,7 @@ using Avalonia.Platform;
namespace Avalonia.Android
{
- class WindowingPlatformStub : IWindowingPlatform
+ internal class WindowingPlatformStub : IWindowingPlatform
{
public IWindowImpl CreateWindow() => throw new NotSupportedException();
@@ -13,7 +13,7 @@ namespace Avalonia.Android
public ITrayIconImpl CreateTrayIcon() => null;
}
- class PlatformIconLoaderStub : IPlatformIconLoader
+ internal class PlatformIconLoaderStub : IPlatformIconLoader
{
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
{
@@ -38,7 +38,7 @@ namespace Avalonia.Android
}
}
- public class IconStub : IWindowIconImpl
+ internal class IconStub : IWindowIconImpl
{
private readonly MemoryStream _ms;
diff --git a/src/Avalonia.Base/Animation/KeySpline.cs b/src/Avalonia.Base/Animation/KeySpline.cs
index 6ca5b2e759..ed6adb79b8 100644
--- a/src/Avalonia.Base/Animation/KeySpline.cs
+++ b/src/Avalonia.Base/Animation/KeySpline.cs
@@ -79,15 +79,12 @@ namespace Avalonia.Animation
/// culture of the string
/// Thrown if the string does not have 4 values
/// A with the appropriate values set
- public static KeySpline Parse(string value, CultureInfo culture)
+ public static KeySpline Parse(string value, CultureInfo? culture)
{
- if (culture is null)
- culture = CultureInfo.InvariantCulture;
+ culture ??= CultureInfo.InvariantCulture;
- using (var tokenizer = new StringTokenizer((string)value, culture, exceptionMessage: $"Invalid KeySpline string: \"{value}\"."))
- {
- return new KeySpline(tokenizer.ReadDouble(), tokenizer.ReadDouble(), tokenizer.ReadDouble(), tokenizer.ReadDouble());
- }
+ using var tokenizer = new StringTokenizer(value, culture, exceptionMessage: $"Invalid KeySpline string: \"{value}\".");
+ return new KeySpline(tokenizer.ReadDouble(), tokenizer.ReadDouble(), tokenizer.ReadDouble(), tokenizer.ReadDouble());
}
///
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 1946d4ba5c..2c9efc7767 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -118,7 +118,7 @@ namespace Avalonia
{
_ = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
- _values.ClearLocalValue(property);
+ _values.ClearValue(property);
}
///
@@ -152,7 +152,7 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
- _values?.ClearLocalValue(property);
+ _values.ClearValue(property);
}
///
@@ -242,7 +242,14 @@ namespace Avalonia
return registered.InvokeGetter(this);
}
- ///
+ ///
+ /// Gets an base value.
+ ///
+ /// The property.
+ ///
+ /// Gets the value of the property excluding animated values, otherwise .
+ /// Note that this method does not return property values that come from inherited or default values.
+ ///
public Optional GetBaseValue(StyledProperty property)
{
_ = property ?? throw new ArgumentNullException(nameof(property));
@@ -261,7 +268,7 @@ namespace Avalonia
VerifyAccess();
- return _values?.IsAnimating(property) ?? false;
+ return _values.IsAnimating(property);
}
///
@@ -270,8 +277,8 @@ namespace Avalonia
/// The property.
/// True if the property is set, otherwise false.
///
- /// Checks whether a value is assigned to the property, or that there is a binding to the
- /// property that is producing a value other than .
+ /// Returns true if is a styled property which has a value
+ /// assigned to it or a binding targeting it; otherwise false.
///
public bool IsSet(AvaloniaProperty property)
{
@@ -279,7 +286,7 @@ namespace Avalonia
VerifyAccess();
- return _values?.IsSet(property) ?? false;
+ return _values.IsSet(property);
}
///
@@ -322,7 +329,7 @@ namespace Avalonia
if (value is UnsetValueType)
{
if (priority == BindingPriority.LocalValue)
- _values.ClearLocalValue(property);
+ _values.ClearValue(property);
}
else if (value is not DoNothingType)
{
@@ -348,6 +355,57 @@ namespace Avalonia
SetDirectValueUnchecked(property, value);
}
+ ///
+ /// Sets the value of a dependency property without changing its value source.
+ ///
+ /// The property.
+ /// The value.
+ ///
+ /// This method is used by a component that programmatically sets the value of one of its
+ /// own properties without disabling an application's declared use of the property. The
+ /// method changes the effective value of the property, but existing data bindings and
+ /// styles will continue to work.
+ ///
+ /// The new value will have the property's current , even if
+ /// that priority is or
+ /// .
+ ///
+ public void SetCurrentValue(AvaloniaProperty property, object? value) =>
+ property.RouteSetCurrentValue(this, value);
+
+ ///
+ /// Sets the value of a dependency property without changing its value source.
+ ///
+ /// The type of the property.
+ /// The property.
+ /// The value.
+ ///
+ /// This method is used by a component that programmatically sets the value of one of its
+ /// own properties without disabling an application's declared use of the property. The
+ /// method changes the effective value of the property, but existing data bindings and
+ /// styles will continue to work.
+ ///
+ /// The new value will have the property's current , even if
+ /// that priority is or
+ /// .
+ ///
+ public void SetCurrentValue(StyledProperty property, T value)
+ {
+ _ = property ?? throw new ArgumentNullException(nameof(property));
+ VerifyAccess();
+
+ LogPropertySet(property, value, BindingPriority.LocalValue);
+
+ if (value is UnsetValueType)
+ {
+ _values.ClearValue(property);
+ }
+ else if (value is not DoNothingType)
+ {
+ _values.SetCurrentValue(property, value);
+ }
+ }
+
///
/// Binds a to an observable.
///
@@ -515,14 +573,12 @@ namespace Avalonia
/// The property.
public void CoerceValue(AvaloniaProperty property) => _values.CoerceValue(property);
- ///
internal void AddInheritanceChild(AvaloniaObject child)
{
_inheritanceChildren ??= new List();
_inheritanceChildren.Add(child);
}
-
- ///
+
internal void RemoveInheritanceChild(AvaloniaObject child)
{
_inheritanceChildren?.Remove(child);
@@ -541,24 +597,12 @@ namespace Avalonia
return new AvaloniaPropertyValue(
property,
GetValue(property),
- BindingPriority.Unset,
- "Local Value");
+ BindingPriority.LocalValue,
+ null,
+ false);
}
- else if (_values != null)
- {
- var result = _values.GetDiagnostic(property);
- if (result != null)
- {
- return result;
- }
- }
-
- return new AvaloniaPropertyValue(
- property,
- GetValue(property),
- BindingPriority.Unset,
- "Unset");
+ return _values.GetDiagnostic(property);
}
internal ValueStore GetValueStore() => _values;
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 5db4d81f03..45ab293a89 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -225,13 +225,8 @@ namespace Avalonia
/// The default value of the property.
/// Whether the property inherits its value.
/// The default binding mode for the property.
- /// A value validation callback.
+ /// A value validation callback.
/// A value coercion callback.
- ///
- /// A method that gets called before and after the property starts being notified on an
- /// object; the bool argument will be true before and false afterwards. This callback is
- /// intended to support IsDataContextChanging.
- ///
/// A
public static StyledProperty Register(
string name,
@@ -239,8 +234,40 @@ namespace Avalonia
bool inherits = false,
BindingMode defaultBindingMode = BindingMode.OneWay,
Func? validate = null,
- Func? coerce = null,
- Action? notifying = null)
+ Func? coerce = null)
+ where TOwner : AvaloniaObject
+ {
+ _ = name ?? throw new ArgumentNullException(nameof(name));
+
+ var metadata = new StyledPropertyMetadata(
+ defaultValue,
+ defaultBindingMode: defaultBindingMode,
+ coerce: coerce);
+
+ var result = new StyledProperty(
+ name,
+ typeof(TOwner),
+ metadata,
+ inherits,
+ validate);
+ AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);
+ return result;
+ }
+
+ ///
+ ///
+ /// A method that gets called before and after the property starts being notified on an
+ /// object; the bool argument will be true before and false afterwards. This callback is
+ /// intended to support IsDataContextChanging.
+ ///
+ internal static StyledProperty Register(
+ string name,
+ TValue defaultValue,
+ bool inherits,
+ BindingMode defaultBindingMode,
+ Func? validate,
+ Func? coerce,
+ Action? notifying)
where TOwner : AvaloniaObject
{
_ = name ?? throw new ArgumentNullException(nameof(name));
@@ -496,6 +523,13 @@ namespace Avalonia
object? value,
BindingPriority priority);
+ ///
+ /// Routes an untyped SetCurrentValue call to a typed call.
+ ///
+ /// The object instance.
+ /// The value.
+ internal abstract void RouteSetCurrentValue(AvaloniaObject o, object? value);
+
///
/// Routes an untyped Bind call to a typed call.
///
diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
index f5c135459d..aeb71d16ae 100644
--- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Data.Converters
{
if (value == null)
{
- return targetType.IsValueType ? AvaloniaProperty.UnsetValue : null;
+ return null;
}
if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1)
diff --git a/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs
index d7b1f2e053..270cac95f2 100644
--- a/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs
@@ -1,6 +1,3 @@
-using System;
-using Avalonia.Data;
-
namespace Avalonia.Diagnostics
{
///
diff --git a/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs b/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
index 4189fd5234..0b3e62f1cc 100644
--- a/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
+++ b/src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
@@ -3,28 +3,23 @@ using Avalonia.Data;
namespace Avalonia.Diagnostics
{
///
- /// Holds diagnostic-related information about the value of a
- /// on a .
+ /// Holds diagnostic-related information about the value of an
+ /// on an .
///
public class AvaloniaPropertyValue
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The property.
- /// The current property value.
- /// The priority of the current value.
- /// A diagnostic string.
- public AvaloniaPropertyValue(
+ internal AvaloniaPropertyValue(
AvaloniaProperty property,
object? value,
BindingPriority priority,
- string? diagnostic)
+ string? diagnostic,
+ bool isOverriddenCurrentValue)
{
Property = property;
Value = value;
Priority = priority;
Diagnostic = diagnostic;
+ IsOverriddenCurrentValue = isOverriddenCurrentValue;
}
///
@@ -46,5 +41,11 @@ namespace Avalonia.Diagnostics
/// Gets a diagnostic string.
///
public string? Diagnostic { get; }
+
+ ///
+ /// Gets a value indicating whether the was overridden by a call to
+ /// .
+ ///
+ public bool IsOverriddenCurrentValue { get; }
}
}
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index 9ee1eee0fa..94dfaaab01 100644
--- a/src/Avalonia.Base/DirectPropertyBase.cs
+++ b/src/Avalonia.Base/DirectPropertyBase.cs
@@ -152,6 +152,11 @@ namespace Avalonia
return null;
}
+ internal override void RouteSetCurrentValue(AvaloniaObject o, object? value)
+ {
+ RouteSetValue(o, value, BindingPriority.LocalValue);
+ }
+
///
/// Routes an untyped Bind call to a typed call.
///
diff --git a/src/Avalonia.Base/Input/DragEventArgs.cs b/src/Avalonia.Base/Input/DragEventArgs.cs
index 403dd6f23e..8d7cc2b9a1 100644
--- a/src/Avalonia.Base/Input/DragEventArgs.cs
+++ b/src/Avalonia.Base/Input/DragEventArgs.cs
@@ -1,36 +1,28 @@
using System;
using Avalonia.Interactivity;
using Avalonia.Metadata;
-using Avalonia.VisualTree;
namespace Avalonia.Input
{
public class DragEventArgs : RoutedEventArgs
{
- private Interactive _target;
- private Point _targetLocation;
+ private readonly Interactive _target;
+ private readonly Point _targetLocation;
public DragDropEffects DragEffects { get; set; }
- public IDataObject Data { get; private set; }
+ public IDataObject Data { get; }
- public KeyModifiers KeyModifiers { get; private set; }
+ public KeyModifiers KeyModifiers { get; }
public Point GetPosition(Visual relativeTo)
{
- var point = new Point(0, 0);
-
if (relativeTo == null)
{
throw new ArgumentNullException(nameof(relativeTo));
}
- if (_target != null)
- {
- point = _target.TranslatePoint(_targetLocation, relativeTo) ?? point;
- }
-
- return point;
+ return _target.TranslatePoint(_targetLocation, relativeTo) ?? new Point(0, 0);
}
[Unstable]
diff --git a/src/Avalonia.Base/Input/KeyGesture.cs b/src/Avalonia.Base/Input/KeyGesture.cs
index c6618fd550..9ee8ae9711 100644
--- a/src/Avalonia.Base/Input/KeyGesture.cs
+++ b/src/Avalonia.Base/Input/KeyGesture.cs
@@ -136,7 +136,7 @@ namespace Avalonia.Input
return StringBuilderCache.GetStringAndRelease(s);
}
- public bool Matches(KeyEventArgs keyEvent) =>
+ public bool Matches(KeyEventArgs? keyEvent) =>
keyEvent != null &&
keyEvent.KeyModifiers == KeyModifiers &&
ResolveNumPadOperationKey(keyEvent.Key) == ResolveNumPadOperationKey(Key);
diff --git a/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs b/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
index b05d8f30bb..ba909de60f 100644
--- a/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
+++ b/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
@@ -1,6 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using Avalonia.Input.Navigation;
using Avalonia.VisualTree;
@@ -51,7 +50,7 @@ namespace Avalonia.Input
// If there's a custom keyboard navigation handler as an ancestor, use that.
var custom = (element as Visual)?.FindAncestorOfType(true);
- if (custom is object && HandlePreCustomNavigation(custom, element, direction, out var ce))
+ if (custom is not null && HandlePreCustomNavigation(custom, element, direction, out var ce))
return ce;
var result = direction switch
@@ -117,32 +116,27 @@ namespace Avalonia.Input
NavigationDirection direction,
[NotNullWhen(true)] out IInputElement? result)
{
- if (customHandler != null)
+ var (handled, next) = customHandler.GetNext(element, direction);
+
+ if (handled)
{
- var (handled, next) = customHandler.GetNext(element, direction);
+ if (next is not null)
+ {
+ result = next;
+ return true;
+ }
- if (handled)
+ var r = direction switch
{
- if (next != null)
- {
- result = next;
- return true;
- }
- else if (direction == NavigationDirection.Next || direction == NavigationDirection.Previous)
- {
- var r = direction switch
- {
- NavigationDirection.Next => TabNavigation.GetNextTabOutside(customHandler),
- NavigationDirection.Previous => TabNavigation.GetPrevTabOutside(customHandler),
- _ => throw new NotSupportedException(),
- };
-
- if (r is object)
- {
- result = r;
- return true;
- }
- }
+ NavigationDirection.Next => TabNavigation.GetNextTabOutside(customHandler),
+ NavigationDirection.Previous => TabNavigation.GetPrevTabOutside(customHandler),
+ _ => null
+ };
+
+ if (r is not null)
+ {
+ result = r;
+ return true;
}
}
diff --git a/src/Avalonia.Base/Input/Navigation/TabNavigation.cs b/src/Avalonia.Base/Input/Navigation/TabNavigation.cs
index d218867cf2..c460ecf3b3 100644
--- a/src/Avalonia.Base/Input/Navigation/TabNavigation.cs
+++ b/src/Avalonia.Base/Input/Navigation/TabNavigation.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using Avalonia.VisualTree;
namespace Avalonia.Input.Navigation
@@ -54,8 +52,7 @@ namespace Avalonia.Input.Navigation
// Avoid the endless loop here for Cycle groups
if (loopStartElement == nextTabElement)
break;
- if (loopStartElement == null)
- loopStartElement = nextTabElement;
+ loopStartElement ??= nextTabElement;
var firstTabElementInside = GetNextTab(null, nextTabElement, true);
if (firstTabElementInside != null)
@@ -80,12 +77,9 @@ namespace Avalonia.Input.Navigation
public static IInputElement? GetNextTabOutside(ICustomKeyboardNavigation e)
{
- if (e is IInputElement container)
+ if (e is IInputElement container && GetLastInTree(container) is { } last)
{
- var last = GetLastInTree(container);
-
- if (last is object)
- return GetNextTab(last, false);
+ return GetNextTab(last, false);
}
return null;
@@ -93,11 +87,8 @@ namespace Avalonia.Input.Navigation
public static IInputElement? GetPrevTab(IInputElement? e, IInputElement? container, bool goDownOnly)
{
- if (e is null && container is null)
- throw new InvalidOperationException("Either 'e' or 'container' must be non-null.");
-
- if (container is null)
- container = GetGroupParent(e!);
+ container ??=
+ GetGroupParent(e ?? throw new InvalidOperationException("Either 'e' or 'container' must be non-null."));
KeyboardNavigationMode tabbingType = GetKeyNavigationMode(container);
@@ -163,8 +154,7 @@ namespace Avalonia.Input.Navigation
// Avoid the endless loop here
if (loopStartElement == nextTabElement)
break;
- if (loopStartElement == null)
- loopStartElement = nextTabElement;
+ loopStartElement ??= nextTabElement;
// At this point nextTabElement is TabGroup
var lastTabElementInside = GetPrevTab(null, nextTabElement, true);
@@ -189,22 +179,18 @@ namespace Avalonia.Input.Navigation
public static IInputElement? GetPrevTabOutside(ICustomKeyboardNavigation e)
{
- if (e is IInputElement container)
+ if (e is IInputElement container && GetFirstChild(container) is { } first)
{
- var first = GetFirstChild(container);
-
- if (first is object)
- return GetPrevTab(first, null, false);
+ return GetPrevTab(first, null, false);
}
return null;
}
- private static IInputElement? FocusedElement(IInputElement e)
+ private static IInputElement? FocusedElement(IInputElement? e)
{
- var iie = e;
// Focus delegation is enabled only if keyboard focus is outside the container
- if (iie != null && !iie.IsKeyboardFocusWithin)
+ if (e != null && !e.IsKeyboardFocusWithin)
{
var focusedElement = (FocusManager.Instance as FocusManager)?.GetFocusedElement(e);
if (focusedElement != null)
@@ -229,13 +215,11 @@ namespace Avalonia.Input.Navigation
private static IInputElement? GetFirstChild(IInputElement e)
{
// If the element has a FocusedElement it should be its first child
- if (FocusedElement(e) is IInputElement focusedElement)
+ if (FocusedElement(e) is { } focusedElement)
return focusedElement;
// Return the first visible element.
- var uiElement = e as InputElement;
-
- if (uiElement is null || IsVisibleAndEnabled(uiElement))
+ if (e is not InputElement uiElement || IsVisibleAndEnabled(uiElement))
{
if (e is Visual elementAsVisual)
{
@@ -265,7 +249,7 @@ namespace Avalonia.Input.Navigation
private static IInputElement? GetLastChild(IInputElement e)
{
// If the element has a FocusedElement it should be its last child
- if (FocusedElement(e) is IInputElement focusedElement)
+ if (FocusedElement(e) is { } focusedElement)
return focusedElement;
// Return the last visible element.
@@ -273,9 +257,7 @@ namespace Avalonia.Input.Navigation
if (uiElement == null || IsVisibleAndEnabled(uiElement))
{
- var elementAsVisual = e as Visual;
-
- if (elementAsVisual != null)
+ if (e is Visual elementAsVisual)
{
var children = elementAsVisual.VisualChildren;
var count = children.Count;
@@ -322,7 +304,7 @@ namespace Avalonia.Input.Navigation
return firstTabElement;
}
- private static IInputElement? GetLastInTree(IInputElement container)
+ private static IInputElement GetLastInTree(IInputElement container)
{
IInputElement? result;
IInputElement? c = container;
diff --git a/src/Avalonia.Base/Input/Platform/IClipboard.cs b/src/Avalonia.Base/Input/Platform/IClipboard.cs
index bf2a5a8602..3de352fc4f 100644
--- a/src/Avalonia.Base/Input/Platform/IClipboard.cs
+++ b/src/Avalonia.Base/Input/Platform/IClipboard.cs
@@ -6,9 +6,9 @@ namespace Avalonia.Input.Platform
[NotClientImplementable]
public interface IClipboard
{
- Task GetTextAsync();
+ Task GetTextAsync();
- Task SetTextAsync(string text);
+ Task SetTextAsync(string? text);
Task ClearAsync();
@@ -16,6 +16,6 @@ namespace Avalonia.Input.Platform
Task GetFormatsAsync();
- Task
void SetPreeditText(string? text);
+ ///
+ /// Sets the current composing region. This doesn't remove the composing text from the commited text.
+ ///
+ void SetComposingRegion(TextRange? region);
+
///
/// Indicates if text input client is capable of providing the text around the cursor
///
@@ -43,6 +49,11 @@ namespace Avalonia.Input.TextInput
///
event EventHandler? SurroundingTextChanged;
+ ///
+ /// Gets or sets a platform editable. Text and selection changes made in the editable are forwarded to the IM client.
+ ///
+ ITextEditable? TextEditable { get; set; }
+
void SelectInSurroundingText(int start, int end);
}
diff --git a/src/Avalonia.Base/LogicalTree/LogicalExtensions.cs b/src/Avalonia.Base/LogicalTree/LogicalExtensions.cs
index 74720c0a77..9ab7da3ff7 100644
--- a/src/Avalonia.Base/LogicalTree/LogicalExtensions.cs
+++ b/src/Avalonia.Base/LogicalTree/LogicalExtensions.cs
@@ -48,7 +48,7 @@ namespace Avalonia.LogicalTree
/// The logical.
/// If given logical should be included in search.
/// First ancestor of given type.
- public static T? FindLogicalAncestorOfType(this ILogical logical, bool includeSelf = false) where T : class
+ public static T? FindLogicalAncestorOfType(this ILogical? logical, bool includeSelf = false) where T : class
{
if (logical is null)
{
@@ -120,7 +120,7 @@ namespace Avalonia.LogicalTree
/// The logical.
/// If given logical should be included in search.
/// First descendant of given type.
- public static T? FindLogicalDescendantOfType(this ILogical logical, bool includeSelf = false) where T : class
+ public static T? FindLogicalDescendantOfType(this ILogical? logical, bool includeSelf = false) where T : class
{
if (logical is null)
{
@@ -185,7 +185,7 @@ namespace Avalonia.LogicalTree
/// True if is an ancestor of ;
/// otherwise false.
///
- public static bool IsLogicalAncestorOf(this ILogical logical, ILogical target)
+ public static bool IsLogicalAncestorOf(this ILogical? logical, ILogical? target)
{
var current = target?.LogicalParent;
diff --git a/src/Avalonia.Base/Media/Color.cs b/src/Avalonia.Base/Media/Color.cs
index 5470a735b3..74e70b2a14 100644
--- a/src/Avalonia.Base/Media/Color.cs
+++ b/src/Avalonia.Base/Media/Color.cs
@@ -147,16 +147,11 @@ namespace Avalonia.Media
/// The color string.
/// The parsed color
/// The status of the operation.
- public static bool TryParse(string s, out Color color)
+ public static bool TryParse(string? s, out Color color)
{
color = default;
- if (s is null)
- {
- return false;
- }
-
- if (s.Length == 0)
+ if (string.IsNullOrEmpty(s))
{
return false;
}
@@ -336,7 +331,7 @@ namespace Avalonia.Media
///
/// Parses the given string representing a CSS color value into a new .
///
- private static bool TryParseCssFormat(string s, out Color color)
+ private static bool TryParseCssFormat(string? s, out Color color)
{
bool prefixMatched = false;
diff --git a/src/Avalonia.Base/Media/DrawingContext.cs b/src/Avalonia.Base/Media/DrawingContext.cs
index d295111d72..622181dba0 100644
--- a/src/Avalonia.Base/Media/DrawingContext.cs
+++ b/src/Avalonia.Base/Media/DrawingContext.cs
@@ -240,7 +240,7 @@ namespace Avalonia.Media
///
/// The foreground brush.
/// The glyph run.
- public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
+ public void DrawGlyphRun(IBrush? foreground, GlyphRun glyphRun)
{
_ = glyphRun ?? throw new ArgumentNullException(nameof(glyphRun));
diff --git a/src/Avalonia.Base/Media/DrawingGroup.cs b/src/Avalonia.Base/Media/DrawingGroup.cs
index 481329c20c..b7abda2c61 100644
--- a/src/Avalonia.Base/Media/DrawingGroup.cs
+++ b/src/Avalonia.Base/Media/DrawingGroup.cs
@@ -13,14 +13,14 @@ namespace Avalonia.Media
public static readonly StyledProperty OpacityProperty =
AvaloniaProperty.Register(nameof(Opacity), 1);
- public static readonly StyledProperty TransformProperty =
- AvaloniaProperty.Register(nameof(Transform));
+ public static readonly StyledProperty TransformProperty =
+ AvaloniaProperty.Register(nameof(Transform));
- public static readonly StyledProperty ClipGeometryProperty =
- AvaloniaProperty.Register(nameof(ClipGeometry));
+ public static readonly StyledProperty ClipGeometryProperty =
+ AvaloniaProperty.Register(nameof(ClipGeometry));
- public static readonly StyledProperty OpacityMaskProperty =
- AvaloniaProperty.Register(nameof(OpacityMask));
+ public static readonly StyledProperty OpacityMaskProperty =
+ AvaloniaProperty.Register(nameof(OpacityMask));
public static readonly DirectProperty ChildrenProperty =
AvaloniaProperty.RegisterDirect(
@@ -36,19 +36,19 @@ namespace Avalonia.Media
set => SetValue(OpacityProperty, value);
}
- public Transform Transform
+ public Transform? Transform
{
get => GetValue(TransformProperty);
set => SetValue(TransformProperty, value);
}
- public Geometry ClipGeometry
+ public Geometry? ClipGeometry
{
get => GetValue(ClipGeometryProperty);
set => SetValue(ClipGeometryProperty, value);
}
- public IBrush OpacityMask
+ public IBrush? OpacityMask
{
get => GetValue(OpacityMaskProperty);
set => SetValue(OpacityMaskProperty, value);
@@ -159,7 +159,7 @@ namespace Avalonia.Media
public void DrawGeometry(IBrush? brush, IPen? pen, IGeometryImpl geometry)
{
- if (((brush == null) && (pen == null)) || (geometry == null))
+ if ((brush == null) && (pen == null))
{
return;
}
@@ -167,9 +167,9 @@ namespace Avalonia.Media
AddNewGeometryDrawing(brush, pen, new PlatformGeometry(geometry));
}
- public void DrawGlyphRun(IBrush foreground, IRef glyphRun)
+ public void DrawGlyphRun(IBrush? foreground, IRef glyphRun)
{
- if (foreground == null || glyphRun == null)
+ if (foreground == null)
{
return;
}
@@ -184,7 +184,7 @@ namespace Avalonia.Media
AddDrawing(glyphRunDrawing);
}
- public void DrawLine(IPen pen, Point p1, Point p2)
+ public void DrawLine(IPen? pen, Point p1, Point p2)
{
if (pen == null)
{
diff --git a/src/Avalonia.Base/Media/DrawingImage.cs b/src/Avalonia.Base/Media/DrawingImage.cs
index 38ddbdfaed..1b22a1ee69 100644
--- a/src/Avalonia.Base/Media/DrawingImage.cs
+++ b/src/Avalonia.Base/Media/DrawingImage.cs
@@ -20,8 +20,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty DrawingProperty =
- AvaloniaProperty.Register(nameof(Drawing));
+ public static readonly StyledProperty DrawingProperty =
+ AvaloniaProperty.Register(nameof(Drawing));
///
public event EventHandler? Invalidated;
@@ -30,7 +30,7 @@ namespace Avalonia.Media
/// Gets or sets the drawing content.
///
[Content]
- public Drawing Drawing
+ public Drawing? Drawing
{
get => GetValue(DrawingProperty);
set => SetValue(DrawingProperty, value);
diff --git a/src/Avalonia.Base/Media/FontFamily.cs b/src/Avalonia.Base/Media/FontFamily.cs
index da84861668..f4406bd010 100644
--- a/src/Avalonia.Base/Media/FontFamily.cs
+++ b/src/Avalonia.Base/Media/FontFamily.cs
@@ -119,7 +119,7 @@ namespace Avalonia.Media
case 2:
{
- var source = segments[0].StartsWith("/")
+ var source = segments[0].StartsWith("/", StringComparison.Ordinal)
? new Uri(segments[0], UriKind.Relative)
: new Uri(segments[0], UriKind.RelativeOrAbsolute);
@@ -188,7 +188,7 @@ namespace Avalonia.Media
{
unchecked
{
- return ((FamilyNames != null ? FamilyNames.GetHashCode() : 0) * 397) ^ (Key != null ? Key.GetHashCode() : 0);
+ return (FamilyNames.GetHashCode() * 397) ^ (Key is not null ? Key.GetHashCode() : 0);
}
}
diff --git a/src/Avalonia.Base/Media/Fonts/FontFamilyKey.cs b/src/Avalonia.Base/Media/Fonts/FontFamilyKey.cs
index f607c67fed..12bb7e77e7 100644
--- a/src/Avalonia.Base/Media/Fonts/FontFamilyKey.cs
+++ b/src/Avalonia.Base/Media/Fonts/FontFamilyKey.cs
@@ -41,10 +41,7 @@ namespace Avalonia.Media.Fonts
{
var hash = (int)2166136261;
- if (Source != null)
- {
- hash = (hash * 16777619) ^ Source.GetHashCode();
- }
+ hash = (hash * 16777619) ^ Source.GetHashCode();
if (BaseUri != null)
{
diff --git a/src/Avalonia.Base/Media/FormattedText.cs b/src/Avalonia.Base/Media/FormattedText.cs
index 28757b1a1d..3b63a98720 100644
--- a/src/Avalonia.Base/Media/FormattedText.cs
+++ b/src/Avalonia.Base/Media/FormattedText.cs
@@ -1354,7 +1354,7 @@ namespace Avalonia.Media
{
var highlightBounds = currentLine.GetTextBounds(x0,x1 - x0);
- if (highlightBounds != null)
+ if (highlightBounds.Count > 0)
{
foreach (var bound in highlightBounds)
{
@@ -1365,7 +1365,7 @@ namespace Avalonia.Media
// Convert logical units (which extend leftward from the right edge
// of the paragraph) to physical units.
//
- // Note that since rect is in logical units, rect.Right corresponds to
+ // Note that since rect is in logical units, rect.Right corresponds to
// the visual *left* edge of the rectangle in the RTL case. Specifically,
// is the distance leftward from the right edge of the formatting rectangle
// whose width is the paragraph width passed to FormatLine.
@@ -1384,7 +1384,7 @@ namespace Avalonia.Media
else
{
accumulatedBounds = Geometry.Combine(accumulatedBounds, rectangleGeometry, GeometryCombineMode.Union);
- }
+ }
}
}
}
diff --git a/src/Avalonia.Base/Media/GeometryDrawing.cs b/src/Avalonia.Base/Media/GeometryDrawing.cs
index 26cc2c3cab..ac2dce1e42 100644
--- a/src/Avalonia.Base/Media/GeometryDrawing.cs
+++ b/src/Avalonia.Base/Media/GeometryDrawing.cs
@@ -15,8 +15,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty GeometryProperty =
- AvaloniaProperty.Register(nameof(Geometry));
+ public static readonly StyledProperty GeometryProperty =
+ AvaloniaProperty.Register(nameof(Geometry));
///
/// Defines the property.
@@ -34,7 +34,7 @@ namespace Avalonia.Media
/// Gets or sets the that describes the shape of this .
///
[Content]
- public Geometry Geometry
+ public Geometry? Geometry
{
get => GetValue(GeometryProperty);
set => SetValue(GeometryProperty, value);
diff --git a/src/Avalonia.Base/Media/GlyphRunDrawing.cs b/src/Avalonia.Base/Media/GlyphRunDrawing.cs
index 242b9913fa..06d92fd81c 100644
--- a/src/Avalonia.Base/Media/GlyphRunDrawing.cs
+++ b/src/Avalonia.Base/Media/GlyphRunDrawing.cs
@@ -2,19 +2,19 @@
{
public class GlyphRunDrawing : Drawing
{
- public static readonly StyledProperty ForegroundProperty =
- AvaloniaProperty.Register(nameof(Foreground));
+ public static readonly StyledProperty ForegroundProperty =
+ AvaloniaProperty.Register(nameof(Foreground));
- public static readonly StyledProperty GlyphRunProperty =
- AvaloniaProperty.Register(nameof(GlyphRun));
+ public static readonly StyledProperty GlyphRunProperty =
+ AvaloniaProperty.Register(nameof(GlyphRun));
- public IBrush Foreground
+ public IBrush? Foreground
{
get => GetValue(ForegroundProperty);
set => SetValue(ForegroundProperty, value);
}
- public GlyphRun GlyphRun
+ public GlyphRun? GlyphRun
{
get => GetValue(GlyphRunProperty);
set => SetValue(GlyphRunProperty, value);
diff --git a/src/Avalonia.Base/Media/HslColor.cs b/src/Avalonia.Base/Media/HslColor.cs
index 425a3138c3..b4bf6fd217 100644
--- a/src/Avalonia.Base/Media/HslColor.cs
+++ b/src/Avalonia.Base/Media/HslColor.cs
@@ -254,7 +254,7 @@ namespace Avalonia.Media
/// The HSL color string to parse.
/// The parsed .
/// True if parsing was successful; otherwise, false.
- public static bool TryParse(string s, out HslColor hslColor)
+ public static bool TryParse(string? s, out HslColor hslColor)
{
bool prefixMatched = false;
diff --git a/src/Avalonia.Base/Media/HsvColor.cs b/src/Avalonia.Base/Media/HsvColor.cs
index 9f95b31518..f97457c54d 100644
--- a/src/Avalonia.Base/Media/HsvColor.cs
+++ b/src/Avalonia.Base/Media/HsvColor.cs
@@ -254,7 +254,7 @@ namespace Avalonia.Media
/// The HSV color string to parse.
/// The parsed .
/// True if parsing was successful; otherwise, false.
- public static bool TryParse(string s, out HsvColor hsvColor)
+ public static bool TryParse(string? s, out HsvColor hsvColor)
{
bool prefixMatched = false;
diff --git a/src/Avalonia.Base/Media/IVisualBrush.cs b/src/Avalonia.Base/Media/IVisualBrush.cs
index 6662613ff4..a7d3e4da10 100644
--- a/src/Avalonia.Base/Media/IVisualBrush.cs
+++ b/src/Avalonia.Base/Media/IVisualBrush.cs
@@ -1,5 +1,4 @@
using Avalonia.Metadata;
-using Avalonia.VisualTree;
namespace Avalonia.Media
{
@@ -12,6 +11,6 @@ namespace Avalonia.Media
///
/// Gets the visual to draw.
///
- Visual Visual { get; }
+ Visual? Visual { get; }
}
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableDashStyle.cs b/src/Avalonia.Base/Media/Immutable/ImmutableDashStyle.cs
index 1f53f06955..6dff006045 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableDashStyle.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableDashStyle.cs
@@ -39,17 +39,8 @@ namespace Avalonia.Media.Immutable
{
return true;
}
- else if (other is null)
- {
- return false;
- }
- if (Offset != other.Offset)
- {
- return false;
- }
-
- return SequenceEqual(Dashes, other.Dashes);
+ return other is not null && Offset == other.Offset && SequenceEqual(_dashes, other.Dashes);
}
///
@@ -58,30 +49,27 @@ namespace Avalonia.Media.Immutable
var hashCode = 717868523;
hashCode = hashCode * -1521134295 + Offset.GetHashCode();
- if (_dashes != null)
+ foreach (var i in _dashes)
{
- foreach (var i in _dashes)
- {
- hashCode = hashCode * -1521134295 + i.GetHashCode();
- }
+ hashCode = hashCode * -1521134295 + i.GetHashCode();
}
return hashCode;
}
- private static bool SequenceEqual(IReadOnlyList left, IReadOnlyList? right)
+ private static bool SequenceEqual(double[] left, IReadOnlyList? right)
{
if (ReferenceEquals(left, right))
{
return true;
}
- if (left == null || right == null || left.Count != right.Count)
+ if (right is null || left.Length != right.Count)
{
return false;
}
- for (var c = 0; c < left.Count; c++)
+ for (var c = 0; c < left.Length; c++)
{
if (left[c] != right[c])
{
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
index 9b443391c5..0b625080e3 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
@@ -1,5 +1,4 @@
using Avalonia.Media.Imaging;
-using Avalonia.VisualTree;
namespace Avalonia.Media.Immutable
{
@@ -31,11 +30,11 @@ namespace Avalonia.Media.Immutable
RelativeRect? destinationRect = null,
double opacity = 1,
ImmutableTransform? transform = null,
- RelativePoint transformOrigin = new RelativePoint(),
+ RelativePoint transformOrigin = default,
RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform,
TileMode tileMode = TileMode.None,
- Imaging.BitmapInterpolationMode bitmapInterpolationMode = Imaging.BitmapInterpolationMode.Default)
+ BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
: base(
alignmentX,
alignmentY,
@@ -62,6 +61,6 @@ namespace Avalonia.Media.Immutable
}
///
- public Visual Visual { get; }
+ public Visual? Visual { get; }
}
}
diff --git a/src/Avalonia.Base/Media/TextDecoration.cs b/src/Avalonia.Base/Media/TextDecoration.cs
index dc9e5cb907..b74b7df9c5 100644
--- a/src/Avalonia.Base/Media/TextDecoration.cs
+++ b/src/Avalonia.Base/Media/TextDecoration.cs
@@ -22,8 +22,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty StrokeProperty =
- AvaloniaProperty.Register(nameof(Stroke));
+ public static readonly StyledProperty StrokeProperty =
+ AvaloniaProperty.Register(nameof(Stroke));
///
/// Defines the property.
@@ -34,8 +34,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty> StrokeDashArrayProperty =
- AvaloniaProperty.Register>(nameof(StrokeDashArray));
+ public static readonly StyledProperty?> StrokeDashArrayProperty =
+ AvaloniaProperty.Register?>(nameof(StrokeDashArray));
///
/// Defines the property.
@@ -82,7 +82,7 @@ namespace Avalonia.Media
///
/// Gets or sets the that specifies how the is painted.
///
- public IBrush Stroke
+ public IBrush? Stroke
{
get { return GetValue(StrokeProperty); }
set { SetValue(StrokeProperty, value); }
@@ -101,7 +101,7 @@ namespace Avalonia.Media
/// Gets or sets a collection of values that indicate the pattern of dashes and gaps
/// that is used to draw the .
///
- public AvaloniaList StrokeDashArray
+ public AvaloniaList? StrokeDashArray
{
get { return GetValue(StrokeDashArrayProperty); }
set { SetValue(StrokeDashArrayProperty, value); }
@@ -220,7 +220,7 @@ namespace Avalonia.Media
var intersections = glyphRun.PlatformImpl.Item.GetIntersections((float)(thickness * 0.5d - offsetY), (float)(thickness * 1.5d - offsetY));
- if (intersections != null && intersections.Count > 0)
+ if (intersections.Count > 0)
{
var last = baselineOrigin.X;
var finalPos = last + glyphRun.Size.Width;
diff --git a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
index c9dafaced7..b4734d702b 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
@@ -118,14 +118,17 @@ namespace Avalonia.Media.TextFormatting
fontManager.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight,
defaultTypeface.Stretch, defaultTypeface.FontFamily, defaultProperties.CultureInfo,
out var fallbackTypeface);
-
- var fallbackGlyphTypeface = fontManager.GetOrAddGlyphTypeface(fallbackTypeface);
-
- if (matchFound && TryGetShapeableLength(textSpan, fallbackGlyphTypeface, defaultGlyphTypeface, out count))
+
+ if (matchFound)
{
- //Fallback found
- return new UnshapedTextRun(text.Slice(0, count), defaultProperties.WithTypeface(fallbackTypeface),
- biDiLevel);
+ // Fallback found
+ var fallbackGlyphTypeface = fontManager.GetOrAddGlyphTypeface(fallbackTypeface);
+
+ if (TryGetShapeableLength(textSpan, fallbackGlyphTypeface, defaultGlyphTypeface, out count))
+ {
+ return new UnshapedTextRun(text.Slice(0, count), defaultProperties.WithTypeface(fallbackTypeface),
+ biDiLevel);
+ }
}
// no fallback found
diff --git a/src/Avalonia.Base/Media/VisualBrush.cs b/src/Avalonia.Base/Media/VisualBrush.cs
index 1261d233ac..2be3e9a94e 100644
--- a/src/Avalonia.Base/Media/VisualBrush.cs
+++ b/src/Avalonia.Base/Media/VisualBrush.cs
@@ -1,5 +1,4 @@
using Avalonia.Media.Immutable;
-using Avalonia.VisualTree;
namespace Avalonia.Media
{
@@ -11,8 +10,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty VisualProperty =
- AvaloniaProperty.Register(nameof(Visual));
+ public static readonly StyledProperty VisualProperty =
+ AvaloniaProperty.Register(nameof(Visual));
static VisualBrush()
{
@@ -38,7 +37,7 @@ namespace Avalonia.Media
///
/// Gets or sets the visual to draw.
///
- public Visual Visual
+ public Visual? Visual
{
get { return GetValue(VisualProperty); }
set { SetValue(VisualProperty, value); }
diff --git a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
index c05c04c22e..8509067cd0 100644
--- a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
+++ b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
@@ -49,7 +49,7 @@ namespace Avalonia.Platform
/// The stroke pen.
/// The first point of the line.
/// The second point of the line.
- void DrawLine(IPen pen, Point p1, Point p2);
+ void DrawLine(IPen? pen, Point p1, Point p2);
///
/// Draws a geometry.
@@ -91,7 +91,7 @@ namespace Avalonia.Platform
///
/// The foreground.
/// The glyph run.
- void DrawGlyphRun(IBrush foreground, IRef glyphRun);
+ void DrawGlyphRun(IBrush? foreground, IRef glyphRun);
///
/// Creates a new that can be used as a render layer
diff --git a/src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs b/src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs
new file mode 100644
index 0000000000..227e65c08d
--- /dev/null
+++ b/src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+
+namespace Avalonia.Platform
+{
+ ///
+ /// Allows to inhibit platform specific behavior.
+ ///
+ public interface IPlatformBehaviorInhibition
+ {
+ Task SetInhibitAppSleep(bool inhibitAppSleep, string reason);
+ }
+}
diff --git a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
index bf18a7da5b..3dbc7c1bb2 100644
--- a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
+++ b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
@@ -26,6 +26,6 @@ namespace Avalonia.Platform
bool CurrentThreadIsLoopThread { get; }
- event Action Signaled;
+ event Action? Signaled;
}
}
diff --git a/src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs b/src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs
index 467cd530fc..6a577c204c 100644
--- a/src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs
+++ b/src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -18,26 +19,21 @@ internal class AssemblyDescriptor : IAssemblyDescriptor
{
public AssemblyDescriptor(Assembly assembly)
{
- Assembly = assembly;
+ Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
+ Resources = assembly.GetManifestResourceNames()
+ .ToDictionary(n => n, n => (IAssetDescriptor)new AssemblyResourceDescriptor(assembly, n));
+ Name = assembly.GetName().Name;
- if (assembly != null)
+ using var resources = assembly.GetManifestResourceStream(Constants.AvaloniaResourceName);
+ if (resources != null)
{
- Resources = assembly.GetManifestResourceNames()
- .ToDictionary(n => n, n => (IAssetDescriptor)new AssemblyResourceDescriptor(assembly, n));
- Name = assembly.GetName().Name;
- using (var resources = assembly.GetManifestResourceStream(Constants.AvaloniaResourceName))
- {
- if (resources != null)
- {
- Resources.Remove(Constants.AvaloniaResourceName);
+ Resources.Remove(Constants.AvaloniaResourceName);
- var indexLength = new BinaryReader(resources).ReadInt32();
- var index = AvaloniaResourcesIndexReaderWriter.ReadIndex(new SlicedStream(resources, 4, indexLength));
- var baseOffset = indexLength + 4;
- AvaloniaResources = index.ToDictionary(r => GetPathRooted(r), r => (IAssetDescriptor)
- new AvaloniaResourceDescriptor(assembly, baseOffset + r.Offset, r.Size));
- }
- }
+ var indexLength = new BinaryReader(resources).ReadInt32();
+ var index = AvaloniaResourcesIndexReaderWriter.ReadIndex(new SlicedStream(resources, 4, indexLength));
+ var baseOffset = indexLength + 4;
+ AvaloniaResources = index.ToDictionary(GetPathRooted, r => (IAssetDescriptor)
+ new AvaloniaResourceDescriptor(assembly, baseOffset + r.Offset, r.Size));
}
}
@@ -45,6 +41,7 @@ internal class AssemblyDescriptor : IAssemblyDescriptor
public Dictionary? Resources { get; }
public Dictionary? AvaloniaResources { get; }
public string? Name { get; }
+
private static string GetPathRooted(AvaloniaResourcesIndexEntry r) =>
r.Path![0] == '/' ? r.Path : '/' + r.Path;
}
diff --git a/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs b/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs
index 75076e2bb8..f9c7f9685d 100644
--- a/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs
+++ b/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs
@@ -7,9 +7,9 @@ namespace Avalonia.Platform.Storage;
///
public sealed class FilePickerFileType
{
- public FilePickerFileType(string name)
+ public FilePickerFileType(string? name)
{
- Name = name;
+ Name = name ?? string.Empty;
}
///
diff --git a/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs b/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs
index 11dc80ef8f..e1ff0970c2 100644
--- a/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs
+++ b/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs
@@ -16,6 +16,8 @@ namespace Avalonia.PropertyStore
private IDisposable? _subscription;
private bool _hasValue;
private TValue? _value;
+ private TValue? _defaultValue;
+ private bool _isDefaultValueInitialized;
protected BindingEntryBase(
ValueFrame frame,
@@ -89,6 +91,7 @@ namespace Avalonia.PropertyStore
protected abstract BindingValue ConvertAndValidate(TSource value);
protected abstract BindingValue ConvertAndValidate(BindingValue value);
+ protected abstract TValue GetDefaultValue(Type ownerType);
protected virtual void Start(bool produceValue)
{
@@ -104,17 +107,6 @@ namespace Avalonia.PropertyStore
};
}
- private void ClearValue()
- {
- if (_hasValue)
- {
- _hasValue = false;
- _value = default;
- if (_subscription is not null)
- Frame.Owner?.OnBindingValueCleared(Property, Frame.Priority);
- }
- }
-
private void SetValue(BindingValue value)
{
static void Execute(BindingEntryBase instance, BindingValue value)
@@ -124,24 +116,20 @@ namespace Avalonia.PropertyStore
LoggingUtils.LogIfNecessary(instance.Frame.Owner.Owner, instance.Property, value);
- if (value.HasValue)
- {
- if (!instance._hasValue || !EqualityComparer.Default.Equals(instance._value, value.Value))
- {
- instance._value = value.Value;
- instance._hasValue = true;
- if (instance._subscription is not null && instance._subscription != s_creatingQuiet)
- instance.Frame.Owner?.OnBindingValueChanged(instance, instance.Frame.Priority);
- }
- }
- else if (value.Type != BindingValueType.DoNothing)
+ var effectiveValue = value.HasValue ? value.Value : instance.GetCachedDefaultValue();
+
+ if (!instance._hasValue || !EqualityComparer.Default.Equals(instance._value, effectiveValue))
{
- instance.ClearValue();
+ instance._value = effectiveValue;
+ instance._hasValue = true;
if (instance._subscription is not null && instance._subscription != s_creatingQuiet)
- instance.Frame.Owner?.OnBindingValueCleared(instance.Property, instance.Frame.Priority);
+ instance.Frame.Owner?.OnBindingValueChanged(instance, instance.Frame.Priority);
}
}
+ if (value.Type == BindingValueType.DoNothing)
+ return;
+
if (Dispatcher.UIThread.CheckAccess())
{
Execute(this, value);
@@ -161,5 +149,16 @@ namespace Avalonia.PropertyStore
_subscription = null;
Frame.OnBindingCompleted(this);
}
+
+ private TValue GetCachedDefaultValue()
+ {
+ if (!_isDefaultValueInitialized)
+ {
+ _defaultValue = GetDefaultValue(Frame.Owner!.Owner.GetType());
+ _isDefaultValueInitialized = true;
+ }
+
+ return _defaultValue!;
+ }
}
}
diff --git a/src/Avalonia.Base/PropertyStore/EffectiveValue.cs b/src/Avalonia.Base/PropertyStore/EffectiveValue.cs
index 04d3c805c2..78f0ad46b7 100644
--- a/src/Avalonia.Base/PropertyStore/EffectiveValue.cs
+++ b/src/Avalonia.Base/PropertyStore/EffectiveValue.cs
@@ -29,6 +29,12 @@ namespace Avalonia.PropertyStore
///
public BindingPriority BasePriority { get; protected set; }
+ ///
+ /// Gets a value indicating whether the was overridden by a call to
+ /// .
+ ///
+ public bool IsOverridenCurrentValue { get; set; }
+
///
/// Begins a reevaluation pass on the effective value.
///
diff --git a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
index 3e20dcce56..0d93e9d8ed 100644
--- a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
+++ b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
@@ -57,7 +57,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(priority != BindingPriority.LocalValue);
UpdateValueEntry(value, priority);
- SetAndRaiseCore(owner, (StyledProperty)value.Property, GetValue(value), priority);
+ SetAndRaiseCore(owner, (StyledProperty)value.Property, GetValue(value), priority, false);
}
public void SetLocalValueAndRaise(
@@ -65,7 +65,16 @@ namespace Avalonia.PropertyStore
StyledProperty property,
T value)
{
- SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue);
+ SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue, false);
+ }
+
+ public void SetCurrentValueAndRaise(
+ ValueStore owner,
+ StyledProperty property,
+ T value)
+ {
+ IsOverridenCurrentValue = true;
+ SetAndRaiseCore(owner, property, value, Priority, true);
}
public bool TryGetBaseValue([MaybeNullWhen(false)] out T value)
@@ -98,7 +107,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(Priority != BindingPriority.Animation);
Debug.Assert(BasePriority != BindingPriority.Unset);
UpdateValueEntry(null, BindingPriority.Animation);
- SetAndRaiseCore(owner, (StyledProperty)property, _baseValue!, BasePriority);
+ SetAndRaiseCore(owner, (StyledProperty)property, _baseValue!, BasePriority, false);
}
public override void CoerceValue(ValueStore owner, AvaloniaProperty property)
@@ -158,15 +167,16 @@ namespace Avalonia.PropertyStore
ValueStore owner,
StyledProperty property,
T value,
- BindingPriority priority)
+ BindingPriority priority,
+ bool isOverriddenCurrentValue)
{
- Debug.Assert(priority < BindingPriority.Inherited);
-
var oldValue = Value;
var valueChanged = false;
var baseValueChanged = false;
var v = value;
+ IsOverridenCurrentValue = isOverriddenCurrentValue;
+
if (_uncommon?._coerce is { } coerce)
v = coerce(owner.Owner, value);
@@ -209,7 +219,6 @@ namespace Avalonia.PropertyStore
T baseValue,
BindingPriority basePriority)
{
- Debug.Assert(priority < BindingPriority.Inherited);
Debug.Assert(basePriority > BindingPriority.Animation);
Debug.Assert(priority <= basePriority);
@@ -225,7 +234,7 @@ namespace Avalonia.PropertyStore
bv = coerce(owner.Owner, baseValue);
}
- if (priority != BindingPriority.Unset && !EqualityComparer.Default.Equals(Value, v))
+ if (!EqualityComparer.Default.Equals(Value, v))
{
Value = v;
valueChanged = true;
@@ -233,9 +242,7 @@ namespace Avalonia.PropertyStore
_uncommon._uncoercedValue = value;
}
- if (priority != BindingPriority.Unset &&
- (BasePriority == BindingPriority.Unset ||
- !EqualityComparer.Default.Equals(_baseValue, bv)))
+ if (!EqualityComparer.Default.Equals(_baseValue, bv))
{
_baseValue = v;
baseValueChanged = true;
diff --git a/src/Avalonia.Base/PropertyStore/LocalValueBindingObserver.cs b/src/Avalonia.Base/PropertyStore/LocalValueBindingObserver.cs
index f89cb029b6..5908d9e535 100644
--- a/src/Avalonia.Base/PropertyStore/LocalValueBindingObserver.cs
+++ b/src/Avalonia.Base/PropertyStore/LocalValueBindingObserver.cs
@@ -10,6 +10,8 @@ namespace Avalonia.PropertyStore
{
private readonly ValueStore _owner;
private IDisposable? _subscription;
+ private T? _defaultValue;
+ private bool _isDefaultValueInitialized;
public LocalValueBindingObserver(ValueStore owner, StyledProperty property)
{
@@ -41,26 +43,28 @@ namespace Avalonia.PropertyStore
public void OnNext(T value)
{
- static void Execute(ValueStore owner, StyledProperty property, T value)
+ static void Execute(LocalValueBindingObserver instance, T value)
{
- if (property.ValidateValue?.Invoke(value) != false)
- owner.SetValue(property, value, BindingPriority.LocalValue);
- else
- owner.ClearLocalValue(property);
+ var owner = instance._owner;
+ var property = instance.Property;
+
+ if (property.ValidateValue?.Invoke(value) == false)
+ value = instance.GetCachedDefaultValue();
+
+ owner.SetValue(property, value, BindingPriority.LocalValue);
}
if (Dispatcher.UIThread.CheckAccess())
{
- Execute(_owner, Property, value);
+ Execute(this, value);
}
else
{
// To avoid allocating closure in the outer scope we need to capture variables
// locally. This allows us to skip most of the allocations when on UI thread.
- var instance = _owner;
- var property = Property;
+ var instance = this;
var newValue = value;
- Dispatcher.UIThread.Post(() => Execute(instance, property, newValue));
+ Dispatcher.UIThread.Post(() => Execute(instance, newValue));
}
}
@@ -74,11 +78,21 @@ namespace Avalonia.PropertyStore
LoggingUtils.LogIfNecessary(owner.Owner, property, value);
if (value.HasValue)
- owner.SetValue(property, value.Value, BindingPriority.LocalValue);
- else if (value.Type != BindingValueType.DataValidationError)
- owner.ClearLocalValue(property);
+ {
+ var effectiveValue = value.Value;
+ if (property.ValidateValue?.Invoke(effectiveValue) == false)
+ effectiveValue = instance.GetCachedDefaultValue();
+ owner.SetValue(property, effectiveValue, BindingPriority.LocalValue);
+ }
+ else
+ {
+ owner.SetValue(property, instance.GetCachedDefaultValue(), BindingPriority.LocalValue);
+ }
}
+ if (value.Type is BindingValueType.DoNothing or BindingValueType.DataValidationError)
+ return;
+
if (Dispatcher.UIThread.CheckAccess())
{
Execute(this, value);
@@ -92,5 +106,16 @@ namespace Avalonia.PropertyStore
Dispatcher.UIThread.Post(() => Execute(instance, newValue));
}
}
+
+ private T GetCachedDefaultValue()
+ {
+ if (!_isDefaultValueInitialized)
+ {
+ _defaultValue = Property.GetDefaultValue(_owner.Owner.GetType());
+ _isDefaultValueInitialized = true;
+ }
+
+ return _defaultValue!;
+ }
}
}
diff --git a/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs b/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs
index 2d157b2519..46e6ed810a 100644
--- a/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs
+++ b/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs
@@ -1,5 +1,4 @@
using System;
-using System.Security.Cryptography;
using Avalonia.Data;
using Avalonia.Threading;
@@ -10,6 +9,8 @@ namespace Avalonia.PropertyStore
{
private readonly ValueStore _owner;
private IDisposable? _subscription;
+ private T? _defaultValue;
+ private bool _isDefaultValueInitialized;
public LocalValueUntypedBindingObserver(ValueStore owner, StyledProperty property)
{
@@ -49,11 +50,7 @@ namespace Avalonia.PropertyStore
if (value == AvaloniaProperty.UnsetValue)
{
- owner.ClearLocalValue(property);
- }
- else if (value == BindingOperations.DoNothing)
- {
- // Do nothing!
+ owner.SetValue(property, instance.GetCachedDefaultValue(), BindingPriority.LocalValue);
}
else if (UntypedValueUtils.TryConvertAndValidate(property, value, out var typedValue))
{
@@ -61,11 +58,14 @@ namespace Avalonia.PropertyStore
}
else
{
- owner.ClearLocalValue(property);
+ owner.SetValue(property, instance.GetCachedDefaultValue(), BindingPriority.LocalValue);
LoggingUtils.LogInvalidValue(owner.Owner, property, typeof(T), value);
}
}
+ if (value == BindingOperations.DoNothing)
+ return;
+
if (Dispatcher.UIThread.CheckAccess())
{
Execute(this, value);
@@ -79,5 +79,16 @@ namespace Avalonia.PropertyStore
Dispatcher.UIThread.Post(() => Execute(instance, newValue));
}
}
+
+ private T GetCachedDefaultValue()
+ {
+ if (!_isDefaultValueInitialized)
+ {
+ _defaultValue = Property.GetDefaultValue(_owner.Owner.GetType());
+ _isDefaultValueInitialized = true;
+ }
+
+ return _defaultValue!;
+ }
}
}
diff --git a/src/Avalonia.Base/PropertyStore/SourceUntypedBindingEntry.cs b/src/Avalonia.Base/PropertyStore/SourceUntypedBindingEntry.cs
index b56d0d4529..b82714817b 100644
--- a/src/Avalonia.Base/PropertyStore/SourceUntypedBindingEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/SourceUntypedBindingEntry.cs
@@ -31,5 +31,7 @@ namespace Avalonia.PropertyStore
{
throw new NotSupportedException();
}
+
+ protected override TTarget GetDefaultValue(Type ownerType) => Property.GetDefaultValue(ownerType);
}
}
diff --git a/src/Avalonia.Base/PropertyStore/TypedBindingEntry.cs b/src/Avalonia.Base/PropertyStore/TypedBindingEntry.cs
index 697725c87b..550f5c0001 100644
--- a/src/Avalonia.Base/PropertyStore/TypedBindingEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/TypedBindingEntry.cs
@@ -48,5 +48,7 @@ namespace Avalonia.PropertyStore
return value;
}
+
+ protected override T GetDefaultValue(Type ownerType) => Property.GetDefaultValue(ownerType);
}
}
diff --git a/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs b/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs
index f8becb2e06..a77d7fddb6 100644
--- a/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs
@@ -29,5 +29,10 @@ namespace Avalonia.PropertyStore
{
throw new NotSupportedException();
}
+
+ protected override object? GetDefaultValue(Type ownerType)
+ {
+ return ((IStyledPropertyMetadata)Property.GetMetadata(ownerType)).DefaultValue;
+ }
}
}
diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs
index f36a96992b..8b702665f8 100644
--- a/src/Avalonia.Base/PropertyStore/ValueStore.cs
+++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs
@@ -7,7 +7,6 @@ using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Styling;
using Avalonia.Utilities;
-using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
namespace Avalonia.PropertyStore
{
@@ -156,11 +155,12 @@ namespace Avalonia.PropertyStore
return observer;
}
- public void ClearLocalValue(AvaloniaProperty property)
+ public void ClearValue(AvaloniaProperty property)
{
if (TryGetEffectiveValue(property, out var effective) &&
- effective.Priority == BindingPriority.LocalValue)
+ (effective.Priority == BindingPriority.LocalValue || effective.IsOverridenCurrentValue))
{
+ effective.IsOverridenCurrentValue = false;
ReevaluateEffectiveValue(property, effective, ignoreLocalValue: true);
}
}
@@ -209,6 +209,20 @@ namespace Avalonia.PropertyStore
}
}
+ public void SetCurrentValue(StyledProperty property, T value)
+ {
+ if (TryGetEffectiveValue(property, out var v))
+ {
+ ((EffectiveValue)v).SetCurrentValueAndRaise(this, property, value);
+ }
+ else
+ {
+ var effectiveValue = new EffectiveValue(Owner, property);
+ AddEffectiveValue(property, effectiveValue);
+ effectiveValue.SetCurrentValueAndRaise(this, property, value);
+ }
+ }
+
public object? GetValue(AvaloniaProperty property)
{
if (_effectiveValues.TryGetValue(property, out var v))
@@ -235,12 +249,7 @@ namespace Avalonia.PropertyStore
return false;
}
- public bool IsSet(AvaloniaProperty property)
- {
- if (_effectiveValues.TryGetValue(property, out var v))
- return v.Priority < BindingPriority.Inherited;
- return false;
- }
+ public bool IsSet(AvaloniaProperty property) => _effectiveValues.TryGetValue(property, out _);
public void CoerceValue(AvaloniaProperty property)
{
@@ -380,23 +389,6 @@ namespace Avalonia.PropertyStore
}
}
- ///
- /// Called by non-LocalValue binding entries to re-evaluate the effective value when the
- /// binding produces an unset value.
- ///
- /// The bound property.
- /// The priority of binding which produced a new value.
- public void OnBindingValueCleared(AvaloniaProperty property, BindingPriority priority)
- {
- Debug.Assert(priority != BindingPriority.LocalValue);
-
- if (TryGetEffectiveValue(property, out var existing))
- {
- if (priority <= existing.Priority)
- ReevaluateEffectiveValue(property, existing);
- }
- }
-
///
/// Called by a when its
/// state changes.
@@ -507,7 +499,7 @@ namespace Avalonia.PropertyStore
if (existing == observer)
{
_localValueBindings?.Remove(property.Id);
- ClearLocalValue(property);
+ ClearValue(property);
}
}
}
@@ -633,11 +625,13 @@ namespace Avalonia.PropertyStore
{
object? value;
BindingPriority priority;
+ bool overridden = false;
if (_effectiveValues.TryGetValue(property, out var v))
{
value = v.Value;
priority = v.Priority;
+ overridden = v.IsOverridenCurrentValue;
}
else if (property.Inherits && TryGetInheritedValue(property, out v))
{
@@ -654,7 +648,8 @@ namespace Avalonia.PropertyStore
property,
value,
priority,
- null);
+ null,
+ overridden);
}
private int InsertFrame(ValueFrame frame)
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
index a6db4330a3..455e9ebb5f 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
@@ -23,7 +23,7 @@ namespace Avalonia.Rendering.Composition.Animations
public abstract class CompositionAnimation : CompositionObject, ICompositionAnimationBase
{
private readonly CompositionPropertySet _propertySet;
- internal CompositionAnimation(Compositor compositor) : base(compositor, null!)
+ internal CompositionAnimation(Compositor compositor) : base(compositor, null)
{
_propertySet = new CompositionPropertySet(compositor);
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs
index bad3991f43..1500e88abe 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimationGroup.cs
@@ -19,7 +19,7 @@ namespace Avalonia.Rendering.Composition.Animations
public void Remove(CompositionAnimation value) => Animations.Remove(value);
public void RemoveAll() => Animations.Clear();
- public CompositionAnimationGroup(Compositor compositor) : base(compositor, null!)
+ public CompositionAnimationGroup(Compositor compositor) : base(compositor, null)
{
}
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
index 72be4edd07..d9adf261f8 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
@@ -23,7 +23,7 @@ namespace Avalonia.Rendering.Composition.Animations
{
private Dictionary _inner = new Dictionary();
private IDictionary _innerface;
- internal ImplicitAnimationCollection(Compositor compositor) : base(compositor, null!)
+ internal ImplicitAnimationCollection(Compositor compositor) : base(compositor, null)
{
_innerface = _inner;
}
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
index 668d650ffd..7fa2d4955f 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
@@ -20,15 +20,17 @@ public class CompositingRenderer : IRendererWithCompositor
{
private readonly IRenderRoot _root;
private readonly Compositor _compositor;
- CompositionDrawingContext _recorder = new();
- DrawingContext _recordingContext;
- private HashSet _dirty = new();
- private HashSet _recalculateChildren = new();
+ private readonly CompositionDrawingContext _recorder = new();
+ private readonly DrawingContext _recordingContext;
+ private readonly HashSet _dirty = new();
+ private readonly HashSet _recalculateChildren = new();
+ private readonly Action _update;
+
private bool _queuedUpdate;
- private Action _update;
private bool _updating;
+ private bool _isDisposed;
- internal CompositionTarget CompositionTarget;
+ internal CompositionTarget CompositionTarget { get; }
///
/// Asks the renderer to only draw frames on the render thread. Makes Paint to wait until frame is rendered.
@@ -38,6 +40,17 @@ public class CompositingRenderer : IRendererWithCompositor
///
public RendererDiagnostics Diagnostics { get; }
+ ///
+ public Compositor Compositor => _compositor;
+
+ ///
+ /// Initializes a new instance of
+ ///
+ /// The render root using this renderer.
+ /// The associated compositors.
+ ///
+ /// A function returning the list of native platform's surfaces that can be consumed by rendering subsystems.
+ ///
public CompositingRenderer(IRenderRoot root, Compositor compositor, Func> surfaces)
{
_root = root;
@@ -66,7 +79,7 @@ public class CompositingRenderer : IRendererWithCompositor
///
public event EventHandler? SceneInvalidated;
- void QueueUpdate()
+ private void QueueUpdate()
{
if(_queuedUpdate)
return;
@@ -77,9 +90,11 @@ public class CompositingRenderer : IRendererWithCompositor
///
public void AddDirty(Visual visual)
{
+ if (_isDisposed)
+ return;
if (_updating)
throw new InvalidOperationException("Visual was invalidated during the render pass");
- _dirty.Add((Visual)visual);
+ _dirty.Add(visual);
QueueUpdate();
}
@@ -126,9 +141,11 @@ public class CompositingRenderer : IRendererWithCompositor
///
public void RecalculateChildren(Visual visual)
{
+ if (_isDisposed)
+ return;
if (_updating)
throw new InvalidOperationException("Visual was invalidated during the render pass");
- _recalculateChildren.Add((Visual)visual);
+ _recalculateChildren.Add(visual);
QueueUpdate();
}
@@ -171,7 +188,7 @@ public class CompositingRenderer : IRendererWithCompositor
if (sortedChildren != null)
for (var c = 0; c < visualChildren.Count; c++)
{
- if (!ReferenceEquals(compositionChildren[c], ((Visual)sortedChildren[c].visual).CompositionVisual))
+ if (!ReferenceEquals(compositionChildren[c], sortedChildren[c].visual.CompositionVisual))
{
mismatch = true;
break;
@@ -179,7 +196,7 @@ public class CompositingRenderer : IRendererWithCompositor
}
else
for (var c = 0; c < visualChildren.Count; c++)
- if (!ReferenceEquals(compositionChildren[c], ((Visual)visualChildren[c]).CompositionVisual))
+ if (!ReferenceEquals(compositionChildren[c], visualChildren[c].CompositionVisual))
{
mismatch = true;
break;
@@ -201,7 +218,7 @@ public class CompositingRenderer : IRendererWithCompositor
{
foreach (var ch in sortedChildren)
{
- var compositionChild = ((Visual)ch.visual).CompositionVisual;
+ var compositionChild = ch.visual.CompositionVisual;
if (compositionChild != null)
compositionChildren.Add(compositionChild);
}
@@ -210,7 +227,7 @@ public class CompositingRenderer : IRendererWithCompositor
else
foreach (var ch in v.GetVisualChildren())
{
- var compositionChild = ((Visual)ch).CompositionVisual;
+ var compositionChild = ch.CompositionVisual;
if (compositionChild != null)
compositionChildren.Add(compositionChild);
}
@@ -289,13 +306,18 @@ public class CompositingRenderer : IRendererWithCompositor
_updating = false;
}
}
-
+
+ ///
public void Resized(Size size)
{
}
+ ///
public void Paint(Rect rect)
{
+ if (_isDisposed)
+ return;
+
QueueUpdate();
CompositionTarget.RequestRedraw();
if(RenderOnlyOnRenderThread && Compositor.Loop.RunsInBackground)
@@ -304,17 +326,34 @@ public class CompositingRenderer : IRendererWithCompositor
CompositionTarget.ImmediateUIThreadRender();
}
- public void Start() => CompositionTarget.IsEnabled = true;
-
- public void Stop()
+ ///
+ public void Start()
{
- CompositionTarget.IsEnabled = false;
+ if (_isDisposed)
+ return;
+
+ CompositionTarget.IsEnabled = true;
}
- public ValueTask TryGetRenderInterfaceFeature(Type featureType) => Compositor.TryGetRenderInterfaceFeature(featureType);
+ ///
+ public void Stop()
+ => CompositionTarget.IsEnabled = false;
+
+ ///
+ public ValueTask TryGetRenderInterfaceFeature(Type featureType)
+ => Compositor.TryGetRenderInterfaceFeature(featureType);
+ ///
public void Dispose()
{
+ if (_isDisposed)
+ return;
+
+ _isDisposed = true;
+ _dirty.Clear();
+ _recalculateChildren.Clear();
+ SceneInvalidated = null;
+
Stop();
CompositionTarget.Dispose();
@@ -323,9 +362,4 @@ public class CompositingRenderer : IRendererWithCompositor
if (Compositor.Loop.RunsInBackground)
_compositor.Commit().Wait();
}
-
- ///
- /// The associated object
- ///
- public Compositor Compositor => _compositor;
}
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionDrawingSurface.cs b/src/Avalonia.Base/Rendering/Composition/CompositionDrawingSurface.cs
index ab4329df62..bfe70d593d 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionDrawingSurface.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionDrawingSurface.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading.Tasks;
using Avalonia.Rendering.Composition.Server;
using Avalonia.Threading;
@@ -7,7 +6,7 @@ namespace Avalonia.Rendering.Composition;
public class CompositionDrawingSurface : CompositionSurface
{
- internal new ServerCompositionDrawingSurface Server => (ServerCompositionDrawingSurface)base.Server;
+ internal new ServerCompositionDrawingSurface Server => (ServerCompositionDrawingSurface)base.Server!;
internal CompositionDrawingSurface(Compositor compositor) : base(compositor, new ServerCompositionDrawingSurface(compositor.Server))
{
}
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs b/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
index 50332926ad..8c21b534db 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
@@ -22,7 +22,7 @@ namespace Avalonia.Rendering.Composition
public ImplicitAnimationCollection? ImplicitAnimations { get; set; }
private protected InlineDictionary PendingAnimations;
- internal CompositionObject(Compositor compositor, ServerObject server)
+ internal CompositionObject(Compositor compositor, ServerObject? server)
{
Compositor = compositor;
Server = server;
@@ -32,7 +32,7 @@ namespace Avalonia.Rendering.Composition
/// The associated Compositor
///
public Compositor Compositor { get; }
- internal ServerObject Server { get; }
+ internal ServerObject? Server { get; }
public bool IsDisposed { get; private set; }
private bool _registeredForSerialization;
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs b/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
index 7d794af9a2..efd89951bb 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
@@ -23,7 +23,7 @@ namespace Avalonia.Rendering.Composition
private readonly Dictionary _variants = new Dictionary();
private readonly Dictionary _objects = new Dictionary();
- internal CompositionPropertySet(Compositor compositor) : base(compositor, null!)
+ internal CompositionPropertySet(Compositor compositor) : base(compositor, null)
{
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
index 05488a558f..b75d080cfd 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
@@ -88,8 +88,13 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW
}
///
- public void DrawLine(IPen pen, Point p1, Point p2)
+ public void DrawLine(IPen? pen, Point p1, Point p2)
{
+ if (pen is null)
+ {
+ return;
+ }
+
var next = NextDrawAs();
if (next == null || !next.Item.Equals(Transform, pen, p1, p2))
@@ -159,8 +164,13 @@ internal class CompositionDrawingContext : IDrawingContextImpl, IDrawingContextW
public object? GetFeature(Type t) => null;
///
- public void DrawGlyphRun(IBrush foreground, IRef glyphRun)
+ public void DrawGlyphRun(IBrush? foreground, IRef glyphRun)
{
+ if (foreground is null)
+ {
+ return;
+ }
+
var next = NextDrawAs();
if (next == null || !next.Item.Equals(Transform, foreground, glyphRun))
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
index 560ee05c10..b15da5d05d 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
@@ -165,8 +165,6 @@ namespace Avalonia.Rendering.Composition.Expressions
public override ExpressionVariant Evaluate(ref ExpressionEvaluationContext context)
{
- if (context.ForeignFunctionInterface == null)
- return default;
var args = new List();
foreach (var expr in Parameters)
args.Add(expr.Evaluate(ref context));
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs
index 9086c59aad..f268364b54 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionEvaluationContext.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using Avalonia.Rendering.Composition.Server;
// Special license applies License.md
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
index c58beebe7f..50df8bd32b 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
@@ -66,7 +66,7 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl, IDrawingCont
_impl.DrawBitmap(source, opacityMask, opacityMaskRect, destRect);
}
- public void DrawLine(IPen pen, Point p1, Point p2)
+ public void DrawLine(IPen? pen, Point p1, Point p2)
{
_impl.DrawLine(pen, p1, p2);
}
@@ -86,7 +86,7 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl, IDrawingCont
_impl.DrawEllipse(brush, pen, rect);
}
- public void DrawGlyphRun(IBrush foreground, IRef glyphRun)
+ public void DrawGlyphRun(IBrush? foreground, IRef glyphRun)
{
_impl.DrawGlyphRun(foreground, glyphRun);
}
diff --git a/src/Avalonia.Base/Rendering/DefaultRenderTimer.cs b/src/Avalonia.Base/Rendering/DefaultRenderTimer.cs
index d0d3dd9715..7b0fecf675 100644
--- a/src/Avalonia.Base/Rendering/DefaultRenderTimer.cs
+++ b/src/Avalonia.Base/Rendering/DefaultRenderTimer.cs
@@ -1,6 +1,4 @@
using System;
-using System.Diagnostics;
-using System.Threading.Tasks;
using Avalonia.Platform;
namespace Avalonia.Rendering
@@ -59,7 +57,8 @@ namespace Avalonia.Rendering
}
}
- public bool RunsInBackground => true;
+ ///
+ public virtual bool RunsInBackground => true;
///
/// Starts the timer.
diff --git a/src/Avalonia.Base/Rendering/IRenderLoop.cs b/src/Avalonia.Base/Rendering/IRenderLoop.cs
index e500ecdf8b..ebe683949d 100644
--- a/src/Avalonia.Base/Rendering/IRenderLoop.cs
+++ b/src/Avalonia.Base/Rendering/IRenderLoop.cs
@@ -27,7 +27,10 @@ namespace Avalonia.Rendering
///
/// The update task.
void Remove(IRenderLoopTask i);
-
+
+ ///
+ /// Indicates if the rendering is done on a non-UI thread.
+ ///
bool RunsInBackground { get; }
}
}
diff --git a/src/Avalonia.Base/Rendering/IRenderRoot.cs b/src/Avalonia.Base/Rendering/IRenderRoot.cs
index fa3260ffb4..09df7b7830 100644
--- a/src/Avalonia.Base/Rendering/IRenderRoot.cs
+++ b/src/Avalonia.Base/Rendering/IRenderRoot.cs
@@ -1,6 +1,4 @@
using Avalonia.Metadata;
-using Avalonia.Platform;
-using Avalonia.VisualTree;
namespace Avalonia.Rendering
{
diff --git a/src/Avalonia.Base/Rendering/IRenderTimer.cs b/src/Avalonia.Base/Rendering/IRenderTimer.cs
index 07af7eeec8..14fcffd6a9 100644
--- a/src/Avalonia.Base/Rendering/IRenderTimer.cs
+++ b/src/Avalonia.Base/Rendering/IRenderTimer.cs
@@ -1,5 +1,4 @@
using System;
-using System.Threading.Tasks;
using Avalonia.Metadata;
namespace Avalonia.Rendering
diff --git a/src/Avalonia.Base/Rendering/IRenderer.cs b/src/Avalonia.Base/Rendering/IRenderer.cs
index ba960ff5f3..7e32504e17 100644
--- a/src/Avalonia.Base/Rendering/IRenderer.cs
+++ b/src/Avalonia.Base/Rendering/IRenderer.cs
@@ -90,6 +90,9 @@ namespace Avalonia.Rendering
public interface IRendererWithCompositor : IRenderer
{
+ ///
+ /// The associated object
+ ///
Compositor Compositor { get; }
}
}
diff --git a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs
index c67ac7057d..8e5dc38317 100644
--- a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs
+++ b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs
@@ -48,8 +48,10 @@ namespace Avalonia.Rendering
///
void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush)
{
- var visual = brush.Visual;
- Render(new DrawingContext(context), visual, visual.Bounds);
+ if (brush.Visual is { } visual)
+ {
+ Render(new DrawingContext(context), visual, visual.Bounds);
+ }
}
internal static void Render(Visual visual, DrawingContext context, bool updateTransformedBounds)
diff --git a/src/Avalonia.Base/Rendering/RenderLoop.cs b/src/Avalonia.Base/Rendering/RenderLoop.cs
index 1f58ca3827..185f44d29a 100644
--- a/src/Avalonia.Base/Rendering/RenderLoop.cs
+++ b/src/Avalonia.Base/Rendering/RenderLoop.cs
@@ -87,6 +87,7 @@ namespace Avalonia.Rendering
}
}
+ ///
public bool RunsInBackground => Timer.RunsInBackground;
private void TimerTick(TimeSpan time)
diff --git a/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs b/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs
index 12b67105e9..82f8fc2d56 100644
--- a/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs
+++ b/src/Avalonia.Base/Rendering/SceneGraph/ExperimentalAcrylicNode.cs
@@ -80,11 +80,8 @@ namespace Avalonia.Rendering.SceneGraph
{
p *= Transform.Invert();
- if (Material != null)
- {
- var rect = Rect.Rect;
- return rect.ContainsExclusive(p);
- }
+ var rect = Rect.Rect;
+ return rect.ContainsExclusive(p);
}
return false;
diff --git a/src/Avalonia.Base/Rendering/UiThreadRenderTimer.cs b/src/Avalonia.Base/Rendering/UiThreadRenderTimer.cs
index 1bbf804b5f..7f2eedc98c 100644
--- a/src/Avalonia.Base/Rendering/UiThreadRenderTimer.cs
+++ b/src/Avalonia.Base/Rendering/UiThreadRenderTimer.cs
@@ -8,13 +8,20 @@ namespace Avalonia.Rendering
///
/// Render timer that ticks on UI thread. Useful for debugging or bootstrapping on new platforms
///
-
public class UiThreadRenderTimer : DefaultRenderTimer
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of frames per second at which the loop should run.
public UiThreadRenderTimer(int framesPerSecond) : base(framesPerSecond)
{
}
+ ///
+ public override bool RunsInBackground => false;
+
+ ///
protected override IDisposable StartCore(Action tick)
{
bool cancelled = false;
diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs
index 5bf022cd51..2cdb973174 100644
--- a/src/Avalonia.Base/StyledElement.cs
+++ b/src/Avalonia.Base/StyledElement.cs
@@ -41,7 +41,11 @@ namespace Avalonia
public static readonly StyledProperty DataContextProperty =
AvaloniaProperty.Register(
nameof(DataContext),
+ defaultValue: null,
inherits: true,
+ defaultBindingMode: BindingMode.OneWay,
+ validate: null,
+ coerce: null,
notifying: DataContextNotifying);
///
diff --git a/src/Avalonia.Base/StyledProperty.cs b/src/Avalonia.Base/StyledProperty.cs
index 79d1b9202d..ad1f09066e 100644
--- a/src/Avalonia.Base/StyledProperty.cs
+++ b/src/Avalonia.Base/StyledProperty.cs
@@ -194,24 +194,48 @@ namespace Avalonia
}
///
- [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
internal override IDisposable? RouteSetValue(
AvaloniaObject target,
object? value,
BindingPriority priority)
+ {
+ if (ShouldSetValue(target, value, out var converted))
+ return target.SetValue(this, converted, priority);
+ return null;
+ }
+
+ internal override void RouteSetCurrentValue(AvaloniaObject target, object? value)
+ {
+ if (ShouldSetValue(target, value, out var converted))
+ target.SetCurrentValue(this, converted);
+ }
+
+ internal override IDisposable RouteBind(
+ AvaloniaObject target,
+ IObservable source,
+ BindingPriority priority)
+ {
+ return target.Bind(this, source, priority);
+ }
+
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
+ private bool ShouldSetValue(AvaloniaObject target, object? value, [NotNullWhen(true)] out TValue? converted)
{
if (value == BindingOperations.DoNothing)
{
- return null;
+ converted = default;
+ return false;
}
- else if (value == UnsetValue)
+ if (value == UnsetValue)
{
target.ClearValue(this);
- return null;
+ converted = default;
+ return false;
}
- else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var converted))
+ else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var v))
{
- return target.SetValue(this, (TValue)converted!, priority);
+ converted = (TValue)v!;
+ return true;
}
else
{
@@ -220,14 +244,6 @@ namespace Avalonia
}
}
- internal override IDisposable RouteBind(
- AvaloniaObject target,
- IObservable source,
- BindingPriority priority)
- {
- return target.Bind(this, source, priority);
- }
-
private object? GetDefaultBoxedValue(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));
diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs
index 3c44dd63ce..fafafabd82 100644
--- a/src/Avalonia.Base/Utilities/TypeUtilities.cs
+++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs
@@ -212,7 +212,7 @@ namespace Avalonia.Utilities
var toTypeConverter = TypeDescriptor.GetConverter(toUnderl);
- if (toTypeConverter.CanConvertFrom(from) == true)
+ if (toTypeConverter.CanConvertFrom(from))
{
result = toTypeConverter.ConvertFrom(null, culture, value);
return true;
@@ -220,7 +220,7 @@ namespace Avalonia.Utilities
var fromTypeConverter = TypeDescriptor.GetConverter(from);
- if (fromTypeConverter.CanConvertTo(toUnderl) == true)
+ if (fromTypeConverter.CanConvertTo(toUnderl))
{
result = fromTypeConverter.ConvertTo(null, culture, value, toUnderl);
return true;
@@ -329,7 +329,7 @@ namespace Avalonia.Utilities
}
[RequiresUnreferencedCode(TrimmingMessages.ImplicitTypeConvertionRequiresUnreferencedCodeMessage)]
- public static T ConvertImplicit(object value)
+ public static T ConvertImplicit(object? value)
{
if (TryConvertImplicit(typeof(T), value, out var result))
{
@@ -369,11 +369,6 @@ namespace Avalonia.Utilities
///
public static bool IsNumeric(Type type)
{
- if (type == null)
- {
- return false;
- }
-
var underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null)
diff --git a/src/Avalonia.Base/Utilities/WeakEvent.cs b/src/Avalonia.Base/Utilities/WeakEvent.cs
index e72606bf70..237a491615 100644
--- a/src/Avalonia.Base/Utilities/WeakEvent.cs
+++ b/src/Avalonia.Base/Utilities/WeakEvent.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Reflection;
using System.Runtime.CompilerServices;
using Avalonia.Threading;
@@ -15,7 +11,7 @@ public class WeakEvent : WeakEvent where TEventArgs : Event
{
private readonly Func, Action> _subscribe;
- readonly ConditionalWeakTable _subscriptions = new();
+ private readonly ConditionalWeakTable _subscriptions = new();
internal WeakEvent(
Action> subscribe,
@@ -51,56 +47,6 @@ public class WeakEvent : WeakEvent where TEventArgs : Event
private readonly WeakEvent _ev;
private readonly TSender _target;
private readonly Action _compact;
-
- struct Entry
- {
- WeakReference>? _reference;
- int _hashCode;
-
- public Entry(IWeakEventSubscriber r)
- {
- if (r == null)
- {
- _reference = null;
- _hashCode = 0;
- return;
- }
-
- _hashCode = r.GetHashCode();
- _reference = new WeakReference>(r);
- }
-
- public bool IsEmpty
- {
- get
- {
- if (_reference == null)
- return true;
- if (_reference.TryGetTarget(out _))
- return false;
- _reference = null;
- return true;
- }
- }
-
- public bool TryGetTarget([MaybeNullWhen(false)]out IWeakEventSubscriber target)
- {
- if (_reference == null)
- {
- target = null!;
- return false;
- }
- return _reference.TryGetTarget(out target);
- }
-
- public bool Equals(IWeakEventSubscriber r)
- {
- if (_reference == null || r.GetHashCode() != _hashCode)
- return false;
- return _reference.TryGetTarget(out var target) && target == r;
- }
- }
-
private readonly Action _unsubscribe;
private readonly WeakHashList> _list = new();
private bool _compactScheduled;
@@ -114,7 +60,7 @@ public class WeakEvent : WeakEvent where TEventArgs : Event
_unsubscribe = ev._subscribe(target, OnEvent);
}
- void Destroy()
+ private void Destroy()
{
if(_destroyed)
return;
@@ -134,15 +80,15 @@ public class WeakEvent : WeakEvent where TEventArgs : Event
ScheduleCompact();
}
- void ScheduleCompact()
+ private void ScheduleCompact()
{
if(_compactScheduled || _destroyed)
return;
_compactScheduled = true;
Dispatcher.UIThread.Post(_compact, DispatcherPriority.Background);
}
-
- void Compact()
+
+ private void Compact()
{
if(!_compactScheduled)
return;
@@ -152,7 +98,7 @@ public class WeakEvent : WeakEvent where TEventArgs : Event
Destroy();
}
- void OnEvent(object? sender, TEventArgs eventArgs)
+ private void OnEvent(object? sender, TEventArgs eventArgs)
{
var alive = _list.GetAlive();
if(alive == null)
@@ -196,4 +142,4 @@ public class WeakEvent
return () => unsubscribe(s, handler);
});
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
index 020ba7a6d9..ef143144e6 100644
--- a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
+++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
@@ -60,8 +60,7 @@ namespace Avalonia.Utilities
private static class SubscriptionTypeStorage
where TArgs : EventArgs where TSubscriber : class
{
- public static readonly ConditionalWeakTable> Subscribers
- = new ConditionalWeakTable>();
+ public static readonly ConditionalWeakTable> Subscribers = new();
}
private class SubscriptionDic : Dictionary>
@@ -69,8 +68,7 @@ namespace Avalonia.Utilities
{
}
- private static readonly Dictionary> Accessors
- = new Dictionary>();
+ private static readonly Dictionary> s_accessors = new();
private class Subscription where T : EventArgs where TSubscriber : class
{
@@ -81,18 +79,17 @@ namespace Avalonia.Utilities
private readonly Delegate _delegate;
private Descriptor[] _data = new Descriptor[2];
- private int _count = 0;
+ private int _count;
- delegate void CallerDelegate(TSubscriber s, object sender, T args);
-
- struct Descriptor
+ private delegate void CallerDelegate(TSubscriber s, object? sender, T args);
+
+ private struct Descriptor
{
- public WeakReference Subscriber;
- public CallerDelegate Caller;
+ public WeakReference? Subscriber;
+ public CallerDelegate? Caller;
}
- private static Dictionary s_Callers =
- new Dictionary();
+ private static readonly Dictionary s_callers = new();
public Subscription(SubscriptionDic sdic,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] Type targetType,
@@ -101,8 +98,8 @@ namespace Avalonia.Utilities
_sdic = sdic;
_target = target;
_eventName = eventName;
- if (!Accessors.TryGetValue(targetType, out var evDic))
- Accessors[targetType] = evDic = new Dictionary();
+ if (!s_accessors.TryGetValue(targetType, out var evDic))
+ s_accessors[targetType] = evDic = new Dictionary();
if (evDic.TryGetValue(eventName, out var info))
{
@@ -123,12 +120,12 @@ namespace Avalonia.Utilities
var del = new Action(OnEvent);
_delegate = del.GetMethodInfo().CreateDelegate(_info.EventHandlerType!, del.Target);
- _info.AddMethod!.Invoke(target, new[] { _delegate });
+ _info.AddMethod!.Invoke(target, new object?[] { _delegate });
}
- void Destroy()
+ private void Destroy()
{
- _info.RemoveMethod!.Invoke(_target, new[] { _delegate });
+ _info.RemoveMethod!.Invoke(_target, new object?[] { _delegate });
_sdic.Remove(_eventName);
}
@@ -146,8 +143,8 @@ namespace Avalonia.Utilities
MethodInfo method = s.Method;
var subscriber = (TSubscriber)s.Target!;
- if (!s_Callers.TryGetValue(method, out var caller))
- s_Callers[method] = caller =
+ if (!s_callers.TryGetValue(method, out var caller))
+ s_callers[method] = caller =
(CallerDelegate)Delegate.CreateDelegate(typeof(CallerDelegate), null, method);
_data[_count] = new Descriptor
{
@@ -178,7 +175,7 @@ namespace Avalonia.Utilities
}
}
- void Compact(bool preventDestroy = false)
+ private void Compact(bool preventDestroy = false)
{
int empty = -1;
for (int c = 0; c < _count; c++)
@@ -206,15 +203,15 @@ namespace Avalonia.Utilities
Destroy();
}
- void OnEvent(object sender, T eventArgs)
+ private void OnEvent(object? sender, T eventArgs)
{
var needCompact = false;
- for(var c=0; c<_count; c++)
+ for (var c = 0; c < _count; c++)
{
- var r = _data[c].Subscriber;
+ var r = _data[c].Subscriber!;
if (r.TryGetTarget(out var sub))
{
- _data[c].Caller(sub, sender, eventArgs);
+ _data[c].Caller!(sub, sender, eventArgs);
}
else
needCompact = true;
diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs
index e6d7492c51..87bb1d3790 100644
--- a/src/Avalonia.Base/Visual.cs
+++ b/src/Avalonia.Base/Visual.cs
@@ -348,7 +348,7 @@ namespace Avalonia
///
public void InvalidateVisual()
{
- VisualRoot?.Renderer?.AddDirty(this);
+ VisualRoot?.Renderer.AddDirty(this);
}
///
@@ -449,7 +449,7 @@ namespace Avalonia
protected override void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.LogicalChildrenCollectionChanged(sender, e);
- VisualRoot?.Renderer?.RecalculateChildren(this);
+ VisualRoot?.Renderer.RecalculateChildren(this);
}
///
@@ -477,23 +477,19 @@ namespace Avalonia
OnAttachedToVisualTree(e);
AttachedToVisualTree?.Invoke(this, e);
InvalidateVisual();
- _visualRoot.Renderer?.RecalculateChildren(_visualParent!);
+ _visualRoot.Renderer.RecalculateChildren(_visualParent!);
if (ZIndex != 0 && VisualParent is Visual parent)
parent.HasNonUniformZIndexChildren = true;
var visualChildren = VisualChildren;
+ var visualChildrenCount = visualChildren.Count;
- if (visualChildren != null)
+ for (var i = 0; i < visualChildrenCount; i++)
{
- var visualChildrenCount = visualChildren.Count;
-
- for (var i = 0; i < visualChildrenCount; i++)
+ if (visualChildren[i] is { } child)
{
- if (visualChildren[i] is Visual child)
- {
- child.OnAttachedToVisualTreeCore(e);
- }
+ child.OnAttachedToVisualTreeCore(e);
}
}
}
@@ -540,20 +536,16 @@ namespace Avalonia
}
DetachedFromVisualTree?.Invoke(this, e);
- e.Root?.Renderer?.AddDirty(this);
+ e.Root.Renderer.AddDirty(this);
var visualChildren = VisualChildren;
+ var visualChildrenCount = visualChildren.Count;
- if (visualChildren != null)
+ for (var i = 0; i < visualChildrenCount; i++)
{
- var visualChildrenCount = visualChildren.Count;
-
- for (var i = 0; i < visualChildrenCount; i++)
+ if (visualChildren[i] is { } child)
{
- if (visualChildren[i] is Visual child)
- {
- child.OnDetachedFromVisualTreeCore(e);
- }
+ child.OnDetachedFromVisualTreeCore(e);
}
}
}
@@ -659,7 +651,7 @@ namespace Avalonia
parentVisual.HasNonUniformZIndexChildren = true;
sender?.InvalidateVisual();
- parent?.VisualRoot?.Renderer?.RecalculateChildren(parent);
+ parent?.VisualRoot?.Renderer.RecalculateChildren(parent);
}
///
diff --git a/src/Avalonia.Base/VisualTree/VisualExtensions.cs b/src/Avalonia.Base/VisualTree/VisualExtensions.cs
index b58db3b276..9e38c6e7f2 100644
--- a/src/Avalonia.Base/VisualTree/VisualExtensions.cs
+++ b/src/Avalonia.Base/VisualTree/VisualExtensions.cs
@@ -46,7 +46,7 @@ namespace Avalonia.VisualTree
Visual? v = visual ?? throw new ArgumentNullException(nameof(visual));
var result = 0;
- v = v?.VisualParent;
+ v = v.VisualParent;
while (v != null)
{
@@ -64,17 +64,13 @@ namespace Avalonia.VisualTree
/// The first visual.
/// The second visual.
/// The common ancestor, or null if not found.
- public static Visual? FindCommonVisualAncestor(this Visual visual, Visual target)
+ public static Visual? FindCommonVisualAncestor(this Visual? visual, Visual? target)
{
- Visual? v = visual ?? throw new ArgumentNullException(nameof(visual));
-
- if (target is null)
+ if (visual is null || target is null)
{
return null;
}
- Visual? t = target;
-
void GoUpwards(ref Visual? node, int count)
{
for (int i = 0; i < count; ++i)
@@ -83,6 +79,9 @@ namespace Avalonia.VisualTree
}
}
+ Visual? v = visual;
+ Visual? t = target;
+
// We want to find lowest node first, then make sure that both nodes are at the same height.
// By doing that we can sometimes find out that other node is our lowest common ancestor.
var firstHeight = CalculateDistanceFromRoot(v);
@@ -144,7 +143,7 @@ namespace Avalonia.VisualTree
/// The visual.
/// If given visual should be included in search.
/// First ancestor of given type.
- public static T? FindAncestorOfType(this Visual visual, bool includeSelf = false) where T : class
+ public static T? FindAncestorOfType(this Visual? visual, bool includeSelf = false) where T : class
{
if (visual is null)
{
@@ -173,7 +172,7 @@ namespace Avalonia.VisualTree
/// The visual.
/// If given visual should be included in search.
/// First descendant of given type.
- public static T? FindDescendantOfType(this Visual visual, bool includeSelf = false) where T : class
+ public static T? FindDescendantOfType(this Visual? visual, bool includeSelf = false) where T : class
{
if (visual is null)
{
@@ -392,7 +391,7 @@ namespace Avalonia.VisualTree
/// True if is an ancestor of ;
/// otherwise false.
///
- public static bool IsVisualAncestorOf(this Visual visual, Visual target)
+ public static bool IsVisualAncestorOf(this Visual? visual, Visual? target)
{
Visual? current = target?.VisualParent;
diff --git a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
index be320246b3..dd5e7d5b01 100644
--- a/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
+++ b/src/Avalonia.Controls.ColorPicker/ColorSlider/ColorSlider.cs
@@ -41,18 +41,6 @@ namespace Avalonia.Controls.Primitives
{
}
- ///
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
- {
- base.OnAttachedToVisualTree(e);
- }
-
- ///
- protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
- {
- base.OnDetachedFromVisualTree(e);
- }
-
///
/// Updates the visual state of the control by applying latest PseudoClasses.
///
@@ -123,28 +111,25 @@ namespace Avalonia.Controls.Primitives
IsAlphaMaxForced,
IsSaturationValueMaxForced);
- if (bgraPixelData != null)
+ if (_backgroundBitmap != null)
{
- if (_backgroundBitmap != null)
- {
- // TODO: CURRENTLY DISABLED DUE TO INTERMITTENT CRASHES IN SKIA/RENDERER
- //
- // Re-use the existing WriteableBitmap
- // This assumes the height, width and byte counts are the same and must be set to null
- // elsewhere if that assumption is ever not true.
- // ColorPickerHelpers.UpdateBitmapFromPixelData(_backgroundBitmap, bgraPixelData);
-
- // TODO: ALSO DISABLED DISPOSE DUE TO INTERMITTENT CRASHES
- //_backgroundBitmap?.Dispose();
- _backgroundBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraPixelData, pixelWidth, pixelHeight);
- }
- else
- {
- _backgroundBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraPixelData, pixelWidth, pixelHeight);
- }
-
- Background = new ImageBrush(_backgroundBitmap);
+ // TODO: CURRENTLY DISABLED DUE TO INTERMITTENT CRASHES IN SKIA/RENDERER
+ //
+ // Re-use the existing WriteableBitmap
+ // This assumes the height, width and byte counts are the same and must be set to null
+ // elsewhere if that assumption is ever not true.
+ // ColorPickerHelpers.UpdateBitmapFromPixelData(_backgroundBitmap, bgraPixelData);
+
+ // TODO: ALSO DISABLED DISPOSE DUE TO INTERMITTENT CRASHES
+ //_backgroundBitmap?.Dispose();
+ _backgroundBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraPixelData, pixelWidth, pixelHeight);
}
+ else
+ {
+ _backgroundBitmap = ColorPickerHelpers.CreateBitmapFromPixelData(bgraPixelData, pixelWidth, pixelHeight);
+ }
+
+ Background = new ImageBrush(_backgroundBitmap);
}
}
diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs
index f35124ee0a..91b65a1f72 100644
--- a/src/Avalonia.Controls.DataGrid/DataGrid.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs
@@ -3979,7 +3979,7 @@ namespace Avalonia.Controls
{
if (focusedObject is Control element)
{
- parent = element.Parent;
+ parent = element.VisualParent;
if (parent != null)
{
dataGridWillReceiveRoutedEvent = false;
diff --git a/src/Avalonia.Controls.DataGrid/Utils/TreeHelper.cs b/src/Avalonia.Controls.DataGrid/Utils/TreeHelper.cs
index f4ba644ae6..6aebf05d6b 100644
--- a/src/Avalonia.Controls.DataGrid/Utils/TreeHelper.cs
+++ b/src/Avalonia.Controls.DataGrid/Utils/TreeHelper.cs
@@ -36,7 +36,7 @@ namespace Avalonia.Controls.Utils
{
if (child is Control childElement)
{
- parent = childElement.Parent;
+ parent = childElement.VisualParent;
}
}
child = parent;
diff --git a/src/Avalonia.Controls.ItemsRepeater/Controls/ItemsRepeater.cs b/src/Avalonia.Controls.ItemsRepeater/Controls/ItemsRepeater.cs
index 6c761ab4cf..951e60c25b 100644
--- a/src/Avalonia.Controls.ItemsRepeater/Controls/ItemsRepeater.cs
+++ b/src/Avalonia.Controls.ItemsRepeater/Controls/ItemsRepeater.cs
@@ -44,8 +44,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly StyledProperty LayoutProperty =
- AvaloniaProperty.Register(nameof(Layout), new StackLayout());
+ public static readonly StyledProperty LayoutProperty =
+ AvaloniaProperty.Register(nameof(Layout), new StackLayout());
///
/// Defines the property.
@@ -53,8 +53,8 @@ namespace Avalonia.Controls
public static readonly StyledProperty VerticalCacheLengthProperty =
AvaloniaProperty.Register(nameof(VerticalCacheLength), 2.0);
- private static readonly StyledProperty VirtualizationInfoProperty =
- AvaloniaProperty.RegisterAttached("VirtualizationInfo");
+ private static readonly StyledProperty VirtualizationInfoProperty =
+ AvaloniaProperty.RegisterAttached("VirtualizationInfo");
internal static readonly Rect InvalidRect = new Rect(-1, -1, -1, -1);
internal static readonly Point ClearedElementsArrangePosition = new Point(-10000.0, -10000.0);
@@ -63,7 +63,7 @@ namespace Avalonia.Controls
private readonly ViewportManager _viewportManager;
private readonly TargetWeakEventSubscriber _layoutWeakSubscriber;
private IEnumerable? _items;
- private VirtualizingLayoutContext? _layoutContext;
+ private RepeaterLayoutContext? _layoutContext;
private EventHandler? _childIndexChanged;
private bool _isLayoutInProgress;
private NotifyCollectionChangedEventArgs? _processingItemsSourceChange;
@@ -104,7 +104,7 @@ namespace Avalonia.Controls
/// The layout used to size and position elements. The default is a StackLayout with
/// vertical orientation.
///
- public AttachedLayout Layout
+ public AttachedLayout? Layout
{
get => GetValue(LayoutProperty);
set => SetValue(LayoutProperty, value);
@@ -164,18 +164,7 @@ namespace Avalonia.Controls
private bool IsProcessingCollectionChange => _processingItemsSourceChange != null;
- private LayoutContext LayoutContext
- {
- get
- {
- if (_layoutContext == null)
- {
- _layoutContext = new RepeaterLayoutContext(this);
- }
-
- return _layoutContext;
- }
- }
+ private RepeaterLayoutContext LayoutContext => _layoutContext ??= new RepeaterLayoutContext(this);
event EventHandler? IChildIndexProvider.ChildIndexChanged
{
@@ -269,39 +258,22 @@ namespace Avalonia.Controls
internal void UnpinElement(Control element) => _viewManager.UpdatePin(element, false);
- internal static VirtualizationInfo? TryGetVirtualizationInfo(Control element)
+ internal static VirtualizationInfo? TryGetVirtualizationInfo(Control? element)
{
- return (element as AvaloniaObject)?.GetValue(VirtualizationInfoProperty);
- }
-
- internal static VirtualizationInfo CreateAndInitializeVirtualizationInfo(Control element)
- {
- if (TryGetVirtualizationInfo(element) != null)
- {
- throw new InvalidOperationException("VirtualizationInfo already created.");
- }
-
- var result = new VirtualizationInfo();
- element.SetValue(VirtualizationInfoProperty, result);
- return result;
+ return element?.GetValue(VirtualizationInfoProperty);
}
internal static VirtualizationInfo GetVirtualizationInfo(Control element)
{
- if (element is AvaloniaObject ao)
- {
- var result = ao.GetValue(VirtualizationInfoProperty);
-
- if (result == null)
- {
- result = new VirtualizationInfo();
- ao.SetValue(VirtualizationInfoProperty, result);
- }
+ var result = element.GetValue(VirtualizationInfoProperty);
- return result;
+ if (result == null)
+ {
+ result = new VirtualizationInfo();
+ element.SetValue(VirtualizationInfoProperty, result);
}
- throw new NotSupportedException("Custom implementations of AvaloniaObject not supported.");
+ return result;
}
private protected override void InvalidateMeasureOnChildrenChanged()
@@ -309,6 +281,7 @@ namespace Avalonia.Controls
// Don't invalidate measure when children change.
}
+ ///
protected override Size MeasureOverride(Size availableSize)
{
if (_isLayoutInProgress)
@@ -334,7 +307,7 @@ namespace Avalonia.Controls
if (layout != null)
{
- var layoutContext = GetLayoutContext();
+ var layoutContext = LayoutContext;
desiredSize = layout.Measure(layoutContext, availableSize);
extent = new Rect(LayoutOrigin.X, LayoutOrigin.Y, desiredSize.Width, desiredSize.Height);
@@ -364,6 +337,7 @@ namespace Avalonia.Controls
}
}
+ ///
protected override Size ArrangeOverride(Size finalSize)
{
if (_isLayoutInProgress)
@@ -380,7 +354,7 @@ namespace Avalonia.Controls
try
{
- var arrangeSize = Layout?.Arrange(GetLayoutContext(), finalSize) ?? default;
+ var arrangeSize = Layout?.Arrange(LayoutContext, finalSize) ?? default;
// The view manager might clear elements during this call.
// That's why we call it before arranging cleared elements
@@ -421,6 +395,7 @@ namespace Avalonia.Controls
}
}
+ ///
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
@@ -428,11 +403,13 @@ namespace Avalonia.Controls
_viewportManager.ResetScrollers();
}
+ ///
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_viewportManager.ResetScrollers();
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
if (change.Property == ItemsProperty)
@@ -501,7 +478,7 @@ namespace Avalonia.Controls
if (parent == this)
{
var virtInfo = TryGetVirtualizationInfo(element);
- return _viewManager.GetElementIndex(virtInfo!);
+ return _viewManager.GetElementIndex(virtInfo);
}
return -1;
@@ -529,7 +506,7 @@ namespace Avalonia.Controls
{
if (index >= 0 && index >= (ItemsSourceView?.Count ?? 0))
{
- throw new ArgumentException("Argument index is invalid.", "index");
+ throw new ArgumentException("Argument index is invalid.", nameof(index));
}
if (_isLayoutInProgress)
@@ -547,7 +524,7 @@ namespace Avalonia.Controls
throw new InvalidOperationException("Cannot make an Anchor when there is no attached layout.");
}
- element = (Control)GetLayoutContext().GetOrCreateElementAt(index);
+ element = (Control)LayoutContext.GetOrCreateElementAt(index);
element.Measure(Size.Infinity);
}
@@ -647,9 +624,9 @@ namespace Avalonia.Controls
if (Layout is VirtualizingLayout virtualLayout)
{
- virtualLayout.OnItemsChanged(GetLayoutContext(), newValue, args);
+ virtualLayout.OnItemsChanged(LayoutContext, newValue, args);
}
- else if (Layout is NonVirtualizingLayout nonVirtualLayout)
+ else if (Layout is NonVirtualizingLayout)
{
// Walk through all the elements and make sure they are cleared for
// non-virtualizing layouts.
@@ -693,7 +670,7 @@ namespace Avalonia.Controls
try
{
- virtualLayout.OnItemsChanged(GetLayoutContext(), newValue, args);
+ virtualLayout.OnItemsChanged(LayoutContext, newValue, args);
}
finally
{
@@ -760,7 +737,7 @@ namespace Avalonia.Controls
AttachedLayout.ArrangeInvalidatedWeakEvent.Subscribe(newValue, _layoutWeakSubscriber);
}
- bool isVirtualizingLayout = newValue != null && newValue is VirtualizingLayout;
+ bool isVirtualizingLayout = newValue is VirtualizingLayout;
_viewportManager.OnLayoutChanged(isVirtualizingLayout);
InvalidateMeasure();
}
@@ -788,7 +765,7 @@ namespace Avalonia.Controls
{
if (Layout is VirtualizingLayout virtualLayout)
{
- virtualLayout.OnItemsChanged(GetLayoutContext(), sender, args);
+ virtualLayout.OnItemsChanged(LayoutContext, sender, args);
}
else
{
@@ -807,15 +784,5 @@ namespace Avalonia.Controls
{
_viewportManager.OnBringIntoViewRequested(e);
}
-
- private VirtualizingLayoutContext GetLayoutContext()
- {
- if (_layoutContext == null)
- {
- _layoutContext = new RepeaterLayoutContext(this);
- }
-
- return _layoutContext;
- }
}
}
diff --git a/src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs b/src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs
index 2d302a95dd..6b9d7934bf 100644
--- a/src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs
+++ b/src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs
@@ -53,7 +53,7 @@ namespace Avalonia.Controls
}
}
}
- if (element == null) { element = GetElementFromUniqueIdResetPool(index); };
+ if (element == null) { element = GetElementFromUniqueIdResetPool(index); }
if (element == null) { element = GetElementFromPinnedElements(index); }
if (element == null) { element = GetElementFromElementFactory(index); }
@@ -221,7 +221,7 @@ namespace Avalonia.Controls
return nextElement;
}
- public int GetElementIndex(VirtualizationInfo virtInfo)
+ public int GetElementIndex(VirtualizationInfo? virtInfo)
{
if (virtInfo == null)
{
@@ -627,11 +627,7 @@ namespace Avalonia.Controls
var element = GetElement();
- var virtInfo = ItemsRepeater.TryGetVirtualizationInfo(element);
- if (virtInfo == null)
- {
- virtInfo = ItemsRepeater.CreateAndInitializeVirtualizationInfo(element);
- }
+ var virtInfo = ItemsRepeater.GetVirtualizationInfo(element);
// Clear flag
virtInfo.MustClearDataContext = false;
@@ -710,9 +706,8 @@ namespace Avalonia.Controls
{
if (parent is ItemsRepeater repeater)
{
- var element = child as Control;
if (repeater == owner &&
- element is not null &&
+ child is Control element &&
ItemsRepeater.GetVirtualizationInfo(element).IsRealized)
{
focusedElement = element;
@@ -722,7 +717,7 @@ namespace Avalonia.Controls
}
child = parent;
- parent = child?.GetVisualParent();
+ parent = child.GetVisualParent();
}
}
diff --git a/src/Avalonia.Controls.ItemsRepeater/Controls/ViewportManager.cs b/src/Avalonia.Controls.ItemsRepeater/Controls/ViewportManager.cs
index 336fb2d228..6ed817c238 100644
--- a/src/Avalonia.Controls.ItemsRepeater/Controls/ViewportManager.cs
+++ b/src/Avalonia.Controls.ItemsRepeater/Controls/ViewportManager.cs
@@ -166,7 +166,7 @@ namespace Avalonia.Controls
if (Math.Abs(_expectedViewportShift.X) > 1 || Math.Abs(_expectedViewportShift.Y) > 1)
{
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Expecting viewport shift of ({Shift})",
- _owner.Layout.LayoutId, _expectedViewportShift);
+ _owner.Layout?.LayoutId, _expectedViewportShift);
// There are cases where we might be expecting a shift but not get it. We will
// be waiting for the effective viewport event but if the scroll viewer is not able
@@ -287,7 +287,7 @@ namespace Avalonia.Controls
if (_pendingViewportShift.X != 0 || _pendingViewportShift.Y != 0)
{
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Layout Updated with pending shift {Shift}- invalidating measure",
- _owner.Layout.LayoutId,
+ _owner.Layout?.LayoutId,
_pendingViewportShift);
// Assume this is never going to come.
@@ -436,7 +436,7 @@ namespace Avalonia.Controls
private void OnEffectiveViewportChanged(object? sender, EffectiveViewportChangedEventArgs e)
{
- Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: EffectiveViewportChanged event callback", _owner.Layout.LayoutId);
+ Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: EffectiveViewportChanged event callback", _owner.Layout?.LayoutId);
UpdateViewport(e.EffectiveViewport);
_pendingViewportShift = default;
@@ -490,14 +490,14 @@ namespace Avalonia.Controls
var previousVisibleWindow = _visibleWindow;
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Effective Viewport: ({Before})->({After})",
- _owner.Layout.LayoutId,
+ _owner.Layout?.LayoutId,
previousVisibleWindow,
viewport);
if (-currentVisibleWindow.X <= ItemsRepeater.ClearedElementsArrangePosition.X &&
-currentVisibleWindow.Y <= ItemsRepeater.ClearedElementsArrangePosition.Y)
{
- Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Viewport is invalid. visible window cleared", _owner.Layout.LayoutId);
+ Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Viewport is invalid. visible window cleared", _owner.Layout?.LayoutId);
// We got cleared.
_visibleWindow = default;
}
@@ -509,7 +509,7 @@ namespace Avalonia.Controls
if (_visibleWindow != previousVisibleWindow)
{
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Used Viewport: ({Before})->({After})",
- _owner.Layout.LayoutId,
+ _owner.Layout?.LayoutId,
previousVisibleWindow,
currentVisibleWindow);
TryInvalidateMeasure();
@@ -532,7 +532,7 @@ namespace Avalonia.Controls
// We invalidate measure instead of just invalidating arrange because
// we don't invalidate measure in UpdateViewport if the view is changing to
// avoid layout cycles.
- Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Invalidating measure due to viewport change", _owner.Layout.LayoutId);
+ Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Invalidating measure due to viewport change", _owner.Layout?.LayoutId);
_owner.InvalidateMeasure();
}
}
diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
index fde401fb01..ada0b94124 100644
--- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
+++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -17,32 +16,34 @@ namespace Avalonia.Controls.ApplicationLifetimes
private int _exitCode;
private CancellationTokenSource? _cts;
private bool _isShuttingDown;
- private HashSet _windows = new HashSet();
+ private readonly HashSet _windows = new();
+
+ private static ClassicDesktopStyleApplicationLifetime? s_activeLifetime;
- private static ClassicDesktopStyleApplicationLifetime? _activeLifetime;
static ClassicDesktopStyleApplicationLifetime()
{
Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened);
- Window.WindowClosedEvent.AddClassHandler(typeof(Window), WindowClosedEvent);
+ Window.WindowClosedEvent.AddClassHandler(typeof(Window), OnWindowClosed);
}
- private static void WindowClosedEvent(object? sender, RoutedEventArgs e)
+ private static void OnWindowClosed(object? sender, RoutedEventArgs e)
{
- _activeLifetime?._windows.Remove((Window)sender!);
- _activeLifetime?.HandleWindowClosed((Window)sender!);
+ var window = (Window)sender!;
+ s_activeLifetime?._windows.Remove(window);
+ s_activeLifetime?.HandleWindowClosed(window);
}
private static void OnWindowOpened(object? sender, RoutedEventArgs e)
{
- _activeLifetime?._windows.Add((Window)sender!);
+ s_activeLifetime?._windows.Add((Window)sender!);
}
public ClassicDesktopStyleApplicationLifetime()
{
- if (_activeLifetime != null)
+ if (s_activeLifetime != null)
throw new InvalidOperationException(
"Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed");
- _activeLifetime = this;
+ s_activeLifetime = this;
}
///
@@ -65,9 +66,10 @@ namespace Avalonia.Controls.ApplicationLifetimes
///
public Window? MainWindow { get; set; }
+ ///
public IReadOnlyList Windows => _windows.ToArray();
- private void HandleWindowClosed(Window window)
+ private void HandleWindowClosed(Window? window)
{
if (window == null)
return;
@@ -130,8 +132,8 @@ namespace Avalonia.Controls.ApplicationLifetimes
public void Dispose()
{
- if (_activeLifetime == this)
- _activeLifetime = null;
+ if (s_activeLifetime == this)
+ s_activeLifetime = null;
}
private bool DoShutdown(
diff --git a/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
index 22b5f8236d..b9a372f935 100644
--- a/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
+++ b/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
@@ -40,7 +40,10 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// The main window.
///
Window? MainWindow { get; set; }
-
+
+ ///
+ /// Gets the list of all open windows in the application.
+ ///
IReadOnlyList Windows { get; }
///
diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
index 98885e11ca..9a949e31d4 100644
--- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
@@ -792,7 +792,7 @@ namespace Avalonia.Controls
Control? element = focused as Control;
if (element != null)
{
- parent = element.Parent;
+ parent = element.VisualParent;
}
}
focused = parent;
@@ -1711,7 +1711,7 @@ namespace Avalonia.Controls
/// The predicate to use for the partial or
/// exact match.
/// Returns the object or null.
- private object? TryGetMatch(string? searchText, AvaloniaList view, AutoCompleteFilterPredicate? predicate)
+ private object? TryGetMatch(string? searchText, AvaloniaList? view, AutoCompleteFilterPredicate? predicate)
{
if (predicate is null)
return null;
diff --git a/src/Avalonia.Controls/Automation/AutomationProperties.cs b/src/Avalonia.Controls/Automation/AutomationProperties.cs
index 35f94722ce..3ea9c170ff 100644
--- a/src/Avalonia.Controls/Automation/AutomationProperties.cs
+++ b/src/Avalonia.Controls/Automation/AutomationProperties.cs
@@ -38,8 +38,8 @@ namespace Avalonia.Automation
///
/// Defines the AutomationProperties.AcceleratorKey attached property.
///
- public static readonly AttachedProperty AcceleratorKeyProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty AcceleratorKeyProperty =
+ AvaloniaProperty.RegisterAttached(
"AcceleratorKey",
typeof(AutomationProperties));
@@ -54,16 +54,16 @@ namespace Avalonia.Automation
///
/// Defines the AutomationProperties.AccessKey attached property
///
- public static readonly AttachedProperty AccessKeyProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty AccessKeyProperty =
+ AvaloniaProperty.RegisterAttached(
"AccessKey",
typeof(AutomationProperties));
///
/// Defines the AutomationProperties.AutomationId attached property.
///
- public static readonly AttachedProperty AutomationIdProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty AutomationIdProperty =
+ AvaloniaProperty.RegisterAttached(
"AutomationId",
typeof(AutomationProperties));
@@ -78,8 +78,8 @@ namespace Avalonia.Automation
///
/// Defines the AutomationProperties.HelpText attached property.
///
- public static readonly AttachedProperty HelpTextProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty HelpTextProperty =
+ AvaloniaProperty.RegisterAttached(
"HelpText",
typeof(AutomationProperties));
@@ -122,16 +122,16 @@ namespace Avalonia.Automation
///
/// Defines the AutomationProperties.ItemStatus attached property.
///
- public static readonly AttachedProperty ItemStatusProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty ItemStatusProperty =
+ AvaloniaProperty.RegisterAttached(
"ItemStatus",
typeof(AutomationProperties));
///
/// Defines the AutomationProperties.ItemType attached property.
///
- public static readonly AttachedProperty ItemTypeProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty ItemTypeProperty =
+ AvaloniaProperty.RegisterAttached(
"ItemType",
typeof(AutomationProperties));
@@ -155,8 +155,8 @@ namespace Avalonia.Automation
///
/// Defines the AutomationProperties.Name attached attached property.
///
- public static readonly AttachedProperty NameProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty NameProperty =
+ AvaloniaProperty.RegisterAttached(
"Name",
typeof(AutomationProperties));
@@ -193,25 +193,17 @@ namespace Avalonia.Automation
///
public static void SetAcceleratorKey(StyledElement element, string value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AcceleratorKeyProperty, value);
}
///
/// Helper for reading AcceleratorKey property from a StyledElement.
///
- public static string GetAcceleratorKey(StyledElement element)
+ public static string? GetAcceleratorKey(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((string)element.GetValue(AcceleratorKeyProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(AcceleratorKeyProperty);
}
///
@@ -219,11 +211,7 @@ namespace Avalonia.Automation
///
public static void SetAccessibilityView(StyledElement element, AccessibilityView value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AccessibilityViewProperty, value);
}
@@ -232,11 +220,7 @@ namespace Avalonia.Automation
///
public static AccessibilityView GetAccessibilityView(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(AccessibilityViewProperty);
}
@@ -245,50 +229,34 @@ namespace Avalonia.Automation
///
public static void SetAccessKey(StyledElement element, string value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AccessKeyProperty, value);
}
///
/// Helper for reading AccessKey property from a StyledElement.
///
- public static string GetAccessKey(StyledElement element)
+ public static string? GetAccessKey(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((string)element.GetValue(AccessKeyProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(AccessKeyProperty);
}
///
/// Helper for setting AutomationId property on a StyledElement.
///
- public static void SetAutomationId(StyledElement element, string value)
+ public static void SetAutomationId(StyledElement element, string? value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AutomationIdProperty, value);
}
///
/// Helper for reading AutomationId property from a StyledElement.
///
- public static string GetAutomationId(StyledElement element)
+ public static string? GetAutomationId(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(AutomationIdProperty);
}
@@ -297,11 +265,7 @@ namespace Avalonia.Automation
///
public static void SetControlTypeOverride(StyledElement element, AutomationControlType? value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ControlTypeOverrideProperty, value);
}
@@ -310,38 +274,26 @@ namespace Avalonia.Automation
///
public static AutomationControlType? GetControlTypeOverride(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ControlTypeOverrideProperty);
}
///
/// Helper for setting HelpText property on a StyledElement.
///
- public static void SetHelpText(StyledElement element, string value)
+ public static void SetHelpText(StyledElement element, string? value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(HelpTextProperty, value);
}
///
/// Helper for reading HelpText property from a StyledElement.
///
- public static string GetHelpText(StyledElement element)
+ public static string? GetHelpText(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((string)element.GetValue(HelpTextProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(HelpTextProperty);
}
///
@@ -349,11 +301,7 @@ namespace Avalonia.Automation
///
public static void SetIsColumnHeader(StyledElement element, bool value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsColumnHeaderProperty, value);
}
@@ -362,12 +310,8 @@ namespace Avalonia.Automation
///
public static bool GetIsColumnHeader(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((bool)element.GetValue(IsColumnHeaderProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(IsColumnHeaderProperty);
}
///
@@ -375,11 +319,7 @@ namespace Avalonia.Automation
///
public static void SetIsRequiredForForm(StyledElement element, bool value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsRequiredForFormProperty, value);
}
@@ -388,12 +328,8 @@ namespace Avalonia.Automation
///
public static bool GetIsRequiredForForm(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((bool)element.GetValue(IsRequiredForFormProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(IsRequiredForFormProperty);
}
///
@@ -401,12 +337,8 @@ namespace Avalonia.Automation
///
public static bool GetIsRowHeader(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((bool)element.GetValue(IsRowHeaderProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(IsRowHeaderProperty);
}
///
@@ -414,11 +346,7 @@ namespace Avalonia.Automation
///
public static void SetIsRowHeader(StyledElement element, bool value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsRowHeaderProperty, value);
}
@@ -427,11 +355,7 @@ namespace Avalonia.Automation
///
public static void SetIsOffscreenBehavior(StyledElement element, IsOffscreenBehavior value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsOffscreenBehaviorProperty, value);
}
@@ -440,64 +364,44 @@ namespace Avalonia.Automation
///
public static IsOffscreenBehavior GetIsOffscreenBehavior(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((IsOffscreenBehavior)element.GetValue(IsOffscreenBehaviorProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(IsOffscreenBehaviorProperty);
}
///
/// Helper for setting ItemStatus property on a StyledElement.
///
- public static void SetItemStatus(StyledElement element, string value)
+ public static void SetItemStatus(StyledElement element, string? value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ItemStatusProperty, value);
}
///
/// Helper for reading ItemStatus property from a StyledElement.
///
- public static string GetItemStatus(StyledElement element)
+ public static string? GetItemStatus(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((string)element.GetValue(ItemStatusProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(ItemStatusProperty);
}
///
/// Helper for setting ItemType property on a StyledElement.
///
- public static void SetItemType(StyledElement element, string value)
+ public static void SetItemType(StyledElement element, string? value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ItemTypeProperty, value);
}
///
/// Helper for reading ItemType property from a StyledElement.
///
- public static string GetItemType(StyledElement element)
+ public static string? GetItemType(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((string)element.GetValue(ItemTypeProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(ItemTypeProperty);
}
///
@@ -505,11 +409,7 @@ namespace Avalonia.Automation
///
public static void SetLabeledBy(StyledElement element, Control value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(LabeledByProperty, value);
}
@@ -518,11 +418,7 @@ namespace Avalonia.Automation
///
public static Control GetLabeledBy(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(LabeledByProperty);
}
@@ -531,11 +427,7 @@ namespace Avalonia.Automation
///
public static void SetLiveSetting(StyledElement element, AutomationLiveSetting value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(LiveSettingProperty, value);
}
@@ -544,38 +436,26 @@ namespace Avalonia.Automation
///
public static AutomationLiveSetting GetLiveSetting(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((AutomationLiveSetting)element.GetValue(LiveSettingProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(LiveSettingProperty);
}
///
/// Helper for setting Name property on a StyledElement.
///
- public static void SetName(StyledElement element, string value)
+ public static void SetName(StyledElement element, string? value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(NameProperty, value);
}
///
/// Helper for reading Name property from a StyledElement.
///
- public static string GetName(StyledElement element)
+ public static string? GetName(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((string)element.GetValue(NameProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(NameProperty);
}
///
@@ -583,11 +463,7 @@ namespace Avalonia.Automation
///
public static void SetPositionInSet(StyledElement element, int value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(PositionInSetProperty, value);
}
@@ -596,12 +472,8 @@ namespace Avalonia.Automation
///
public static int GetPositionInSet(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((int)element.GetValue(PositionInSetProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(PositionInSetProperty);
}
///
@@ -609,11 +481,7 @@ namespace Avalonia.Automation
///
public static void SetSizeOfSet(StyledElement element, int value)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
+ _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(SizeOfSetProperty, value);
}
@@ -622,12 +490,8 @@ namespace Avalonia.Automation
///
public static int GetSizeOfSet(StyledElement element)
{
- if (element == null)
- {
- throw new ArgumentNullException(nameof(element));
- }
-
- return ((int)element.GetValue(SizeOfSetProperty));
+ _ = element ?? throw new ArgumentNullException(nameof(element));
+ return element.GetValue(SizeOfSetProperty);
}
}
}
diff --git a/src/Avalonia.Controls/Automation/Peers/ProgressBarAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ProgressBarAutomationPeer.cs
new file mode 100644
index 0000000000..3c59f74c90
--- /dev/null
+++ b/src/Avalonia.Controls/Automation/Peers/ProgressBarAutomationPeer.cs
@@ -0,0 +1,62 @@
+using System;
+using Avalonia.Automation.Peers;
+using Avalonia.Automation.Provider;
+using Avalonia.Controls.Primitives;
+
+namespace Avalonia.Controls.Automation.Peers
+{
+ public class ProgressBarAutomationPeer : RangeBaseAutomationPeer, IRangeValueProvider
+ {
+ public ProgressBarAutomationPeer(RangeBase owner) : base(owner)
+ {
+ }
+
+ protected override string GetClassNameCore()
+ {
+ return "ProgressBar";
+ }
+
+ protected override AutomationControlType GetAutomationControlTypeCore()
+ {
+ return AutomationControlType.ProgressBar;
+ }
+
+ ///
+ /// Request to set the value that this UI element is representing
+ ///
+ /// Value to set the UI to, as an object
+ /// true if the UI element was successfully set to the specified value
+ void IRangeValueProvider.SetValue(double val)
+ {
+ throw new InvalidOperationException("ProgressBar is ReadOnly, value can't be set.");
+ }
+
+ ///Indicates that the value can only be read, not modified.
+ ///returns True if the control is read-only
+ bool IRangeValueProvider.IsReadOnly
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ ///Value of a Large Change
+ double IRangeValueProvider.LargeChange
+ {
+ get
+ {
+ return double.NaN;
+ }
+ }
+
+ ///Value of a Small Change
+ double IRangeValueProvider.SmallChange
+ {
+ get
+ {
+ return double.NaN;
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Controls/Border.cs b/src/Avalonia.Controls/Border.cs
index 1bb574acd2..78ba23c1dd 100644
--- a/src/Avalonia.Controls/Border.cs
+++ b/src/Avalonia.Controls/Border.cs
@@ -225,7 +225,7 @@ namespace Avalonia.Controls
/// Renders the control.
///
/// The drawing context.
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
{
_borderRenderHelper.Render(context, Bounds.Size, LayoutThickness, CornerRadius, Background, BorderBrush,
BoxShadow, BorderDashOffset, BorderLineCap, BorderLineJoin, BorderDashArray);
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index 9627f200df..1ec6f8dabc 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -394,10 +394,10 @@ namespace Avalonia.Controls
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
IsPressed = true;
+ e.Handled = true;
if (ClickMode == ClickMode.Press)
{
- e.Handled = true;
OnClick();
}
}
@@ -411,11 +411,11 @@ namespace Avalonia.Controls
if (IsPressed && e.InitialPressMouseButton == MouseButton.Left)
{
IsPressed = false;
+ e.Handled = true;
if (ClickMode == ClickMode.Release &&
this.GetVisualsAt(e.GetPosition(this)).Any(c => this == c || this.IsVisualAncestorOf(c)))
{
- e.Handled = true;
OnClick();
}
}
diff --git a/src/Avalonia.Controls/Calendar/Calendar.cs b/src/Avalonia.Controls/Calendar/Calendar.cs
index 9c88bae5f6..3300292857 100644
--- a/src/Avalonia.Controls/Calendar/Calendar.cs
+++ b/src/Avalonia.Controls/Calendar/Calendar.cs
@@ -237,11 +237,11 @@ namespace Avalonia.Controls
private DateTime _selectedYear;
private DateTime _displayDate = DateTime.Today;
- private DateTime? _displayDateStart = null;
- private DateTime? _displayDateEnd = null;
+ private DateTime? _displayDateStart;
+ private DateTime? _displayDateEnd;
private bool _isShiftPressed;
- private bool _displayDateIsChanging = false;
+ private bool _displayDateIsChanging;
internal CalendarDayButton? FocusButton { get; set; }
internal CalendarButton? FocusCalendarButton { get; set; }
@@ -291,7 +291,7 @@ namespace Avalonia.Controls
}
else
{
- throw new ArgumentOutOfRangeException("d", "Invalid DayOfWeek");
+ throw new ArgumentOutOfRangeException(nameof(e), "Invalid DayOfWeek");
}
}
@@ -346,10 +346,10 @@ namespace Avalonia.Controls
}
}
- public static readonly StyledProperty HeaderBackgroundProperty =
- AvaloniaProperty.Register(nameof(HeaderBackground));
+ public static readonly StyledProperty HeaderBackgroundProperty =
+ AvaloniaProperty.Register(nameof(HeaderBackground));
- public IBrush HeaderBackground
+ public IBrush? HeaderBackground
{
get { return GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); }
@@ -478,7 +478,7 @@ namespace Avalonia.Controls
}
else
{
- throw new ArgumentOutOfRangeException("d", "Invalid SelectionMode");
+ throw new ArgumentOutOfRangeException(nameof(e), "Invalid SelectionMode");
}
}
@@ -574,7 +574,7 @@ namespace Avalonia.Controls
}
else
{
- throw new ArgumentOutOfRangeException("d", "SelectedDate value is not valid.");
+ throw new ArgumentOutOfRangeException(nameof(e), "SelectedDate value is not valid.");
}
}
else
diff --git a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
index fe8b616e02..8fb9b66f3d 100644
--- a/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
@@ -15,7 +15,7 @@ namespace Avalonia.Controls.Primitives
///
/// The Calendar whose dates this object represents.
///
- private Calendar _owner;
+ private readonly Calendar _owner;
///
/// Initializes a new instance of the
@@ -79,13 +79,13 @@ namespace Avalonia.Controls.Primitives
if (DateTime.Compare(end, start) > -1)
{
- rangeStart = DateTimeHelper.DiscardTime(start).Value;
- rangeEnd = DateTimeHelper.DiscardTime(end).Value;
+ rangeStart = DateTimeHelper.DiscardTime(start);
+ rangeEnd = DateTimeHelper.DiscardTime(end);
}
else
{
- rangeStart = DateTimeHelper.DiscardTime(end).Value;
- rangeEnd = DateTimeHelper.DiscardTime(start).Value;
+ rangeStart = DateTimeHelper.DiscardTime(end);
+ rangeEnd = DateTimeHelper.DiscardTime(start);
}
int count = Count;
@@ -144,7 +144,7 @@ namespace Avalonia.Controls.Primitives
if (!IsValid(item))
{
- throw new ArgumentOutOfRangeException("Value is not valid.");
+ throw new ArgumentOutOfRangeException(nameof(item), "Value is not valid.");
}
base.InsertItem(index, item);
@@ -186,7 +186,7 @@ namespace Avalonia.Controls.Primitives
if (!IsValid(item))
{
- throw new ArgumentOutOfRangeException("Value is not valid.");
+ throw new ArgumentOutOfRangeException(nameof(item), "Value is not valid.");
}
base.SetItem(index, item);
diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs
index 032f452111..3d436b4485 100644
--- a/src/Avalonia.Controls/Calendar/CalendarItem.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs
@@ -44,30 +44,30 @@ namespace Avalonia.Controls.Primitives
private ITemplate? _dayTitleTemplate;
private DateTime _currentMonth;
- private bool _isMouseLeftButtonDown = false;
- private bool _isMouseLeftButtonDownYearView = false;
- private bool _isControlPressed = false;
+ private bool _isMouseLeftButtonDown;
+ private bool _isMouseLeftButtonDownYearView;
+ private bool _isControlPressed;
- private System.Globalization.Calendar _calendar = new System.Globalization.GregorianCalendar();
-
- private PointerPressedEventArgs? _downEventArg;
- private PointerPressedEventArgs? _downEventArgYearView;
+ private readonly System.Globalization.Calendar _calendar = new GregorianCalendar();
internal Calendar? Owner { get; set; }
internal CalendarDayButton? CurrentButton { get; set; }
- public static readonly StyledProperty HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner();
- public IBrush HeaderBackground
+ public static readonly StyledProperty HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner();
+
+ public IBrush? HeaderBackground
{
get { return GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); }
}
+
public static readonly DirectProperty?> DayTitleTemplateProperty =
AvaloniaProperty.RegisterDirect?>(
nameof(DayTitleTemplate),
o => o.DayTitleTemplate,
(o,v) => o.DayTitleTemplate = v,
defaultBindingMode: BindingMode.OneTime);
+
public ITemplate? DayTitleTemplate
{
get { return _dayTitleTemplate; }
@@ -178,7 +178,7 @@ namespace Avalonia.Controls.Primitives
{
if (_dayTitleTemplate != null)
{
- var cell = (Control) _dayTitleTemplate.Build();
+ var cell = _dayTitleTemplate.Build();
cell.DataContext = string.Empty;
cell.SetValue(Grid.RowProperty, 0);
cell.SetValue(Grid.ColumnProperty, i);
@@ -308,16 +308,13 @@ namespace Avalonia.Controls.Primitives
for (int childIndex = 0; childIndex < Calendar.ColumnsPerMonth; childIndex++)
{
var daytitle = MonthView!.Children[childIndex];
- if (daytitle != null)
+ if (Owner != null)
{
- if (Owner != null)
- {
- daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)Owner.FirstDayOfWeek) % NumberOfDaysPerWeek];
- }
- else
- {
- daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek) % NumberOfDaysPerWeek];
- }
+ daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)Owner.FirstDayOfWeek) % NumberOfDaysPerWeek];
+ }
+ else
+ {
+ daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek) % NumberOfDaysPerWeek];
}
}
}
@@ -527,7 +524,7 @@ namespace Avalonia.Controls.Primitives
childButton.Content = dateToAdd.Day.ToString(DateTimeHelper.GetCurrentDateFormat());
childButton.DataContext = dateToAdd;
- if (DateTime.Compare((DateTime)DateTimeHelper.DiscardTime(DateTime.MaxValue), dateToAdd) > 0)
+ if (DateTime.Compare(DateTimeHelper.DiscardTime(DateTime.MaxValue), dateToAdd) > 0)
{
// Since we are sure DisplayDate is not equal to
// DateTime.MaxValue, it is safe to use AddDays
@@ -587,7 +584,7 @@ namespace Avalonia.Controls.Primitives
{
if (Owner != null)
{
- _currentMonth = (DateTime)Owner.SelectedMonth;
+ _currentMonth = Owner.SelectedMonth;
}
else
{
@@ -676,7 +673,7 @@ namespace Avalonia.Controls.Primitives
if (Owner != null)
{
selectedYear = Owner.SelectedYear;
- _currentMonth = (DateTime)Owner.SelectedMonth;
+ _currentMonth = Owner.SelectedMonth;
}
else
{
@@ -696,9 +693,9 @@ namespace Avalonia.Controls.Primitives
SetYearButtons(decade, decadeEnd);
}
}
- internal void UpdateYearViewSelection(CalendarButton calendarButton)
+ internal void UpdateYearViewSelection(CalendarButton? calendarButton)
{
- if (Owner != null && calendarButton != null && calendarButton.DataContext != null)
+ if (Owner != null && calendarButton?.DataContext is DateTime selectedDate)
{
Owner.FocusCalendarButton!.IsCalendarButtonFocused = false;
Owner.FocusCalendarButton = calendarButton;
@@ -706,11 +703,11 @@ namespace Avalonia.Controls.Primitives
if (Owner.DisplayMode == CalendarMode.Year)
{
- Owner.SelectedMonth = (DateTime)calendarButton.DataContext;
+ Owner.SelectedMonth = selectedDate;
}
else
{
- Owner.SelectedYear = (DateTime)calendarButton.DataContext;
+ Owner.SelectedYear = selectedDate;
}
}
}
@@ -719,7 +716,7 @@ namespace Avalonia.Controls.Primitives
{
int year;
int count = -1;
- foreach (object child in YearView!.Children)
+ foreach (var child in YearView!.Children)
{
CalendarButton childButton = (CalendarButton)child;
year = decade + count;
@@ -859,7 +856,8 @@ namespace Avalonia.Controls.Primitives
{
if (Owner != null)
{
- if (_isMouseLeftButtonDown && sender is CalendarDayButton b && b.IsEnabled && !b.IsBlackout)
+ if (_isMouseLeftButtonDown
+ && sender is CalendarDayButton { IsEnabled: true, IsBlackout: false, DataContext: DateTime selectedDate } b)
{
// Update the states of all buttons to be selected starting
// from HoverStart to b
@@ -867,7 +865,6 @@ namespace Avalonia.Controls.Primitives
{
case CalendarSelectionMode.SingleDate:
{
- DateTime selectedDate = (DateTime)b.DataContext!;
Owner.CalendarDatePickerDisplayDateFlag = true;
if (Owner.SelectedDates.Count == 0)
{
@@ -882,10 +879,9 @@ namespace Avalonia.Controls.Primitives
case CalendarSelectionMode.SingleRange:
case CalendarSelectionMode.MultipleRange:
{
- Debug.Assert(b.DataContext != null, "The DataContext should not be null!");
Owner.UnHighlightDays();
Owner.HoverEndIndex = b.Index;
- Owner.HoverEnd = (DateTime?)b.DataContext;
+ Owner.HoverEnd = selectedDate;
// Update the States of the buttons
Owner.HighlightDays();
return;
@@ -904,22 +900,14 @@ namespace Avalonia.Controls.Primitives
Owner.Focus();
}
- bool ctrl, shift;
- CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out ctrl, out shift);
- CalendarDayButton b = (CalendarDayButton)sender!;
+ CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out var ctrl, out var shift);
- if (b != null)
+ if (sender is CalendarDayButton b)
{
_isControlPressed = ctrl;
- if (b.IsEnabled && !b.IsBlackout)
+ if (b.IsEnabled && !b.IsBlackout && b.DataContext is DateTime selectedDate)
{
- DateTime selectedDate = (DateTime)b.DataContext!;
_isMouseLeftButtonDown = true;
- // null check is added for unit tests
- if (e != null)
- {
- _downEventArg = e;
- }
switch (Owner.SelectionMode)
{
@@ -1010,12 +998,12 @@ namespace Avalonia.Controls.Primitives
}
}
}
- private void AddSelection(CalendarDayButton b)
+ private void AddSelection(CalendarDayButton b, DateTime selectedDate)
{
if (Owner != null)
{
Owner.HoverEndIndex = b.Index;
- Owner.HoverEnd = (DateTime)b.DataContext!;
+ Owner.HoverEnd = selectedDate;
if (Owner.HoverEnd != null && Owner.HoverStart != null)
{
@@ -1025,7 +1013,7 @@ namespace Avalonia.Controls.Primitives
// SelectionMode
Owner.IsMouseSelection = true;
Owner.SelectedDates.AddRange(Owner.HoverStart.Value, Owner.HoverEnd.Value);
- Owner.OnDayClick((DateTime)b.DataContext);
+ Owner.OnDayClick(selectedDate);
}
}
}
@@ -1039,11 +1027,11 @@ namespace Avalonia.Controls.Primitives
Owner.OnDayButtonMouseUp(e);
}
_isMouseLeftButtonDown = false;
- if (b != null && b.DataContext != null)
+ if (b != null && b.DataContext is DateTime selectedDate)
{
if (Owner.SelectionMode == CalendarSelectionMode.None || Owner.SelectionMode == CalendarSelectionMode.SingleDate)
{
- Owner.OnDayClick((DateTime)b.DataContext);
+ Owner.OnDayClick(selectedDate);
return;
}
if (Owner.HoverStart.HasValue)
@@ -1058,14 +1046,14 @@ namespace Avalonia.Controls.Primitives
Owner.RemovedItems.Add(item);
}
Owner.SelectedDates.ClearInternal();
- AddSelection(b);
+ AddSelection(b, selectedDate);
return;
}
case CalendarSelectionMode.MultipleRange:
{
// add the selection (either single day or
// SingleRange day)
- AddSelection(b);
+ AddSelection(b, selectedDate);
return;
}
}
@@ -1076,7 +1064,7 @@ namespace Avalonia.Controls.Primitives
// be able to switch months
if (b.IsInactive && b.IsBlackout)
{
- Owner.OnDayClick((DateTime)b.DataContext);
+ Owner.OnDayClick(selectedDate);
}
}
}
@@ -1095,9 +1083,9 @@ namespace Avalonia.Controls.Primitives
Owner.HoverStart = null;
_isMouseLeftButtonDown = false;
b.IsSelected = false;
- if (b.DataContext != null)
+ if (b.DataContext is DateTime selectedDate)
{
- Owner.SelectedDates.Remove((DateTime)b.DataContext);
+ Owner.SelectedDates.Remove(selectedDate);
}
}
}
@@ -1107,35 +1095,26 @@ namespace Avalonia.Controls.Primitives
private void Month_CalendarButtonMouseDown(object? sender, PointerPressedEventArgs e)
{
- CalendarButton b = (CalendarButton)sender!;
-
_isMouseLeftButtonDownYearView = true;
- if (e != null)
- {
- _downEventArgYearView = e;
- }
-
- UpdateYearViewSelection(b);
+ UpdateYearViewSelection(sender as CalendarButton);
}
internal void Month_CalendarButtonMouseUp(object? sender, PointerReleasedEventArgs e)
{
_isMouseLeftButtonDownYearView = false;
- if (Owner != null)
+ if (Owner != null && (sender as CalendarButton)?.DataContext is DateTime newMonth)
{
- DateTime newmonth = (DateTime)((CalendarButton)sender!).DataContext!;
-
if (Owner.DisplayMode == CalendarMode.Year)
{
- Owner.DisplayDate = newmonth;
+ Owner.DisplayDate = newMonth;
Owner.DisplayMode = CalendarMode.Month;
}
else
{
Debug.Assert(Owner.DisplayMode == CalendarMode.Decade, "The owning Calendar should be in decade mode!");
- Owner.SelectedMonth = newmonth;
+ Owner.SelectedMonth = newMonth;
Owner.DisplayMode = CalendarMode.Year;
}
}
@@ -1145,8 +1124,7 @@ namespace Avalonia.Controls.Primitives
{
if (_isMouseLeftButtonDownYearView)
{
- CalendarButton b = (CalendarButton)sender!;
- UpdateYearViewSelection(b);
+ UpdateYearViewSelection(sender as CalendarButton);
}
}
diff --git a/src/Avalonia.Controls/Calendar/DateTimeHelper.cs b/src/Avalonia.Controls/Calendar/DateTimeHelper.cs
index bfff03a926..570f05cfe8 100644
--- a/src/Avalonia.Controls/Calendar/DateTimeHelper.cs
+++ b/src/Avalonia.Controls/Calendar/DateTimeHelper.cs
@@ -53,7 +53,7 @@ namespace Avalonia.Controls
public static int CompareDays(DateTime dt1, DateTime dt2)
{
- return DateTime.Compare(DiscardTime(dt1).Value, DiscardTime(dt2).Value);
+ return DateTime.Compare(DiscardTime(dt1), DiscardTime(dt2));
}
public static int CompareYearMonth(DateTime dt1, DateTime dt2)
@@ -71,14 +71,9 @@ namespace Avalonia.Controls
return new DateTime(d.Year, d.Month, 1, 0, 0, 0);
}
- [return: NotNullIfNotNull("d")]
- public static DateTime? DiscardTime(DateTime? d)
+ public static DateTime DiscardTime(DateTime d)
{
- if (d == null)
- {
- return null;
- }
- return d.Value.Date;
+ return d.Date;
}
public static int EndOfDecade(DateTime date)
@@ -127,28 +122,14 @@ namespace Avalonia.Controls
public static string ToYearMonthPatternString(DateTime date)
{
- string result = string.Empty;
- DateTimeFormatInfo format = GetCurrentDateFormat();
-
- if (format != null)
- {
- result = date.ToString(format.YearMonthPattern, format);
- }
-
- return result;
+ var format = GetCurrentDateFormat();
+ return date.ToString(format.YearMonthPattern, format);
}
public static string ToYearString(DateTime date)
{
- string result = string.Empty;
- DateTimeFormatInfo format = GetCurrentDateFormat();
-
- if (format != null)
- {
- result = date.Year.ToString(format);
- }
-
- return result;
+ var format = GetCurrentDateFormat();
+ return date.Year.ToString(format);
}
}
}
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
index b17648f5bb..869bdeabea 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
@@ -51,11 +51,11 @@ namespace Avalonia.Controls
private bool _isDropDownOpen;
private DateTime? _selectedDate;
private string? _text;
- private bool _suspendTextChangeHandler = false;
- private bool _isPopupClosing = false;
- private bool _ignoreButtonClick = false;
- private bool _isFlyoutOpen = false;
- private bool _isPressed = false;
+ private bool _suspendTextChangeHandler;
+ private bool _isPopupClosing;
+ private bool _ignoreButtonClick;
+ private bool _isFlyoutOpen;
+ private bool _isPressed;
///
/// Occurs when the drop-down
@@ -185,7 +185,7 @@ namespace Avalonia.Controls
{
_textBox.KeyDown += TextBox_KeyDown;
_textBox.GotFocus += TextBox_GotFocus;
- _textBoxTextChangedSubscription = _textBox.GetObservable(TextBox.TextProperty).Subscribe(txt => TextBox_TextChanged());
+ _textBoxTextChangedSubscription = _textBox.GetObservable(TextBox.TextProperty).Subscribe(_ => TextBox_TextChanged());
if(SelectedDate.HasValue)
{
@@ -292,7 +292,7 @@ namespace Avalonia.Controls
// Text
else if (change.Property == TextProperty)
{
- var (oldValue, newValue) = change.GetOldAndNewValue();
+ var (_, newValue) = change.GetOldAndNewValue();
if (!_suspendTextChangeHandler)
{
@@ -595,9 +595,9 @@ namespace Avalonia.Controls
private void Calendar_KeyDown(object? sender, KeyEventArgs e)
{
- Calendar? c = sender as Calendar ?? throw new ArgumentException("Sender must be Calendar.", nameof(sender));
-
- if (!e.Handled && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape) && c.DisplayMode == CalendarMode.Month)
+ if (!e.Handled
+ && sender is Calendar { DisplayMode: CalendarMode.Month }
+ && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape))
{
Focus();
IsDropDownOpen = false;
diff --git a/src/Avalonia.Controls/Chrome/TitleBar.cs b/src/Avalonia.Controls/Chrome/TitleBar.cs
index 47b0bb6e2d..368c9d4c2f 100644
--- a/src/Avalonia.Controls/Chrome/TitleBar.cs
+++ b/src/Avalonia.Controls/Chrome/TitleBar.cs
@@ -17,28 +17,26 @@ namespace Avalonia.Controls.Chrome
private void UpdateSize(Window window)
{
- if (window != null)
+ Margin = new Thickness(
+ window.OffScreenMargin.Left,
+ window.OffScreenMargin.Top,
+ window.OffScreenMargin.Right,
+ window.OffScreenMargin.Bottom);
+
+ if (window.WindowState != WindowState.FullScreen)
{
- Margin = new Thickness(
- window.OffScreenMargin.Left,
- window.OffScreenMargin.Top,
- window.OffScreenMargin.Right,
- window.OffScreenMargin.Bottom);
+ Height = window.WindowDecorationMargin.Top;
- if (window.WindowState != WindowState.FullScreen)
+ if (_captionButtons != null)
{
- Height = window.WindowDecorationMargin.Top;
-
- if (_captionButtons != null)
- {
- _captionButtons.Height = Height;
- }
+ _captionButtons.Height = Height;
}
-
- IsVisible = window.PlatformImpl?.NeedsManagedDecorations ?? false;
}
+
+ IsVisible = window.PlatformImpl?.NeedsManagedDecorations ?? false;
}
+ ///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@@ -55,6 +53,7 @@ namespace Avalonia.Controls.Chrome
}
}
+ ///
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
@@ -64,13 +63,13 @@ namespace Avalonia.Controls.Chrome
_disposables = new CompositeDisposable(6)
{
window.GetObservable(Window.WindowDecorationMarginProperty)
- .Subscribe(x => UpdateSize(window)),
+ .Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
- .Subscribe(x => UpdateSize(window)),
+ .Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.OffScreenMarginProperty)
- .Subscribe(x => UpdateSize(window)),
+ .Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.ExtendClientAreaChromeHintsProperty)
- .Subscribe(x => UpdateSize(window)),
+ .Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.WindowStateProperty)
.Subscribe(x =>
{
@@ -80,11 +79,12 @@ namespace Avalonia.Controls.Chrome
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
}),
window.GetObservable(Window.IsExtendedIntoWindowDecorationsProperty)
- .Subscribe(x => UpdateSize(window))
+ .Subscribe(_ => UpdateSize(window))
};
}
}
+ ///
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs
index b7a298bb16..17a6ad7a09 100644
--- a/src/Avalonia.Controls/ComboBox.cs
+++ b/src/Avalonia.Controls/ComboBox.cs
@@ -1,19 +1,19 @@
using System;
+using System.Diagnostics;
using System.Linq;
using Avalonia.Automation.Peers;
-using Avalonia.Reactive;
-using Avalonia.Controls.Generators;
-using Avalonia.Controls.Mixins;
-using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Selection;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
+using Avalonia.Controls.Utils;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
+using Avalonia.Reactive;
using Avalonia.VisualTree;
-using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
@@ -219,7 +219,7 @@ namespace Avalonia.Controls
}
else if (e.Key == Key.Up)
{
- SelectPrev();
+ SelectPrevious();
e.Handled = true;
}
}
@@ -250,7 +250,7 @@ namespace Avalonia.Controls
if (e.Delta.Y < 0)
SelectNext();
else
- SelectPrev();
+ SelectPrevious();
e.Handled = true;
}
@@ -478,19 +478,40 @@ namespace Avalonia.Controls
}
}
- private void SelectNext()
- {
- if (ItemCount >= 1)
- {
- MoveSelection(NavigationDirection.Next, WrapSelection);
- }
- }
+ private void SelectNext() => MoveSelection(SelectedIndex, 1, WrapSelection);
+ private void SelectPrevious() => MoveSelection(SelectedIndex, -1, WrapSelection);
- private void SelectPrev()
+ private void MoveSelection(int startIndex, int step, bool wrap)
{
- if (ItemCount >= 1)
+ static bool IsSelectable(object? o) => (o as AvaloniaObject)?.GetValue(IsEnabledProperty) ?? true;
+
+ var count = ItemCount;
+
+ for (int i = startIndex + step; i != startIndex; i += step)
{
- MoveSelection(NavigationDirection.Previous, WrapSelection);
+ if (i < 0 || i >= count)
+ {
+ if (wrap)
+ {
+ if (i < 0)
+ i += count;
+ else if (i >= count)
+ i %= count;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ var item = ItemsView[i];
+ var container = ContainerFromIndex(i);
+
+ if (IsSelectable(item) && IsSelectable(container))
+ {
+ SelectedIndex = i;
+ break;
+ }
}
}
}
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index ed24c3c7c2..ab7c9948c4 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -2,14 +2,12 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using Avalonia.Automation.Peers;
-using Avalonia.Controls.Documents;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
-using Avalonia.Media;
using Avalonia.Rendering;
using Avalonia.Styling;
using Avalonia.Threading;
@@ -211,8 +209,6 @@ namespace Avalonia.Controls
remove => RemoveHandler(SizeChangedEvent, value);
}
- public new Control? Parent => (Control?)base.Parent;
-
///
bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;
diff --git a/src/Avalonia.Controls/Controls.cs b/src/Avalonia.Controls/Controls.cs
index 8b0e998f64..736c7e8a77 100644
--- a/src/Avalonia.Controls/Controls.cs
+++ b/src/Avalonia.Controls/Controls.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Avalonia.Collections;
@@ -13,7 +14,7 @@ namespace Avalonia.Controls
///
public Controls()
{
- ResetBehavior = ResetBehavior.Remove;
+ Configure();
}
///
@@ -21,9 +22,22 @@ namespace Avalonia.Controls
///
/// The initial items in the collection.
public Controls(IEnumerable items)
- : base(items)
+ {
+ Configure();
+ AddRange(items); // virtual member call in ctor, ok for our current implementation
+ }
+
+ private void Configure()
{
ResetBehavior = ResetBehavior.Remove;
+ Validate = item =>
+ {
+ if (item is null)
+ {
+ throw new ArgumentNullException(nameof(item),
+ $"A null control cannot be added to a {nameof(Controls)} collection.");
+ }
+ };
}
}
}
diff --git a/src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs b/src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
index 9d859a753a..18d668e9a4 100644
--- a/src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
+++ b/src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
@@ -14,7 +14,6 @@ namespace Avalonia.Controls.Converters
public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture)
{
if (parameter == null ||
- values == null ||
values.Count != 4 ||
!(values[0] is ScrollBarVisibility visibility) ||
!(values[1] is double offset) ||
diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs
index 5c35a09f1c..eb587fb157 100644
--- a/src/Avalonia.Controls/DefinitionBase.cs
+++ b/src/Avalonia.Controls/DefinitionBase.cs
@@ -21,9 +21,9 @@ namespace Avalonia.Controls
///
/// SharedSizeGroup property.
///
- public string SharedSizeGroup
+ public string? SharedSizeGroup
{
- get { return (string)GetValue(SharedSizeGroupProperty); }
+ get { return GetValue(SharedSizeGroupProperty); }
set { SetValue(SharedSizeGroupProperty, value); }
}
@@ -32,20 +32,15 @@ namespace Avalonia.Controls
///
internal void OnEnterParentTree()
{
- this.InheritanceParent = Parent;
+ InheritanceParent = Parent;
if (_sharedState == null)
{
// start with getting SharedSizeGroup value.
// this property is NOT inherited which should result in better overall perf.
- string sharedSizeGroupId = SharedSizeGroup;
- if (sharedSizeGroupId != null)
+ if (SharedSizeGroup is { } sharedSizeGroupId && PrivateSharedSizeScope is { } privateSharedSizeScope)
{
- SharedSizeScope? privateSharedSizeScope = PrivateSharedSizeScope;
- if (privateSharedSizeScope != null)
- {
- _sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
- _sharedState.AddMember(this);
- }
+ _sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
+ _sharedState.AddMember(this);
}
}
@@ -321,13 +316,12 @@ namespace Avalonia.Controls
return ((_flags & flags) == flags);
}
- private static void OnSharedSizeGroupPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
+ private static void OnSharedSizeGroupPropertyChanged(DefinitionBase definition,
+ AvaloniaPropertyChangedEventArgs e)
{
- DefinitionBase definition = (DefinitionBase)d;
-
if (definition.Parent != null)
{
- string sharedSizeGroupId = (string)e.NewValue!;
+ string? sharedSizeGroupId = e.NewValue.Value;
if (definition._sharedState != null)
{
@@ -337,16 +331,14 @@ namespace Avalonia.Controls
definition._sharedState = null;
}
- if ((definition._sharedState == null) && (sharedSizeGroupId != null))
+ if (definition._sharedState == null
+ && sharedSizeGroupId != null
+ && definition.PrivateSharedSizeScope is { } privateSharedSizeScope)
{
- SharedSizeScope? privateSharedSizeScope = definition.PrivateSharedSizeScope;
- if (privateSharedSizeScope != null)
- {
- // if definition is not registered and both: shared size group id AND private shared scope
- // are available, then register definition.
- definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
- definition._sharedState.AddMember(definition);
- }
+ // if definition is not registered and both: shared size group id AND private shared scope
+ // are available, then register definition.
+ definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
+ definition._sharedState.AddMember(definition);
}
}
}
@@ -357,17 +349,15 @@ namespace Avalonia.Controls
/// b) contains only letters, digits and underscore ('_').
/// c) does not start with a digit.
///
- private static bool SharedSizeGroupPropertyValueValid(string value)
+ private static bool SharedSizeGroupPropertyValueValid(string? id)
{
// null is default value
- if (value == null)
+ if (id == null)
{
return true;
}
- string id = (string)value;
-
- if (!string.IsNullOrEmpty(id))
+ if (id.Length > 0)
{
int i = -1;
while (++i < id.Length)
@@ -397,14 +387,11 @@ namespace Avalonia.Controls
/// existing scope just left. In both cases if the DefinitionBase object is already registered
/// in SharedSizeState, it should un-register and register itself in a new one.
///
- private static void OnPrivateSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
+ private static void OnPrivateSharedSizeScopePropertyChanged(DefinitionBase definition,
+ AvaloniaPropertyChangedEventArgs e)
{
- DefinitionBase definition = (DefinitionBase)d;
-
if (definition.Parent != null)
{
- SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue!;
-
if (definition._sharedState != null)
{
// if definition is already registered And shared size scope is changing,
@@ -413,16 +400,14 @@ namespace Avalonia.Controls
definition._sharedState = null;
}
- if ((definition._sharedState == null) && (privateSharedSizeScope != null))
+ if (definition._sharedState == null
+ && e.NewValue.Value is { } privateSharedSizeScope
+ && definition.SharedSizeGroup is { } sharedSizeGroup)
{
- string sharedSizeGroup = definition.SharedSizeGroup;
- if (sharedSizeGroup != null)
- {
- // if definition is not registered and both: shared size group id AND private shared scope
- // are available, then register definition.
- definition._sharedState = privateSharedSizeScope.EnsureSharedState(definition.SharedSizeGroup);
- definition._sharedState.AddMember(definition);
- }
+ // if definition is not registered and both: shared size group id AND private shared scope
+ // are available, then register definition.
+ definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroup);
+ definition._sharedState.AddMember(definition);
}
}
}
@@ -432,7 +417,7 @@ namespace Avalonia.Controls
///
private SharedSizeScope? PrivateSharedSizeScope
{
- get { return (SharedSizeScope?)GetValue(PrivateSharedSizeScopeProperty); }
+ get { return GetValue(PrivateSharedSizeScopeProperty); }
}
///
@@ -465,7 +450,7 @@ namespace Avalonia.Controls
private SharedSizeState? _sharedState; // reference to shared state object this instance is registered with
- [System.Flags]
+ [Flags]
private enum Flags : byte
{
//
@@ -520,11 +505,10 @@ namespace Avalonia.Controls
///
internal SharedSizeState(SharedSizeScope sharedSizeScope, string sharedSizeGroupId)
{
- Debug.Assert(sharedSizeScope != null && sharedSizeGroupId != null);
_sharedSizeScope = sharedSizeScope;
_sharedSizeGroupId = sharedSizeGroupId;
_registry = new List();
- _layoutUpdated = new EventHandler(OnLayoutUpdated);
+ _layoutUpdated = OnLayoutUpdated;
_broadcastInvalidation = true;
}
@@ -568,7 +552,7 @@ namespace Avalonia.Controls
{
for (int i = 0, count = _registry.Count; i < count; ++i)
{
- Grid parentGrid = (Grid)(_registry[i].Parent!);
+ Grid parentGrid = _registry[i].Parent!;
parentGrid.Invalidate();
}
_broadcastInvalidation = false;
@@ -703,7 +687,7 @@ namespace Avalonia.Controls
// measure is invalid - it used the old shared size,
// which is larger than d's (possibly changed) minSize
measureIsValid = (definitionBase.LayoutWasUpdated &&
- MathUtilities.GreaterThanOrClose(definitionBase._minSize, this.MinSize));
+ MathUtilities.GreaterThanOrClose(definitionBase._minSize, MinSize));
}
if(!measureIsValid)
@@ -786,8 +770,8 @@ namespace Avalonia.Controls
///
///
///
- public static readonly AttachedProperty SharedSizeGroupProperty =
- AvaloniaProperty.RegisterAttached(
+ public static readonly AttachedProperty SharedSizeGroupProperty =
+ AvaloniaProperty.RegisterAttached(
"SharedSizeGroup",
validate: SharedSizeGroupPropertyValueValid);
@@ -796,8 +780,8 @@ namespace Avalonia.Controls
///
static DefinitionBase()
{
- SharedSizeGroupProperty.Changed.AddClassHandler(OnSharedSizeGroupPropertyChanged);
- PrivateSharedSizeScopeProperty.Changed.AddClassHandler(OnPrivateSharedSizeScopePropertyChanged);
+ SharedSizeGroupProperty.Changed.AddClassHandler(OnSharedSizeGroupPropertyChanged);
+ PrivateSharedSizeScopeProperty.Changed.AddClassHandler(OnPrivateSharedSizeScopePropertyChanged);
}
///
diff --git a/src/Avalonia.Controls/DockPanel.cs b/src/Avalonia.Controls/DockPanel.cs
index 3e3ed509b5..1a0cf1644a 100644
--- a/src/Avalonia.Controls/DockPanel.cs
+++ b/src/Avalonia.Controls/DockPanel.cs
@@ -101,9 +101,6 @@ namespace Avalonia.Controls
Size childConstraint; // Contains the suggested input constraint for this child.
Size childDesiredSize; // Contains the return size from child measure.
- if (child == null)
- { continue; }
-
// Child constraint is the remaining size; this is total size minus size consumed by previous children.
childConstraint = new Size(Math.Max(0.0, constraint.Width - accumulatedWidth),
Math.Max(0.0, constraint.Height - accumulatedHeight));
@@ -122,7 +119,7 @@ namespace Avalonia.Controls
// will deal with computing our minimum size (parentSize) due to that accumulation.
// Therefore, we only need to compute our minimum size (parentSize) in dimensions that this child does
// not accumulate: Width for Top/Bottom, Height for Left/Right.
- switch (DockPanel.GetDock((Control)child))
+ switch (GetDock(child))
{
case Dock.Left:
case Dock.Right:
@@ -164,8 +161,6 @@ namespace Avalonia.Controls
for (int i = 0; i < totalChildrenCount; ++i)
{
var child = children[i];
- if (child == null)
- { continue; }
Size childDesiredSize = child.DesiredSize;
Rect rcChild = new Rect(
@@ -176,7 +171,7 @@ namespace Avalonia.Controls
if (i < nonFillChildrenCount)
{
- switch (DockPanel.GetDock((Control)child))
+ switch (GetDock(child))
{
case Dock.Left:
accumulatedLeft += childDesiredSize.Width;
diff --git a/src/Avalonia.Controls/Documents/Inline.cs b/src/Avalonia.Controls/Documents/Inline.cs
index 47581e87f1..23b806583e 100644
--- a/src/Avalonia.Controls/Documents/Inline.cs
+++ b/src/Avalonia.Controls/Documents/Inline.cs
@@ -13,8 +13,8 @@ namespace Avalonia.Controls.Documents
///
/// AvaloniaProperty for property.
///
- public static readonly StyledProperty TextDecorationsProperty =
- AvaloniaProperty.Register(
+ public static readonly StyledProperty TextDecorationsProperty =
+ AvaloniaProperty.Register(
nameof(TextDecorations));
///
@@ -28,7 +28,7 @@ namespace Avalonia.Controls.Documents
///
/// The TextDecorations property specifies decorations that are added to the text of an element.
///
- public TextDecorationCollection TextDecorations
+ public TextDecorationCollection? TextDecorations
{
get { return GetValue(TextDecorationsProperty); }
set { SetValue(TextDecorationsProperty, value); }
@@ -83,7 +83,8 @@ namespace Avalonia.Controls.Documents
return new GenericTextRunProperties(new Typeface(FontFamily, fontStyle, fontWeight), FontSize,
textDecorations, Foreground, background, BaselineAlignment);
}
-
+
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
diff --git a/src/Avalonia.Controls/Documents/InlineUIContainer.cs b/src/Avalonia.Controls/Documents/InlineUIContainer.cs
index 58afb24b5c..f06c8515ee 100644
--- a/src/Avalonia.Controls/Documents/InlineUIContainer.cs
+++ b/src/Avalonia.Controls/Documents/InlineUIContainer.cs
@@ -64,5 +64,23 @@ namespace Avalonia.Controls.Documents
internal override void AppendText(StringBuilder stringBuilder)
{
}
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == ChildProperty)
+ {
+ if(change.OldValue is Control oldChild)
+ {
+ LogicalChildren.Remove(oldChild);
+ }
+
+ if(change.NewValue is Control newChild)
+ {
+ LogicalChildren.Add(newChild);
+ }
+ }
+ }
}
}
diff --git a/src/Avalonia.Controls/Documents/Span.cs b/src/Avalonia.Controls/Documents/Span.cs
index a7a702ceae..d3565cbdd5 100644
--- a/src/Avalonia.Controls/Documents/Span.cs
+++ b/src/Avalonia.Controls/Documents/Span.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Media.TextFormatting;
@@ -51,6 +52,7 @@ namespace Avalonia.Controls.Documents
}
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@@ -68,26 +70,26 @@ namespace Avalonia.Controls.Documents
{
base.OnInlineHostChanged(oldValue, newValue);
- if (Inlines is not null)
- {
- Inlines.InlineHost = newValue;
- }
+ Inlines.InlineHost = newValue;
}
private void OnInlinesChanged(InlineCollection? oldValue, InlineCollection? newValue)
{
+ void OnInlinesInvalidated(object? sender, EventArgs e)
+ => InlineHost?.Invalidate();
+
if (oldValue is not null)
{
oldValue.LogicalChildren = null;
oldValue.InlineHost = null;
- oldValue.Invalidated -= (s, e) => InlineHost?.Invalidate();
+ oldValue.Invalidated -= OnInlinesInvalidated;
}
if (newValue is not null)
{
newValue.LogicalChildren = LogicalChildren;
newValue.InlineHost = InlineHost;
- newValue.Invalidated += (s, e) => InlineHost?.Invalidate();
+ newValue.Invalidated += OnInlinesInvalidated;
}
}
}
diff --git a/src/Avalonia.Controls/ExperimentalAcrylicBorder.cs b/src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
index e4487d29fa..e1f840672d 100644
--- a/src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
+++ b/src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
@@ -80,7 +80,7 @@ namespace Avalonia.Controls
_subscription?.Dispose();
}
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
{
if (context.PlatformImpl is IDrawingContextWithAcrylicLikeSupport idc)
{
diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs
index 7737fdac2e..ff9fb4e31d 100644
--- a/src/Avalonia.Controls/Grid.cs
+++ b/src/Avalonia.Controls/Grid.cs
@@ -164,20 +164,21 @@ namespace Avalonia.Controls
///
/// Returns a ColumnDefinitions of column definitions.
///
+ [MemberNotNull(nameof(_extData))]
public ColumnDefinitions ColumnDefinitions
{
get
{
- if (_data == null) { _data = new ExtendedData(); }
- if (_data.ColumnDefinitions == null) { _data.ColumnDefinitions = new ColumnDefinitions() { Parent = this }; }
+ if (_extData == null) { _extData = new ExtendedData(); }
+ if (_extData.ColumnDefinitions == null) { _extData.ColumnDefinitions = new ColumnDefinitions() { Parent = this }; }
- return (_data.ColumnDefinitions);
+ return (_extData.ColumnDefinitions);
}
set
{
- if (_data == null) { _data = new ExtendedData(); }
- _data.ColumnDefinitions = value;
- _data.ColumnDefinitions.Parent = this;
+ if (_extData == null) { _extData = new ExtendedData(); }
+ _extData.ColumnDefinitions = value;
+ _extData.ColumnDefinitions.Parent = this;
InvalidateMeasure();
}
}
@@ -185,20 +186,21 @@ namespace Avalonia.Controls
///
/// Returns a RowDefinitions of row definitions.
///
+ [MemberNotNull(nameof(_extData))]
public RowDefinitions RowDefinitions
{
get
{
- if (_data == null) { _data = new ExtendedData(); }
- if (_data.RowDefinitions == null) { _data.RowDefinitions = new RowDefinitions() { Parent = this }; }
+ if (_extData == null) { _extData = new ExtendedData(); }
+ if (_extData.RowDefinitions == null) { _extData.RowDefinitions = new RowDefinitions() { Parent = this }; }
- return (_data.RowDefinitions);
+ return (_extData.RowDefinitions);
}
set
{
- if (_data == null) { _data = new ExtendedData(); }
- _data.RowDefinitions = value;
- _data.RowDefinitions.Parent = this;
+ if (_extData == null) { _extData = new ExtendedData(); }
+ _extData.RowDefinitions = value;
+ _extData.RowDefinitions.Parent = this;
InvalidateMeasure();
}
}
@@ -211,7 +213,7 @@ namespace Avalonia.Controls
protected override Size MeasureOverride(Size constraint)
{
Size gridDesiredSize;
- ExtendedData extData = ExtData;
+ var extData = _extData;
try
{
@@ -221,17 +223,14 @@ namespace Avalonia.Controls
if (extData == null)
{
gridDesiredSize = new Size();
- var children = this.Children;
+ var children = Children;
for (int i = 0, count = children.Count; i < count; ++i)
{
var child = children[i];
- if (child != null)
- {
- child.Measure(constraint);
- gridDesiredSize = new Size(Math.Max(gridDesiredSize.Width, child.DesiredSize.Width),
- Math.Max(gridDesiredSize.Height, child.DesiredSize.Height));
- }
+ child.Measure(constraint);
+ gridDesiredSize = new Size(Math.Max(gridDesiredSize.Width, child.DesiredSize.Width),
+ Math.Max(gridDesiredSize.Height, child.DesiredSize.Height));
}
}
else
@@ -512,17 +511,14 @@ namespace Avalonia.Controls
{
ArrangeOverrideInProgress = true;
- if (_data == null)
+ if (_extData is null)
{
- var children = this.Children;
+ var children = Children;
for (int i = 0, count = children.Count; i < count; ++i)
{
var child = children[i];
- if (child != null)
- {
- child.Arrange(new Rect(arrangeSize));
- }
+ child.Arrange(new Rect(arrangeSize));
}
}
else
@@ -532,15 +528,11 @@ namespace Avalonia.Controls
SetFinalSize(DefinitionsU, arrangeSize.Width, true);
SetFinalSize(DefinitionsV, arrangeSize.Height, false);
- var children = this.Children;
+ var children = Children;
for (int currentCell = 0; currentCell < PrivateCells.Length; ++currentCell)
{
var cell = children[currentCell];
- if (cell == null)
- {
- continue;
- }
int columnIndex = PrivateCells[currentCell].ColumnIndex;
int rowIndex = PrivateCells[currentCell].RowIndex;
@@ -599,7 +591,7 @@ namespace Avalonia.Controls
{
double value = 0.0;
- Debug.Assert(_data != null);
+ Debug.Assert(_extData != null);
// actual value calculations require structure to be up-to-date
if (!ColumnDefinitionsDirty)
@@ -621,7 +613,7 @@ namespace Avalonia.Controls
{
double value = 0.0;
- Debug.Assert(_data != null);
+ Debug.Assert(_extData != null);
// actual value calculations require structure to be up-to-date
if (!RowDefinitionsDirty)
@@ -654,18 +646,20 @@ namespace Avalonia.Controls
///
/// Convenience accessor to ValidDefinitionsUStructure bit flag.
///
+ [MemberNotNull(nameof(_extData))]
internal bool ColumnDefinitionsDirty
{
- get => ColumnDefinitions?.IsDirty ?? false;
+ get => ColumnDefinitions.IsDirty;
set => ColumnDefinitions.IsDirty = value;
}
///
/// Convenience accessor to ValidDefinitionsVStructure bit flag.
///
+ [MemberNotNull(nameof(_extData))]
internal bool RowDefinitionsDirty
{
- get => RowDefinitions?.IsDirty ?? false;
+ get => RowDefinitions.IsDirty;
set => RowDefinitions.IsDirty = value;
}
@@ -686,8 +680,10 @@ namespace Avalonia.Controls
///
private void ValidateCellsCore()
{
- var children = this.Children;
- ExtendedData extData = ExtData;
+ Debug.Assert(_extData is not null);
+
+ var children = Children;
+ var extData = _extData!;
extData.CellCachesCollection = new CellCache[children.Count];
extData.CellGroup1 = int.MaxValue;
@@ -702,10 +698,6 @@ namespace Avalonia.Controls
for (int i = PrivateCells.Length - 1; i >= 0; --i)
{
var child = children[i];
- if (child == null)
- {
- continue;
- }
CellCache cell = new CellCache();
@@ -713,19 +705,19 @@ namespace Avalonia.Controls
// Read indices from the corresponding properties:
// clamp to value < number_of_columns
// column >= 0 is guaranteed by property value validation callback
- cell.ColumnIndex = Math.Min(GetColumn((Control)child), DefinitionsU.Count - 1);
+ cell.ColumnIndex = Math.Min(GetColumn(child), DefinitionsU.Count - 1);
// clamp to value < number_of_rows
// row >= 0 is guaranteed by property value validation callback
- cell.RowIndex = Math.Min(GetRow((Control)child), DefinitionsV.Count - 1);
+ cell.RowIndex = Math.Min(GetRow(child), DefinitionsV.Count - 1);
// Read span properties:
// clamp to not exceed beyond right side of the grid
// column_span > 0 is guaranteed by property value validation callback
- cell.ColumnSpan = Math.Min(GetColumnSpan((Control)child), DefinitionsU.Count - cell.ColumnIndex);
+ cell.ColumnSpan = Math.Min(GetColumnSpan(child), DefinitionsU.Count - cell.ColumnIndex);
// clamp to not exceed beyond bottom side of the grid
// row_span > 0 is guaranteed by property value validation callback
- cell.RowSpan = Math.Min(GetRowSpan((Control)child), DefinitionsV.Count - cell.RowIndex);
+ cell.RowSpan = Math.Min(GetRowSpan(child), DefinitionsV.Count - cell.RowIndex);
Debug.Assert(0 <= cell.ColumnIndex && cell.ColumnIndex < DefinitionsU.Count);
Debug.Assert(0 <= cell.RowIndex && cell.RowIndex < DefinitionsV.Count);
@@ -792,7 +784,7 @@ namespace Avalonia.Controls
{
if (ColumnDefinitionsDirty)
{
- ExtendedData extData = ExtData;
+ var extData = _extData;
if (extData.ColumnDefinitions == null)
{
@@ -818,7 +810,7 @@ namespace Avalonia.Controls
ColumnDefinitionsDirty = false;
}
- Debug.Assert(ExtData.DefinitionsU != null && ExtData.DefinitionsU.Count > 0);
+ Debug.Assert(_extData is { DefinitionsU.Count: > 0 });
}
///
@@ -833,7 +825,7 @@ namespace Avalonia.Controls
{
if (RowDefinitionsDirty)
{
- ExtendedData extData = ExtData;
+ var extData = _extData;
if (extData.RowDefinitions == null)
{
@@ -859,7 +851,7 @@ namespace Avalonia.Controls
RowDefinitionsDirty = false;
}
- Debug.Assert(ExtData.DefinitionsV != null && ExtData.DefinitionsV.Count > 0);
+ Debug.Assert(_extData is { DefinitionsV.Count: > 0 });
}
///
@@ -965,8 +957,7 @@ namespace Avalonia.Controls
bool ignoreDesiredSizeU,
bool forceInfinityV)
{
- bool unusedHasDesiredSizeUChanged;
- MeasureCellsGroup(cellsHead, referenceSize, ignoreDesiredSizeU, forceInfinityV, out unusedHasDesiredSizeUChanged);
+ MeasureCellsGroup(cellsHead, referenceSize, ignoreDesiredSizeU, forceInfinityV, out _);
}
///
@@ -994,7 +985,7 @@ namespace Avalonia.Controls
return;
}
- var children = this.Children;
+ var children = Children;
Hashtable? spanStore = null;
bool ignoreDesiredSizeV = forceInfinityV;
@@ -1101,8 +1092,6 @@ namespace Avalonia.Controls
int cell,
bool forceInfinityV)
{
-
-
double cellMeasureWidth;
double cellMeasureHeight;
@@ -1144,15 +1133,9 @@ namespace Avalonia.Controls
}
- var child = this.Children[cell];
- if (child != null)
- {
- Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight);
- child.Measure(childConstraint);
- }
-
-
-
+ var child = Children[cell];
+ Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight);
+ child.Measure(childConstraint);
}
///
@@ -1230,7 +1213,7 @@ namespace Avalonia.Controls
// avoid processing when asked to distribute "0"
if (!MathUtilities.IsZero(requestedSize))
{
- DefinitionBase[] tempDefinitions = TempDefinitions; // temp array used to remember definitions for sorting
+ DefinitionBase?[] tempDefinitions = TempDefinitions; // temp array used to remember definitions for sorting
int end = start + count;
int autoDefinitionsCount = 0;
double rangeMinSize = 0;
@@ -1288,20 +1271,24 @@ namespace Avalonia.Controls
Array.Sort(tempDefinitions, 0, count, s_spanPreferredDistributionOrderComparer);
for (i = 0, sizeToDistribute = requestedSize; i < autoDefinitionsCount; ++i)
{
+ var tempDefinition = tempDefinitions[i]!;
+
// sanity check: only auto definitions allowed in this loop
- Debug.Assert(tempDefinitions[i].UserSize.IsAuto);
+ Debug.Assert(tempDefinition.UserSize.IsAuto);
// adjust sizeToDistribute value by subtracting auto definition min size
- sizeToDistribute -= (tempDefinitions[i].MinSize);
+ sizeToDistribute -= (tempDefinition.MinSize);
}
for (; i < count; ++i)
{
+ var tempDefinition = tempDefinitions[i]!;
+
// sanity check: no auto definitions allowed in this loop
- Debug.Assert(!tempDefinitions[i].UserSize.IsAuto);
+ Debug.Assert(!tempDefinition.UserSize.IsAuto);
- double newMinSize = Math.Min(sizeToDistribute / (count - i), tempDefinitions[i].PreferredSize);
- if (newMinSize > tempDefinitions[i].MinSize) { tempDefinitions[i].UpdateMinSize(newMinSize); }
+ double newMinSize = Math.Min(sizeToDistribute / (count - i), tempDefinition.PreferredSize);
+ if (newMinSize > tempDefinition.MinSize) { tempDefinition.UpdateMinSize(newMinSize); }
sizeToDistribute -= newMinSize;
}
@@ -1325,24 +1312,28 @@ namespace Avalonia.Controls
Array.Sort(tempDefinitions, 0, count, s_spanMaxDistributionOrderComparer);
for (i = 0, sizeToDistribute = requestedSize - rangePreferredSize; i < count - autoDefinitionsCount; ++i)
{
+ var tempDefinition = tempDefinitions[i]!;
+
// sanity check: no auto definitions allowed in this loop
- Debug.Assert(!tempDefinitions[i].UserSize.IsAuto);
+ Debug.Assert(!tempDefinition.UserSize.IsAuto);
- double preferredSize = tempDefinitions[i].PreferredSize;
+ double preferredSize = tempDefinition.PreferredSize;
double newMinSize = preferredSize + sizeToDistribute / (count - autoDefinitionsCount - i);
- tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache));
- sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize);
+ tempDefinition.UpdateMinSize(Math.Min(newMinSize, tempDefinition.SizeCache));
+ sizeToDistribute -= (tempDefinition.MinSize - preferredSize);
}
for (; i < count; ++i)
{
+ var tempDefinition = tempDefinitions[i]!;
+
// sanity check: only auto definitions allowed in this loop
- Debug.Assert(tempDefinitions[i].UserSize.IsAuto);
+ Debug.Assert(tempDefinition.UserSize.IsAuto);
- double preferredSize = tempDefinitions[i].MinSize;
+ double preferredSize = tempDefinition.MinSize;
double newMinSize = preferredSize + sizeToDistribute / (count - i);
- tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache));
- sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize);
+ tempDefinition.UpdateMinSize(Math.Min(newMinSize, tempDefinition.SizeCache));
+ sizeToDistribute -= (tempDefinition.MinSize - preferredSize);
}
// sanity check: requested size must all be distributed
@@ -1376,8 +1367,10 @@ namespace Avalonia.Controls
for (int i = 0; i < count; ++i)
{
- double deltaSize = (maxMaxSize - tempDefinitions[i].SizeCache) * sizeToDistribute / totalRemainingSize;
- tempDefinitions[i].UpdateMinSize(tempDefinitions[i].SizeCache + deltaSize);
+ var tempDefinition = tempDefinitions[i]!;
+
+ double deltaSize = (maxMaxSize - tempDefinition.SizeCache) * sizeToDistribute / totalRemainingSize;
+ tempDefinition.UpdateMinSize(tempDefinition.SizeCache + deltaSize);
}
}
else
@@ -1388,7 +1381,7 @@ namespace Avalonia.Controls
//
for (int i = 0; i < count; ++i)
{
- tempDefinitions[i].UpdateMinSize(equalSize);
+ tempDefinitions[i]!.UpdateMinSize(equalSize);
}
}
}
@@ -1429,7 +1422,7 @@ namespace Avalonia.Controls
double availableSize)
{
int defCount = definitions.Count;
- DefinitionBase[] tempDefinitions = TempDefinitions;
+ DefinitionBase?[] tempDefinitions = TempDefinitions;
int minCount = 0, maxCount = 0;
double takenSize = 0;
double totalStarWeight = 0.0;
@@ -1560,8 +1553,8 @@ namespace Avalonia.Controls
remainingStarWeight = totalStarWeight - takenStarWeight;
}
- double minRatio = (minCount > 0) ? tempDefinitions[minCount - 1].MeasureSize : Double.PositiveInfinity;
- double maxRatio = (maxCount > 0) ? tempDefinitions[defCount + maxCount - 1].SizeCache : -1.0;
+ double minRatio = (minCount > 0) ? tempDefinitions[minCount - 1]!.MeasureSize : Double.PositiveInfinity;
+ double maxRatio = (maxCount > 0) ? tempDefinitions[defCount + maxCount - 1]!.SizeCache : -1.0;
// choose the def with larger ratio to the current proportion ("max discrepancy")
double proportion = remainingStarWeight / remainingAvailableSize;
@@ -1579,13 +1572,13 @@ namespace Avalonia.Controls
double resolvedSize;
if (chooseMin == true)
{
- resolvedDef = tempDefinitions[minCount - 1];
+ resolvedDef = tempDefinitions[minCount - 1]!;
resolvedSize = resolvedDef.MinSize;
--minCount;
}
else
{
- resolvedDef = tempDefinitions[defCount + maxCount - 1];
+ resolvedDef = tempDefinitions[defCount + maxCount - 1]!;
resolvedSize = Math.Max(resolvedDef.MinSize, resolvedDef.UserMaxSize);
--maxCount;
}
@@ -1603,12 +1596,12 @@ namespace Avalonia.Controls
// advance to the next candidate defs, removing ones that have been resolved.
// Both counts are advanced, as a def might appear in both lists.
- while (minCount > 0 && tempDefinitions[minCount - 1].MeasureSize < 0.0)
+ while (minCount > 0 && tempDefinitions[minCount - 1]!.MeasureSize < 0.0)
{
--minCount;
tempDefinitions[minCount] = null!;
}
- while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1].MeasureSize < 0.0)
+ while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1]!.MeasureSize < 0.0)
{
--maxCount;
tempDefinitions[defCount + maxCount] = null!;
@@ -1637,8 +1630,7 @@ namespace Avalonia.Controls
// resolved as 'min'. Their allocation can be increased to make up the gap.
for (int i = minCount; i < minCountPhase2; ++i)
{
- DefinitionBase def = tempDefinitions[i];
- if (def != null)
+ if (tempDefinitions[i] is { } def)
{
def.MeasureSize = 1.0; // mark as 'not yet resolved'
++starCount;
@@ -1653,8 +1645,7 @@ namespace Avalonia.Controls
// resolved as 'max'. Their allocation can be decreased to make up the gap.
for (int i = maxCount; i < maxCountPhase2; ++i)
{
- DefinitionBase def = tempDefinitions[defCount + i];
- if (def != null)
+ if (tempDefinitions[defCount + i] is { } def)
{
def.MeasureSize = 1.0; // mark as 'not yet resolved'
++starCount;
@@ -1695,7 +1686,7 @@ namespace Avalonia.Controls
totalStarWeight = 0.0;
for (int i = 0; i < starCount; ++i)
{
- DefinitionBase def = tempDefinitions[i];
+ DefinitionBase def = tempDefinitions[i]!;
totalStarWeight += def.MeasureSize;
def.SizeCache = totalStarWeight;
}
@@ -1703,7 +1694,7 @@ namespace Avalonia.Controls
// resolve the defs, in decreasing order of weight
for (int i = starCount - 1; i >= 0; --i)
{
- DefinitionBase def = tempDefinitions[i];
+ DefinitionBase def = tempDefinitions[i]!;
double resolvedSize = (def.MeasureSize > 0.0) ? Math.Max(availableSize - takenSize, 0.0) * (def.MeasureSize / def.SizeCache) : 0.0;
// min and max should have no effect by now, but just in case...
@@ -2095,7 +2086,7 @@ namespace Avalonia.Controls
{
// DpiScale dpiScale = GetDpi();
// double dpi = columns ? dpiScale.DpiScaleX : dpiScale.DpiScaleY;
- var dpi = (VisualRoot as Layout.ILayoutRoot)?.LayoutScaling ?? 1.0;
+ var dpi = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
double[] roundingErrors = RoundingErrors;
double roundedTakenSize = 0.0;
@@ -2302,8 +2293,7 @@ namespace Avalonia.Controls
///
private void SetValid()
{
- ExtendedData extData = ExtData;
- if (extData != null)
+ if (_extData is { } extData)
{
// for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid ();
// for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid ();
@@ -2330,12 +2320,12 @@ namespace Avalonia.Controls
if (ShowGridLines && (_gridLinesRenderer == null))
{
_gridLinesRenderer = new GridLinesRenderer();
- this.VisualChildren.Add(_gridLinesRenderer);
+ VisualChildren.Add(_gridLinesRenderer);
}
if ((!ShowGridLines) && (_gridLinesRenderer != null))
{
- this.VisualChildren.Add(_gridLinesRenderer);
+ VisualChildren.Add(_gridLinesRenderer);
_gridLinesRenderer = null;
}
@@ -2364,7 +2354,7 @@ namespace Avalonia.Controls
{
Grid grid = (Grid)d;
- if (grid.ExtData != null // trivial grid is 1 by 1. there is no grid lines anyway
+ if (grid._extData != null // trivial grid is 1 by 1. there is no grid lines anyway
&& grid.ListenToNotifications)
{
grid.InvalidateVisual();
@@ -2375,13 +2365,11 @@ namespace Avalonia.Controls
private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
- Visual? child = d as Visual;
-
- if (child != null)
+ if (d is Visual child)
{
Grid? grid = child.GetVisualParent();
if (grid != null
- && grid.ExtData != null
+ && grid._extData != null
&& grid.ListenToNotifications)
{
grid.CellsStructureDirty = true;
@@ -2427,7 +2415,7 @@ namespace Avalonia.Controls
///
private IReadOnlyList DefinitionsU
{
- get { return (ExtData.DefinitionsU!); }
+ get { return _extData!.DefinitionsU!; }
}
///
@@ -2435,17 +2423,19 @@ namespace Avalonia.Controls
///
private IReadOnlyList DefinitionsV
{
- get { return (ExtData.DefinitionsV!); }
+ get { return _extData!.DefinitionsV!; }
}
///
/// Helper accessor to layout time array of definitions.
///
- private DefinitionBase[] TempDefinitions
+ private DefinitionBase?[] TempDefinitions
{
get
{
- ExtendedData extData = ExtData;
+ Debug.Assert(_extData is not null);
+
+ var extData = _extData!;
int requiredLength = Math.Max(DefinitionsU.Count, DefinitionsV.Count) * 2;
if (extData.TempDefinitions == null
@@ -2516,7 +2506,7 @@ namespace Avalonia.Controls
///
private CellCache[] PrivateCells
{
- get { return (ExtData.CellCachesCollection!); }
+ get { return _extData!.CellCachesCollection!; }
}
///
@@ -2582,18 +2572,10 @@ namespace Avalonia.Controls
set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); }
}
- ///
- /// Returns reference to extended data bag.
- ///
- private ExtendedData ExtData
- {
- get { return (_data!); }
- }
-
///
/// Returns *-weight, adjusted for scale computed during Phase 1
///
- static double StarWeight(DefinitionBase def, double scale)
+ private static double StarWeight(DefinitionBase def, double scale)
{
if (scale < 0.0)
{
@@ -2609,17 +2591,17 @@ namespace Avalonia.Controls
}
// Extended data instantiated on demand, for non-trivial case handling only
- private ExtendedData? _data;
+ private ExtendedData? _extData;
// Grid validity / property caches dirtiness flags
private Flags _flags;
private GridLinesRenderer? _gridLinesRenderer;
// Keeps track of definition indices.
- int[]? _definitionIndices;
+ private int[]? _definitionIndices;
// Stores unrounded values and rounding errors during layout rounding.
- double[]? _roundingErrors;
+ private double[]? _roundingErrors;
// 5 is an arbitrary constant chosen to end the measure loop
private const int c_layoutLoopMaxCount = 5;
@@ -2645,14 +2627,14 @@ namespace Avalonia.Controls
internal int CellGroup2; // index of the first cell in second cell group
internal int CellGroup3; // index of the first cell in third cell group
internal int CellGroup4; // index of the first cell in forth cell group
- internal DefinitionBase[]? TempDefinitions; // temporary array used during layout for various purposes
+ internal DefinitionBase?[]? TempDefinitions; // temporary array used during layout for various purposes
// TempDefinitions.Length == Max(definitionsU.Length, definitionsV.Length)
}
///
/// Grid validity / property caches dirtiness flags
///
- [System.Flags]
+ [Flags]
private enum Flags
{
//
@@ -2768,7 +2750,7 @@ namespace Avalonia.Controls
///
/// LayoutTimeSizeType is used internally and reflects layout-time size type.
///
- [System.Flags]
+ [Flags]
internal enum LayoutTimeSizeType : byte
{
None = 0x00,
@@ -3274,7 +3256,7 @@ namespace Avalonia.Controls
///
/// UpdateRenderBounds.
///
- public override void Render(DrawingContext drawingContext)
+ public sealed override void Render(DrawingContext drawingContext)
{
var grid = this.GetVisualParent();
@@ -3317,7 +3299,7 @@ namespace Avalonia.Controls
internal void UpdateRenderBounds(Size arrangeSize)
{
_lastArrangeSize = arrangeSize;
- this.InvalidateVisual();
+ InvalidateVisual();
}
private static Size _lastArrangeSize;
diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs
index 7408bff902..3e76835e92 100644
--- a/src/Avalonia.Controls/Image.cs
+++ b/src/Avalonia.Controls/Image.cs
@@ -14,8 +14,8 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly StyledProperty SourceProperty =
- AvaloniaProperty.Register(nameof(Source));
+ public static readonly StyledProperty SourceProperty =
+ AvaloniaProperty.Register(nameof(Source));
///
/// Defines the property.
@@ -42,7 +42,7 @@ namespace Avalonia.Controls
/// Gets or sets the image that will be displayed.
///
[Content]
- public IImage Source
+ public IImage? Source
{
get { return GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
@@ -66,13 +66,14 @@ namespace Avalonia.Controls
set { SetValue(StretchDirectionProperty, value); }
}
+ ///
protected override bool BypassFlowDirectionPolicies => true;
///
/// Renders the control.
///
/// The drawing context.
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
{
var source = Source;
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index 59b5bf48a5..ce12d5f2bf 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
-using System.Diagnostics.CodeAnalysis;
using Avalonia.Automation.Peers;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
@@ -17,7 +16,6 @@ using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Styling;
-using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@@ -91,10 +89,11 @@ namespace Avalonia.Controls
/// Gets or sets the to use for binding to the display member of each item.
///
[AssignBinding]
+ [InheritDataTypeFromItems(nameof(Items))]
public IBinding? DisplayMemberBinding
{
- get { return GetValue(DisplayMemberBindingProperty); }
- set { SetValue(DisplayMemberBindingProperty, value); }
+ get => GetValue(DisplayMemberBindingProperty);
+ set => SetValue(DisplayMemberBindingProperty, value);
}
private IEnumerable? _items = new AvaloniaList();
@@ -106,7 +105,6 @@ namespace Avalonia.Controls
private Tuple? _containerBeingPrepared;
private ScrollViewer? _scrollViewer;
private ItemsPresenter? _itemsPresenter;
- private IScrollSnapPointsInfo? _scrolSnapPointInfo;
///
/// Initializes a new instance of the class.
@@ -134,8 +132,8 @@ namespace Avalonia.Controls
[Content]
public IEnumerable? Items
{
- get { return _items; }
- set { SetAndRaise(ItemsProperty, ref _items, value); }
+ get => _items;
+ set => SetAndRaise(ItemsProperty, ref _items, value);
}
///
@@ -143,8 +141,8 @@ namespace Avalonia.Controls
///
public ControlTheme? ItemContainerTheme
{
- get { return GetValue(ItemContainerThemeProperty); }
- set { SetValue(ItemContainerThemeProperty, value); }
+ get => GetValue(ItemContainerThemeProperty);
+ set => SetValue(ItemContainerThemeProperty, value);
}
///
@@ -161,8 +159,8 @@ namespace Avalonia.Controls
///
public ITemplate ItemsPanel
{
- get { return GetValue(ItemsPanelProperty); }
- set { SetValue(ItemsPanelProperty, value); }
+ get => GetValue(ItemsPanelProperty);
+ set => SetValue(ItemsPanelProperty, value);
}
///
@@ -171,8 +169,8 @@ namespace Avalonia.Controls
[InheritDataTypeFromItems(nameof(Items))]
public IDataTemplate? ItemTemplate
{
- get { return GetValue(ItemTemplateProperty); }
- set { SetValue(ItemTemplateProperty, value); }
+ get => GetValue(ItemTemplateProperty);
+ set => SetValue(ItemTemplateProperty, value);
}
///
@@ -221,6 +219,7 @@ namespace Avalonia.Controls
}
+ ///
public event EventHandler HorizontalSnapPointsChanged
{
add
@@ -240,6 +239,7 @@ namespace Avalonia.Controls
}
}
+ ///
public event EventHandler VerticalSnapPointsChanged
{
add
@@ -264,8 +264,8 @@ namespace Avalonia.Controls
///
public bool AreHorizontalSnapPointsRegular
{
- get { return GetValue(AreHorizontalSnapPointsRegularProperty); }
- set { SetValue(AreHorizontalSnapPointsRegularProperty, value); }
+ get => GetValue(AreHorizontalSnapPointsRegularProperty);
+ set => SetValue(AreHorizontalSnapPointsRegularProperty, value);
}
///
@@ -273,8 +273,8 @@ namespace Avalonia.Controls
///
public bool AreVerticalSnapPointsRegular
{
- get { return GetValue(AreVerticalSnapPointsRegularProperty); }
- set { SetValue(AreVerticalSnapPointsRegularProperty, value); }
+ get => GetValue(AreVerticalSnapPointsRegularProperty);
+ set => SetValue(AreVerticalSnapPointsRegularProperty, value);
}
///
@@ -424,13 +424,12 @@ namespace Avalonia.Controls
/// true if the item is (or is eligible to be) its own container; otherwise, false.
protected internal virtual bool IsItemItsOwnContainerOverride(Control item) => true;
+ ///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_scrollViewer = e.NameScope.Find("PART_ScrollViewer");
_itemsPresenter = e.NameScope.Find("PART_ItemsPresenter");
-
- _scrolSnapPointInfo = _itemsPresenter as IScrollSnapPointsInfo;
}
///
@@ -477,11 +476,13 @@ namespace Avalonia.Controls
base.OnKeyDown(e);
}
+ ///
protected override AutomationPeer OnCreateAutomationPeer()
{
return new ItemsControlAutomationPeer(this);
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@@ -558,7 +559,12 @@ namespace Avalonia.Controls
return new ItemContainerGenerator(this);
}
- internal void AddLogicalChild(Control c) => LogicalChildren.Add(c);
+ internal void AddLogicalChild(Control c)
+ {
+ if (!LogicalChildren.Contains(c))
+ LogicalChildren.Add(c);
+ }
+
internal void RemoveLogicalChild(Control c) => LogicalChildren.Remove(c);
///
@@ -748,11 +754,13 @@ namespace Avalonia.Controls
return true;
}
+ ///
public IReadOnlyList GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment)
{
return _itemsPresenter?.GetIrregularSnapPoints(orientation, snapPointsAlignment) ?? new List();
}
+ ///
public double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset)
{
offset = 0;
diff --git a/src/Avalonia.Controls/LayoutTransformControl.cs b/src/Avalonia.Controls/LayoutTransformControl.cs
index ce254684b7..387dc27562 100644
--- a/src/Avalonia.Controls/LayoutTransformControl.cs
+++ b/src/Avalonia.Controls/LayoutTransformControl.cs
@@ -28,7 +28,7 @@ namespace Avalonia.Controls
.AddClassHandler((x, e) => x.OnLayoutTransformChanged(e));
ChildProperty.Changed
- .AddClassHandler((x, e) => x.OnChildChanged(e));
+ .AddClassHandler((x, _) => x.OnChildChanged());
UseRenderTransformProperty.Changed
.AddClassHandler((x, e) => x.OnUseRenderTransformPropertyChanged(e));
@@ -146,7 +146,7 @@ namespace Avalonia.Controls
return transformedDesiredSize;
}
- IDisposable? _renderTransformChangedEvent;
+ private IDisposable? _renderTransformChangedEvent;
private void OnUseRenderTransformPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
@@ -167,8 +167,7 @@ namespace Avalonia.Controls
.Subscribe(
(x) =>
{
- var target2 = x.Sender as LayoutTransformControl;
- if (target2 != null)
+ if (x.Sender is LayoutTransformControl target2)
{
target2.LayoutTransform = target2.RenderTransform;
}
@@ -182,7 +181,7 @@ namespace Avalonia.Controls
}
}
- private void OnChildChanged(AvaloniaPropertyChangedEventArgs e)
+ private void OnChildChanged()
{
if (null != TransformRoot)
{
@@ -206,18 +205,18 @@ namespace Avalonia.Controls
///
/// Actual DesiredSize of Child element (the value it returned from its MeasureOverride method).
///
- private Size _childActualSize = default;
+ private Size _childActualSize;
///
/// RenderTransform/MatrixTransform applied to TransformRoot.
///
- private MatrixTransform _matrixTransform = new MatrixTransform();
+ private readonly MatrixTransform _matrixTransform = new();
///
/// Transformation matrix corresponding to _matrixTransform.
///
private Matrix _transformation;
- private IDisposable? _transformChangedEvent = null;
+ private IDisposable? _transformChangedEvent;
///
/// Returns true if Size a is smaller than Size b in either dimension.
@@ -263,10 +262,7 @@ namespace Avalonia.Controls
// Get the transform matrix and apply it
_transformation = RoundMatrix(LayoutTransform.Value, DecimalsAfterRound);
- if (null != _matrixTransform)
- {
- _matrixTransform.Matrix = _transformation;
- }
+ _matrixTransform.Matrix = _transformation;
// New transform means re-layout is necessary
InvalidateMeasure();
diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs
index 8b1a307182..80d1677c2f 100644
--- a/src/Avalonia.Controls/ListBox.cs
+++ b/src/Avalonia.Controls/ListBox.cs
@@ -104,6 +104,7 @@ namespace Avalonia.Controls
public void UnselectAll() => Selection.Clear();
protected internal override Control CreateContainerForItemOverride() => new ListBoxItem();
+ protected internal override bool IsItemItsOwnContainerOverride(Control item) => item is ListBoxItem;
///
protected override void OnGotFocus(GotFocusEventArgs e)
diff --git a/src/Avalonia.Controls/MaskedTextBox.cs b/src/Avalonia.Controls/MaskedTextBox.cs
index 080326606e..5a3eb47ce4 100644
--- a/src/Avalonia.Controls/MaskedTextBox.cs
+++ b/src/Avalonia.Controls/MaskedTextBox.cs
@@ -178,12 +178,11 @@ namespace Avalonia.Controls
}
}
-
-
}
Type IStyleable.StyleKey => typeof(TextBox);
+ ///
protected override void OnGotFocus(GotFocusEventArgs e)
{
if (HidePromptOnLeave == true && MaskProvider != null)
@@ -193,6 +192,7 @@ namespace Avalonia.Controls
base.OnGotFocus(e);
}
+ ///
protected override async void OnKeyDown(KeyEventArgs e)
{
if (MaskProvider == null)
@@ -271,15 +271,17 @@ namespace Avalonia.Controls
}
}
+ ///
protected override void OnLostFocus(RoutedEventArgs e)
{
- if (HidePromptOnLeave == true && MaskProvider != null)
+ if (HidePromptOnLeave && MaskProvider != null)
{
Text = MaskProvider.ToString(!HidePromptOnLeave, true);
}
base.OnLostFocus(e);
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
void UpdateMaskProvider()
@@ -357,6 +359,8 @@ namespace Avalonia.Controls
}
base.OnPropertyChanged(change);
}
+
+ ///
protected override void OnTextInput(TextInputEventArgs e)
{
_ignoreTextChanges = true;
@@ -423,7 +427,7 @@ namespace Avalonia.Controls
return startPosition;
}
- private void RefreshText(MaskedTextProvider provider, int position)
+ private void RefreshText(MaskedTextProvider? provider, int position)
{
if (provider != null)
{
diff --git a/src/Avalonia.Controls/NativeControlHost.cs b/src/Avalonia.Controls/NativeControlHost.cs
index 6b9e378d3d..a94a1ee983 100644
--- a/src/Avalonia.Controls/NativeControlHost.cs
+++ b/src/Avalonia.Controls/NativeControlHost.cs
@@ -16,19 +16,17 @@ namespace Avalonia.Controls
private IPlatformHandle? _nativeControlHandle;
private bool _queuedForDestruction;
private bool _queuedForMoveResize;
- private readonly List _propertyChangedSubscriptions = new List();
+ private readonly List _propertyChangedSubscriptions = new();
+ ///
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
_currentRoot = e.Root as TopLevel;
var visual = (Visual)this;
while (visual != null)
{
- if (visual is Visual v)
- {
- v.PropertyChanged += PropertyChangedHandler;
- _propertyChangedSubscriptions.Add(v);
- }
+ visual.PropertyChanged += PropertyChangedHandler;
+ _propertyChangedSubscriptions.Add(visual);
visual = visual.GetVisualParent();
}
@@ -42,15 +40,13 @@ namespace Avalonia.Controls
EnqueueForMoveResize();
}
+ ///
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_currentRoot = null;
- if (_propertyChangedSubscriptions != null)
- {
- foreach (var v in _propertyChangedSubscriptions)
- v.PropertyChanged -= PropertyChangedHandler;
- _propertyChangedSubscriptions.Clear();
- }
+ foreach (var v in _propertyChangedSubscriptions)
+ v.PropertyChanged -= PropertyChangedHandler;
+ _propertyChangedSubscriptions.Clear();
UpdateHost();
}
@@ -128,7 +124,7 @@ namespace Avalonia.Controls
return new Rect(position.Value, bounds.Size);
}
- void EnqueueForMoveResize()
+ private void EnqueueForMoveResize()
{
if(_queuedForMoveResize)
return;
diff --git a/src/Avalonia.Controls/NativeMenu.Export.cs b/src/Avalonia.Controls/NativeMenu.Export.cs
index 9c1fb93a48..ab64416a2c 100644
--- a/src/Avalonia.Controls/NativeMenu.Export.cs
+++ b/src/Avalonia.Controls/NativeMenu.Export.cs
@@ -12,10 +12,10 @@ namespace Avalonia.Controls
public static bool GetIsNativeMenuExported(TopLevel tl) => tl.GetValue(IsNativeMenuExportedProperty);
- private static readonly AttachedProperty s_nativeMenuInfoProperty =
- AvaloniaProperty.RegisterAttached("___NativeMenuInfo");
-
- class NativeMenuInfo
+ private static readonly AttachedProperty s_nativeMenuInfoProperty =
+ AvaloniaProperty.RegisterAttached("___NativeMenuInfo");
+
+ private sealed class NativeMenuInfo
{
public bool ChangingIsExported { get; set; }
public ITopLevelNativeMenuExporter? Exporter { get; }
@@ -33,7 +33,7 @@ namespace Avalonia.Controls
}
}
- static NativeMenuInfo GetInfo(TopLevel target)
+ private static NativeMenuInfo GetInfo(TopLevel target)
{
var rv = target.GetValue(s_nativeMenuInfoProperty);
if (rv == null)
@@ -45,18 +45,18 @@ namespace Avalonia.Controls
return rv;
}
- static void SetIsNativeMenuExported(TopLevel tl, bool value)
+ private static void SetIsNativeMenuExported(TopLevel tl, bool value)
{
GetInfo(tl).ChangingIsExported = true;
tl.SetValue(IsNativeMenuExportedProperty, value);
}
- public static readonly AttachedProperty MenuProperty
- = AvaloniaProperty.RegisterAttached("Menu");
+ public static readonly AttachedProperty MenuProperty
+ = AvaloniaProperty.RegisterAttached("Menu");
- public static void SetMenu(AvaloniaObject o, NativeMenu menu) => o.SetValue(MenuProperty, menu);
+ public static void SetMenu(AvaloniaObject o, NativeMenu? menu) => o.SetValue(MenuProperty, menu);
- public static NativeMenu GetMenu(AvaloniaObject o) => o.GetValue(MenuProperty);
+ public static NativeMenu? GetMenu(AvaloniaObject o) => o.GetValue(MenuProperty);
static NativeMenu()
{
diff --git a/src/Avalonia.Controls/Panel.cs b/src/Avalonia.Controls/Panel.cs
index 007d18c813..a7dc035459 100644
--- a/src/Avalonia.Controls/Panel.cs
+++ b/src/Avalonia.Controls/Panel.cs
@@ -68,7 +68,7 @@ namespace Avalonia.Controls
/// Renders the visual to a .
///
/// The drawing context.
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
{
var background = Background;
if (background != null)
diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
index de3aca76d9..4dd868253e 100644
--- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
+++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
@@ -553,7 +553,7 @@ namespace Avalonia.Controls.Platform
}
}
- protected static IMenuItem? GetMenuItem(Control? item)
+ protected static IMenuItem? GetMenuItem(StyledElement? item)
{
while (true)
{
diff --git a/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs b/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
index 0658f9211c..d609dd94c8 100644
--- a/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
+++ b/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
@@ -13,6 +13,6 @@ namespace Avalonia.Platform
///
/// Raised on on OSX via the Quit menu or right-clicking on the application icon and selecting Quit.
///
- event EventHandler ShutdownRequested;
+ event EventHandler? ShutdownRequested;
}
}
diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs
index 8d9d8e0e7b..31b144ce00 100644
--- a/src/Avalonia.Controls/Platform/IWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs
@@ -19,7 +19,7 @@ namespace Avalonia.Platform
///
/// Gets or sets a method called when the minimized/maximized state of the window changes.
///
- Action WindowStateChanged { get; set; }
+ Action? WindowStateChanged { get; set; }
///
/// Sets the title of the window.
@@ -42,7 +42,7 @@ namespace Avalonia.Platform
///
/// Called when a disabled window received input. Can be used to activate child windows.
///
- Action GotInputWhenDisabled { get; set; }
+ Action? GotInputWhenDisabled { get; set; }
///
/// Enables or disables system window decorations (title bar, buttons, etc)
@@ -68,7 +68,7 @@ namespace Avalonia.Platform
/// Gets or sets a method called before the underlying implementation is destroyed.
/// Return true to prevent the underlying implementation from closing.
///
- Func Closing { get; set; }
+ Func? Closing { get; set; }
///
/// Gets a value to indicate if the platform was able to extend client area to non-client area.
@@ -78,7 +78,7 @@ namespace Avalonia.Platform
///
/// Gets or Sets an action that is called whenever one of the extend client area properties changed.
///
- Action ExtendClientAreaToDecorationsChanged { get; set; }
+ Action? ExtendClientAreaToDecorationsChanged { get; set; }
///
/// Gets a flag that indicates if Managed decorations i.e. caption buttons are required.
diff --git a/src/Avalonia.Controls/PlatformInhibitionType.cs b/src/Avalonia.Controls/PlatformInhibitionType.cs
new file mode 100644
index 0000000000..03e3270e0b
--- /dev/null
+++ b/src/Avalonia.Controls/PlatformInhibitionType.cs
@@ -0,0 +1,13 @@
+namespace Avalonia.Controls
+{
+ ///
+ /// A platform specific behavior that can be inhibited.
+ ///
+ public enum PlatformInhibitionType
+ {
+ ///
+ /// When inhibited, prevents the app from being put to sleep or being given a lower priority when not in focus.
+ ///
+ AppSleep
+ }
+}
diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
index 584dfea97f..be61bb18a1 100644
--- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
@@ -534,7 +534,7 @@ namespace Avalonia.Controls.Presenters
}
///
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
{
_borderRenderer.Render(context, Bounds.Size, LayoutThickness, CornerRadius, Background, BorderBrush,
BoxShadow);
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
index 8594b584fa..e8eaac7d17 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
@@ -28,19 +28,19 @@ namespace Avalonia.Controls.Presenters
/// Defines the property.
///
public static readonly StyledProperty AreHorizontalSnapPointsRegularProperty =
- AvaloniaProperty.Register(nameof(AreHorizontalSnapPointsRegular));
+ AvaloniaProperty.Register(nameof(AreHorizontalSnapPointsRegular));
///
/// Defines the property.
///
public static readonly StyledProperty AreVerticalSnapPointsRegularProperty =
- AvaloniaProperty.Register(nameof(AreVerticalSnapPointsRegular));
+ AvaloniaProperty.Register(nameof(AreVerticalSnapPointsRegular));
///
/// Defines the event.
///
public static readonly RoutedEvent HorizontalSnapPointsChangedEvent =
- RoutedEvent.Register(
+ RoutedEvent.Register(
nameof(HorizontalSnapPointsChanged),
RoutingStrategies.Bubble);
@@ -48,7 +48,7 @@ namespace Avalonia.Controls.Presenters
/// Defines the event.
///
public static readonly RoutedEvent VerticalSnapPointsChangedEvent =
- RoutedEvent.Register(
+ RoutedEvent.Register(
nameof(VerticalSnapPointsChanged),
RoutingStrategies.Bubble);
@@ -139,7 +139,7 @@ namespace Avalonia.Controls.Presenters
Size IScrollable.Viewport => _logicalScrollable?.Viewport ?? default;
///
- /// Gets or sets whether the horizontal snap points for the are equidistant from each other.
+ /// Gets or sets whether the horizontal snap points for the are equidistant from each other.
///
public bool AreHorizontalSnapPointsRegular
{
@@ -148,7 +148,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets whether the vertical snap points for the are equidistant from each other.
+ /// Gets or sets whether the vertical snap points for the are equidistant from each other.
///
public bool AreVerticalSnapPointsRegular
{
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index f599511392..bb6b03d59a 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -63,6 +63,15 @@ namespace Avalonia.Controls.Presenters
o => o.PreeditText,
(o, v) => o.PreeditText = v);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly DirectProperty CompositionRegionProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(CompositionRegion),
+ o => o.CompositionRegion,
+ (o, v) => o.CompositionRegion = v);
+
///
/// Defines the property.
///
@@ -106,6 +115,7 @@ namespace Avalonia.Controls.Presenters
private Rect _caretBounds;
private Point _navigationPosition;
private string? _preeditText;
+ private TextRange? _compositionRegion;
static TextPresenter()
{
@@ -146,6 +156,12 @@ namespace Avalonia.Controls.Presenters
set => SetAndRaise(PreeditTextProperty, ref _preeditText, value);
}
+ public TextRange? CompositionRegion
+ {
+ get => _compositionRegion;
+ set => SetAndRaise(CompositionRegionProperty, ref _compositionRegion, value);
+ }
+
///
/// Gets or sets the font family.
///
@@ -388,7 +404,7 @@ namespace Avalonia.Controls.Presenters
TextLayout.Draw(context, new Point(left, top));
}
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
{
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
@@ -548,7 +564,20 @@ namespace Avalonia.Controls.Presenters
var foreground = Foreground;
- if (!string.IsNullOrEmpty(_preeditText))
+ if(_compositionRegion != null)
+ {
+ var preeditHighlight = new ValueSpan(_compositionRegion?.Start ?? 0, _compositionRegion?.Length ?? 0,
+ new GenericTextRunProperties(typeface, FontSize,
+ foregroundBrush: foreground,
+ textDecorations: TextDecorations.Underline));
+
+ textStyleOverrides = new[]
+ {
+ preeditHighlight
+ };
+
+ }
+ else if (!string.IsNullOrEmpty(_preeditText))
{
var preeditHighlight = new ValueSpan(_caretIndex, _preeditText.Length,
new GenericTextRunProperties(typeface, FontSize,
@@ -911,6 +940,7 @@ namespace Avalonia.Controls.Presenters
break;
}
+ case nameof(CompositionRegion):
case nameof(Foreground):
case nameof(FontSize):
case nameof(FontStyle):
@@ -931,7 +961,6 @@ namespace Avalonia.Controls.Presenters
case nameof(PasswordChar):
case nameof(RevealPassword):
-
case nameof(FlowDirection):
{
InvalidateTextLayout();
diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs
index 49e76d0728..ed3412bb45 100644
--- a/src/Avalonia.Controls/Primitives/AccessText.cs
+++ b/src/Avalonia.Controls/Primitives/AccessText.cs
@@ -60,10 +60,9 @@ namespace Avalonia.Controls.Primitives
/// Renders the to a drawing context.
///
/// The drawing context.
- public override void Render(DrawingContext context)
+ protected internal override void RenderCore(DrawingContext context)
{
- base.Render(context);
-
+ base.RenderCore(context);
int underscore = Text?.IndexOf('_') ?? -1;
if (underscore != -1 && ShowAccessKey)
diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
index 3464857131..79719912ea 100644
--- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs
+++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
@@ -34,8 +34,8 @@ namespace Avalonia.Controls.Primitives
public static readonly AttachedProperty AdornerProperty =
AvaloniaProperty.RegisterAttached("Adorner");
- private static readonly AttachedProperty s_adornedElementInfoProperty =
- AvaloniaProperty.RegisterAttached("AdornedElementInfo");
+ private static readonly AttachedProperty s_adornedElementInfoProperty =
+ AvaloniaProperty.RegisterAttached("AdornedElementInfo");
private static readonly AttachedProperty s_savedAdornerLayerProperty =
AvaloniaProperty.RegisterAttached("SavedAdornerLayer");
@@ -159,8 +159,8 @@ namespace Avalonia.Controls.Primitives
return;
}
- AdornerLayer.SetAdornedElement(adorner, visual);
- AdornerLayer.SetIsClipEnabled(adorner, false);
+ SetAdornedElement(adorner, visual);
+ SetIsClipEnabled(adorner, false);
((ISetLogicalParent) adorner).SetParent(visual);
layer.Children.Add(adorner);
@@ -177,6 +177,7 @@ namespace Avalonia.Controls.Primitives
((ISetLogicalParent) adorner).SetParent(null);
}
+ ///
protected override Size MeasureOverride(Size availableSize)
{
foreach (var child in Children)
@@ -199,6 +200,7 @@ namespace Avalonia.Controls.Primitives
return default;
}
+ ///
protected override Size ArrangeOverride(Size finalSize)
{
foreach (var child in Children)
@@ -217,7 +219,7 @@ namespace Avalonia.Controls.Primitives
}
else
{
- ArrangeChild((Control) child, finalSize);
+ ArrangeChild(child, finalSize);
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
index e265f4eb6a..e16633483b 100644
--- a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
+++ b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using Avalonia.Reactive;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Interactivity;
using Avalonia.Media;
@@ -18,8 +17,8 @@ namespace Avalonia.Controls.Primitives
PopupRoot.TransformProperty.AddOwner();
private readonly OverlayLayer _overlayLayer;
- private PopupPositionerParameters _positionerParameters = new PopupPositionerParameters();
- private ManagedPopupPositioner _positioner;
+ private readonly ManagedPopupPositioner _positioner;
+ private PopupPositionerParameters _positionerParameters;
private Point _lastRequestedPosition;
private bool _shown;
@@ -29,13 +28,16 @@ namespace Avalonia.Controls.Primitives
_positioner = new ManagedPopupPositioner(this);
}
+ ///
public void SetChild(Control? control)
{
Content = control;
}
+ ///
public Visual? HostedVisualTreeRoot => null;
+ ///
public Transform? Transform
{
get => GetValue(TransformProperty);
@@ -48,23 +50,27 @@ namespace Avalonia.Controls.Primitives
set { /* Not currently supported in overlay popups */ }
}
- protected internal override Interactive? InteractiveParent => Parent;
+ ///
+ protected internal override Interactive? InteractiveParent => (Interactive?)VisualParent;
+ ///
public void Dispose() => Hide();
-
+ ///
public void Show()
{
_overlayLayer.Children.Add(this);
_shown = true;
}
+ ///
public void Hide()
{
_overlayLayer.Children.Remove(this);
_shown = false;
}
+ ///
public void ConfigurePosition(Visual target, PlacementMode placement, Point offset,
PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
@@ -75,6 +81,7 @@ namespace Avalonia.Controls.Primitives
UpdatePosition();
}
+ ///
protected override Size ArrangeOverride(Size finalSize)
{
if (_positionerParameters.Size != finalSize)
@@ -123,17 +130,18 @@ namespace Avalonia.Controls.Primitives
public static IPopupHost CreatePopupHost(Visual target, IAvaloniaDependencyResolver? dependencyResolver)
{
- var platform = TopLevel.GetTopLevel(target)?.PlatformImpl?.CreatePopup();
- if (platform != null)
- return new PopupRoot((TopLevel)target.GetVisualRoot()!, platform, dependencyResolver);
-
- var overlayLayer = OverlayLayer.GetOverlayLayer(target);
- if (overlayLayer == null)
- throw new InvalidOperationException(
- "Unable to create IPopupImpl and no overlay layer is found for the target control");
+ if (TopLevel.GetTopLevel(target) is { } topLevel && topLevel.PlatformImpl?.CreatePopup() is { } popupImpl)
+ {
+ return new PopupRoot(topLevel, popupImpl, dependencyResolver);
+ }
+ if (OverlayLayer.GetOverlayLayer(target) is { } overlayLayer)
+ {
+ return new OverlayPopupHost(overlayLayer);
+ }
- return new OverlayPopupHost(overlayLayer);
+ throw new InvalidOperationException(
+ "Unable to create IPopupImpl and no overlay layer is found for the target control");
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index c85199a665..d6cd71aedc 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -120,7 +120,7 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty TopmostProperty =
AvaloniaProperty.Register(nameof(Topmost));
- private bool _isOpenRequested = false;
+ private bool _isOpenRequested;
private bool _isOpen;
private bool _ignoreIsOpenChanged;
private PopupOpenState? _openState;
@@ -377,9 +377,9 @@ namespace Avalonia.Controls.Primitives
popupHost.SetChild(Child);
((ISetLogicalParent)popupHost).SetParent(this);
- if (InheritsTransform && placementTarget is Control c)
+ if (InheritsTransform)
{
- TransformTrackingHelper.Track(c, PlacementTargetTransformChanged)
+ TransformTrackingHelper.Track(placementTarget, PlacementTargetTransformChanged)
.DisposeWith(handlerCleanup);
}
else
@@ -518,6 +518,7 @@ namespace Avalonia.Controls.Primitives
Close();
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@@ -579,7 +580,7 @@ namespace Avalonia.Controls.Primitives
var scaleX = 1.0;
var scaleY = 1.0;
- if (InheritsTransform && placementTarget.TransformToVisual(topLevel) is Matrix m)
+ if (InheritsTransform && placementTarget.TransformToVisual(topLevel) is { } m)
{
scaleX = Math.Sqrt(m.M11 * m.M11 + m.M12 * m.M12);
scaleY = Math.Sqrt(m.M11 * m.M11 + m.M12 * m.M12);
@@ -623,6 +624,7 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
protected override AutomationPeer OnCreateAutomationPeer()
{
return new PopupAutomationPeer(this);
@@ -723,7 +725,7 @@ namespace Avalonia.Controls.Primitives
while (e is object && (!e.Focusable || !e.IsEffectivelyEnabled || !e.IsVisible))
{
- e = e.Parent;
+ e = e.VisualParent as Control;
}
if (e is object)
@@ -850,7 +852,7 @@ namespace Avalonia.Controls.Primitives
var popupHost = _openState.PopupHost;
- return popupHost != null && ((Visual)popupHost).IsVisualAncestorOf(visual);
+ return ((Visual)popupHost).IsVisualAncestorOf(visual);
}
public bool IsPointerOverPopup => ((IInputElement?)_openState?.PopupHost)?.IsPointerOver ?? false;
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index 57ec864cad..b3436d4176 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -72,12 +72,12 @@ namespace Avalonia.Controls.Primitives
///
/// Popup events are passed to their parent window. This facilitates this.
///
- protected internal override Interactive? InteractiveParent => Parent;
+ protected internal override Interactive? InteractiveParent => (Interactive?)Parent;
///
/// Gets the control that is hosting the popup root.
///
- Visual? IHostedVisualTreeRoot.Host => Parent;
+ Visual? IHostedVisualTreeRoot.Host => VisualParent;
///
/// Gets the styling parent of the popup root.
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 5210362505..065c4ff2e5 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -3,16 +3,16 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
-using System.Xml.Linq;
-using Avalonia.Controls.Generators;
using Avalonia.Controls.Selection;
+using Avalonia.Controls.Utils;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
+using Avalonia.Metadata;
using Avalonia.Threading;
-using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
{
@@ -66,6 +66,19 @@ namespace Avalonia.Controls.Primitives
(o, v) => o.SelectedItem = v,
defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
+ ///
+ /// Defines the property
+ ///
+ public static readonly StyledProperty SelectedValueProperty =
+ AvaloniaProperty.Register(nameof(SelectedValue),
+ defaultBindingMode: BindingMode.TwoWay);
+
+ ///
+ /// Defines the property
+ ///
+ public static readonly StyledProperty SelectedValueBindingProperty =
+ AvaloniaProperty.Register(nameof(SelectedValueBinding));
+
///
/// Defines the property.
///
@@ -129,6 +142,8 @@ namespace Avalonia.Controls.Primitives
private bool _ignoreContainerSelectionChanged;
private UpdateState? _updateState;
private bool _hasScrolledToSelectedItem;
+ private BindingHelper? _bindingHelper;
+ private bool _isSelectionChangeActive;
///
/// Initializes static members of the class.
@@ -143,8 +158,8 @@ namespace Avalonia.Controls.Primitives
///
public event EventHandler? SelectionChanged
{
- add { AddHandler(SelectionChangedEvent, value); }
- remove { RemoveHandler(SelectionChangedEvent, value); }
+ add => AddHandler(SelectionChangedEvent, value);
+ remove => RemoveHandler(SelectionChangedEvent, value);
}
///
@@ -152,8 +167,8 @@ namespace Avalonia.Controls.Primitives
///
public bool AutoScrollToSelectedItem
{
- get { return GetValue(AutoScrollToSelectedItemProperty); }
- set { SetValue(AutoScrollToSelectedItemProperty, value); }
+ get => GetValue(AutoScrollToSelectedItemProperty);
+ set => SetValue(AutoScrollToSelectedItemProperty, value);
}
///
@@ -209,6 +224,28 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
+ /// Gets the instance used to obtain the
+ /// property
+ ///
+ [AssignBinding]
+ [InheritDataTypeFromItems(nameof(Items))]
+ public IBinding? SelectedValueBinding
+ {
+ get => GetValue(SelectedValueBindingProperty);
+ set => SetValue(SelectedValueBindingProperty, value);
+ }
+
+ ///
+ /// Gets or sets the value of the selected item, obtained using
+ ///
+ ///
+ public object? SelectedValue
+ {
+ get => GetValue(SelectedValueProperty);
+ set => SetValue(SelectedValueProperty, value);
+ }
+
///
/// Gets or sets the selected items.
///
@@ -255,6 +292,7 @@ namespace Avalonia.Controls.Primitives
///
/// Gets or sets the model that holds the current selection.
///
+ [AllowNull]
protected ISelectionModel Selection
{
get
@@ -322,8 +360,8 @@ namespace Avalonia.Controls.Primitives
///
public bool IsTextSearchEnabled
{
- get { return GetValue(IsTextSearchEnabledProperty); }
- set { SetValue(IsTextSearchEnabledProperty, value); }
+ get => GetValue(IsTextSearchEnabledProperty);
+ set => SetValue(IsTextSearchEnabledProperty, value);
}
///
@@ -332,8 +370,8 @@ namespace Avalonia.Controls.Primitives
///
public bool WrapSelection
{
- get { return GetValue(WrapSelectionProperty); }
- set { SetValue(WrapSelectionProperty, value); }
+ get => GetValue(WrapSelectionProperty);
+ set => SetValue(WrapSelectionProperty, value);
}
///
@@ -345,8 +383,8 @@ namespace Avalonia.Controls.Primitives
///
protected SelectionMode SelectionMode
{
- get { return GetValue(SelectionModeProperty); }
- set { SetValue(SelectionModeProperty, value); }
+ get => GetValue(SelectionModeProperty);
+ set => SetValue(SelectionModeProperty, value);
}
///
@@ -399,6 +437,7 @@ namespace Avalonia.Controls.Primitives
return null;
}
+ ///
protected override void ItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.ItemsCollectionChanged(sender!, e);
@@ -409,12 +448,14 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
AutoScrollToSelectedItemIfNecessary();
}
+ ///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@@ -431,6 +472,7 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
protected internal override void PrepareContainerForItemOverride(Control element, object? item, int index)
{
base.PrepareContainerForItemOverride(element, item, index);
@@ -447,12 +489,14 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
protected override void ContainerIndexChangedOverride(Control container, int oldIndex, int newIndex)
{
base.ContainerIndexChangedOverride(container, oldIndex, newIndex);
MarkContainerSelected(container, Selection.IsSelected(newIndex));
}
+ ///
protected internal override void ClearContainerForItemOverride(Control element)
{
base.ClearContainerForItemOverride(element);
@@ -463,7 +507,7 @@ namespace Avalonia.Controls.Primitives
KeyboardNavigation.SetTabOnceActiveElement(panel, null);
}
- if (element is ISelectable selectable)
+ if (element is ISelectable)
MarkContainerSelected(element, false);
}
@@ -498,7 +542,8 @@ namespace Avalonia.Controls.Primitives
DataValidationErrors.SetError(this, error);
}
}
-
+
+ ///
protected override void OnInitialized()
{
base.OnInitialized();
@@ -509,6 +554,7 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
protected override void OnTextInput(TextInputEventArgs e)
{
if (!e.Handled)
@@ -551,6 +597,7 @@ namespace Avalonia.Controls.Primitives
base.OnTextInput(e);
}
+ ///
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
@@ -582,6 +629,7 @@ namespace Avalonia.Controls.Primitives
}
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@@ -592,7 +640,7 @@ namespace Avalonia.Controls.Primitives
}
if (change.Property == ItemsProperty && _updateState is null && _selection is object)
{
- var newValue = change.GetNewValue();
+ var newValue = change.GetNewValue();
_selection.Source = newValue;
if (newValue is null)
@@ -609,6 +657,60 @@ namespace Avalonia.Controls.Primitives
{
WrapFocus = WrapSelection;
}
+ else if (change.Property == SelectedValueProperty)
+ {
+ if (_isSelectionChangeActive)
+ return;
+
+ if (_updateState is not null)
+ {
+ _updateState.SelectedValue = change.NewValue;
+ return;
+ }
+
+ SelectItemWithValue(change.NewValue);
+ }
+ else if (change.Property == SelectedValueBindingProperty)
+ {
+ var idx = SelectedIndex;
+
+ // If no selection is active, don't do anything as SelectedValue is already null
+ if (idx == -1)
+ {
+ return;
+ }
+
+ var value = change.GetNewValue();
+ if (value is null)
+ {
+ // Clearing SelectedValueBinding makes the SelectedValue the item itself
+ SelectedValue = SelectedItem;
+ return;
+ }
+
+ var selectedItem = SelectedItem;
+
+ try
+ {
+ _isSelectionChangeActive = true;
+
+ if (_bindingHelper is null)
+ {
+ _bindingHelper = new BindingHelper(value);
+ }
+ else
+ {
+ _bindingHelper.UpdateBinding(value);
+ }
+
+ // Re-evaluate SelectedValue with the new binding
+ SelectedValue = _bindingHelper.Evaluate(selectedItem);
+ }
+ finally
+ {
+ _isSelectionChangeActive = false;
+ }
+ }
}
///
@@ -695,7 +797,7 @@ namespace Avalonia.Controls.Primitives
{
if (multi)
{
- if (Selection.IsSelected(index) == true)
+ if (Selection.IsSelected(index))
{
Selection.Deselect(index);
}
@@ -716,12 +818,10 @@ namespace Avalonia.Controls.Primitives
Selection.Select(index);
}
- if (Presenter?.Panel != null)
+ if (Presenter?.Panel is { } panel)
{
var container = ContainerFromIndex(index);
- KeyboardNavigation.SetTabOnceActiveElement(
- (InputElement)Presenter.Panel,
- container);
+ KeyboardNavigation.SetTabOnceActiveElement(panel, container);
}
}
@@ -815,6 +915,10 @@ namespace Avalonia.Controls.Primitives
new BindingValue(SelectedItems));
_oldSelectedItems = SelectedItems;
}
+ else if (e.PropertyName == nameof(ISelectionModel.Source))
+ {
+ ClearValue(SelectedValueProperty);
+ }
}
///
@@ -845,6 +949,11 @@ namespace Avalonia.Controls.Primitives
Mark(i, false);
}
+ if (!_isSelectionChangeActive)
+ {
+ UpdateSelectedValueFromItem();
+ }
+
var route = BuildEventRoute(SelectionChangedEvent);
if (route.HasHandlers)
@@ -871,6 +980,109 @@ namespace Avalonia.Controls.Primitives
}
}
+ private void SelectItemWithValue(object? value)
+ {
+ if (ItemCount == 0 || _isSelectionChangeActive)
+ return;
+
+ try
+ {
+ _isSelectionChangeActive = true;
+ var si = FindItemWithValue(value);
+ if (si != AvaloniaProperty.UnsetValue)
+ {
+ SelectedItem = si;
+ }
+ else
+ {
+ SelectedItem = null;
+ }
+ }
+ finally
+ {
+ _isSelectionChangeActive = false;
+ }
+ }
+
+ private object FindItemWithValue(object? value)
+ {
+ if (ItemCount == 0 || value is null)
+ {
+ return AvaloniaProperty.UnsetValue;
+ }
+
+ var items = Items;
+ var binding = SelectedValueBinding;
+
+ if (binding is null)
+ {
+ // No SelectedValueBinding set, SelectedValue is the item itself
+ // Still verify the value passed in is in the Items list
+ var index = items!.IndexOf(value);
+
+ if (index >= 0)
+ {
+ return value;
+ }
+ else
+ {
+ return AvaloniaProperty.UnsetValue;
+ }
+ }
+
+ _bindingHelper ??= new BindingHelper(binding);
+
+ // Matching UWP behavior, if duplicates are present, return the first item matching
+ // the SelectedValue provided
+ foreach (var item in items!)
+ {
+ var itemValue = _bindingHelper.Evaluate(item);
+
+ if (itemValue.Equals(value))
+ {
+ return item;
+ }
+ }
+
+ return AvaloniaProperty.UnsetValue;
+ }
+
+ private void UpdateSelectedValueFromItem()
+ {
+ if (_isSelectionChangeActive)
+ return;
+
+ var binding = SelectedValueBinding;
+ var item = SelectedItem;
+
+ if (binding is null || item is null)
+ {
+ // No SelectedValueBinding, SelectedValue is Item itself
+ try
+ {
+ _isSelectionChangeActive = true;
+ SelectedValue = item;
+ }
+ finally
+ {
+ _isSelectionChangeActive = false;
+ }
+ return;
+ }
+
+ _bindingHelper ??= new BindingHelper(binding);
+
+ try
+ {
+ _isSelectionChangeActive = true;
+ SelectedValue = _bindingHelper.Evaluate(item);
+ }
+ finally
+ {
+ _isSelectionChangeActive = false;
+ }
+ }
+
private void AutoScrollToSelectedItemIfNecessary()
{
if (AutoScrollToSelectedItem &&
@@ -940,7 +1152,7 @@ namespace Avalonia.Controls.Primitives
private void UpdateContainerSelection()
{
- if (Presenter?.Panel is Panel panel)
+ if (Presenter?.Panel is { } panel)
{
foreach (var container in panel.Children)
{
@@ -1037,6 +1249,13 @@ namespace Avalonia.Controls.Primitives
Selection.Clear();
}
+ if (state.SelectedValue.HasValue)
+ {
+ var item = FindItemWithValue(state.SelectedValue.Value);
+ if (item != AvaloniaProperty.UnsetValue)
+ state.SelectedItem = item;
+ }
+
if (state.SelectedIndex.HasValue)
{
SelectedIndex = state.SelectedIndex.Value;
@@ -1098,6 +1317,7 @@ namespace Avalonia.Controls.Primitives
{
private Optional _selectedIndex;
private Optional _selectedItem;
+ private Optional _selectedValue;
public int UpdateCount { get; set; }
public Optional Selection { get; set; }
@@ -1122,6 +1342,54 @@ namespace Avalonia.Controls.Primitives
_selectedIndex = default;
}
}
+
+ public Optional SelectedValue
+ {
+ get => _selectedValue;
+ set
+ {
+ _selectedValue = value;
+ }
+ }
+ }
+
+ ///
+ /// Helper class for evaluating a binding from an Item and IBinding instance
+ ///
+ private class BindingHelper : StyledElement
+ {
+ public BindingHelper(IBinding binding)
+ {
+ UpdateBinding(binding);
+ }
+
+ public static readonly StyledProperty ValueProperty =
+ AvaloniaProperty.Register("Value");
+
+ public object Evaluate(object? dataContext)
+ {
+ dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
+
+ // Only update the DataContext if necessary
+ if (!dataContext.Equals(DataContext))
+ DataContext = dataContext;
+
+ return GetValue(ValueProperty);
+ }
+
+ public void UpdateBinding(IBinding binding)
+ {
+ _lastBinding = binding;
+ var ib = binding.Initiate(this, ValueProperty);
+ if (ib is null)
+ {
+ throw new InvalidOperationException("Unable to create binding");
+ }
+
+ BindingOperations.Apply(this, ValueProperty, ib, null);
+ }
+
+ private IBinding? _lastBinding;
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
index 9a684c4534..d8874832bd 100644
--- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs
+++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
@@ -290,12 +290,6 @@ namespace Avalonia.Controls.Primitives
ApplyTemplatedParent(child, this);
((ISetLogicalParent)child).SetParent(this);
VisualChildren.Add(child);
-
- // Existing code kinda expect to see a NameScope even if it's empty
- if (nameScope == null)
- {
- nameScope = new NameScope();
- }
var e = new TemplateAppliedEventArgs(nameScope);
OnApplyTemplate(e);
@@ -320,6 +314,7 @@ namespace Avalonia.Controls.Primitives
return this;
}
+ ///
protected sealed override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
var count = VisualChildren.Count;
diff --git a/src/Avalonia.Controls/Primitives/TextSearch.cs b/src/Avalonia.Controls/Primitives/TextSearch.cs
index 949532cb16..962fba361e 100644
--- a/src/Avalonia.Controls/Primitives/TextSearch.cs
+++ b/src/Avalonia.Controls/Primitives/TextSearch.cs
@@ -11,15 +11,15 @@ namespace Avalonia.Controls.Primitives
/// Defines the Text attached property.
/// This text will be considered during text search in (such as )
///
- public static readonly AttachedProperty TextProperty
- = AvaloniaProperty.RegisterAttached("Text", typeof(TextSearch));
+ public static readonly AttachedProperty TextProperty
+ = AvaloniaProperty.RegisterAttached("Text", typeof(TextSearch));
///
/// Sets the for a control.
///
/// The control
/// The search text to set
- public static void SetText(Control control, string text)
+ public static void SetText(Control control, string? text)
{
control.SetValue(TextProperty, text);
}
@@ -29,7 +29,7 @@ namespace Avalonia.Controls.Primitives
///
/// The control
/// The property value
- public static string GetText(Control control)
+ public static string? GetText(Control control)
{
return control.GetValue(TextProperty);
}
diff --git a/src/Avalonia.Controls/Primitives/ToggleButton.cs b/src/Avalonia.Controls/Primitives/ToggleButton.cs
index dfb436a55e..158c5d875b 100644
--- a/src/Avalonia.Controls/Primitives/ToggleButton.cs
+++ b/src/Avalonia.Controls/Primitives/ToggleButton.cs
@@ -20,7 +20,7 @@ namespace Avalonia.Controls.Primitives
nameof(IsChecked),
o => o.IsChecked,
(o, v) => o.IsChecked = v,
- unsetValue: null,
+ unsetValue: false,
defaultBindingMode: BindingMode.TwoWay);
///
diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs
index 14ec7a2849..9e8d1478fa 100644
--- a/src/Avalonia.Controls/Primitives/Track.cs
+++ b/src/Avalonia.Controls/Primitives/Track.cs
@@ -5,7 +5,6 @@
using System;
using Avalonia.Controls.Metadata;
-using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Metadata;
@@ -31,14 +30,14 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty OrientationProperty =
ScrollBar.OrientationProperty.AddOwner
/// The drawing context.
- public override void Render(DrawingContext context)
+ public sealed override void Render(DrawingContext context)
+ {
+ RenderCore(context);
+ }
+
+ // Workaround to seal Render method, we need to make so because AccessText was overriding Render method which is sealed now.
+ internal protected virtual void RenderCore(DrawingContext context)
{
var background = Background;
@@ -673,8 +679,6 @@ namespace Avalonia.Controls
controlRun.Control is Control control)
{
VisualChildren.Remove(control);
-
- LogicalChildren.Remove(control);
}
}
}
@@ -693,8 +697,6 @@ namespace Avalonia.Controls
{
VisualChildren.Add(control);
- LogicalChildren.Add(control);
-
control.Measure(Size.Infinity);
}
}
diff --git a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
index 10c2f36f43..3a28836a99 100644
--- a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
+++ b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs
@@ -5,6 +5,7 @@ using Avalonia.Media.TextFormatting;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.VisualTree;
+using static System.Net.Mime.MediaTypeNames;
namespace Avalonia.Controls
{
@@ -12,6 +13,7 @@ namespace Avalonia.Controls
{
private TextBox? _parent;
private TextPresenter? _presenter;
+ private ITextEditable? _textEditable;
public Visual TextViewVisual => _presenter!;
@@ -45,7 +47,7 @@ namespace Avalonia.Controls
{
get
{
- if(_presenter is null || _parent is null)
+ if (_presenter is null || _parent is null)
{
return default;
}
@@ -71,13 +73,70 @@ namespace Avalonia.Controls
}
}
+ public ITextEditable? TextEditable
+ {
+ get => _textEditable; set
+ {
+ if(_textEditable != null)
+ {
+ _textEditable.TextChanged -= TextEditable_TextChanged;
+ _textEditable.SelectionChanged -= TextEditable_SelectionChanged;
+ _textEditable.CompositionChanged -= TextEditable_CompositionChanged;
+ }
+
+ _textEditable = value;
+
+ if(_textEditable != null)
+ {
+ _textEditable.TextChanged += TextEditable_TextChanged;
+ _textEditable.SelectionChanged += TextEditable_SelectionChanged;
+ _textEditable.CompositionChanged += TextEditable_CompositionChanged;
+
+ if (_presenter != null)
+ {
+ _textEditable.Text = _presenter.Text;
+ _textEditable.SelectionStart = _presenter.SelectionStart;
+ _textEditable.SelectionEnd = _presenter.SelectionEnd;
+ }
+ }
+ }
+ }
+
+ private void TextEditable_CompositionChanged(object? sender, EventArgs e)
+ {
+ if (_presenter != null && _textEditable != null)
+ {
+ _presenter.CompositionRegion = new TextRange(_textEditable.CompositionStart, _textEditable.CompositionEnd);
+ }
+ }
+
+ private void TextEditable_SelectionChanged(object? sender, EventArgs e)
+ {
+ if(_parent != null && _textEditable != null)
+ {
+ _parent.SelectionStart = _textEditable.SelectionStart;
+ _parent.SelectionEnd = _textEditable.SelectionEnd;
+ }
+ }
+
+ private void TextEditable_TextChanged(object? sender, EventArgs e)
+ {
+ if (_parent != null)
+ {
+ if (_parent.Text != _textEditable?.Text)
+ {
+ _parent.Text = _textEditable?.Text;
+ }
+ }
+ }
+
private static string GetTextLineText(TextLine textLine)
{
var builder = StringBuilderCache.Acquire(textLine.Length);
foreach (var run in textLine.TextRuns)
{
- if(run.Length > 0)
+ if (run.Length > 0)
{
#if NET6_0_OR_GREATER
builder.Append(run.Text.Span);
@@ -110,9 +169,18 @@ namespace Avalonia.Controls
_presenter.PreeditText = text;
}
+ public void SetComposingRegion(TextRange? region)
+ {
+ if (_presenter == null)
+ {
+ return;
+ }
+ _presenter.CompositionRegion = region;
+ }
+
public void SelectInSurroundingText(int start, int end)
{
- if(_parent is null ||_presenter is null)
+ if (_parent is null || _presenter is null)
{
return;
}
@@ -125,21 +193,21 @@ namespace Avalonia.Controls
var selectionStart = lineStart + start;
var selectionEnd = lineStart + end;
-
+
_parent.SelectionStart = selectionStart;
_parent.SelectionEnd = selectionEnd;
- }
-
+ }
+
public void SetPresenter(TextPresenter? presenter, TextBox? parent)
{
- if(_parent != null)
+ if (_parent != null)
{
_parent.PropertyChanged -= OnParentPropertyChanged;
}
_parent = parent;
- if(_parent != null)
+ if (_parent != null)
{
_parent.PropertyChanged += OnParentPropertyChanged;
}
@@ -148,16 +216,18 @@ namespace Avalonia.Controls
{
_presenter.PreeditText = null;
- _presenter.CaretBoundsChanged -= OnCaretBoundsChanged;
+ _presenter.CompositionRegion = null;
+
+ _presenter.CaretBoundsChanged -= OnCaretBoundsChanged;
}
-
+
_presenter = presenter;
-
+
if (_presenter != null)
{
_presenter.CaretBoundsChanged += OnCaretBoundsChanged;
}
-
+
TextViewVisualChanged?.Invoke(this, EventArgs.Empty);
OnCaretBoundsChanged(this, EventArgs.Empty);
@@ -165,12 +235,33 @@ namespace Avalonia.Controls
private void OnParentPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
- if(e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty)
+ if (e.Property == TextBox.SelectionStartProperty || e.Property == TextBox.SelectionEndProperty)
{
if (SupportsSurroundingText)
{
SurroundingTextChanged?.Invoke(this, e);
}
+ if (_textEditable != null)
+ {
+ var value = (int)(e.NewValue ?? 0);
+ if (e.Property == TextBox.SelectionStartProperty)
+ {
+ _textEditable.SelectionStart = value;
+ }
+
+ if (e.Property == TextBox.SelectionEndProperty)
+ {
+ _textEditable.SelectionEnd = value;
+ }
+ }
+ }
+
+ if(e.Property == TextBox.TextProperty)
+ {
+ if(_textEditable != null)
+ {
+ _textEditable.Text = (string?)e.NewValue;
+ }
}
}
diff --git a/src/Avalonia.Controls/TickBar.cs b/src/Avalonia.Controls/TickBar.cs
index 12ae766052..63fe9c9384 100644
--- a/src/Avalonia.Controls/TickBar.cs
+++ b/src/Avalonia.Controls/TickBar.cs
@@ -51,20 +51,16 @@ namespace Avalonia.Controls
TicksProperty);
}
- public TickBar() : base()
- {
- }
-
///
/// Defines the property.
///
- public static readonly StyledProperty FillProperty =
- AvaloniaProperty.Register(nameof(Fill));
+ public static readonly StyledProperty FillProperty =
+ AvaloniaProperty.Register(nameof(Fill));
///
/// Brush used to fill the TickBar's Ticks.
///
- public IBrush Fill
+ public IBrush? Fill
{
get { return GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
@@ -136,15 +132,15 @@ namespace Avalonia.Controls
///
/// Defines the property.
///
- public static readonly StyledProperty> TicksProperty =
- AvaloniaProperty.Register>(nameof(Ticks));
+ public static readonly StyledProperty?> TicksProperty =
+ AvaloniaProperty.Register?>(nameof(Ticks));
///
/// The Ticks property contains collection of value of type Double which
/// are the logical positions use to draw the ticks.
/// The property value is a .
///
- public AvaloniaList Ticks
+ public AvaloniaList? Ticks
{
get { return GetValue(TicksProperty); }
set { SetValue(TicksProperty, value); }
@@ -217,7 +213,7 @@ namespace Avalonia.Controls
///
/// Brush that use to fill ticks is specified by Fill property.
///
- public override void Render(DrawingContext dc)
+ public sealed override void Render(DrawingContext dc)
{
var size = new Size(Bounds.Width, Bounds.Height);
var range = Maximum - Minimum;
@@ -281,7 +277,7 @@ namespace Avalonia.Controls
endPoint = new Point(0d, halfReservedSpace);
logicalToPhysical = size.Height / range * -1;
break;
- };
+ }
tickLen2 = tickLen * 0.75;
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index 676fa1519a..ed11dec1d0 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -20,6 +20,7 @@ using Avalonia.Styling;
using Avalonia.Utilities;
using Avalonia.Input.Platform;
using System.Linq;
+using System.Threading.Tasks;
namespace Avalonia.Controls
{
@@ -94,7 +95,6 @@ namespace Avalonia.Controls
private readonly IInputManager? _inputManager;
private readonly IAccessKeyHandler? _accessKeyHandler;
private readonly IKeyboardNavigationHandler? _keyboardNavigationHandler;
- private readonly IPlatformRenderInterface? _renderInterface;
private readonly IGlobalStyles? _globalStyles;
private readonly IGlobalThemeVariantProvider? _applicationThemeHost;
private readonly PointerOverPreProcessor? _pointerOverPreProcessor;
@@ -136,36 +136,21 @@ namespace Avalonia.Controls
///
public TopLevel(ITopLevelImpl impl, IAvaloniaDependencyResolver? dependencyResolver)
{
- if (impl == null)
- {
- throw new InvalidOperationException(
- "Could not create window implementation: maybe no windowing subsystem was initialized?");
- }
-
- PlatformImpl = impl;
+ PlatformImpl = impl ?? throw new InvalidOperationException(
+ "Could not create window implementation: maybe no windowing subsystem was initialized?");
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
- dependencyResolver = dependencyResolver ?? AvaloniaLocator.Current;
+ dependencyResolver ??= AvaloniaLocator.Current;
_accessKeyHandler = TryGetService(dependencyResolver);
_inputManager = TryGetService(dependencyResolver);
_keyboardNavigationHandler = TryGetService(dependencyResolver);
- _renderInterface = TryGetService(dependencyResolver);
_globalStyles = TryGetService(dependencyResolver);
_applicationThemeHost = TryGetService(dependencyResolver);
Renderer = impl.CreateRenderer(this);
-
- if (Renderer != null)
- {
- Renderer.SceneInvalidated += SceneInvalidated;
- }
- else
- {
- // Prevent nullable error.
- Renderer = null!;
- }
+ Renderer.SceneInvalidated += SceneInvalidated;
impl.SetInputRoot(this);
@@ -216,7 +201,7 @@ namespace Avalonia.Controls
if(impl.TryGetFeature() is {} systemNavigationManager)
{
- systemNavigationManager.BackRequested += (s, e) =>
+ systemNavigationManager.BackRequested += (_, e) =>
{
e.RoutedEvent = BackRequestedEvent;
RaiseEvent(e);
@@ -337,7 +322,7 @@ namespace Avalonia.Controls
{
_layoutManager = CreateLayoutManager();
- if (_layoutManager is LayoutManager typedLayoutManager && Renderer is not null)
+ if (_layoutManager is LayoutManager typedLayoutManager)
{
_layoutDiagnosticBridge = new LayoutDiagnosticBridge(Renderer.Diagnostics, typedLayoutManager);
_layoutDiagnosticBridge.SetupBridge();
@@ -356,7 +341,7 @@ namespace Avalonia.Controls
///
/// Gets the renderer for the window.
///
- public IRenderer Renderer { get; private set; }
+ public IRenderer Renderer { get; }
internal PixelPoint? LastPointerPosition => _pointerOverPreProcessor?.LastPosition;
@@ -418,7 +403,7 @@ namespace Avalonia.Controls
/// The TopLevel
public static TopLevel? GetTopLevel(Visual? visual)
{
- return visual == null ? null : visual.VisualRoot as TopLevel;
+ return visual?.VisualRoot as TopLevel;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
@@ -450,7 +435,7 @@ namespace Avalonia.Controls
/// The dirty area.
protected virtual void HandlePaint(Rect rect)
{
- Renderer?.Paint(rect);
+ Renderer.Paint(rect);
}
///
@@ -468,8 +453,8 @@ namespace Avalonia.Controls
_applicationThemeHost.ActualThemeVariantChanged -= GlobalActualThemeVariantChanged;
}
- Renderer?.Dispose();
- Renderer = null!;
+ Renderer.SceneInvalidated -= SceneInvalidated;
+ Renderer.Dispose();
_layoutDiagnosticBridge?.Dispose();
_layoutDiagnosticBridge = null;
@@ -488,7 +473,7 @@ namespace Avalonia.Controls
OnClosed(EventArgs.Empty);
- LayoutManager?.Dispose();
+ LayoutManager.Dispose();
}
///
@@ -503,7 +488,7 @@ namespace Avalonia.Controls
Width = clientSize.Width;
Height = clientSize.Height;
LayoutManager.ExecuteLayoutPass();
- Renderer?.Resized(clientSize);
+ Renderer.Resized(clientSize);
}
///
@@ -586,6 +571,30 @@ namespace Avalonia.Controls
/// The event args.
protected virtual void OnClosed(EventArgs e) => Closed?.Invoke(this, e);
+ ///
+ /// Requests a to be inhibited.
+ /// The behavior remains inhibited until the return value is disposed.
+ /// The available set of s depends on the platform.
+ /// If a behavior is inhibited on a platform where this type is not supported the request will have no effect.
+ ///
+ protected async Task RequestPlatformInhibition(PlatformInhibitionType type, string reason)
+ {
+ var platformBehaviorInhibition = PlatformImpl?.TryGetFeature();
+ if (platformBehaviorInhibition == null)
+ {
+ return Disposable.Create(() => { });
+ }
+
+ switch (type)
+ {
+ case PlatformInhibitionType.AppSleep:
+ await platformBehaviorInhibition.SetInhibitAppSleep(true, reason);
+ return Disposable.Create(() => platformBehaviorInhibition.SetInhibitAppSleep(false, reason).Wait());
+ default:
+ return Disposable.Create(() => { });
+ }
+ }
+
///
/// Tries to get a service from an , logging a
/// warning if not found.
diff --git a/src/Avalonia.Controls/TrayIcon.cs b/src/Avalonia.Controls/TrayIcon.cs
index d1a7a1f727..93b177715e 100644
--- a/src/Avalonia.Controls/TrayIcon.cs
+++ b/src/Avalonia.Controls/TrayIcon.cs
@@ -100,8 +100,8 @@ namespace Avalonia.Controls
///
/// Defines the attached property.
///
- public static readonly AttachedProperty IconsProperty
- = AvaloniaProperty.RegisterAttached("Icons");
+ public static readonly AttachedProperty IconsProperty
+ = AvaloniaProperty.RegisterAttached("Icons");
///
/// Defines the property.
@@ -127,9 +127,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty IsVisibleProperty =
Visual.IsVisibleProperty.AddOwner();
- public static void SetIcons(Application o, TrayIcons trayIcons) => o.SetValue(IconsProperty, trayIcons);
+ public static void SetIcons(Application o, TrayIcons? trayIcons) => o.SetValue(IconsProperty, trayIcons);
- public static TrayIcons GetIcons(Application o) => o.GetValue(IconsProperty);
+ public static TrayIcons? GetIcons(Application o) => o.GetValue(IconsProperty);
///
/// Gets or sets the property of a TrayIcon.
@@ -213,6 +213,7 @@ namespace Avalonia.Controls
}
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index 67e0d85436..8f2636a783 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -3,17 +3,13 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
-using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
-using Avalonia.Reactive;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Primitives;
-using Avalonia.Controls.Utils;
-using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
-using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
@@ -132,6 +128,7 @@ namespace Avalonia.Controls
///
/// Gets or sets the selected items.
///
+ [AllowNull]
public IList SelectedItems
{
get
@@ -144,7 +141,6 @@ namespace Avalonia.Controls
return _selectedItems;
}
-
set
{
if (value?.IsFixedSize == true || value?.IsReadOnly == true)
@@ -167,9 +163,9 @@ namespace Avalonia.Controls
{
item.IsExpanded = true;
- if (item.Presenter?.Panel != null)
+ if (item.Presenter?.Panel is { } panel)
{
- foreach (var child in item.Presenter.Panel.Children)
+ foreach (var child in panel.Children)
{
if (child is TreeViewItem treeViewItem)
{
@@ -589,7 +585,7 @@ namespace Avalonia.Controls
case NavigationDirection.Right:
if (from?.IsExpanded == true && intoChildren && from.ItemCount > 0)
{
- result = (TreeViewItem)from.ItemContainerGenerator.ContainerFromIndex(0)!;
+ result = (TreeViewItem)from.ContainerFromIndex(0)!;
}
else if (index < parent?.ItemCount - 1)
{
@@ -865,7 +861,7 @@ namespace Avalonia.Controls
///
/// The container.
/// Whether the control is selected
- private void MarkContainerSelected(Control container, bool selected)
+ private void MarkContainerSelected(Control? container, bool selected)
{
if (container == null)
{
diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs
index 1c2ee7ec2c..1518fb49e3 100644
--- a/src/Avalonia.Controls/Viewbox.cs
+++ b/src/Avalonia.Controls/Viewbox.cs
@@ -36,6 +36,9 @@ namespace Avalonia.Controls
AffectsMeasure(StretchProperty, StretchDirectionProperty);
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
public Viewbox()
{
// The Child control is hosted inside a ViewboxContainer control so that the transform
@@ -85,13 +88,14 @@ namespace Avalonia.Controls
set => _containerVisual.RenderTransform = value;
}
+ ///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ChildProperty)
{
- var (oldChild, newChild) = change.GetOldAndNewValue();
+ var (oldChild, newChild) = change.GetOldAndNewValue();
if (oldChild is not null)
{
@@ -111,41 +115,33 @@ namespace Avalonia.Controls
}
}
+ ///
protected override Size MeasureOverride(Size availableSize)
{
var child = _containerVisual;
- if (child != null)
- {
- child.Measure(Size.Infinity);
-
- var childSize = child.DesiredSize;
+ child.Measure(Size.Infinity);
- var size = Stretch.CalculateSize(availableSize, childSize, StretchDirection);
+ var childSize = child.DesiredSize;
- return size;
- }
+ var size = Stretch.CalculateSize(availableSize, childSize, StretchDirection);
- return new Size();
+ return size;
}
+ ///
protected override Size ArrangeOverride(Size finalSize)
{
var child = _containerVisual;
- if (child != null)
- {
- var childSize = child.DesiredSize;
- var scale = Stretch.CalculateScaling(finalSize, childSize, StretchDirection);
-
- InternalTransform = new ImmutableTransform(Matrix.CreateScale(scale.X, scale.Y));
+ var childSize = child.DesiredSize;
+ var scale = Stretch.CalculateScaling(finalSize, childSize, StretchDirection);
- child.Arrange(new Rect(childSize));
+ InternalTransform = new ImmutableTransform(Matrix.CreateScale(scale.X, scale.Y));
- return childSize * scale;
- }
+ child.Arrange(new Rect(childSize));
- return finalSize;
+ return childSize * scale;
}
///
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index a20b4eee58..ba1b599421 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -450,7 +450,7 @@ namespace Avalonia.Controls
/// resulting task will produce the value when the window
/// is closed.
///
- public void Close(object dialogResult)
+ public void Close(object? dialogResult)
{
_dialogResult = dialogResult;
CloseCore(WindowCloseReason.WindowClosing, true);
@@ -573,7 +573,7 @@ namespace Avalonia.Controls
return;
}
- Renderer?.Stop();
+ Renderer.Stop();
if (Owner is Window owner)
{
@@ -721,7 +721,7 @@ namespace Avalonia.Controls
SetWindowStartupLocation(owner?.PlatformImpl);
PlatformImpl?.Show(ShowActivated, false);
- Renderer?.Start();
+ Renderer.Start();
OnOpened(EventArgs.Empty);
}
}
@@ -798,7 +798,7 @@ namespace Avalonia.Controls
PlatformImpl?.Show(ShowActivated, true);
- Renderer?.Start();
+ Renderer.Start();
Observable.FromEventPattern(
x => Closed += x,
diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs
index aad0482b50..26e11f0d4a 100644
--- a/src/Avalonia.Controls/WindowBase.cs
+++ b/src/Avalonia.Controls/WindowBase.cs
@@ -94,7 +94,7 @@ namespace Avalonia.Controls
private set { SetAndRaise(IsActiveProperty, ref _isActive, value); }
}
- public Screens Screens { get; private set; }
+ public Screens Screens { get; }
///
/// Gets or sets the owner of the window.
@@ -129,7 +129,7 @@ namespace Avalonia.Controls
{
using (FreezeVisibilityChangeHandling())
{
- Renderer?.Stop();
+ Renderer.Stop();
PlatformImpl?.Hide();
IsVisible = false;
}
@@ -153,7 +153,7 @@ namespace Avalonia.Controls
}
PlatformImpl?.Show(true, false);
- Renderer?.Start();
+ Renderer.Start();
OnOpened(EventArgs.Empty);
}
}
@@ -219,7 +219,7 @@ namespace Avalonia.Controls
{
ClientSize = clientSize;
LayoutManager.ExecuteLayoutPass();
- Renderer?.Resized(clientSize);
+ Renderer.Resized(clientSize);
}
}
diff --git a/src/Avalonia.Controls/WrapPanel.cs b/src/Avalonia.Controls/WrapPanel.cs
index 0426291d67..71b3234aff 100644
--- a/src/Avalonia.Controls/WrapPanel.cs
+++ b/src/Avalonia.Controls/WrapPanel.cs
@@ -144,35 +144,32 @@ namespace Avalonia.Controls
for (int i = 0, count = children.Count; i < count; i++)
{
var child = children[i];
- if (child != null)
- {
- // Flow passes its own constraint to children
- child.Measure(childConstraint);
+ // Flow passes its own constraint to children
+ child.Measure(childConstraint);
- // This is the size of the child in UV space
- var sz = new UVSize(orientation,
- itemWidthSet ? itemWidth : child.DesiredSize.Width,
- itemHeightSet ? itemHeight : child.DesiredSize.Height);
+ // This is the size of the child in UV space
+ var sz = new UVSize(orientation,
+ itemWidthSet ? itemWidth : child.DesiredSize.Width,
+ itemHeightSet ? itemHeight : child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line
- {
- panelSize.U = Max(curLineSize.U, panelSize.U);
- panelSize.V += curLineSize.V;
- curLineSize = sz;
-
- if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line
- {
- panelSize.U = Max(sz.U, panelSize.U);
- panelSize.V += sz.V;
- curLineSize = new UVSize(orientation);
- }
- }
- else // Continue to accumulate a line
+ if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line
+ {
+ panelSize.U = Max(curLineSize.U, panelSize.U);
+ panelSize.V += curLineSize.V;
+ curLineSize = sz;
+
+ if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line
{
- curLineSize.U += sz.U;
- curLineSize.V = Max(sz.V, curLineSize.V);
+ panelSize.U = Max(sz.U, panelSize.U);
+ panelSize.V += sz.V;
+ curLineSize = new UVSize(orientation);
}
}
+ else // Continue to accumulate a line
+ {
+ curLineSize.U += sz.U;
+ curLineSize.V = Max(sz.V, curLineSize.V);
+ }
}
// The last line size, if any should be added
@@ -202,34 +199,31 @@ namespace Avalonia.Controls
for (int i = 0; i < children.Count; i++)
{
var child = children[i];
- if (child != null)
- {
- var sz = new UVSize(orientation,
- itemWidthSet ? itemWidth : child.DesiredSize.Width,
- itemHeightSet ? itemHeight : child.DesiredSize.Height);
+ var sz = new UVSize(orientation,
+ itemWidthSet ? itemWidth : child.DesiredSize.Width,
+ itemHeightSet ? itemHeight : child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) // Need to switch to another line
- {
- ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
-
- accumulatedV += curLineSize.V;
- curLineSize = sz;
+ if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) // Need to switch to another line
+ {
+ ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
- if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) // The element is wider then the constraint - give it a separate line
- {
- // Switch to next line which only contain one element
- ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
+ accumulatedV += curLineSize.V;
+ curLineSize = sz;
- accumulatedV += sz.V;
- curLineSize = new UVSize(orientation);
- }
- firstInLine = i;
- }
- else // Continue to accumulate a line
+ if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) // The element is wider then the constraint - give it a separate line
{
- curLineSize.U += sz.U;
- curLineSize.V = Max(sz.V, curLineSize.V);
+ // Switch to next line which only contain one element
+ ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
+
+ accumulatedV += sz.V;
+ curLineSize = new UVSize(orientation);
}
+ firstInLine = i;
+ }
+ else // Continue to accumulate a line
+ {
+ curLineSize.U += sz.U;
+ curLineSize.V = Max(sz.V, curLineSize.V);
}
}
@@ -252,17 +246,14 @@ namespace Avalonia.Controls
for (int i = start; i < end; i++)
{
var child = children[i];
- if (child != null)
- {
- var childSize = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height);
- double layoutSlotU = useItemU ? itemU : childSize.U;
- child.Arrange(new Rect(
- isHorizontal ? u : v,
- isHorizontal ? v : u,
- isHorizontal ? layoutSlotU : lineV,
- isHorizontal ? lineV : layoutSlotU));
- u += layoutSlotU;
- }
+ var childSize = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height);
+ double layoutSlotU = useItemU ? itemU : childSize.U;
+ child.Arrange(new Rect(
+ isHorizontal ? u : v,
+ isHorizontal ? v : u,
+ isHorizontal ? layoutSlotU : lineV,
+ isHorizontal ? lineV : layoutSlotU));
+ u += layoutSlotU;
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs b/src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs
index 7426c4e2ed..a0ff3a714f 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Diagnostics.Controls
RendererRoot = application.ApplicationLifetime switch
{
Lifetimes.IClassicDesktopStyleApplicationLifetime classic => classic.MainWindow?.Renderer,
- Lifetimes.ISingleViewApplicationLifetime single => (single.MainView as Visual)?.VisualRoot?.Renderer,
+ Lifetimes.ISingleViewApplicationLifetime single => single.MainView?.VisualRoot?.Renderer,
_ => null
};
diff --git a/src/Avalonia.Diagnostics/Diagnostics/KeyGestureExtesions.cs b/src/Avalonia.Diagnostics/Diagnostics/KeyGestureExtesions.cs
index bb3ebc4708..5929ff18fa 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/KeyGestureExtesions.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/KeyGestureExtesions.cs
@@ -3,10 +3,9 @@ using Avalonia.Input.Raw;
namespace Avalonia.Diagnostics
{
- static class KeyGestureExtesions
+ internal static class KeyGestureExtesions
{
public static bool Matches(this KeyGesture gesture, RawKeyEventArgs keyEvent) =>
- keyEvent != null &&
(KeyModifiers)(keyEvent.Modifiers & RawInputModifiers.KeyboardMask) == gesture.KeyModifiers &&
ResolveNumPadOperationKey(keyEvent.Key) == ResolveNumPadOperationKey(gesture.Key);
diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs
index 0140281d50..785fd49983 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs
@@ -115,7 +115,7 @@ namespace Avalonia.Diagnostics.ViewModels
var link = _currentEvent.EventChain[linkIndex];
link.Handled = true;
- _currentEvent.HandledBy = link;
+ _currentEvent.HandledBy ??= link;
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml
index cd2e92914a..f62d8a0b79 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml
@@ -29,6 +29,7 @@
diff --git a/src/Avalonia.FreeDesktop/DBusHelper.cs b/src/Avalonia.FreeDesktop/DBusHelper.cs
index ef99838208..fac77521dc 100644
--- a/src/Avalonia.FreeDesktop/DBusHelper.cs
+++ b/src/Avalonia.FreeDesktop/DBusHelper.cs
@@ -6,7 +6,7 @@ using Tmds.DBus;
namespace Avalonia.FreeDesktop
{
- public static class DBusHelper
+ internal static class DBusHelper
{
///
/// This class uses synchronous execution at DBus connection establishment stage
diff --git a/src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs b/src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs
index 86978c8b60..d8874b6fae 100644
--- a/src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs
+++ b/src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs
@@ -6,7 +6,7 @@ using Tmds.DBus;
namespace Avalonia.FreeDesktop.DBusIme
{
- public class X11DBusImeHelper
+ internal class X11DBusImeHelper
{
private static readonly Dictionary> KnownMethods =
new Dictionary>
diff --git a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs
index 0e6bee5f24..cfbafc53e5 100644
--- a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs
+++ b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs
@@ -15,7 +15,7 @@ using Tmds.DBus;
namespace Avalonia.FreeDesktop
{
- public class DBusMenuExporter
+ internal class DBusMenuExporter
{
public static ITopLevelNativeMenuExporter? TryCreateTopLevelNativeMenu(IntPtr xid)
{
diff --git a/src/Avalonia.FreeDesktop/IX11InputMethod.cs b/src/Avalonia.FreeDesktop/IX11InputMethod.cs
index 9fa9c1809e..7274b58876 100644
--- a/src/Avalonia.FreeDesktop/IX11InputMethod.cs
+++ b/src/Avalonia.FreeDesktop/IX11InputMethod.cs
@@ -6,13 +6,13 @@ using Avalonia.Input.TextInput;
namespace Avalonia.FreeDesktop
{
- public interface IX11InputMethodFactory
+ internal interface IX11InputMethodFactory
{
(ITextInputMethodImpl method, IX11InputMethodControl control) CreateClient(IntPtr xid);
}
#pragma warning disable CA1815 // Override equals and operator equals on value types
- public struct X11InputMethodForwardedKey
+ internal struct X11InputMethodForwardedKey
#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public int KeyVal { get; set; }
@@ -20,7 +20,7 @@ namespace Avalonia.FreeDesktop
public RawKeyEventType Type { get; set; }
}
- public interface IX11InputMethodControl : IDisposable
+ internal interface IX11InputMethodControl : IDisposable
{
void SetWindowActive(bool active);
bool IsEnabled { get; }
diff --git a/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoProvider.cs b/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoProvider.cs
index 4624a9c340..4aa6bed329 100644
--- a/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoProvider.cs
+++ b/src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoProvider.cs
@@ -5,7 +5,7 @@ using Avalonia.Controls.Platform;
namespace Avalonia.FreeDesktop
{
- public class LinuxMountedVolumeInfoProvider : IMountedVolumeInfoProvider
+ internal class LinuxMountedVolumeInfoProvider : IMountedVolumeInfoProvider
{
public IDisposable Listen(ObservableCollection mountedDrives)
{
diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
index 225e846390..68466fe381 100644
--- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
+++ b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
@@ -141,9 +141,7 @@ namespace Avalonia.Headless
}
public IReadOnlyList GetIntersections(float lowerBound, float upperBound)
- {
- return null;
- }
+ => Array.Empty();
}
class HeadlessGeometryStub : IGeometryImpl
diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs
index 2a04e624cb..46e3515d11 100644
--- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs
+++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs
@@ -69,27 +69,17 @@ namespace Avalonia.Headless
{
public FontMetrics Metrics => new FontMetrics
{
-
+ DesignEmHeight = 1,
+ Ascent = 8,
+ Descent = 4,
+ LineGap = 0,
+ UnderlinePosition = 2,
+ UnderlineThickness = 1,
+ StrikethroughPosition = 2,
+ StrikethroughThickness = 1,
+ IsFixedPitch = true
};
- public short DesignEmHeight => 10;
-
- public int Ascent => 5;
-
- public int Descent => 5;
-
- public int LineGap => 2;
-
- public int UnderlinePosition => 5;
-
- public int UnderlineThickness => 5;
-
- public int StrikethroughPosition => 5;
-
- public int StrikethroughThickness => 2;
-
- public bool IsFixedPitch => true;
-
public int GlyphCount => 1337;
public FontSimulations FontSimulations { get; }
@@ -112,7 +102,7 @@ namespace Avalonia.Headless
public int GetGlyphAdvance(ushort glyph)
{
- return 1;
+ return 12;
}
public int[] GetGlyphAdvances(ReadOnlySpan glyphs)
@@ -136,7 +126,7 @@ namespace Avalonia.Headless
metrics = new GlyphMetrics
{
Height = 10,
- Width = 10
+ Width = 8
};
return true;
diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs
index 09feb0c768..67b55bd512 100644
--- a/src/Avalonia.Native/AvaloniaNativePlatform.cs
+++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs
@@ -158,25 +158,4 @@ namespace Avalonia.Native
throw new NotImplementedException();
}
}
-
- public class AvaloniaNativeMacOptions
- {
- private readonly IAvnMacOptions _opts;
- private bool _showInDock;
- internal AvaloniaNativeMacOptions(IAvnMacOptions opts)
- {
- _opts = opts;
- ShowInDock = true;
- }
-
- public bool ShowInDock
- {
- get => _showInDock;
- set
- {
- _showInDock = value;
- _opts.SetShowInDock(value ? 1 : 0);
- }
- }
- }
}
diff --git a/src/Avalonia.Native/CallbackBase.cs b/src/Avalonia.Native/CallbackBase.cs
index 2d875dbc0e..9f59c97f9b 100644
--- a/src/Avalonia.Native/CallbackBase.cs
+++ b/src/Avalonia.Native/CallbackBase.cs
@@ -6,7 +6,7 @@ using MicroCom.Runtime;
namespace Avalonia.Native
{
- public abstract class NativeCallbackBase : CallbackBase, IMicroComExceptionCallback
+ internal abstract class NativeCallbackBase : CallbackBase, IMicroComExceptionCallback
{
public void RaiseException(Exception e)
{
diff --git a/src/Avalonia.Native/MacOSMountedVolumeInfoProvider.cs b/src/Avalonia.Native/MacOSMountedVolumeInfoProvider.cs
index e79c7a40d3..1170a6fd9b 100644
--- a/src/Avalonia.Native/MacOSMountedVolumeInfoProvider.cs
+++ b/src/Avalonia.Native/MacOSMountedVolumeInfoProvider.cs
@@ -64,7 +64,7 @@ namespace Avalonia.Native
}
}
- public class MacOSMountedVolumeInfoProvider : IMountedVolumeInfoProvider
+ internal class MacOSMountedVolumeInfoProvider : IMountedVolumeInfoProvider
{
public IDisposable Listen(ObservableCollection mountedDrives)
{
diff --git a/src/Avalonia.Native/MenuActionCallback.cs b/src/Avalonia.Native/MenuActionCallback.cs
index 3acbb9c19c..e9446e2da1 100644
--- a/src/Avalonia.Native/MenuActionCallback.cs
+++ b/src/Avalonia.Native/MenuActionCallback.cs
@@ -3,7 +3,7 @@ using Avalonia.Native.Interop;
namespace Avalonia.Native
{
- public class MenuActionCallback : NativeCallbackBase, IAvnActionCallback
+ internal class MenuActionCallback : NativeCallbackBase, IAvnActionCallback
{
private Action _action;
diff --git a/src/Avalonia.Native/PlatformBehaviorInhibition.cs b/src/Avalonia.Native/PlatformBehaviorInhibition.cs
new file mode 100644
index 0000000000..dfbfe8a5e5
--- /dev/null
+++ b/src/Avalonia.Native/PlatformBehaviorInhibition.cs
@@ -0,0 +1,20 @@
+using System.Threading.Tasks;
+using Avalonia.Native.Interop;
+using Avalonia.Platform;
+
+namespace Avalonia.Native
+{
+ internal class PlatformBehaviorInhibition : IPlatformBehaviorInhibition
+ {
+ readonly IAvnPlatformBehaviorInhibition _native;
+
+ internal PlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition native)
+ => _native = native;
+
+ public Task SetInhibitAppSleep(bool inhibitAppSleep, string reason)
+ {
+ _native.SetInhibitAppSleep(inhibitAppSleep ? 1 : 0, reason);
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/Avalonia.Native/PredicateCallback.cs b/src/Avalonia.Native/PredicateCallback.cs
index dbb65791f0..1ff71063af 100644
--- a/src/Avalonia.Native/PredicateCallback.cs
+++ b/src/Avalonia.Native/PredicateCallback.cs
@@ -3,7 +3,7 @@ using Avalonia.Native.Interop;
namespace Avalonia.Native
{
- public class PredicateCallback : NativeCallbackBase, IAvnPredicateCallback
+ internal class PredicateCallback : NativeCallbackBase, IAvnPredicateCallback
{
private Func _predicate;
diff --git a/src/Avalonia.Native/ScreenImpl.cs b/src/Avalonia.Native/ScreenImpl.cs
index 53bd12cde1..c64d1378e8 100644
--- a/src/Avalonia.Native/ScreenImpl.cs
+++ b/src/Avalonia.Native/ScreenImpl.cs
@@ -5,7 +5,7 @@ using Avalonia.Platform;
namespace Avalonia.Native
{
- class ScreenImpl : IScreenImpl, IDisposable
+ internal class ScreenImpl : IScreenImpl, IDisposable
{
private IAvnScreens _native;
diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs
index f27d94b61a..64c1d0da10 100644
--- a/src/Avalonia.Native/WindowImpl.cs
+++ b/src/Avalonia.Native/WindowImpl.cs
@@ -119,7 +119,8 @@ namespace Avalonia.Native
{
if(e.Type == RawPointerEventType.LeftButtonDown)
{
- var visual = (_inputRoot as Window).Renderer.HitTestFirst(e.Position, _inputRoot as Window, x =>
+ var window = _inputRoot as Window;
+ var visual = window?.Renderer.HitTestFirst(e.Position, window, x =>
{
if (x is IInputElement ie && (!ie.IsHitTestVisible || !ie.IsEffectivelyVisible))
{
diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs
index 50bee0d395..4357f3b705 100644
--- a/src/Avalonia.Native/WindowImplBase.cs
+++ b/src/Avalonia.Native/WindowImplBase.cs
@@ -63,6 +63,7 @@ namespace Avalonia.Native
private GlPlatformSurface _glSurface;
private NativeControlHostImpl _nativeControlHost;
private IStorageProvider _storageProvider;
+ private PlatformBehaviorInhibition _platformBehaviorInhibition;
internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
AvaloniaNativeGlPlatformGraphics glFeature)
@@ -88,6 +89,7 @@ namespace Avalonia.Native
_savedScaling = RenderScaling;
_nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost());
_storageProvider = new SystemDialogs(this, _factory.CreateSystemDialogs());
+ _platformBehaviorInhibition = new PlatformBehaviorInhibition(_factory.CreatePlatformBehaviorInhibition());
var monitor = Screen.AllScreens.OrderBy(x => x.Scaling)
.FirstOrDefault(m => m.Bounds.Contains(Position));
@@ -521,6 +523,11 @@ namespace Avalonia.Native
return _storageProvider;
}
+ if (featureType == typeof(IPlatformBehaviorInhibition))
+ {
+ return _platformBehaviorInhibition;
+ }
+
return null;
}
diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl
index a062fdc61d..db78873672 100644
--- a/src/Avalonia.Native/avn.idl
+++ b/src/Avalonia.Native/avn.idl
@@ -503,6 +503,7 @@ interface IAvaloniaNativeFactory : IUnknown
HRESULT CreateTrayIcon(IAvnTrayIcon** ppv);
HRESULT CreateApplicationCommands(IAvnApplicationCommands** ppv);
HRESULT CreatePlatformSettings(IAvnPlatformSettings** ppv);
+ HRESULT CreatePlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition** ppv);
}
[uuid(233e094f-9b9f-44a3-9a6e-6948bbdd9fb1)]
@@ -924,3 +925,9 @@ interface IAvnPlatformSettings : IUnknown
uint GetAccentColor();
void RegisterColorsChange(IAvnActionCallback* callback);
}
+
+[uuid(12edf00d-5803-4d3f-9947-b4840e5e9372)]
+interface IAvnPlatformBehaviorInhibition : IUnknown
+{
+ void SetInhibitAppSleep(bool inhibitAppSleep, char* reason);
+}
diff --git a/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml b/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
index 4b9fb76b8a..e2273cd487 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
@@ -19,6 +19,7 @@
+
@@ -34,6 +35,7 @@
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}"
IsScrollChainingEnabled="{TemplateBinding (ScrollViewer.IsScrollChainingEnabled)}"
+ IsScrollInertiaEnabled="{TemplateBinding (ScrollViewer.IsScrollInertiaEnabled)}"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}">
CreateContext(CreatePBuffer(), share,
share.SampleCount, share.StencilSize, true);
-
- GlxContext CreateContext(IntPtr defaultXid, IGlContext share,
+
+ private GlxContext CreateContext(IntPtr defaultXid, IGlContext share,
int sampleCount, int stencilSize, bool ownsPBuffer)
{
var sharelist = ((GlxContext)share)?.Handle ?? IntPtr.Zero;
diff --git a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
index ebb1e18723..17c5909a39 100644
--- a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
+++ b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
@@ -6,7 +6,7 @@ using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.X11.Glx
{
- class GlxGlPlatformSurface: IGlPlatformSurface
+ internal class GlxGlPlatformSurface: IGlPlatformSurface
{
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
@@ -21,7 +21,7 @@ namespace Avalonia.X11.Glx
return new RenderTarget((GlxContext)context, _info);
}
- class RenderTarget : IGlPlatformSurfaceRenderTarget
+ private class RenderTarget : IGlPlatformSurfaceRenderTarget
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
@@ -46,8 +46,8 @@ namespace Avalonia.X11.Glx
return new Session(_context, _info, oldContext);
}
-
- class Session : IGlPlatformSurfaceRenderingSession
+
+ private class Session : IGlPlatformSurfaceRenderingSession
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
diff --git a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
index bc50fa61aa..06766e0963 100644
--- a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
+++ b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
@@ -6,7 +6,7 @@ using Avalonia.Platform;
namespace Avalonia.X11.Glx
{
- class GlxPlatformGraphics : IPlatformGraphics
+ internal class GlxPlatformGraphics : IPlatformGraphics
{
public GlxDisplay Display { get; private set; }
public bool CanCreateContexts => true;
diff --git a/src/Avalonia.X11/Keysyms.cs b/src/Avalonia.X11/Keysyms.cs
index 651a06f574..970cf5ad4d 100644
--- a/src/Avalonia.X11/Keysyms.cs
+++ b/src/Avalonia.X11/Keysyms.cs
@@ -3,7 +3,7 @@
// ReSharper disable CommentTypo
namespace Avalonia.X11
{
- enum X11Key
+ internal enum X11Key
{
VoidSymbol = 0xffffff /* Void symbol */,
BackSpace = 0xff08 /* Back space, back char */,
diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs
index 4e56ae73cf..3f225dc6bc 100644
--- a/src/Avalonia.X11/NativeDialogs/Gtk.cs
+++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs
@@ -7,8 +7,7 @@ using Avalonia.Platform.Interop;
// ReSharper disable IdentifierTypo
namespace Avalonia.X11.NativeDialogs
{
-
- static unsafe class Glib
+ internal static unsafe class Glib
{
private const string GlibName = "libglib-2.0.so.0";
private const string GObjectName = "libgobject-2.0.so.0";
@@ -36,7 +35,7 @@ namespace Avalonia.X11.NativeDialogs
IntPtr destroy);
- class ConnectedSignal : IDisposable
+ private class ConnectedSignal : IDisposable
{
private readonly IntPtr _instance;
private GCHandle _handle;
@@ -75,7 +74,7 @@ namespace Avalonia.X11.NativeDialogs
}
- static bool TimeoutHandler(IntPtr data)
+ private static bool TimeoutHandler(IntPtr data)
{
var handle = GCHandle.FromIntPtr(data);
var cb = (Func)handle.Target;
@@ -95,7 +94,7 @@ namespace Avalonia.X11.NativeDialogs
s_pinnedHandler = TimeoutHandler;
}
- static void AddTimeout(int priority, uint interval, Func callback)
+ private static void AddTimeout(int priority, uint interval, Func callback)
{
var handle = GCHandle.Alloc(callback);
g_timeout_add_full(priority, interval, s_pinnedHandler, GCHandle.ToIntPtr(handle), IntPtr.Zero);
@@ -123,13 +122,13 @@ namespace Avalonia.X11.NativeDialogs
}
[StructLayout(LayoutKind.Sequential)]
- unsafe struct GSList
+ internal unsafe struct GSList
{
public readonly IntPtr Data;
public readonly GSList* Next;
}
- enum GtkFileChooserAction
+ internal enum GtkFileChooserAction
{
Open,
Save,
@@ -137,7 +136,7 @@ namespace Avalonia.X11.NativeDialogs
}
// ReSharper disable UnusedMember.Global
- enum GtkResponseType
+ internal enum GtkResponseType
{
Help = -11,
Apply = -10,
@@ -153,14 +152,14 @@ namespace Avalonia.X11.NativeDialogs
}
// ReSharper restore UnusedMember.Global
- static unsafe class Gtk
+ internal static unsafe class Gtk
{
private static IntPtr s_display;
private const string GdkName = "libgdk-3.so.0";
private const string GtkName = "libgtk-3.so.0";
[DllImport(GtkName)]
- static extern void gtk_main_iteration();
+ private static extern void gtk_main_iteration();
[DllImport(GtkName)]
@@ -231,10 +230,10 @@ namespace Avalonia.X11.NativeDialogs
public static extern void gtk_widget_hide(IntPtr gtkWidget);
[DllImport(GtkName)]
- static extern bool gtk_init_check(int argc, IntPtr argv);
+ private static extern bool gtk_init_check(int argc, IntPtr argv);
[DllImport(GdkName)]
- static extern IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid);
+ private static extern IntPtr gdk_x11_window_foreign_new_for_display(IntPtr display, IntPtr xid);
[DllImport(GdkName)]
public static extern IntPtr gdk_x11_window_get_xid(IntPtr window);
@@ -244,13 +243,13 @@ namespace Avalonia.X11.NativeDialogs
public static extern IntPtr gtk_container_add(IntPtr container, IntPtr widget);
[DllImport(GdkName)]
- static extern IntPtr gdk_set_allowed_backends(Utf8Buffer backends);
+ private static extern IntPtr gdk_set_allowed_backends(Utf8Buffer backends);
[DllImport(GdkName)]
- static extern IntPtr gdk_display_get_default();
+ private static extern IntPtr gdk_display_get_default();
[DllImport(GtkName)]
- static extern IntPtr gtk_application_new(Utf8Buffer appId, int flags);
+ private static extern IntPtr gtk_application_new(Utf8Buffer appId, int flags);
[DllImport(GdkName)]
public static extern void gdk_window_set_transient_for(IntPtr window, IntPtr parent);
diff --git a/src/Avalonia.X11/TransparencyHelper.cs b/src/Avalonia.X11/TransparencyHelper.cs
index 2140b61b6f..5ca2d1d337 100644
--- a/src/Avalonia.X11/TransparencyHelper.cs
+++ b/src/Avalonia.X11/TransparencyHelper.cs
@@ -3,7 +3,7 @@ using Avalonia.Controls;
namespace Avalonia.X11
{
- class TransparencyHelper : IDisposable, X11Globals.IGlobalsSubscriber
+ internal class TransparencyHelper : IDisposable, X11Globals.IGlobalsSubscriber
{
private readonly X11Info _x11;
private readonly IntPtr _window;
diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs
index 2aa7797067..04d1aae194 100644
--- a/src/Avalonia.X11/X11Clipboard.cs
+++ b/src/Avalonia.X11/X11Clipboard.cs
@@ -9,7 +9,7 @@ using Avalonia.Input.Platform;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- class X11Clipboard : IClipboard
+ internal class X11Clipboard : IClipboard
{
private readonly X11Info _x11;
private IDataObject _storedDataObject;
@@ -33,12 +33,12 @@ namespace Avalonia.X11
}.Where(a => a != IntPtr.Zero).ToArray();
}
- bool IsStringAtom(IntPtr atom)
+ private bool IsStringAtom(IntPtr atom)
{
return _textAtoms.Contains(atom);
}
-
- Encoding GetStringEncoding(IntPtr atom)
+
+ private Encoding GetStringEncoding(IntPtr atom)
{
return (atom == _x11.Atoms.XA_STRING
|| atom == _x11.Atoms.OEMTEXT)
@@ -213,7 +213,7 @@ namespace Avalonia.X11
}
}
- Task SendFormatRequest()
+ private Task SendFormatRequest()
{
if (_requestedFormatsTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedFormatsTcs = new TaskCompletionSource();
@@ -222,7 +222,7 @@ namespace Avalonia.X11
return _requestedFormatsTcs.Task;
}
- Task SendDataRequest(IntPtr format)
+ private Task SendDataRequest(IntPtr format)
{
if (_requestedDataTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedDataTcs = new TaskCompletionSource();
@@ -230,7 +230,7 @@ namespace Avalonia.X11
return _requestedDataTcs.Task;
}
- bool HasOwner => XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) != IntPtr.Zero;
+ private bool HasOwner => XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) != IntPtr.Zero;
public async Task GetTextAsync()
{
@@ -252,7 +252,7 @@ namespace Avalonia.X11
return (string)await SendDataRequest(target);
}
- void StoreAtomsInClipboardManager(IntPtr[] atoms)
+ private void StoreAtomsInClipboardManager(IntPtr[] atoms)
{
if (_x11.Atoms.CLIPBOARD_MANAGER != IntPtr.Zero && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
{
diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs
index 16de10e163..56fd2f14ef 100644
--- a/src/Avalonia.X11/X11CursorFactory.cs
+++ b/src/Avalonia.X11/X11CursorFactory.cs
@@ -12,7 +12,7 @@ using Avalonia.Utilities;
namespace Avalonia.X11
{
- partial class X11CursorFactory : ICursorFactory
+ internal partial class X11CursorFactory : ICursorFactory
{
private static readonly byte[] NullCursorData = new byte[] { 0 };
@@ -142,7 +142,7 @@ namespace Avalonia.X11
}
}
- class CursorImpl : ICursorImpl
+ internal class CursorImpl : ICursorImpl
{
public CursorImpl() { }
public CursorImpl(IntPtr handle) => Handle = handle;
diff --git a/src/Avalonia.X11/X11Enums.cs b/src/Avalonia.X11/X11Enums.cs
index d97e1c42bb..9d671ae6d2 100644
--- a/src/Avalonia.X11/X11Enums.cs
+++ b/src/Avalonia.X11/X11Enums.cs
@@ -3,7 +3,7 @@ using System;
namespace Avalonia.X11
{
- public enum Status
+ internal enum Status
{
Success = 0, /* everything's okay */
BadRequest = 1, /* bad request code */
@@ -38,7 +38,7 @@ namespace Avalonia.X11
}
[Flags]
- public enum XEventMask : int
+ internal enum XEventMask : int
{
NoEventMask = 0,
KeyPressMask = (1 << 0),
@@ -69,7 +69,7 @@ namespace Avalonia.X11
}
[Flags]
- public enum XModifierMask
+ internal enum XModifierMask
{
ShiftMask = (1 << 0),
LockMask = (1 << 1),
@@ -89,7 +89,7 @@ namespace Avalonia.X11
}
[Flags]
- public enum XCreateWindowFlags
+ internal enum XCreateWindowFlags
{
CWBackPixmap = (1 << 0),
CWBackPixel = (1 << 1),
diff --git a/src/Avalonia.X11/X11Exception.cs b/src/Avalonia.X11/X11Exception.cs
index 2ac5a31d9b..231ece497b 100644
--- a/src/Avalonia.X11/X11Exception.cs
+++ b/src/Avalonia.X11/X11Exception.cs
@@ -2,7 +2,7 @@ using System;
namespace Avalonia.X11
{
- public class X11Exception : Exception
+ internal class X11Exception : Exception
{
public X11Exception(string message) : base(message)
{
diff --git a/src/Avalonia.X11/X11Framebuffer.cs b/src/Avalonia.X11/X11Framebuffer.cs
index a9fedff8b5..90e4b18571 100644
--- a/src/Avalonia.X11/X11Framebuffer.cs
+++ b/src/Avalonia.X11/X11Framebuffer.cs
@@ -5,7 +5,7 @@ using SkiaSharp;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- class X11Framebuffer : ILockedFramebuffer
+ internal class X11Framebuffer : ILockedFramebuffer
{
private readonly IntPtr _display;
private readonly IntPtr _xid;
diff --git a/src/Avalonia.X11/X11FramebufferSurface.cs b/src/Avalonia.X11/X11FramebufferSurface.cs
index 07c88b51a8..05885d1a25 100644
--- a/src/Avalonia.X11/X11FramebufferSurface.cs
+++ b/src/Avalonia.X11/X11FramebufferSurface.cs
@@ -4,7 +4,7 @@ using Avalonia.Platform;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- public class X11FramebufferSurface : IFramebufferPlatformSurface
+ internal class X11FramebufferSurface : IFramebufferPlatformSurface
{
private readonly IntPtr _display;
private readonly IntPtr _xid;
diff --git a/src/Avalonia.X11/X11Globals.cs b/src/Avalonia.X11/X11Globals.cs
index 39834a44b3..1ae0544724 100644
--- a/src/Avalonia.X11/X11Globals.cs
+++ b/src/Avalonia.X11/X11Globals.cs
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- unsafe class X11Globals
+ internal unsafe class X11Globals
{
private readonly AvaloniaX11Platform _plat;
private readonly int _screenNumber;
@@ -75,7 +75,7 @@ namespace Avalonia.X11
}
}
- IntPtr GetSupportingWmCheck(IntPtr window)
+ private IntPtr GetSupportingWmCheck(IntPtr window)
{
XGetWindowProperty(_x11.Display, _rootWindow, _x11.Atoms._NET_SUPPORTING_WM_CHECK,
IntPtr.Zero, new IntPtr(IntPtr.Size), false,
@@ -95,7 +95,7 @@ namespace Avalonia.X11
}
}
- void UpdateCompositingAtomOwner()
+ private void UpdateCompositingAtomOwner()
{
// This procedure is described in https://tronche.com/gui/x/icccm/sec-2.html#s-2.8
@@ -128,10 +128,10 @@ namespace Avalonia.X11
if(ev.type == XEventName.DestroyNotify)
UpdateCompositingAtomOwner();
}
-
- void UpdateWmName() => WmName = GetWmName();
- string GetWmName()
+ private void UpdateWmName() => WmName = GetWmName();
+
+ private string GetWmName()
{
var wm = GetSupportingWmCheck(_rootWindow);
if (wm == IntPtr.Zero || wm != GetSupportingWmCheck(wm))
diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs
index bf59d72c0f..51db815b31 100644
--- a/src/Avalonia.X11/X11IconLoader.cs
+++ b/src/Avalonia.X11/X11IconLoader.cs
@@ -7,9 +7,9 @@ using Avalonia.Platform;
namespace Avalonia.X11
{
- class X11IconLoader : IPlatformIconLoader
+ internal class X11IconLoader : IPlatformIconLoader
{
- static IWindowIconImpl LoadIcon(Bitmap bitmap)
+ private static IWindowIconImpl LoadIcon(Bitmap bitmap)
{
var rv = new X11IconData(bitmap);
bitmap.Dispose();
@@ -28,8 +28,8 @@ namespace Avalonia.X11
return LoadIcon(ms);
}
}
-
- unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface
+
+ internal unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface
{
private int _width;
private int _height;
diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs
index 72f3bf3137..17cd6b12c6 100644
--- a/src/Avalonia.X11/X11Info.cs
+++ b/src/Avalonia.X11/X11Info.cs
@@ -6,7 +6,7 @@ using static Avalonia.X11.XLib;
// ReSharper disable UnusedAutoPropertyAccessor.Local
namespace Avalonia.X11
{
- unsafe class X11Info
+ internal unsafe class X11Info
{
public IntPtr Display { get; }
public IntPtr DeferredDisplay { get; }
diff --git a/src/Avalonia.X11/X11KeyTransform.cs b/src/Avalonia.X11/X11KeyTransform.cs
index 59f1da564c..6732a0f448 100644
--- a/src/Avalonia.X11/X11KeyTransform.cs
+++ b/src/Avalonia.X11/X11KeyTransform.cs
@@ -4,7 +4,7 @@ using Avalonia.Input;
namespace Avalonia.X11
{
- static class X11KeyTransform
+ internal static class X11KeyTransform
{
private static readonly Dictionary KeyDic = new Dictionary
{
diff --git a/src/Avalonia.X11/X11NativeControlHost.cs b/src/Avalonia.X11/X11NativeControlHost.cs
index 6c4eb81c84..e8710580eb 100644
--- a/src/Avalonia.X11/X11NativeControlHost.cs
+++ b/src/Avalonia.X11/X11NativeControlHost.cs
@@ -6,7 +6,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
// TODO: Actually implement XEmbed instead of simply using XReparentWindow
- class X11NativeControlHost : INativeControlHostImpl
+ internal class X11NativeControlHost : INativeControlHostImpl
{
private readonly AvaloniaX11Platform _platform;
public X11Window Window { get; }
@@ -57,7 +57,7 @@ namespace Avalonia.X11
public bool IsCompatibleWith(IPlatformHandle handle) => handle.HandleDescriptor == "XID";
- class DumbWindow : INativeControlHostDestroyableControlHandle
+ private class DumbWindow : INativeControlHostDestroyableControlHandle
{
private readonly IntPtr _display;
@@ -96,8 +96,8 @@ namespace Avalonia.X11
}
}
}
-
- class Attachment : INativeControlHostControlTopLevelAttachment
+
+ private class Attachment : INativeControlHostControlTopLevelAttachment
{
private readonly IntPtr _display;
private readonly IntPtr _orphanedWindow;
@@ -129,7 +129,7 @@ namespace Avalonia.X11
_attachedTo = null;
}
- void CheckDisposed()
+ private void CheckDisposed()
{
if (_child == null)
throw new ObjectDisposedException("X11 INativeControlHostControlTopLevelAttachment");
diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs
index c5ae327c2f..170c6ce6b3 100644
--- a/src/Avalonia.X11/X11Platform.cs
+++ b/src/Avalonia.X11/X11Platform.cs
@@ -20,7 +20,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- class AvaloniaX11Platform : IWindowingPlatform
+ internal class AvaloniaX11Platform : IWindowingPlatform
{
private Lazy _keyboardDevice = new Lazy(() => new KeyboardDevice());
public KeyboardDevice KeyboardDevice => _keyboardDevice.Value;
@@ -35,7 +35,7 @@ namespace Avalonia.X11
public IntPtr OrphanedWindow { get; private set; }
public X11Globals Globals { get; private set; }
[DllImport("libc")]
- static extern void setlocale(int type, string s);
+ private static extern void setlocale(int type, string s);
public void Initialize(X11PlatformOptions options)
{
Options = options;
@@ -138,7 +138,7 @@ namespace Avalonia.X11
throw new NotSupportedException();
}
- static bool EnableIme(X11PlatformOptions options)
+ private static bool EnableIme(X11PlatformOptions options)
{
// Disable if explicitly asked by user
var avaloniaImModule = Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE");
@@ -160,7 +160,7 @@ namespace Avalonia.X11
return isCjkLocale;
}
- static bool ShouldUseXim()
+ private static bool ShouldUseXim()
{
// Check if we are forbidden from using IME
if (Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE") == "none"
diff --git a/src/Avalonia.X11/X11PlatformThreading.cs b/src/Avalonia.X11/X11PlatformThreading.cs
index d724cd2aed..1946642de3 100644
--- a/src/Avalonia.X11/X11PlatformThreading.cs
+++ b/src/Avalonia.X11/X11PlatformThreading.cs
@@ -9,7 +9,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- unsafe class X11PlatformThreading : IPlatformThreadingInterface
+ internal unsafe class X11PlatformThreading : IPlatformThreadingInterface
{
private readonly AvaloniaX11Platform _platform;
private readonly IntPtr _display;
@@ -19,7 +19,7 @@ namespace Avalonia.X11
private Thread _mainThread;
[StructLayout(LayoutKind.Explicit)]
- struct epoll_data
+ private struct epoll_data
{
[FieldOffset(0)]
public IntPtr ptr;
@@ -36,30 +36,30 @@ namespace Avalonia.X11
private const int O_NONBLOCK = 2048;
[StructLayout(LayoutKind.Sequential)]
- struct epoll_event
+ private struct epoll_event
{
public uint events;
public epoll_data data;
}
[DllImport("libc")]
- extern static int epoll_create1(int size);
+ private extern static int epoll_create1(int size);
[DllImport("libc")]
- extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event);
+ private extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event);
[DllImport("libc")]
- extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout);
+ private extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout);
[DllImport("libc")]
- extern static int pipe2(int* fds, int flags);
+ private extern static int pipe2(int* fds, int flags);
[DllImport("libc")]
- extern static IntPtr write(int fd, void* buf, IntPtr count);
+ private extern static IntPtr write(int fd, void* buf, IntPtr count);
[DllImport("libc")]
- extern static IntPtr read(int fd, void* buf, IntPtr count);
-
- enum EventCodes
+ private extern static IntPtr read(int fd, void* buf, IntPtr count);
+
+ private enum EventCodes
{
X11 = 1,
Signal =2
@@ -72,7 +72,7 @@ namespace Avalonia.X11
private int _epoll;
private Stopwatch _clock = Stopwatch.StartNew();
- class X11Timer : IDisposable
+ private class X11Timer : IDisposable
{
private readonly X11PlatformThreading _parent;
@@ -104,7 +104,7 @@ namespace Avalonia.X11
}
}
- List _timers = new List();
+ private List _timers = new List();
public X11PlatformThreading(AvaloniaX11Platform platform)
{
@@ -139,12 +139,12 @@ namespace Avalonia.X11
throw new X11Exception("Unable to attach signal pipe to epoll");
}
- int TimerComparer(X11Timer t1, X11Timer t2)
+ private int TimerComparer(X11Timer t1, X11Timer t2)
{
return t2.Priority - t1.Priority;
}
- void CheckSignaled()
+ private void CheckSignaled()
{
int buf = 0;
while (read(_sigread, &buf, new IntPtr(4)).ToInt64() > 0)
@@ -164,7 +164,7 @@ namespace Avalonia.X11
Signaled?.Invoke(prio);
}
- unsafe void HandleX11(CancellationToken cancellationToken)
+ private unsafe void HandleX11(CancellationToken cancellationToken)
{
while (XPending(_display) != 0)
{
diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs
index 87899b11ed..6c7283952d 100644
--- a/src/Avalonia.X11/X11Screens.cs
+++ b/src/Avalonia.X11/X11Screens.cs
@@ -8,7 +8,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- class X11Screens : IScreenImpl
+ internal class X11Screens : IScreenImpl
{
private IX11Screens _impl;
@@ -17,7 +17,7 @@ namespace Avalonia.X11
_impl = impl;
}
- static unsafe X11Screen[] UpdateWorkArea(X11Info info, X11Screen[] screens)
+ private static unsafe X11Screen[] UpdateWorkArea(X11Info info, X11Screen[] screens)
{
var rect = default(PixelRect);
foreach (var s in screens)
@@ -58,14 +58,14 @@ namespace Avalonia.X11
XFree(prop);
return screens;
}
-
- class Randr15ScreensImpl : IX11Screens
+
+ private class Randr15ScreensImpl : IX11Screens
{
private readonly X11ScreensUserSettings _settings;
private X11Screen[] _cache;
private X11Info _x11;
private IntPtr _window;
- const int EDIDStructureLength = 32; // Length of a EDID-Block-Length(128 bytes), XRRGetOutputProperty multiplies offset and length by 4
+ private const int EDIDStructureLength = 32; // Length of a EDID-Block-Length(128 bytes), XRRGetOutputProperty multiplies offset and length by 4
public Randr15ScreensImpl(AvaloniaX11Platform platform, X11ScreensUserSettings settings)
{
@@ -160,7 +160,7 @@ namespace Avalonia.X11
}
}
- class FallbackScreensImpl : IX11Screens
+ private class FallbackScreensImpl : IX11Screens
{
public FallbackScreensImpl(X11Info info, X11ScreensUserSettings settings)
{
@@ -220,17 +220,17 @@ namespace Avalonia.X11
_impl.Screens.Select(s => new Screen(s.Scaling, s.Bounds, s.WorkingArea, s.IsPrimary)).ToArray();
}
- interface IX11Screens
+ internal interface IX11Screens
{
X11Screen[] Screens { get; }
}
- class X11ScreensUserSettings
+ internal class X11ScreensUserSettings
{
public double GlobalScaleFactor { get; set; } = 1;
public Dictionary NamedScaleFactors { get; set; }
- static double? TryParse(string s)
+ private static double? TryParse(string s)
{
if (s == null)
return null;
@@ -276,7 +276,7 @@ namespace Avalonia.X11
}
}
- class X11Screen
+ internal class X11Screen
{
private const int FullHDWidth = 1920;
private const int FullHDHeight = 1080;
diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs
index 26515762b4..18f860a1a8 100644
--- a/src/Avalonia.X11/X11Structs.cs
+++ b/src/Avalonia.X11/X11Structs.cs
@@ -1751,8 +1751,7 @@ namespace Avalonia.X11 {
{
public IntPtr client_data;
public XIMProc callback;
- [NonSerialized]
- GCHandle gch;
+ [NonSerialized] private GCHandle gch;
public XIMCallback (IntPtr clientData, XIMProc proc)
{
@@ -1769,7 +1768,7 @@ namespace Avalonia.X11 {
[StructLayout(LayoutKind.Sequential)]
#pragma warning disable CA1815 // Override equals and operator equals on value types
- public unsafe struct XImage
+ internal unsafe struct XImage
#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public int width, height; /* size of image */
@@ -1896,8 +1895,8 @@ namespace Avalonia.X11 {
public const string XNSpotLocation = "spotLocation";
public const string XNFontSet = "fontSet";
}
-
- unsafe struct XRRMonitorInfo {
+
+ internal unsafe struct XRRMonitorInfo {
public IntPtr Name;
public int Primary;
public int Automatic;
diff --git a/src/Avalonia.X11/X11Window.Ime.cs b/src/Avalonia.X11/X11Window.Ime.cs
index e6066c7964..26ead5e6b8 100644
--- a/src/Avalonia.X11/X11Window.Ime.cs
+++ b/src/Avalonia.X11/X11Window.Ime.cs
@@ -11,7 +11,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- partial class X11Window
+ internal partial class X11Window
{
private ITextInputMethodImpl _ime;
private IX11InputMethodControl _imeControl;
@@ -20,7 +20,7 @@ namespace Avalonia.X11
private Queue<(RawKeyEventArgs args, XEvent xev, int keyval, int keycode)> _imeQueue =
new Queue<(RawKeyEventArgs args, XEvent xev, int keyVal, int keyCode)>();
- unsafe void CreateIC()
+ private unsafe void CreateIC()
{
if (_x11.HasXim)
{
@@ -65,8 +65,8 @@ namespace Avalonia.X11
new IntPtr((int)(XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing)),
XNames.XNClientWindow, _handle, XNames.XNFocusWindow, _handle, IntPtr.Zero);
}
-
- void InitializeIme()
+
+ private void InitializeIme()
{
var ime = AvaloniaLocator.Current.GetService()?.CreateClient(_handle);
if (ime == null && _x11.HasXim)
@@ -89,9 +89,9 @@ namespace Avalonia.X11
}
}
- void UpdateImePosition() => _imeControl?.UpdateWindowInfo(Position, RenderScaling);
+ private void UpdateImePosition() => _imeControl?.UpdateWindowInfo(Position, RenderScaling);
- void HandleKeyEvent(ref XEvent ev)
+ private void HandleKeyEvent(ref XEvent ev)
{
var index = ev.KeyEvent.state.HasAllFlags(XModifierMask.ShiftMask);
@@ -117,7 +117,7 @@ namespace Avalonia.X11
ScheduleKeyInput(args, ref ev, (int)key, ev.KeyEvent.keycode);
}
- void TriggerClassicTextInputEvent(ref XEvent ev)
+ private void TriggerClassicTextInputEvent(ref XEvent ev)
{
var text = TranslateEventToString(ref ev);
if (text != null)
@@ -128,8 +128,8 @@ namespace Avalonia.X11
private const int ImeBufferSize = 64 * 1024;
[ThreadStatic] private static IntPtr ImeBuffer;
-
- unsafe string TranslateEventToString(ref XEvent ev)
+
+ private unsafe string TranslateEventToString(ref XEvent ev)
{
if (ImeBuffer == IntPtr.Zero)
ImeBuffer = Marshal.AllocHGlobal(ImeBufferSize);
@@ -158,9 +158,9 @@ namespace Avalonia.X11
return text;
}
-
-
- void ScheduleKeyInput(RawKeyEventArgs args, ref XEvent xev, int keyval, int keycode)
+
+
+ private void ScheduleKeyInput(RawKeyEventArgs args, ref XEvent xev, int keyval, int keycode)
{
_x11.LastActivityTimestamp = xev.ButtonEvent.time;
@@ -170,8 +170,8 @@ namespace Avalonia.X11
ScheduleInput(args);
}
-
- bool FilterIme(RawKeyEventArgs args, XEvent xev, int keyval, int keycode)
+
+ private bool FilterIme(RawKeyEventArgs args, XEvent xev, int keyval, int keycode)
{
if (_ime == null)
return false;
@@ -182,7 +182,7 @@ namespace Avalonia.X11
return true;
}
- async void ProcessNextImeEvent()
+ private async void ProcessNextImeEvent()
{
if(_processingIme)
return;
@@ -203,7 +203,7 @@ namespace Avalonia.X11
}
// This class is used to attach the text value of the key to an asynchronously dispatched KeyDown event
- class RawKeyEventArgsWithText : RawKeyEventArgs
+ private class RawKeyEventArgsWithText : RawKeyEventArgs
{
public RawKeyEventArgsWithText(IKeyboardDevice device, ulong timestamp, IInputRoot root,
RawKeyEventType type, Key key, RawInputModifiers modifiers, string text) :
diff --git a/src/Avalonia.X11/X11Window.Xim.cs b/src/Avalonia.X11/X11Window.Xim.cs
index 8446d35cc6..cc5ecad09f 100644
--- a/src/Avalonia.X11/X11Window.Xim.cs
+++ b/src/Avalonia.X11/X11Window.Xim.cs
@@ -8,9 +8,9 @@ using Avalonia.Threading;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- partial class X11Window
+ internal partial class X11Window
{
- class XimInputMethod : ITextInputMethodImpl, IX11InputMethodControl
+ private class XimInputMethod : ITextInputMethodImpl, IX11InputMethodControl
{
private readonly X11Window _parent;
private bool _windowActive, _imeActive;
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index c78ef2350e..9f09212814 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -27,7 +27,7 @@ using static Avalonia.X11.XLib;
// ReSharper disable StringLiteralTypo
namespace Avalonia.X11
{
- unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
+ internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
{
private readonly AvaloniaX11Platform _platform;
private readonly bool _popup;
@@ -59,7 +59,7 @@ namespace Avalonia.X11
private bool _useRenderWindow = false;
private bool _usePositioningFlags = false;
- enum XSyncState
+ private enum XSyncState
{
None,
WaitConfigure,
@@ -219,7 +219,7 @@ namespace Avalonia.X11
});
}
- class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
+ private class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
{
private readonly X11Window _window;
private readonly IntPtr _display;
@@ -249,7 +249,7 @@ namespace Avalonia.X11
public double Scaling => _window.RenderScaling;
}
- void UpdateMotifHints()
+ private void UpdateMotifHints()
{
var functions = MotifFunctions.Move | MotifFunctions.Close | MotifFunctions.Resize |
MotifFunctions.Minimize | MotifFunctions.Maximize;
@@ -278,7 +278,7 @@ namespace Avalonia.X11
PropertyMode.Replace, ref hints, 5);
}
- void UpdateSizeHints(PixelSize? preResize)
+ private void UpdateSizeHints(PixelSize? preResize)
{
var min = _minMaxSize.minSize;
var max = _minMaxSize.maxSize;
@@ -386,7 +386,7 @@ namespace Avalonia.X11
public IRenderer CreateRenderer(IRenderRoot root) =>
new CompositingRenderer(root, _platform.Compositor, () => Surfaces);
- void OnEvent(ref XEvent ev)
+ private void OnEvent(ref XEvent ev)
{
if (ev.type == XEventName.MapNotify)
{
@@ -668,7 +668,7 @@ namespace Avalonia.X11
}
- static RawInputModifiers TranslateModifiers(XModifierMask state)
+ private static RawInputModifiers TranslateModifiers(XModifierMask state)
{
var rv = default(RawInputModifiers);
if (state.HasAllFlags(XModifierMask.Button1Mask))
@@ -704,13 +704,13 @@ namespace Avalonia.X11
private double _scaling = 1;
- void ScheduleInput(RawInputEventArgs args, ref XEvent xev)
+ private void ScheduleInput(RawInputEventArgs args, ref XEvent xev)
{
_x11.LastActivityTimestamp = xev.ButtonEvent.time;
ScheduleInput(args);
}
- void DispatchInput(RawInputEventArgs args)
+ private void DispatchInput(RawInputEventArgs args)
{
Input?.Invoke(args);
if (!args.Handled && args is RawKeyEventArgsWithText text && !string.IsNullOrEmpty(text.Text))
@@ -746,8 +746,8 @@ namespace Avalonia.X11
_rawEventGrouper.HandleEvent(args);
}
-
- void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
+
+ private void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
{
var mev = new RawPointerEventArgs(
_mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot,
@@ -755,7 +755,7 @@ namespace Avalonia.X11
ScheduleInput(mev, ref ev);
}
- void EnqueuePaint()
+ private void EnqueuePaint()
{
if (!_triggeredExpose)
{
@@ -767,8 +767,8 @@ namespace Avalonia.X11
}, DispatcherPriority.Render);
}
}
-
- void DoPaint()
+
+ private void DoPaint()
{
Paint?.Invoke(new Rect());
if (_xSyncCounter != IntPtr.Zero && _xSyncState == XSyncState.WaitPaint)
@@ -819,8 +819,8 @@ namespace Avalonia.X11
return null;
}
-
- void Cleanup()
+
+ private void Cleanup()
{
if (_rawEventGrouper != null)
{
@@ -871,7 +871,7 @@ namespace Avalonia.X11
}
}
- bool ActivateTransientChildIfNeeded()
+ private bool ActivateTransientChildIfNeeded()
{
if (_disabled)
{
@@ -923,9 +923,9 @@ namespace Avalonia.X11
Resize(size, true, PlatformResizeReason.Layout);
}
- PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * RenderScaling), (int)(size.Height * RenderScaling));
-
- void Resize(Size clientSize, bool force, PlatformResizeReason reason)
+ private PixelSize ToPixelSize(Size size) => new PixelSize((int)(size.Width * RenderScaling), (int)(size.Height * RenderScaling));
+
+ private void Resize(Size clientSize, bool force, PlatformResizeReason reason)
{
if (!force && clientSize == ClientSize)
return;
@@ -1020,7 +1020,7 @@ namespace Avalonia.X11
.OrderByDescending(x => x.Width + x.Height).FirstOrDefault();
- void SendNetWMMessage(IntPtr message_type, IntPtr l0,
+ private void SendNetWMMessage(IntPtr message_type, IntPtr l0,
IntPtr? l1 = null, IntPtr? l2 = null, IntPtr? l3 = null, IntPtr? l4 = null)
{
var xev = new XEvent
@@ -1044,7 +1044,7 @@ namespace Avalonia.X11
}
- void BeginMoveResize(NetWmMoveResize side, PointerPressedEventArgs e)
+ private void BeginMoveResize(NetWmMoveResize side, PointerPressedEventArgs e)
{
var pos = GetCursorPos(_x11);
XUngrabPointer(_x11.Display, new IntPtr(0));
@@ -1184,7 +1184,7 @@ namespace Avalonia.X11
ChangeWMAtoms(!value, _x11.Atoms._NET_WM_STATE_SKIP_TASKBAR);
}
- void ChangeWMAtoms(bool enable, params IntPtr[] atoms)
+ private void ChangeWMAtoms(bool enable, params IntPtr[] atoms)
{
if (atoms.Length != 1 && atoms.Length != 2)
throw new ArgumentException();
diff --git a/src/Avalonia.X11/XError.cs b/src/Avalonia.X11/XError.cs
index 2cc8f63c96..fbe9c34686 100644
--- a/src/Avalonia.X11/XError.cs
+++ b/src/Avalonia.X11/XError.cs
@@ -2,11 +2,12 @@ using System;
namespace Avalonia.X11
{
- static class XError
+ internal static class XError
{
private static readonly XErrorHandler s_errorHandlerDelegate = Handler;
public static XErrorEvent LastError;
- static int Handler(IntPtr display, ref XErrorEvent error)
+
+ private static int Handler(IntPtr display, ref XErrorEvent error)
{
LastError = error;
return 0;
diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs
index 7bf1df41b6..f66616f2aa 100644
--- a/src/Avalonia.X11/XI2Manager.cs
+++ b/src/Avalonia.X11/XI2Manager.cs
@@ -7,7 +7,7 @@ using static Avalonia.X11.XLib;
namespace Avalonia.X11
{
- unsafe class XI2Manager
+ internal unsafe class XI2Manager
{
private static readonly XiEventType[] DefaultEventTypes = new XiEventType[]
{
@@ -30,7 +30,7 @@ namespace Avalonia.X11
private bool _multitouch;
private Dictionary _clients = new Dictionary();
- class DeviceInfo
+ private class DeviceInfo
{
public int Id { get; }
public XIValuatorClassInfo[] Valuators { get; private set; }
@@ -67,7 +67,7 @@ namespace Avalonia.X11
}
}
- class PointerDeviceInfo : DeviceInfo
+ private class PointerDeviceInfo : DeviceInfo
{
public PointerDeviceInfo(XIDeviceInfo info) : base(info)
{
@@ -197,7 +197,7 @@ namespace Avalonia.X11
}
}
- void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
+ private void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
{
if (ev.evtype == XiEventType.XI_Leave)
{
@@ -215,7 +215,7 @@ namespace Avalonia.X11
}
}
- void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
+ private void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
{
if (ev.Type == XiEventType.XI_TouchBegin
|| ev.Type == XiEventType.XI_TouchUpdate
@@ -304,7 +304,7 @@ namespace Avalonia.X11
}
}
- unsafe class ParsedDeviceEvent
+ internal unsafe class ParsedDeviceEvent
{
public XiEventType Type { get; }
public RawInputModifiers Modifiers { get; }
@@ -367,8 +367,8 @@ namespace Avalonia.X11
Emulated = ev->flags.HasAllFlags(XiDeviceEventFlags.XIPointerEmulated);
}
}
-
- interface IXI2Client
+
+ internal interface IXI2Client
{
IInputRoot InputRoot { get; }
void ScheduleXI2Input(RawInputEventArgs args);
diff --git a/src/Avalonia.X11/XIStructs.cs b/src/Avalonia.X11/XIStructs.cs
index f4581a99ba..9a1ed01764 100644
--- a/src/Avalonia.X11/XIStructs.cs
+++ b/src/Avalonia.X11/XIStructs.cs
@@ -10,7 +10,7 @@ using Atom = System.IntPtr;
namespace Avalonia.X11
{
[StructLayout(LayoutKind.Sequential)]
- struct XIAddMasterInfo
+ internal struct XIAddMasterInfo
{
public int Type;
public IntPtr Name;
@@ -19,7 +19,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
- struct XIRemoveMasterInfo
+ internal struct XIRemoveMasterInfo
{
public int Type;
public int Deviceid;
@@ -29,7 +29,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- struct XIAttachSlaveInfo
+ internal struct XIAttachSlaveInfo
{
public int Type;
public int Deviceid;
@@ -37,14 +37,14 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- struct XIDetachSlaveInfo
+ internal struct XIDetachSlaveInfo
{
public int Type;
public int Deviceid;
};
[StructLayout(LayoutKind.Explicit)]
- struct XIAnyHierarchyChangeInfo
+ internal struct XIAnyHierarchyChangeInfo
{
[FieldOffset(0)]
public int type; /* must be first element */
@@ -59,7 +59,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- struct XIModifierState
+ internal struct XIModifierState
{
public int Base;
public int Latched;
@@ -68,14 +68,14 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIButtonState
+ internal unsafe struct XIButtonState
{
public int MaskLen;
public byte* Mask;
};
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIValuatorState
+ internal unsafe struct XIValuatorState
{
public int MaskLen;
public byte* Mask;
@@ -83,7 +83,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIEventMask
+ internal unsafe struct XIEventMask
{
public int Deviceid;
public int MaskLen;
@@ -91,14 +91,14 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- struct XIAnyClassInfo
+ internal struct XIAnyClassInfo
{
public XiDeviceClass Type;
public int Sourceid;
};
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIButtonClassInfo
+ internal unsafe struct XIButtonClassInfo
{
public int Type;
public int Sourceid;
@@ -108,7 +108,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIKeyClassInfo
+ internal unsafe struct XIKeyClassInfo
{
public int Type;
public int Sourceid;
@@ -117,7 +117,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- struct XIValuatorClassInfo
+ internal struct XIValuatorClassInfo
{
public int Type;
public int Sourceid;
@@ -132,7 +132,7 @@ namespace Avalonia.X11
/* new in XI 2.1 */
[StructLayout(LayoutKind.Sequential)]
- struct XIScrollClassInfo
+ internal struct XIScrollClassInfo
{
public int Type;
public int Sourceid;
@@ -142,14 +142,14 @@ namespace Avalonia.X11
public int Flags;
};
- enum XiScrollType
+ internal enum XiScrollType
{
Vertical = 1,
Horizontal = 2
}
[StructLayout(LayoutKind.Sequential)]
- struct XITouchClassInfo
+ internal struct XITouchClassInfo
{
public int Type;
public int Sourceid;
@@ -158,7 +158,7 @@ namespace Avalonia.X11
};
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIDeviceInfo
+ internal unsafe struct XIDeviceInfo
{
public int Deviceid;
public IntPtr Name;
@@ -169,7 +169,7 @@ namespace Avalonia.X11
public XIAnyClassInfo** Classes;
}
- enum XiDeviceType
+ internal enum XiDeviceType
{
XIMasterPointer = 1,
XIMasterKeyboard = 2,
@@ -178,13 +178,13 @@ namespace Avalonia.X11
XIFloatingSlave = 5
}
- enum XiPredefinedDeviceId : int
+ internal enum XiPredefinedDeviceId : int
{
XIAllDevices = 0,
XIAllMasterDevices = 1
}
- enum XiDeviceClass
+ internal enum XiDeviceClass
{
XIKeyClass = 0,
XIButtonClass = 1,
@@ -194,7 +194,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIDeviceChangedEvent
+ internal unsafe struct XIDeviceChangedEvent
{
public int Type; /* GenericEvent */
public UIntPtr Serial; /* # of last request processed by server */
@@ -211,7 +211,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
- struct XIDeviceEvent
+ internal struct XIDeviceEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
@@ -238,7 +238,7 @@ namespace Avalonia.X11
}
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIEnterLeaveEvent
+ internal unsafe struct XIEnterLeaveEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
@@ -266,14 +266,14 @@ namespace Avalonia.X11
}
[Flags]
- public enum XiDeviceEventFlags : int
+ internal enum XiDeviceEventFlags : int
{
None = 0,
XIPointerEmulated = (1 << 16)
}
[StructLayout(LayoutKind.Sequential)]
- unsafe struct XIEvent
+ internal unsafe struct XIEvent
{
public int type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
@@ -284,7 +284,7 @@ namespace Avalonia.X11
public IntPtr time;
}
- enum XiEventType
+ internal enum XiEventType
{
XI_DeviceChanged = 1,
XI_KeyPress = 2,
@@ -315,7 +315,7 @@ namespace Avalonia.X11
XI_LASTEVENT = XI_BarrierLeave,
}
- enum XiEnterLeaveDetail
+ internal enum XiEnterLeaveDetail
{
XINotifyAncestor = 0,
XINotifyVirtual = 1,
diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs
index 753d5f530c..7a43cd378b 100644
--- a/src/Avalonia.X11/XLib.cs
+++ b/src/Avalonia.X11/XLib.cs
@@ -16,11 +16,11 @@ namespace Avalonia.X11
{
internal unsafe static class XLib
{
- const string libX11 = "libX11.so.6";
- const string libX11Randr = "libXrandr.so.2";
- const string libX11Ext = "libXext.so.6";
- const string libXInput = "libXi.so.6";
- const string libXCursor = "libXcursor.so.1";
+ private const string libX11 = "libX11.so.6";
+ private const string libX11Randr = "libXrandr.so.2";
+ private const string libX11Ext = "libXext.so.6";
+ private const string libXInput = "libXi.so.6";
+ private const string libXCursor = "libXcursor.so.1";
[DllImport(libX11)]
public static extern IntPtr XOpenDisplay(IntPtr display);
diff --git a/src/Browser/Avalonia.Browser.Blazor/Avalonia.Browser.Blazor.csproj b/src/Browser/Avalonia.Browser.Blazor/Avalonia.Browser.Blazor.csproj
index a9cad0538f..9017ce1546 100644
--- a/src/Browser/Avalonia.Browser.Blazor/Avalonia.Browser.Blazor.csproj
+++ b/src/Browser/Avalonia.Browser.Blazor/Avalonia.Browser.Blazor.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Browser/Avalonia.Browser/AvaloniaView.cs b/src/Browser/Avalonia.Browser/AvaloniaView.cs
index 294216ee03..3f4aa0d0ba 100644
--- a/src/Browser/Avalonia.Browser/AvaloniaView.cs
+++ b/src/Browser/Avalonia.Browser/AvaloniaView.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices.JavaScript;
using Avalonia.Browser.Interop;
@@ -15,6 +16,7 @@ using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
using SkiaSharp;
+using static System.Runtime.CompilerServices.RuntimeHelpers;
namespace Avalonia.Browser
{
@@ -94,6 +96,7 @@ namespace Avalonia.Browser
InputHelper.SubscribeTextEvents(
_inputElement,
+ OnBeforeInput,
OnTextInput,
OnCompositionStart,
OnCompositionUpdate,
@@ -316,6 +319,30 @@ namespace Avalonia.Browser
return _topLevelImpl.RawTextEvent(data);
}
+ private bool OnBeforeInput(JSObject arg, int start, int end)
+ {
+ var type = arg.GetPropertyAsString("inputType");
+ if (type != "deleteByComposition")
+ {
+ if (type == "deleteContentBackward")
+ {
+ start = _inputElement.GetPropertyAsInt32("selectionStart");
+ end = _inputElement.GetPropertyAsInt32("selectionEnd");
+ }
+ else
+ {
+ start = -1;
+ end = -1;
+ }
+ }
+
+ if(start != -1 && end != -1 && _client != null)
+ {
+ _client.SelectInSurroundingText(start, end);
+ }
+ return false;
+ }
+
private bool OnCompositionStart (JSObject args)
{
if (_client == null)
diff --git a/src/Browser/Avalonia.Browser/ClipboardImpl.cs b/src/Browser/Avalonia.Browser/ClipboardImpl.cs
index f24d607dae..b94fe2df9e 100644
--- a/src/Browser/Avalonia.Browser/ClipboardImpl.cs
+++ b/src/Browser/Avalonia.Browser/ClipboardImpl.cs
@@ -8,14 +8,14 @@ namespace Avalonia.Browser
{
internal class ClipboardImpl : IClipboard
{
- public Task GetTextAsync()
+ public Task GetTextAsync()
{
- return InputHelper.ReadClipboardTextAsync();
+ return InputHelper.ReadClipboardTextAsync()!;
}
- public Task SetTextAsync(string text)
+ public Task SetTextAsync(string? text)
{
- return InputHelper.WriteClipboardTextAsync(text);
+ return InputHelper.WriteClipboardTextAsync(text ?? string.Empty);
}
public async Task ClearAsync() => await SetTextAsync("");
@@ -24,6 +24,6 @@ namespace Avalonia.Browser
public Task GetFormatsAsync() => Task.FromResult(Array.Empty());
- public Task GetDataAsync(string format) => Task.FromResult(new());
+ public Task GetDataAsync(string format) => Task.FromResult(new());
}
}
diff --git a/src/Browser/Avalonia.Browser/Interop/InputHelper.cs b/src/Browser/Avalonia.Browser/Interop/InputHelper.cs
index 7a010dc782..a816e39da8 100644
--- a/src/Browser/Avalonia.Browser/Interop/InputHelper.cs
+++ b/src/Browser/Avalonia.Browser/Interop/InputHelper.cs
@@ -18,6 +18,8 @@ internal static partial class InputHelper
[JSImport("InputHelper.subscribeTextEvents", AvaloniaModule.MainModuleName)]
public static partial void SubscribeTextEvents(
JSObject htmlElement,
+ [JSMarshalAs>]
+ Func onBeforeInput,
[JSMarshalAs>]
Func onInput,
[JSMarshalAs>]
diff --git a/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs b/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
index 4d3d8dcd97..3c04935f0d 100644
--- a/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
+++ b/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
@@ -6,7 +6,7 @@ using Avalonia.Reactive;
namespace Avalonia.Browser.Skia
{
- public class BrowserSkiaGpu : ISkiaGpu
+ internal class BrowserSkiaGpu : ISkiaGpu
{
public ISkiaGpuRenderTarget? TryCreateRenderTarget(IEnumerable surfaces)
{
diff --git a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts
index 83e8ee7f1c..0f0e5eb512 100644
--- a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts
+++ b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts
@@ -47,6 +47,7 @@ export class InputHelper {
public static subscribeTextEvents(
element: HTMLInputElement,
+ beforeInputCallback: (args: InputEvent, start: number, end: number) => boolean,
inputCallback: (type: string, data: string | null) => boolean,
compositionStartCallback: (args: CompositionEvent) => boolean,
compositionUpdateCallback: (args: CompositionEvent) => boolean,
@@ -68,6 +69,25 @@ export class InputHelper {
};
element.addEventListener("compositionstart", compositionStartHandler);
+ const beforeInputHandler = (args: InputEvent) => {
+ const ranges = args.getTargetRanges();
+ let start = -1;
+ let end = -1;
+ if (ranges.length > 0) {
+ start = ranges[0].startOffset;
+ end = ranges[0].endOffset;
+ }
+
+ if (args.inputType === "insertCompositionText") {
+ start = 2;
+ end = start + 2;
+ }
+ if (beforeInputCallback(args, start, end)) {
+ args.preventDefault();
+ }
+ };
+ element.addEventListener("beforeinput", beforeInputHandler);
+
const compositionUpdateHandler = (args: CompositionEvent) => {
if (compositionUpdateCallback(args)) {
args.preventDefault();
diff --git a/src/Shared/RawEventGrouping.cs b/src/Shared/RawEventGrouping.cs
index 966744888c..c4772db820 100644
--- a/src/Shared/RawEventGrouping.cs
+++ b/src/Shared/RawEventGrouping.cs
@@ -17,8 +17,8 @@ internal class RawEventGrouper : IDisposable
private readonly Action _eventCallback;
private readonly Queue _inputQueue = new();
private readonly Action _dispatchFromQueue;
- readonly Dictionary _lastTouchPoints = new();
- RawInputEventArgs? _lastEvent;
+ private readonly Dictionary _lastTouchPoints = new();
+ private RawInputEventArgs? _lastEvent;
public RawEventGrouper(Action eventCallback)
{
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index dcb20d2a44..ba646c64ee 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -208,6 +208,12 @@ namespace Avalonia.Skia
public void DrawLine(IPen pen, Point p1, Point p2)
{
CheckLease();
+
+ if (pen is null)
+ {
+ return;
+ }
+
using (var paint = CreatePaint(_strokePaint, pen, new Size(Math.Abs(p2.X - p1.X), Math.Abs(p2.Y - p1.Y))))
{
if (paint.Paint is object)
@@ -495,6 +501,12 @@ namespace Avalonia.Skia
public void DrawGlyphRun(IBrush foreground, IRef glyphRun)
{
CheckLease();
+
+ if (foreground is null)
+ {
+ return;
+ }
+
using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Item.Size))
{
var glyphRunImpl = (GlyphRunImpl)glyphRun.Item;
diff --git a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
index cc669f9aaa..cfd6fc12f8 100644
--- a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
+++ b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
-using Avalonia.Metadata;
using Avalonia.Platform;
using SkiaSharp;
#nullable enable
namespace Avalonia.Skia
{
- ///
- [Unstable]
- public class GlyphRunImpl : IGlyphRunImpl
+ internal class GlyphRunImpl : IGlyphRunImpl
{
public GlyphRunImpl(SKTextBlob textBlob, Size size, Point baselineOrigin)
{
diff --git a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
index 71bdc1bd6b..a8dd289a13 100644
--- a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
+++ b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
@@ -1,14 +1,12 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Media;
-using Avalonia.Metadata;
using HarfBuzzSharp;
using SkiaSharp;
namespace Avalonia.Skia
{
- [Unstable]
- public class GlyphTypefaceImpl : IGlyphTypeface
+ internal class GlyphTypefaceImpl : IGlyphTypeface
{
private bool _isDisposed;
diff --git a/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs b/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs
index 1f3f20730f..73f58e66bc 100644
--- a/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs
+++ b/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs
@@ -4,7 +4,7 @@ using SkiaSharp;
namespace Avalonia.Skia
{
- public class SKTypefaceCollection
+ internal class SKTypefaceCollection
{
private readonly ConcurrentDictionary _typefaces =
new ConcurrentDictionary();
diff --git a/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs b/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs
index f7a86c11ff..b49efd59cd 100644
--- a/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs
+++ b/src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs
@@ -7,7 +7,7 @@ using SkiaSharp;
namespace Avalonia.Skia
{
- public static class SKTypefaceCollectionCache
+ internal static class SKTypefaceCollectionCache
{
private static readonly ConcurrentDictionary s_cachedCollections;
diff --git a/src/Skia/Avalonia.Skia/readme.md b/src/Skia/Avalonia.Skia/readme.md
deleted file mode 100644
index 7ed92c5453..0000000000
--- a/src/Skia/Avalonia.Skia/readme.md
+++ /dev/null
@@ -1,22 +0,0 @@
-DrawingContextImpl
-- Alpha support missing as SkiaSharp does not expose this
-- Gradient Shader caching?
-- Pen Dash styles
-
-Formatted Text Rendering
-- Minor polish
-
-Linux
-- Need gpu platform implementation
-
-macOS
-- Need gpu platform implementation
-
-Android
-- Not tested at all yet
-
-iOS
-- Not tested at all yet
-
-General
-- Get Skia Unit Tests passing (most of the issues are related to antialiasing)
\ No newline at end of file
diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
index 32bcdba758..3c2d7b3322 100644
--- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
+++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
@@ -5,11 +5,6 @@
Avalonia.Direct2D1
true
-
-
- UnmanagedMethods.cs
-
-
@@ -22,6 +17,7 @@
+
diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
index 99c01dd111..57379d1878 100644
--- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
+++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
@@ -27,7 +27,7 @@ namespace Avalonia
namespace Avalonia.Direct2D1
{
- public class Direct2D1Platform : IPlatformRenderInterface
+ internal class Direct2D1Platform : IPlatformRenderInterface
{
private static readonly Direct2D1Platform s_instance = new Direct2D1Platform();
diff --git a/src/Windows/Avalonia.Direct2D1/Disposable.cs b/src/Windows/Avalonia.Direct2D1/Disposable.cs
deleted file mode 100644
index 63dfeb2e0b..0000000000
--- a/src/Windows/Avalonia.Direct2D1/Disposable.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-
-namespace Avalonia.Direct2D1
-{
- public class Disposable : IDisposable where T : IDisposable
- {
- private readonly IDisposable _extra;
-
- public Disposable(T inner)
- {
- Inner = inner;
- }
-
- public Disposable(T inner, IDisposable extra)
- {
- Inner = inner;
- _extra = extra;
- }
-
- public T Inner { get; }
-
- public static implicit operator T(Disposable i)
- {
- return i.Inner;
- }
-
- public void Dispose()
- {
- Inner.Dispose();
- _extra?.Dispose();
- }
- }
-}
diff --git a/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs b/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs
index a15bc0056a..504f4981f7 100644
--- a/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs
+++ b/src/Windows/Avalonia.Direct2D1/ILayerFactory.cs
@@ -2,7 +2,7 @@
namespace Avalonia.Direct2D1
{
- public interface ILayerFactory
+ internal interface ILayerFactory
{
IDrawingContextLayerImpl CreateLayer(Size size);
}
diff --git a/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs
index 602ea9b568..9fac86e0d2 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs
@@ -1,10 +1,8 @@
using System;
-using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public abstract class BrushImpl : IDisposable
+ internal abstract class BrushImpl : IDisposable
{
public SharpDX.Direct2D1.Brush PlatformBrush { get; set; }
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs
index c144e12aea..42cc969b66 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileEnumerator.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Direct2D1.Media
///
/// Resource FontFileEnumerator.
///
- public class DWriteResourceFontFileEnumerator : CallbackBase, FontFileEnumerator
+ internal class DWriteResourceFontFileEnumerator : CallbackBase, FontFileEnumerator
{
private readonly Factory _factory;
private readonly FontFileLoader _loader;
@@ -64,4 +64,4 @@ namespace Avalonia.Direct2D1.Media
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs
index 1802ef4d21..bd2e9ab8c3 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DWriteResourceFontFileStream.cs
@@ -7,7 +7,7 @@ namespace Avalonia.Direct2D1.Media
///
/// This FontFileStream implementation is reading data from a .
///
- public class DWriteResourceFontFileStream : CallbackBase, FontFileStream
+ internal class DWriteResourceFontFileStream : CallbackBase, FontFileStream
{
private readonly DataStream _stream;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
index d5d6cd8c29..3506abc63b 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
@@ -11,15 +11,13 @@ using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using BitmapInterpolationMode = Avalonia.Media.Imaging.BitmapInterpolationMode;
-using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
///
/// Draws using Direct2D1.
///
- [Unstable]
- public class DrawingContextImpl : IDrawingContextImpl
+ internal class DrawingContextImpl : IDrawingContextImpl
{
private readonly IVisualBrushRenderer _visualBrushRenderer;
private readonly ILayerFactory _layerFactory;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs
index c84c14daac..9a93d1afd3 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs
@@ -1,5 +1,4 @@
using Avalonia.Logging;
-using Avalonia.Metadata;
using Avalonia.Platform;
using SharpDX.Direct2D1;
@@ -8,8 +7,7 @@ namespace Avalonia.Direct2D1.Media
///
/// The platform-specific interface for .
///
- [Unstable]
- public abstract class GeometryImpl : IGeometryImpl
+ internal abstract class GeometryImpl : IGeometryImpl
{
private const float ContourApproximation = 0.0001f;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs
index 24b8fc04b3..446db47d92 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/GlyphRunImpl.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using Avalonia.Platform;
using SharpDX.DirectWrite;
@@ -25,8 +26,6 @@ namespace Avalonia.Direct2D1.Media
}
public IReadOnlyList GetIntersections(float lowerBound, float upperBound)
- {
- return null;
- }
+ => Array.Empty();
}
}
diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
index 705c715455..e4988322e7 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
@@ -1,6 +1,5 @@
using System;
using Avalonia.Media;
-using Avalonia.Metadata;
using HarfBuzzSharp;
using SharpDX.DirectWrite;
using FontMetrics = Avalonia.Media.FontMetrics;
@@ -9,8 +8,7 @@ using GlyphMetrics = Avalonia.Media.GlyphMetrics;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class GlyphTypefaceImpl : IGlyphTypeface
+ internal class GlyphTypefaceImpl : IGlyphTypeface
{
private bool _isDisposed;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
index 17dc359ed7..829b887d9d 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
@@ -1,13 +1,11 @@
using Avalonia.Media;
-using Avalonia.Metadata;
using Avalonia.Rendering.Utilities;
using Avalonia.Utilities;
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public sealed class ImageBrushImpl : BrushImpl
+ internal sealed class ImageBrushImpl : BrushImpl
{
private readonly OptionalDispose _bitmap;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs
index 059105c112..740efe833f 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs
@@ -1,13 +1,11 @@
using System;
using System.IO;
-using Avalonia.Metadata;
using Avalonia.Platform;
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public abstract class BitmapImpl : IBitmapImpl, IDisposable
+ internal abstract class BitmapImpl : IBitmapImpl, IDisposable
{
public abstract Vector Dpi { get; }
public abstract PixelSize PixelSize { get; }
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs
index a321b225a0..940d4673b5 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs
@@ -1,6 +1,5 @@
using System;
using System.IO;
-using Avalonia.Metadata;
using SharpDX.WIC;
using Bitmap = SharpDX.Direct2D1.Bitmap;
@@ -9,8 +8,7 @@ namespace Avalonia.Direct2D1.Media
///
/// A Direct2D Bitmap implementation that uses a GPU memory bitmap as its image.
///
- [Unstable]
- public class D2DBitmapImpl : BitmapImpl
+ internal class D2DBitmapImpl : BitmapImpl
{
private readonly Bitmap _direct2DBitmap;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
index 84f11acdd7..2dbc1d67d1 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
@@ -1,6 +1,5 @@
using System;
using System.IO;
-using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Utilities;
@@ -10,8 +9,7 @@ using D2DBitmap = SharpDX.Direct2D1.Bitmap;
namespace Avalonia.Direct2D1.Media.Imaging
{
- [Unstable]
- public class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IDrawingContextLayerImpl, ILayerFactory
+ internal class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IDrawingContextLayerImpl, ILayerFactory
{
private readonly BitmapRenderTarget _renderTarget;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
index 72a48aca0c..533a29f68c 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs
@@ -6,7 +6,6 @@ using SharpDX.WIC;
using APixelFormat = Avalonia.Platform.PixelFormat;
using AlphaFormat = Avalonia.Platform.AlphaFormat;
using D2DBitmap = SharpDX.Direct2D1.Bitmap;
-using Avalonia.Metadata;
using Avalonia.Platform;
using PixelFormat = SharpDX.WIC.PixelFormat;
@@ -15,8 +14,7 @@ namespace Avalonia.Direct2D1.Media
///
/// A WIC implementation of a .
///
- [Unstable]
- public class WicBitmapImpl : BitmapImpl, IReadableBitmapImpl
+ internal class WicBitmapImpl : BitmapImpl, IReadableBitmapImpl
{
private readonly BitmapDecoder _decoder;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs
index 9f0d48dbc7..d6b1e618e5 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs
@@ -1,13 +1,11 @@
using System;
-using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Rendering;
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class WicRenderTargetBitmapImpl : WicBitmapImpl, IDrawingContextLayerImpl
+ internal class WicRenderTargetBitmapImpl : WicBitmapImpl, IDrawingContextLayerImpl
{
private readonly WicRenderTarget _renderTarget;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs
index 5f4c033cf7..0bdf901613 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs
@@ -6,7 +6,7 @@ using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Direct2D1.Media.Imaging
{
- class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl
+ internal class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl
{
public WriteableWicBitmapImpl(Stream stream, int decodeSize, bool horizontal,
Avalonia.Media.Imaging.BitmapInterpolationMode interpolationMode)
diff --git a/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs
index 5dfe683f59..5de988c30e 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs
@@ -1,11 +1,9 @@
using System.Linq;
using Avalonia.Media;
-using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class LinearGradientBrushImpl : BrushImpl
+ internal class LinearGradientBrushImpl : BrushImpl
{
public LinearGradientBrushImpl(
ILinearGradientBrush brush,
diff --git a/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs
index 0069e47001..bbb34651c5 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs
@@ -1,11 +1,9 @@
using System.Linq;
using Avalonia.Media;
-using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class RadialGradientBrushImpl : BrushImpl
+ internal class RadialGradientBrushImpl : BrushImpl
{
public RadialGradientBrushImpl(
IRadialGradientBrush brush,
diff --git a/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs
index b85494e2c1..bf974798a2 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs
@@ -1,10 +1,8 @@
using Avalonia.Media;
-using Avalonia.Metadata;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class SolidColorBrushImpl : BrushImpl
+ internal class SolidColorBrushImpl : BrushImpl
{
public SolidColorBrushImpl(ISolidColorBrush brush, SharpDX.Direct2D1.RenderTarget target)
{
diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs
index ec8f82556d..5ffe331ca2 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs
@@ -9,8 +9,7 @@ using SweepDirection = SharpDX.Direct2D1.SweepDirection;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class StreamGeometryContextImpl : IStreamGeometryContextImpl
+ internal class StreamGeometryContextImpl : IStreamGeometryContextImpl
{
private readonly GeometrySink _sink;
diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs
index e1677c0ed1..684460916e 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs
@@ -1,4 +1,3 @@
-using Avalonia.Metadata;
using Avalonia.Platform;
using SharpDX.Direct2D1;
@@ -7,8 +6,7 @@ namespace Avalonia.Direct2D1.Media
///
/// A Direct2D implementation of a .
///
- [Unstable]
- public class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl
+ internal class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl
{
///
/// Initializes a new instance of the class.
diff --git a/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs
index 3ecdb49e46..64aaea6f0a 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs
@@ -1,11 +1,9 @@
-using Avalonia.Metadata;
using Avalonia.Platform;
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
- [Unstable]
- public class TransformedGeometryImpl : GeometryImpl, ITransformedGeometryImpl
+ internal class TransformedGeometryImpl : GeometryImpl, ITransformedGeometryImpl
{
///
/// Initializes a new instance of the class.
diff --git a/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs b/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs
index 1cdf7661df..d526da2b5d 100644
--- a/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs
+++ b/src/Windows/Avalonia.Direct2D1/OptionalDispose.cs
@@ -2,7 +2,7 @@
namespace Avalonia.Direct2D1
{
- public readonly record struct OptionalDispose : IDisposable where T : IDisposable
+ internal readonly record struct OptionalDispose : IDisposable where T : IDisposable
{
private readonly bool _dispose;
diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
index 669e139d8f..d042d56160 100644
--- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
+++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs
@@ -8,7 +8,7 @@ using DWrite = SharpDX.DirectWrite;
namespace Avalonia.Direct2D1
{
- public static class PrimitiveExtensions
+ internal static class PrimitiveExtensions
{
///
/// The value for which all absolute numbers smaller than are considered equal to zero.
diff --git a/src/Windows/Avalonia.Direct2D1/RenderTarget.cs b/src/Windows/Avalonia.Direct2D1/RenderTarget.cs
index 1a749c1a7f..8d5062336c 100644
--- a/src/Windows/Avalonia.Direct2D1/RenderTarget.cs
+++ b/src/Windows/Avalonia.Direct2D1/RenderTarget.cs
@@ -5,7 +5,7 @@ using Avalonia.Rendering;
namespace Avalonia.Direct2D1
{
- public class RenderTarget : IRenderTarget, ILayerFactory
+ internal class RenderTarget : IRenderTarget, ILayerFactory
{
///
/// The render target.
diff --git a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs
index 4935e3db48..531c4119af 100644
--- a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs
+++ b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs
@@ -8,7 +8,7 @@ using SharpDX.DXGI;
namespace Avalonia.Direct2D1
{
- public abstract class SwapChainRenderTarget : IRenderTarget, ILayerFactory
+ internal abstract class SwapChainRenderTarget : IRenderTarget, ILayerFactory
{
private Size2 _savedSize;
private Size2F _savedDpi;
diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
index 2d0f351d58..13eae1992c 100644
--- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
+++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
@@ -45,13 +45,6 @@ namespace Avalonia.Win32.Interop.Wpf
((FrameworkElement)PlatformImpl)?.InvalidateMeasure();
}
- protected override void HandleResized(Size clientSize, PlatformResizeReason reason)
- {
- ClientSize = clientSize;
- LayoutManager.ExecuteLayoutPass();
- Renderer?.Resized(clientSize);
- }
-
public Size AllocatedSize => ClientSize;
}
@@ -223,7 +216,7 @@ namespace Avalonia.Win32.Interop.Wpf
(Key)e.Key,
GetModifiers(null)));
- protected override void OnTextInput(TextCompositionEventArgs e)
+ protected override void OnTextInput(TextCompositionEventArgs e)
=> _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, e.Text));
void ITopLevelImpl.SetCursor(ICursorImpl cursor)
diff --git a/src/Windows/Avalonia.Win32/AngleOptions.cs b/src/Windows/Avalonia.Win32/AngleOptions.cs
index 076ddd2a5d..94c67120df 100644
--- a/src/Windows/Avalonia.Win32/AngleOptions.cs
+++ b/src/Windows/Avalonia.Win32/AngleOptions.cs
@@ -17,6 +17,6 @@ namespace Avalonia.Win32
new GlVersion(GlProfileType.OpenGLES, 2, 0)
};
- public IList AllowedPlatformApis { get; set; } = null;
+ public IList? AllowedPlatformApis { get; set; } = null;
}
}
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs
index 5f3f863493..aaad9cb3ba 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs
@@ -2,8 +2,6 @@
using Avalonia.Automation.Provider;
using UIA = Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
internal partial class AutomationNode : UIA.IExpandCollapseProvider
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs
index b91cb76888..518c945aa9 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs
@@ -1,8 +1,6 @@
using Avalonia.Automation.Provider;
using UIA = Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
internal partial class AutomationNode : UIA.IRangeValueProvider
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs
index 4f2d4ae269..0248a8d6a7 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs
@@ -1,8 +1,6 @@
using Avalonia.Automation.Provider;
using UIA = Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
internal partial class AutomationNode : UIA.IScrollProvider, UIA.IScrollItemProvider
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs
index 61903ab5b0..3751bb6476 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs
@@ -1,12 +1,9 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using UIA = Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
internal partial class AutomationNode : UIA.ISelectionProvider, UIA.ISelectionItemProvider
@@ -27,8 +24,7 @@ namespace Avalonia.Win32.Automation
UIA.IRawElementProviderSimple[] UIA.ISelectionProvider.GetSelection()
{
var peers = InvokeSync>(x => x.GetSelection());
- return peers?.Select(x => (UIA.IRawElementProviderSimple)GetOrCreate(x)!).ToArray() ??
- Array.Empty();
+ return peers.Select(x => (UIA.IRawElementProviderSimple)GetOrCreate(x)).ToArray();
}
void UIA.ISelectionItemProvider.AddToSelection() => InvokeSync(x => x.AddToSelection());
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs
index 38f4d80946..08f4b62d83 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs
@@ -1,8 +1,6 @@
using Avalonia.Automation.Provider;
using UIA = Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
internal partial class AutomationNode : UIA.IToggleProvider
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs
index 34f5dfe0b9..204e159049 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs
@@ -2,8 +2,6 @@
using Avalonia.Automation.Provider;
using UIA = Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
internal partial class AutomationNode : UIA.IValueProvider
diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs
index 29ab2cea3a..5ca4ef63bf 100644
--- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs
+++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs
@@ -12,8 +12,6 @@ using Avalonia.Threading;
using Avalonia.Win32.Interop.Automation;
using AAP = Avalonia.Automation.Provider;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
[ComVisible(true)]
@@ -25,7 +23,7 @@ namespace Avalonia.Win32.Automation
IRawElementProviderAdviseEvents,
IInvokeProvider
{
- private static Dictionary s_propertyMap = new Dictionary()
+ private static Dictionary s_propertyMap = new()
{
{ AutomationElementIdentifiers.BoundingRectangleProperty, UiaPropertyId.BoundingRectangle },
{ AutomationElementIdentifiers.ClassNameProperty, UiaPropertyId.ClassName },
@@ -46,8 +44,7 @@ namespace Avalonia.Win32.Automation
{ SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection },
};
- private static ConditionalWeakTable s_nodes =
- new ConditionalWeakTable();
+ private static ConditionalWeakTable s_nodes = new();
private readonly int[] _runtimeId;
private int _raiseFocusChanged;
@@ -174,11 +171,12 @@ namespace Avalonia.Win32.Automation
NavigateDirection.LastChild => GetOrCreate(Peer.GetChildren().LastOrDefault()),
_ => null,
};
- }) as IRawElementProviderFragment;
+ });
}
public void SetFocus() => InvokeSync(() => Peer.SetFocus());
+ [return: NotNullIfNotNull(nameof(peer))]
public static AutomationNode? GetOrCreate(AutomationPeer? peer)
{
return peer is null ? null : s_nodes.GetValue(peer, Create);
diff --git a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs
index b732c4169f..3d8b4995ad 100644
--- a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs
+++ b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs
@@ -6,8 +6,6 @@ using Avalonia.Automation.Provider;
using Avalonia.Platform;
using Avalonia.Win32.Interop.Automation;
-#nullable enable
-
namespace Avalonia.Win32.Automation
{
[RequiresUnreferencedCode("Requires .NET COM interop")]
diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
index a24fe31df8..92ebbd57b8 100644
--- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
+++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
@@ -6,7 +6,6 @@
-
@@ -16,7 +15,8 @@
-
+
+
@@ -29,5 +29,6 @@
+
diff --git a/src/Windows/Avalonia.Win32/ClipboardFormats.cs b/src/Windows/Avalonia.Win32/ClipboardFormats.cs
index 7bd7765f8c..5fc4f21b2e 100644
--- a/src/Windows/Avalonia.Win32/ClipboardFormats.cs
+++ b/src/Windows/Avalonia.Win32/ClipboardFormats.cs
@@ -8,15 +8,15 @@ using Avalonia.Utilities;
namespace Avalonia.Win32
{
- static class ClipboardFormats
+ internal static class ClipboardFormats
{
private const int MAX_FORMAT_NAME_LENGTH = 260;
- class ClipboardFormat
+ private class ClipboardFormat
{
- public ushort Format { get; private set; }
- public string Name { get; private set; }
- public ushort[] Synthesized { get; private set; }
+ public ushort Format { get; }
+ public string Name { get; }
+ public ushort[] Synthesized { get; }
public ClipboardFormat(string name, ushort format, params ushort[] synthesized)
{
@@ -26,14 +26,14 @@ namespace Avalonia.Win32
}
}
- private static readonly List FormatList = new List()
+ private static readonly List s_formatList = new()
{
new ClipboardFormat(DataFormats.Text, (ushort)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, (ushort)UnmanagedMethods.ClipboardFormat.CF_TEXT),
new ClipboardFormat(DataFormats.FileNames, (ushort)UnmanagedMethods.ClipboardFormat.CF_HDROP),
};
- private static string QueryFormatName(ushort format)
+ private static string? QueryFormatName(ushort format)
{
var sb = StringBuilderCache.Acquire(MAX_FORMAT_NAME_LENGTH);
if (UnmanagedMethods.GetClipboardFormatName(format, sb, sb.Capacity) > 0)
@@ -43,16 +43,16 @@ namespace Avalonia.Win32
public static string GetFormat(ushort format)
{
- lock (FormatList)
+ lock (s_formatList)
{
- var pd = FormatList.FirstOrDefault(f => f.Format == format || Array.IndexOf(f.Synthesized, format) >= 0);
+ var pd = s_formatList.FirstOrDefault(f => f.Format == format || Array.IndexOf(f.Synthesized, format) >= 0);
if (pd == null)
{
- string name = QueryFormatName(format);
+ string? name = QueryFormatName(format);
if (string.IsNullOrEmpty(name))
- name = string.Format("Unknown_Format_{0}", format);
+ name = $"Unknown_Format_{format}";
pd = new ClipboardFormat(name, format);
- FormatList.Add(pd);
+ s_formatList.Add(pd);
}
return pd.Name;
}
@@ -60,16 +60,16 @@ namespace Avalonia.Win32
public static ushort GetFormat(string format)
{
- lock (FormatList)
+ lock (s_formatList)
{
- var pd = FormatList.FirstOrDefault(f => StringComparer.OrdinalIgnoreCase.Equals(f.Name, format));
+ var pd = s_formatList.FirstOrDefault(f => StringComparer.OrdinalIgnoreCase.Equals(f.Name, format));
if (pd == null)
{
int id = UnmanagedMethods.RegisterClipboardFormat(format);
if (id == 0)
throw new Win32Exception();
pd = new ClipboardFormat(format, (ushort)id);
- FormatList.Add(pd);
+ s_formatList.Add(pd);
}
return pd.Format;
}
diff --git a/src/Windows/Avalonia.Win32/ClipboardImpl.cs b/src/Windows/Avalonia.Win32/ClipboardImpl.cs
index 82fd1109f4..1a760aeab8 100644
--- a/src/Windows/Avalonia.Win32/ClipboardImpl.cs
+++ b/src/Windows/Avalonia.Win32/ClipboardImpl.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Win32
return Disposable.Create(() => UnmanagedMethods.CloseClipboard());
}
- public async Task GetTextAsync()
+ public async Task GetTextAsync()
{
using(await OpenClipboard())
{
@@ -52,19 +52,17 @@ namespace Avalonia.Win32
}
}
- public async Task SetTextAsync(string text)
+ public async Task SetTextAsync(string? text)
{
- if (text == null)
- {
- throw new ArgumentNullException(nameof(text));
- }
-
using(await OpenClipboard())
{
UnmanagedMethods.EmptyClipboard();
- var hGlobal = Marshal.StringToHGlobalUni(text);
- UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal);
+ if (text is not null)
+ {
+ var hGlobal = Marshal.StringToHGlobalUni(text);
+ UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal);
+ }
}
}
@@ -121,7 +119,7 @@ namespace Avalonia.Win32
}
}
- public async Task GetDataAsync(string format)
+ public async Task GetDataAsync(string format)
{
Dispatcher.UIThread.VerifyAccess();
var i = OleRetryCount;
diff --git a/src/Windows/Avalonia.Win32/DataObject.cs b/src/Windows/Avalonia.Win32/DataObject.cs
index 7d22e57a30..272300cbf3 100644
--- a/src/Windows/Avalonia.Win32/DataObject.cs
+++ b/src/Windows/Avalonia.Win32/DataObject.cs
@@ -22,9 +22,9 @@ namespace Avalonia.Win32
// Compatibility with WinForms + WPF...
internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray();
- class FormatEnumerator : CallbackBase, Win32Com.IEnumFORMATETC
+ private class FormatEnumerator : CallbackBase, Win32Com.IEnumFORMATETC
{
- private FORMATETC[] _formats;
+ private readonly FORMATETC[] _formats;
private uint _current;
private FormatEnumerator(FORMATETC[] formats, uint current)
@@ -105,16 +105,12 @@ namespace Avalonia.Win32
public DataObject(IDataObject wrapped)
{
- if (wrapped == null)
+ _wrapped = wrapped switch
{
- throw new ArgumentNullException(nameof(wrapped));
- }
- if (_wrapped is DataObject || _wrapped is OleDataObject)
- {
- throw new InvalidOperationException();
- }
-
- _wrapped = wrapped;
+ null => throw new ArgumentNullException(nameof(wrapped)),
+ DataObject or OleDataObject => throw new ArgumentException($"Cannot wrap a {wrapped.GetType()}"),
+ _ => wrapped
+ };
}
#region IDataObject
@@ -128,17 +124,17 @@ namespace Avalonia.Win32
return _wrapped.GetDataFormats();
}
- IEnumerable IDataObject.GetFileNames()
+ IEnumerable? IDataObject.GetFileNames()
{
return _wrapped.GetFileNames();
}
- string IDataObject.GetText()
+ string? IDataObject.GetText()
{
return _wrapped.GetText();
}
- object IDataObject.Get(string dataFormat)
+ object? IDataObject.Get(string dataFormat)
{
return _wrapped.Get(dataFormat);
}
@@ -182,9 +178,6 @@ namespace Avalonia.Win32
if (_wrapped is Win32Com.IDataObject ole)
return ole.GetCanonicalFormatEtc(formatIn);
- var formatOut = new FORMATETC();
- formatOut.ptd = IntPtr.Zero;
-
throw new COMException(nameof(UnmanagedMethods.HRESULT.E_NOTIMPL), unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL));
}
@@ -264,9 +257,9 @@ namespace Avalonia.Win32
private uint WriteDataToHGlobal(string dataFormat, ref IntPtr hGlobal)
{
- object data = _wrapped.Get(dataFormat);
+ object data = _wrapped.Get(dataFormat)!;
if (dataFormat == DataFormats.Text || data is string)
- return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data));
+ return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data) ?? string.Empty);
if (dataFormat == DataFormats.FileNames && data is IEnumerable files)
return WriteFileListToHGlobal(ref hGlobal, files);
if (data is Stream stream)
@@ -286,7 +279,7 @@ namespace Avalonia.Win32
}
if (data is IEnumerable bytes)
{
- var byteArr = bytes is byte[] ? (byte[])bytes : bytes.ToArray();
+ var byteArr = bytes as byte[] ?? bytes.ToArray();
return WriteBytesToHGlobal(ref hGlobal, byteArr);
}
return WriteBytesToHGlobal(ref hGlobal, SerializeObject(data));
@@ -332,7 +325,7 @@ namespace Avalonia.Win32
private static uint WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable files)
{
- if (!files?.Any() ?? false)
+ if (!files.Any())
return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
char[] filesStr = (string.Join("\0", files) + "\0\0").ToCharArray();
@@ -392,7 +385,7 @@ namespace Avalonia.Win32
public void ReleaseWrapped()
{
- _wrapped = null;
+ _wrapped = null!;
}
#endregion
}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs b/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs
index c11a6026e7..af8168d564 100644
--- a/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs
+++ b/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs
@@ -1,18 +1,11 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
using static Avalonia.Win32.Interop.UnmanagedMethods;
// ReSharper disable InconsistentNaming
#pragma warning disable CS0649
namespace Avalonia.Win32.DirectX
{
-#nullable enable
- public unsafe struct HANDLE
+ internal unsafe struct HANDLE
{
public readonly void* Value;
@@ -288,5 +281,4 @@ namespace Avalonia.Win32.DirectX
public D3D11_RESOURCE_MISC_FLAG MiscFlags;
}
-#nullable restore
}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
index e82f7633be..07fb3169cb 100644
--- a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
@@ -1,36 +1,26 @@
using System;
-using System.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
using System.Threading.Tasks;
using Avalonia.Logging;
-using Avalonia.OpenGL.Angle;
-using Avalonia.OpenGL.Egl;
using Avalonia.Rendering;
-using Avalonia.Win32.OpenGl.Angle;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods;
using MicroCom.Runtime;
namespace Avalonia.Win32.DirectX
{
-#pragma warning disable CA1416 // This should only be reachable on Windows
-#nullable enable
- public unsafe class DxgiConnection : IRenderTimer
+ internal unsafe class DxgiConnection : IRenderTimer
{
public const uint ENUM_CURRENT_SETTINGS = unchecked((uint)(-1));
public bool RunsInBackground => true;
public event Action? Tick;
- private object _syncLock;
+ private readonly object _syncLock;
- private IDXGIOutput? _output = null;
+ private IDXGIOutput? _output;
- private Stopwatch? _stopwatch = null;
+ private Stopwatch? _stopwatch;
private const string LogArea = "DXGI";
public DxgiConnection(object syncLock)
@@ -51,9 +41,9 @@ namespace Avalonia.Win32.DirectX
}
}
- private unsafe void RunLoop()
+ private void RunLoop()
{
- _stopwatch = System.Diagnostics.Stopwatch.StartNew();
+ _stopwatch = Stopwatch.StartNew();
try
{
GetBestOutputToVWaitOn();
@@ -162,7 +152,7 @@ namespace Avalonia.Win32.DirectX
}
// Used the windows composition as a blueprint for this startup/creation
- static private bool TryCreateAndRegisterCore()
+ private static bool TryCreateAndRegisterCore()
{
var tcs = new TaskCompletionSource();
var pumpLock = new object();
@@ -170,9 +160,7 @@ namespace Avalonia.Win32.DirectX
{
try
{
- DxgiConnection connection;
-
- connection = new DxgiConnection(pumpLock);
+ var connection = new DxgiConnection(pumpLock);
AvaloniaLocator.CurrentMutable.BindToSelf(connection);
AvaloniaLocator.CurrentMutable.Bind().ToConstant(connection);
@@ -191,6 +179,4 @@ namespace Avalonia.Win32.DirectX
return tcs.Task.Result;
}
}
-#nullable restore
-#pragma warning restore CA1416 // Validate platform compatibility
}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
index cb7826e185..513aba4f20 100644
--- a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
@@ -1,40 +1,28 @@
using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Win32.OpenGl.Angle;
using MicroCom.Runtime;
-using static Avalonia.OpenGL.Egl.EglGlPlatformSurfaceBase;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32.DirectX
{
-#pragma warning disable CA1416 // Validate platform compatibility, if you enter this not on windows you have messed up badly
-#nullable enable
- public unsafe class DxgiRenderTarget : EglPlatformSurfaceRenderTargetBase
+ internal unsafe class DxgiRenderTarget : EglPlatformSurfaceRenderTargetBase
{
// DXGI_FORMAT_B8G8R8A8_UNORM is target texture format as per ANGLE documentation
public const uint DXGI_USAGE_RENDER_TARGET_OUTPUT = 0x00000020U;
+ private readonly Guid ID3D11Texture2DGuid = Guid.Parse("6F15AAF2-D208-4E89-9AB4-489535D34F9C");
- private EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _window;
- private DxgiConnection _connection;
- private IDXGIDevice? _dxgiDevice = null;
- private IDXGIFactory2? _dxgiFactory = null;
- private IDXGISwapChain1? _swapChain = null;
- private IUnknown? _renderTexture = null;
+ private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _window;
+ private readonly DxgiConnection _connection;
+ private readonly IDXGIDevice? _dxgiDevice;
+ private readonly IDXGIFactory2? _dxgiFactory;
+ private readonly IDXGISwapChain1? _swapChain;
+ private readonly uint _flagsUsed;
- private Interop.UnmanagedMethods.RECT _clientRect = default;
-
- private uint _flagsUsed;
-
- private Guid ID3D11Texture2DGuid = Guid.Parse("6F15AAF2-D208-4E89-9AB4-489535D34F9C");
+ private IUnknown? _renderTexture;
+ private RECT _clientRect;
public DxgiRenderTarget(EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo window, EglContext context, DxgiConnection connection) : base(context)
{
@@ -80,11 +68,11 @@ namespace Avalonia.Win32.DirectX
null
);
- Interop.UnmanagedMethods.RECT pClientRect;
- GetClientRect(_window.Handle, out pClientRect);
+ GetClientRect(_window.Handle, out var pClientRect);
_clientRect = pClientRect;
}
+ ///
public override IGlPlatformSurfaceRenderingSession BeginDrawCore()
{
if (_swapChain is null)
@@ -98,8 +86,7 @@ namespace Avalonia.Win32.DirectX
var success = false;
try
{
- Interop.UnmanagedMethods.RECT pClientRect;
- GetClientRect(_window.Handle, out pClientRect);
+ GetClientRect(_window.Handle, out var pClientRect);
if (!RectsEqual(pClientRect, _clientRect))
{
// we gotta resize
@@ -137,7 +124,7 @@ namespace Avalonia.Win32.DirectX
var res = base.BeginDraw(surface, _window.Size, _window.Scaling, () =>
{
_swapChain.Present((ushort)0U, (ushort)0U);
- surface?.Dispose();
+ surface.Dispose();
transaction?.Dispose();
contextLock?.Dispose();
}, true);
@@ -178,6 +165,4 @@ namespace Avalonia.Win32.DirectX
}
}
-#pragma warning restore CA1416 // Validate platform compatibility
-#nullable restore
}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs
index 88226c5c89..a4c6598473 100644
--- a/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs
@@ -9,7 +9,7 @@ using Avalonia.OpenGL.Surfaces;
namespace Avalonia.Win32.DirectX
{
- public class DxgiSwapchainWindow : EglGlPlatformSurfaceBase
+ internal class DxgiSwapchainWindow : EglGlPlatformSurfaceBase
{
private DxgiConnection _connection;
private EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _window;
diff --git a/src/Windows/Avalonia.Win32/DirectX/directx.idl b/src/Windows/Avalonia.Win32/DirectX/directx.idl
index 1d66c898db..120d1d5159 100644
--- a/src/Windows/Avalonia.Win32/DirectX/directx.idl
+++ b/src/Windows/Avalonia.Win32/DirectX/directx.idl
@@ -36,6 +36,8 @@
@clr-map DXGI_SHARED_RESOURCE void*
@clr-map LUID ulong
@clr-map LPSTR ushort*
+@clr-map LPWSTR ushort*
+@clr-map LPCWSTR ushort*
enum DXGI_FORMAT
@@ -501,6 +503,44 @@ interface ID3D11Device : IUnknown
UINT GetExceptionMode();
}
+[uuid(a04bfb29-08ef-43d6-a49c-a9bdbdcbe686)]
+interface ID3D11Device1 : ID3D11Device
+{
+ void GetImmediateContext1( void** ppImmediateContext );
+
+ HRESULT CreateDeferredContext1(
+ UINT ContextFlags, // Reserved parameter; must be 0
+ [out, retval] IUnknown** ppDeferredContext );
+
+ HRESULT CreateBlendState1(
+ void* pBlendStateDesc,
+ [out, retval] IUnknown** ppBlendState );
+
+ HRESULT CreateRasterizerState1(
+ void* pRasterizerDesc,
+ [out, retval] IUnknown** ppRasterizerState );
+
+ HRESULT CreateDeviceContextState(
+ UINT Flags,
+ void* pFeatureLevels,
+ UINT FeatureLevels,
+ UINT SDKVersion,
+ GUID* EmulatedInterface,
+ void* pChosenFeatureLevel,
+ [out, retval] IUnknown** ppContextState);
+
+ HRESULT OpenSharedResource1(
+ IntPtr hResource,
+ Guid* ReturnedInterface,
+ [out, retval] IUnknown** ppResource);
+
+ HRESULT OpenSharedResourceByName(
+ LPCWSTR lpName,
+ DWORD dwDesiredAccess,
+ REFIID returnedInterface,
+ void** ppResource);
+};
+
[uuid( 6f15aaf2-d208-4e89-9ab4-489535d34f9c)]
interface ID3D11Texture2D : IUnknown
diff --git a/src/Windows/Avalonia.Win32/FramebufferManager.cs b/src/Windows/Avalonia.Win32/FramebufferManager.cs
index 8feecab4dd..cba4879f5b 100644
--- a/src/Windows/Avalonia.Win32/FramebufferManager.cs
+++ b/src/Windows/Avalonia.Win32/FramebufferManager.cs
@@ -4,8 +4,6 @@ using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using Avalonia.Win32.Interop;
-#nullable enable
-
namespace Avalonia.Win32
{
internal class FramebufferManager : IFramebufferPlatformSurface, IDisposable
diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
index 7ef1cb1d1c..41417dd950 100644
--- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
+++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Text;
using Avalonia.Input.TextInput;
using Avalonia.Threading;
@@ -10,21 +11,21 @@ namespace Avalonia.Win32.Input
///
/// A Windows input method editor based on Windows Input Method Manager (IMM32).
///
- class Imm32InputMethod : ITextInputMethodImpl
+ internal class Imm32InputMethod : ITextInputMethodImpl
{
- public IntPtr HWND { get; private set; }
+ public IntPtr Hwnd { get; private set; }
private IntPtr _currentHimc;
- private WindowImpl _parent;
- private ITextInputMethodClient _client;
+ private WindowImpl? _parent;
- private Imm32CaretManager _caretManager = new();
+ private Imm32CaretManager _caretManager;
private ushort _langId;
- private const int _caretMargin = 1;
+ private const int CaretMargin = 1;
- public ITextInputMethodClient Client => _client;
+ public ITextInputMethodClient? Client { get; private set; }
- public bool IsActive => _client != null;
+ [MemberNotNullWhen(true, nameof(Client))]
+ public bool IsActive => Client != null;
public bool IsComposing { get; set; }
@@ -32,12 +33,12 @@ namespace Avalonia.Win32.Input
public void CreateCaret()
{
- _caretManager.TryCreate(HWND);
+ _caretManager.TryCreate(Hwnd);
}
public void EnableImm()
{
- var himc = ImmGetContext(HWND);
+ var himc = ImmGetContext(Hwnd);
if(himc == IntPtr.Zero)
{
@@ -51,13 +52,13 @@ namespace Avalonia.Win32.Input
DisableImm();
}
- ImmAssociateContext(HWND, himc);
+ ImmAssociateContext(Hwnd, himc);
- ImmReleaseContext(HWND, himc);
+ ImmReleaseContext(Hwnd, himc);
_currentHimc = himc;
- _caretManager.TryCreate(HWND);
+ _caretManager.TryCreate(Hwnd);
}
}
@@ -67,7 +68,7 @@ namespace Avalonia.Win32.Input
Reset();
- ImmAssociateContext(HWND, IntPtr.Zero);
+ ImmAssociateContext(Hwnd, IntPtr.Zero);
_caretManager.TryDestroy();
@@ -76,7 +77,7 @@ namespace Avalonia.Win32.Input
public void SetLanguageAndWindow(WindowImpl parent, IntPtr hwnd, IntPtr HKL)
{
- HWND = hwnd;
+ Hwnd = hwnd;
_parent = parent;
_langId = PRIMARYLANGID(LGID(HKL));
@@ -98,9 +99,9 @@ namespace Avalonia.Win32.Input
{
DisableImm();
- HWND = IntPtr.Zero;
+ Hwnd = IntPtr.Zero;
_parent = null;
- _client = null;
+ Client = null;
_langId = 0;
IsComposing = false;
@@ -108,13 +109,13 @@ namespace Avalonia.Win32.Input
//Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers -
//every Dispatcher should have their own InputMethod.
- public static Imm32InputMethod Current { get; } = new Imm32InputMethod();
+ public static Imm32InputMethod Current { get; } = new();
public void Reset()
{
Dispatcher.UIThread.Post(() =>
{
- var himc = ImmGetContext(HWND);
+ var himc = ImmGetContext(Hwnd);
if (IsComposing)
{
@@ -123,13 +124,13 @@ namespace Avalonia.Win32.Input
IsComposing = false;
}
- ImmReleaseContext(HWND, himc);
+ ImmReleaseContext(Hwnd, himc);
});
}
- public void SetClient(ITextInputMethodClient client)
+ public void SetClient(ITextInputMethodClient? client)
{
- _client = client;
+ Client = client;
Dispatcher.UIThread.Post(() =>
{
@@ -152,7 +153,7 @@ namespace Avalonia.Win32.Input
public void SetCursorRect(Rect rect)
{
- var focused = GetActiveWindow() == HWND;
+ var focused = GetActiveWindow() == Hwnd;
if (!focused)
{
@@ -161,7 +162,7 @@ namespace Avalonia.Win32.Input
Dispatcher.UIThread.Post(() =>
{
- var himc = ImmGetContext(HWND);
+ var himc = ImmGetContext(Hwnd);
if (himc == IntPtr.Zero)
{
@@ -170,7 +171,7 @@ namespace Avalonia.Win32.Input
MoveImeWindow(rect, himc);
- ImmReleaseContext(HWND, himc);
+ ImmReleaseContext(Hwnd, himc);
});
}
@@ -219,7 +220,7 @@ namespace Avalonia.Win32.Input
// the caret to move the position of their candidate windows.
// On the other hand, Korean IMEs require the lower-left corner of the
// caret to move their candidate windows.
- y2 += _caretMargin;
+ y2 += CaretMargin;
}
// Need to return here since some Chinese IMEs would stuck if set
@@ -238,7 +239,7 @@ namespace Avalonia.Win32.Input
dwIndex = 0,
dwStyle = CFS_EXCLUDE,
ptCurrentPos = new POINT {X = x1, Y = y1},
- rcArea = new RECT {left = x1, top = y1, right = x2, bottom = y2 + _caretMargin}
+ rcArea = new RECT {left = x1, top = y1, right = x2, bottom = y2 + CaretMargin}
};
ImmSetCandidateWindow(himc, ref excludeRectangle);
@@ -275,34 +276,21 @@ namespace Avalonia.Win32.Input
return;
}
- if(!IsActive || !_client.SupportsPreedit)
+ if(!IsActive || !Client.SupportsPreedit)
{
return;
}
var composition = GetCompositionString();
- _client.SetPreeditText(composition);
+ Client.SetPreeditText(composition);
}
- private string GetCompositionString()
+ private string? GetCompositionString()
{
- var himc = ImmGetContext(HWND);
+ var himc = ImmGetContext(Hwnd);
- var length = ImmGetCompositionString(himc, GCS.GCS_COMPSTR, IntPtr.Zero, 0);
-
- var buffer = new byte[length];
-
- unsafe
- {
- fixed (byte* bufferPtr = buffer)
- {
- var error = ImmGetCompositionString(himc, GCS.GCS_COMPSTR, (IntPtr)bufferPtr, (uint)length);
-
- return Encoding.Unicode.GetString(buffer, 0, buffer.Length);
- }
- }
-
+ return ImmGetCompositionString(himc, GCS.GCS_COMPSTR);
}
~Imm32InputMethod()
diff --git a/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs b/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
index 998ff4a427..c7bc511b99 100644
--- a/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
+++ b/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
@@ -5,9 +5,10 @@ using Avalonia.Win32.Interop;
namespace Avalonia.Win32.Input
{
- class WindowsMouseDevice : MouseDevice
+ internal class WindowsMouseDevice : MouseDevice
{
private readonly IPointer _pointer;
+
public WindowsMouseDevice() : base(WindowsMousePointer.CreatePointer(out var pointer))
{
_pointer = pointer;
@@ -15,14 +16,14 @@ namespace Avalonia.Win32.Input
// Normally user should use IPointer.Capture instead of MouseDevice.Capture,
// But on Windows we need to handle WM_MOUSE capture manually without having access to the Pointer.
- internal void Capture(IInputElement control)
+ internal void Capture(IInputElement? control)
{
_pointer.Capture(control);
}
internal class WindowsMousePointer : Pointer
{
- private WindowsMousePointer() : base(Pointer.GetNextFreeId(),PointerType.Mouse, true)
+ private WindowsMousePointer() : base(GetNextFreeId(),PointerType.Mouse, true)
{
}
@@ -31,7 +32,7 @@ namespace Avalonia.Win32.Input
return pointer = new WindowsMousePointer();
}
- protected override void PlatformCapture(IInputElement element)
+ protected override void PlatformCapture(IInputElement? element)
{
var hwnd = (TopLevel.GetTopLevel(element as Visual)?.PlatformImpl as WindowImpl)
?.Handle.Handle;
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs
index a8caf26524..be8b998a9e 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs
@@ -1,4 +1,3 @@
-using System;
using System.Runtime.InteropServices;
namespace Avalonia.Win32.Interop.Automation
@@ -8,7 +7,7 @@ namespace Avalonia.Win32.Interop.Automation
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGridProvider
{
- IRawElementProviderSimple GetItem(int row, int column);
+ IRawElementProviderSimple? GetItem(int row, int column);
int RowCount { get; }
int ColumnCount { get; }
}
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs
index a62aa842cb..46d8dc6cdb 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs
@@ -1,8 +1,6 @@
using System;
using System.Runtime.InteropServices;
-#nullable enable
-
namespace Avalonia.Win32.Interop.Automation
{
[ComVisible(true)]
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs
index 71d1bdce60..1fd0cb13ba 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs
@@ -1,4 +1,3 @@
-using System;
using System.Runtime.InteropServices;
namespace Avalonia.Win32.Interop.Automation
@@ -8,7 +7,7 @@ namespace Avalonia.Win32.Interop.Automation
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IRawElementProviderFragmentRoot : IRawElementProviderFragment
{
- IRawElementProviderFragment ElementProviderFromPoint(double x, double y);
- IRawElementProviderFragment GetFocus();
+ IRawElementProviderFragment? ElementProviderFromPoint(double x, double y);
+ IRawElementProviderFragment? GetFocus();
}
}
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs
index 439036290e..5b67d10206 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs
@@ -1,8 +1,6 @@
using System;
using System.Runtime.InteropServices;
-#nullable enable
-
namespace Avalonia.Win32.Interop.Automation
{
[Flags]
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs
index f3504b8d77..c2e8a42f87 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Runtime.InteropServices;
-
-#nullable enable
+using System.Runtime.InteropServices;
namespace Avalonia.Win32.Interop.Automation
{
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs
index 8d6677315c..072e210027 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs
@@ -1,5 +1,3 @@
-#nullable enable
-using System;
using System.Runtime.InteropServices;
namespace Avalonia.Win32.Interop.Automation
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs
index 919be647f8..0356f93ab8 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs
@@ -1,8 +1,5 @@
-using System;
using System.Runtime.InteropServices;
-#nullable enable
-
namespace Avalonia.Win32.Interop.Automation
{
[ComVisible(true)]
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs
index 4ba7a710d4..bd939c56b7 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs
@@ -71,21 +71,21 @@ namespace Avalonia.Win32.Interop.Automation
public static extern bool UiaClientsAreListening();
[DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)]
- public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple el);
+ public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple? el);
[DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)]
public static extern int UiaHostProviderFromHwnd(IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] out IRawElementProviderSimple provider);
[DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)]
- public static extern int UiaRaiseAutomationEvent(IRawElementProviderSimple provider, int id);
+ public static extern int UiaRaiseAutomationEvent(IRawElementProviderSimple? provider, int id);
[DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)]
- public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple provider, int id, object oldValue, object newValue);
+ public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple? provider, int id, object? oldValue, object? newValue);
[DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)]
- public static extern int UiaRaiseStructureChangedEvent(IRawElementProviderSimple provider, StructureChangeType structureChangeType, int[] runtimeId, int runtimeIdLen);
+ public static extern int UiaRaiseStructureChangedEvent(IRawElementProviderSimple? provider, StructureChangeType structureChangeType, int[]? runtimeId, int runtimeIdLen);
[DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)]
- public static extern int UiaDisconnectProvider(IRawElementProviderSimple provider);
+ public static extern int UiaDisconnectProvider(IRawElementProviderSimple? provider);
}
}
diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs
index 08b3ee32fa..b6b069ac37 100644
--- a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs
+++ b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs
@@ -63,8 +63,8 @@ namespace Avalonia.Win32.Interop.Automation
}
#endif
- var comConfig = AppContext.GetData("System.Runtime.InteropServices.BuiltInComInterop.IsSupported");
- return comConfig == null || bool.Parse(comConfig.ToString());
+ var comConfig = AppContext.GetData("System.Runtime.InteropServices.BuiltInComInterop.IsSupported") as string;
+ return comConfig == null || bool.Parse(comConfig);
}
[DllImport("UIAutomationCore.dll", EntryPoint = "UiaLookupId", CharSet = CharSet.Unicode)]
diff --git a/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs b/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs
index 88b907aeec..7eb457480b 100644
--- a/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs
+++ b/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs
@@ -7,8 +7,8 @@ namespace Avalonia.Win32.Interop
internal class TaskBarList
{
private static IntPtr s_taskBarList;
- private static HrInit s_hrInitDelegate;
- private static MarkFullscreenWindow s_markFullscreenWindowDelegate;
+ private static HrInit? s_hrInitDelegate;
+ private static MarkFullscreenWindow? s_markFullscreenWindowDelegate;
///
/// Ported from https://github.com/chromium/chromium/blob/master/ui/views/win/fullscreen_handler.cc
@@ -28,10 +28,7 @@ namespace Avalonia.Win32.Interop
{
var ptr = (ITaskBarList2VTable**)s_taskBarList.ToPointer();
- if (s_hrInitDelegate is null)
- {
- s_hrInitDelegate = Marshal.GetDelegateForFunctionPointer((*ptr)->HrInit);
- }
+ s_hrInitDelegate ??= Marshal.GetDelegateForFunctionPointer((*ptr)->HrInit);
if (s_hrInitDelegate(s_taskBarList) != HRESULT.S_OK)
{
@@ -44,10 +41,8 @@ namespace Avalonia.Win32.Interop
{
var ptr = (ITaskBarList2VTable**)s_taskBarList.ToPointer();
- if (s_markFullscreenWindowDelegate is null)
- {
- s_markFullscreenWindowDelegate = Marshal.GetDelegateForFunctionPointer((*ptr)->MarkFullscreenWindow);
- }
+ s_markFullscreenWindowDelegate ??=
+ Marshal.GetDelegateForFunctionPointer((*ptr)->MarkFullscreenWindow);
s_markFullscreenWindowDelegate(s_taskBarList, hwnd, fullscreen);
}
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index 672f3a781a..1dd2ef20c7 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -1,14 +1,12 @@
+#nullable enable
+
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
-
-using Avalonia.MicroCom;
using MicroCom.Runtime;
-using Avalonia.Win32.Win32Com;
// ReSharper disable InconsistentNaming
#pragma warning disable 169, 649
@@ -1092,7 +1090,7 @@ namespace Avalonia.Win32.Interop
public const int SizeOf_BITMAPINFOHEADER = 40;
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
- unsafe internal static extern int GetMouseMovePointsEx(
+ internal static extern int GetMouseMovePointsEx(
uint cbSize, MOUSEMOVEPOINT* pointsIn,
MOUSEMOVEPOINT* pointsBufferOut, int nBufPoints, uint resolution);
@@ -1167,7 +1165,7 @@ namespace Avalonia.Win32.Interop
public static extern IntPtr CreateWindowEx(
int dwExStyle,
uint lpClassName,
- string lpWindowName,
+ string? lpWindowName,
uint dwStyle,
int x,
int y,
@@ -1218,7 +1216,7 @@ namespace Avalonia.Win32.Interop
public static extern int GetMessageTime();
[DllImport("kernel32.dll")]
- public static extern IntPtr GetModuleHandle(string lpModuleName);
+ public static extern IntPtr GetModuleHandle(string? lpModuleName);
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(SystemMetric smIndex);
@@ -1255,7 +1253,7 @@ namespace Avalonia.Win32.Interop
}
else
{
- return (uint)SetWindowLong64b(hWnd, nIndex, new IntPtr((uint)value)).ToInt32();
+ return (uint)SetWindowLong64b(hWnd, nIndex, new IntPtr(value)).ToInt32();
}
}
@@ -1421,7 +1419,7 @@ namespace Avalonia.Win32.Interop
public static extern bool UnregisterClass(string lpClassName, IntPtr hInstance);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SetWindowTextW")]
- public static extern bool SetWindowText(IntPtr hwnd, string lpString);
+ public static extern bool SetWindowText(IntPtr hwnd, string? lpString);
public enum ClassLongIndex : int
{
@@ -1482,7 +1480,7 @@ namespace Avalonia.Win32.Interop
internal static extern int CoCreateInstance(ref Guid clsid,
IntPtr ignore1, int ignore2, ref Guid iid, [Out] out IntPtr pUnkOuter);
- internal unsafe static T CreateInstance(ref Guid clsid, ref Guid iid) where T : IUnknown
+ internal static T CreateInstance(ref Guid clsid, ref Guid iid) where T : IUnknown
{
var hresult = CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out IntPtr pUnk);
if (hresult != 0)
@@ -1490,7 +1488,7 @@ namespace Avalonia.Win32.Interop
throw new COMException("CreateInstance", hresult);
}
using var unk = MicroComRuntime.CreateProxyFor(pUnk, true);
- return MicroComRuntime.QueryInterface(unk);
+ return unk.QueryInterface();
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
@@ -1581,7 +1579,7 @@ namespace Avalonia.Win32.Interop
public static extern bool GetMonitorInfo([In] IntPtr hMonitor, ref MONITORINFO lpmi);
[DllImport("user32")]
- public static extern unsafe bool GetTouchInputInfo(
+ public static extern bool GetTouchInputInfo(
IntPtr hTouchInput,
uint cInputs,
TOUCHINPUT* pInputs,
@@ -1680,7 +1678,7 @@ namespace Avalonia.Win32.Interop
public static extern IntPtr GlobalSize(IntPtr hGlobal);
[DllImport("shell32.dll", BestFitMapping = false, CharSet = CharSet.Auto)]
- public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
+ public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder? lpszFile, int cch);
[DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)]
internal static extern void DoDragDrop(IntPtr dataObject, IntPtr dropSource, int allowedEffects, [Out] out int finalEffect);
@@ -1734,7 +1732,7 @@ namespace Avalonia.Win32.Interop
public DWM_BLURBEHIND(bool enabled)
{
- fEnable = enabled ? true : false;
+ fEnable = enabled;
hRgnBlur = IntPtr.Zero;
fTransitionOnMaximized = false;
dwFlags = DWM_BB.Enable;
@@ -1855,20 +1853,22 @@ namespace Avalonia.Win32.Interop
[DllImport("imm32.dll", SetLastError = false, CharSet = CharSet.Unicode)]
public static extern int ImmGetCompositionString(IntPtr hIMC, GCS dwIndex, [Out, Optional] IntPtr lpBuf, uint dwBufLen);
- public static string ImmGetCompositionString(IntPtr hIMC, GCS dwIndex)
+ public static string? ImmGetCompositionString(IntPtr hIMC, GCS dwIndex)
{
int bufferLength = ImmGetCompositionString(hIMC, dwIndex, IntPtr.Zero, 0);
if (bufferLength > 0)
{
- var buffer = new byte[bufferLength];
+ var buffer = bufferLength <= 64 ? stackalloc byte[bufferLength] : new byte[bufferLength];
- fixed(byte* bufferPtr = buffer)
+ fixed (byte* bufferPtr = buffer)
{
- var error = ImmGetCompositionString(hIMC, dwIndex, (IntPtr)bufferPtr, (uint)bufferLength);
-
- return Marshal.PtrToStringUni((IntPtr)bufferPtr);
- }
+ var result = ImmGetCompositionString(hIMC, dwIndex, (IntPtr)bufferPtr, (uint)bufferLength);
+ if (result >= 0)
+ {
+ return Marshal.PtrToStringUni((IntPtr)bufferPtr);
+ }
+ }
}
return null;
@@ -2380,7 +2380,7 @@ namespace Avalonia.Win32.Interop
}
}
- [StructLayoutAttribute(LayoutKind.Sequential)]
+ [StructLayout(LayoutKind.Sequential)]
internal struct _DROPFILES
{
public Int32 pFiles;
@@ -2390,7 +2390,7 @@ namespace Avalonia.Win32.Interop
public bool fWide;
}
- [StructLayoutAttribute(LayoutKind.Sequential)]
+ [StructLayout(LayoutKind.Sequential)]
internal struct STGMEDIUM
{
public TYMED tymed;
@@ -2398,7 +2398,7 @@ namespace Avalonia.Win32.Interop
public IntPtr pUnkForRelease;
}
- [StructLayoutAttribute(LayoutKind.Sequential)]
+ [StructLayout(LayoutKind.Sequential)]
internal struct FORMATETC
{
public ushort cfFormat;
@@ -2507,14 +2507,14 @@ namespace Avalonia.Win32.Interop
public int uCallbackMessage;
public IntPtr hIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string szTip;
+ public string? szTip;
public int dwState = 0;
public int dwStateMask = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
- public string szInfo;
+ public string? szInfo;
public int uTimeoutOrVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
- public string szInfoTitle;
+ public string? szInfoTitle;
public NIIF dwInfoFlags;
}
}
diff --git a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
index f295dd7394..2c4d2c9468 100644
--- a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
+++ b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
@@ -1,7 +1,6 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Threading;
-using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Win32.Interop;
@@ -9,17 +8,42 @@ namespace Avalonia.Win32
{
internal class NonPumpingSyncContext : SynchronizationContext, IDisposable
{
- private readonly SynchronizationContext _inner;
+ private readonly SynchronizationContext? _inner;
- private NonPumpingSyncContext(SynchronizationContext inner)
+ private NonPumpingSyncContext(SynchronizationContext? inner)
{
_inner = inner;
SetWaitNotificationRequired();
SetSynchronizationContext(this);
}
- public override void Post(SendOrPostCallback d, object state) => _inner.Post(d, state);
- public override void Send(SendOrPostCallback d, object state) => _inner.Send(d, state);
+ public override void Post(SendOrPostCallback d, object? state)
+ {
+ if (_inner is null)
+ {
+#if NET6_0_OR_GREATER
+ ThreadPool.QueueUserWorkItem(static x => x.d(x.state), (d, state), false);
+#else
+ ThreadPool.QueueUserWorkItem(_ => d(state));
+#endif
+ }
+ else
+ {
+ _inner.Post(d, state);
+ }
+ }
+
+ public override void Send(SendOrPostCallback d, object? state)
+ {
+ if (_inner is null)
+ {
+ d(state);
+ }
+ else
+ {
+ _inner.Send(d, state);
+ }
+ }
#if !NET6_0_OR_GREATER
[PrePrepareMethod]
@@ -32,7 +56,7 @@ namespace Avalonia.Win32
public void Dispose() => SetSynchronizationContext(_inner);
- public static IDisposable Use()
+ public static IDisposable? Use()
{
var current = Current;
if (current == null)
@@ -42,13 +66,13 @@ namespace Avalonia.Win32
}
if (current is NonPumpingSyncContext)
return null;
-
+
return new NonPumpingSyncContext(current);
}
internal class HelperImpl : NonPumpingLockHelper.IHelperImpl
{
- IDisposable NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use();
+ IDisposable? NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use();
}
}
}
diff --git a/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs b/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs
index 9de105a3d5..7253b3c0ed 100644
--- a/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs
+++ b/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs
@@ -1,17 +1,18 @@
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
-using Avalonia.Platform;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
- class OffscreenParentWindow
+ internal class OffscreenParentWindow
{
public static IntPtr Handle { get; } = CreateParentWindow();
- private static UnmanagedMethods.WndProc s_wndProcDelegate;
+
+ private static UnmanagedMethods.WndProc? s_wndProcDelegate;
+
private static IntPtr CreateParentWindow()
{
- s_wndProcDelegate = new UnmanagedMethods.WndProc(ParentWndProc);
+ s_wndProcDelegate = ParentWndProc;
var wndClassEx = new UnmanagedMethods.WNDCLASSEX
{
diff --git a/src/Windows/Avalonia.Win32/OleContext.cs b/src/Windows/Avalonia.Win32/OleContext.cs
index e41423a334..897033e835 100644
--- a/src/Windows/Avalonia.Win32/OleContext.cs
+++ b/src/Windows/Avalonia.Win32/OleContext.cs
@@ -11,18 +11,16 @@ namespace Avalonia.Win32
{
internal class OleContext
{
- private static OleContext s_current;
+ private static OleContext? s_current;
- internal static OleContext Current
+ internal static OleContext? Current
{
get
{
if (!IsValidOleThread())
return null;
- if (s_current == null)
- s_current = new OleContext();
- return s_current;
+ return s_current ??= new OleContext();
}
}
@@ -41,7 +39,7 @@ namespace Avalonia.Win32
Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
}
- internal bool RegisterDragDrop(IPlatformHandle hwnd, IDropTarget target)
+ internal bool RegisterDragDrop(IPlatformHandle? hwnd, IDropTarget? target)
{
if (hwnd?.HandleDescriptor != "HWND" || target == null)
{
@@ -52,7 +50,7 @@ namespace Avalonia.Win32
return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK;
}
- internal bool UnregisterDragDrop(IPlatformHandle hwnd)
+ internal bool UnregisterDragDrop(IPlatformHandle? hwnd)
{
if (hwnd?.HandleDescriptor != "HWND")
{
diff --git a/src/Windows/Avalonia.Win32/OleDataObject.cs b/src/Windows/Avalonia.Win32/OleDataObject.cs
index 79b55e4f77..247d0340c3 100644
--- a/src/Windows/Avalonia.Win32/OleDataObject.cs
+++ b/src/Windows/Avalonia.Win32/OleDataObject.cs
@@ -8,7 +8,6 @@ using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Serialization.Formatters.Binary;
using Avalonia.Input;
-using Avalonia.MicroCom;
using Avalonia.Utilities;
using Avalonia.Win32.Interop;
using MicroCom.Runtime;
@@ -35,23 +34,23 @@ namespace Avalonia.Win32
return GetDataFormatsCore().Distinct();
}
- public string GetText()
+ public string? GetText()
{
- return (string)GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT);
+ return (string?)GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT);
}
- public IEnumerable GetFileNames()
+ public IEnumerable? GetFileNames()
{
- return (IEnumerable)GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT);
+ return (IEnumerable?)GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT);
}
- public object Get(string dataFormat)
+ public object? Get(string dataFormat)
{
return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT);
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We still use BinaryFormatter for WinForms dragndrop compatability")]
- private unsafe object GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
+ private unsafe object? GetDataFromOleHGLOBAL(string format, DVASPECT aspect)
{
var formatEtc = new Interop.FORMATETC();
formatEtc.cfFormat = ClipboardFormats.GetFormat(format);
@@ -100,7 +99,7 @@ namespace Avalonia.Win32
private static IEnumerable ReadFileNamesFromHGlobal(IntPtr hGlobal)
{
- List files = new List();
+ var files = new List();
int fileCount = UnmanagedMethods.DragQueryFile(hGlobal, -1, null, 0);
if (fileCount > 0)
{
@@ -118,7 +117,7 @@ namespace Avalonia.Win32
return files;
}
- private static string ReadStringFromHGlobal(IntPtr hGlobal)
+ private static string? ReadStringFromHGlobal(IntPtr hGlobal)
{
IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal);
try
diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs
index 8bbdfe5fd9..a81652ffc2 100644
--- a/src/Windows/Avalonia.Win32/OleDropTarget.cs
+++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs
@@ -1,5 +1,5 @@
using System;
-
+using System.Diagnostics.CodeAnalysis;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.MicroCom;
@@ -13,16 +13,16 @@ namespace Avalonia.Win32
internal class OleDropTarget : CallbackBase, Win32Com.IDropTarget
{
private readonly IInputRoot _target;
- private readonly ITopLevelImpl _tl;
+ private readonly ITopLevelImpl _topLevel;
private readonly IDragDropDevice _dragDevice;
- private IDataObject _currentDrag = null;
+ private IDataObject? _currentDrag;
- public OleDropTarget(ITopLevelImpl tl, IInputRoot target)
+ public OleDropTarget(ITopLevelImpl topLevel, IInputRoot target, IDragDropDevice dragDevice)
{
- _dragDevice = AvaloniaLocator.Current.GetService();
- _tl = tl;
+ _topLevel = topLevel;
_target = target;
+ _dragDevice = dragDevice;
}
public static DropEffect ConvertDropEffect(DragDropEffects operation)
@@ -71,10 +71,11 @@ namespace Avalonia.Win32
unsafe void Win32Com.IDropTarget.DragEnter(Win32Com.IDataObject pDataObj, int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect)
{
- var dispatch = _tl?.Input;
+ var dispatch = _topLevel.Input;
if (dispatch == null)
{
*pdwEffect= (int)DropEffect.None;
+ return;
}
SetDataObject(pDataObj);
@@ -94,10 +95,11 @@ namespace Avalonia.Win32
unsafe void Win32Com.IDropTarget.DragOver(int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect)
{
- var dispatch = _tl?.Input;
- if (dispatch == null)
+ var dispatch = _topLevel.Input;
+ if (dispatch == null || _currentDrag is null)
{
*pdwEffect = (int)DropEffect.None;
+ return;
}
var args = new RawDragEvent(
@@ -115,14 +117,20 @@ namespace Avalonia.Win32
void Win32Com.IDropTarget.DragLeave()
{
+ var dispatch = _topLevel.Input;
+ if (dispatch == null || _currentDrag is null)
+ {
+ return;
+ }
+
try
{
- _tl?.Input(new RawDragEvent(
+ dispatch(new RawDragEvent(
_dragDevice,
RawDragEventType.DragLeave,
_target,
default,
- null,
+ _currentDrag,
DragDropEffects.None,
RawInputModifiers.None
));
@@ -137,10 +145,11 @@ namespace Avalonia.Win32
{
try
{
- var dispatch = _tl?.Input;
+ var dispatch = _topLevel.Input;
if (dispatch == null)
{
*pdwEffect = (int)DropEffect.None;
+ return;
}
SetDataObject(pDataObj);
@@ -163,6 +172,7 @@ namespace Avalonia.Win32
}
}
+ [MemberNotNull(nameof(_currentDrag))]
private void SetDataObject(Win32Com.IDataObject pDataObj)
{
var newDrag = GetAvaloniaObjectFromCOM(pDataObj);
@@ -178,9 +188,9 @@ namespace Avalonia.Win32
// OleDataObject keeps COM reference, so it should be disposed.
if (_currentDrag is OleDataObject oleDragSource)
{
- oleDragSource?.Dispose();
- _currentDrag = null;
+ oleDragSource.Dispose();
}
+ _currentDrag = null;
}
private Point GetDragLocation(UnmanagedMethods.POINT dragPoint)
@@ -194,7 +204,7 @@ namespace Avalonia.Win32
ReleaseDataObject();
}
- public static unsafe IDataObject GetAvaloniaObjectFromCOM(Win32Com.IDataObject pDataObj)
+ public static IDataObject GetAvaloniaObjectFromCOM(Win32Com.IDataObject pDataObj)
{
if (pDataObj is null)
{
@@ -205,8 +215,7 @@ namespace Avalonia.Win32
return disposableDataObject;
}
- var dataObject = MicroComRuntime.TryUnwrapManagedObject(pDataObj) as DataObject;
- if (dataObject is not null)
+ if (MicroComRuntime.TryUnwrapManagedObject(pDataObj) is DataObject dataObject)
{
return dataObject;
}
diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs
index 6c951010c8..ffdd4fdfd6 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs
@@ -14,7 +14,7 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory
Display: AngleWin32EglDisplay { PlatformApi: AngleOptions.PlatformApi.DirectX11 }
} && surface is IDirect3D11TexturePlatformSurface;
- class RenderTargetWrapper : EglPlatformSurfaceRenderTargetBase
+ private class RenderTargetWrapper : EglPlatformSurfaceRenderTargetBase
{
private readonly AngleWin32EglDisplay _angle;
private readonly IDirect3D11TextureRenderTarget _target;
@@ -31,8 +31,8 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory
{
var success = false;
var contextLock = Context.EnsureCurrent();
- IDirect3D11TextureRenderTargetRenderSession session = null;
- EglSurface surface = null;
+ IDirect3D11TextureRenderTargetRenderSession? session = null;
+ EglSurface? surface = null;
try
{
try
diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs
index 4e00bc2c72..2fd2e0f33c 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs
@@ -22,7 +22,7 @@ namespace Avalonia.OpenGL.Angle
}
[GetProcAddress("eglCreateDeviceANGLE", true)]
- public partial IntPtr CreateDeviceANGLE(int deviceType, IntPtr nativeDevice, int[] attribs);
+ public partial IntPtr CreateDeviceANGLE(int deviceType, IntPtr nativeDevice, int[]? attribs);
[GetProcAddress("eglReleaseDeviceANGLE", true)]
public partial void ReleaseDeviceANGLE(IntPtr device);
diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs
index b0fa76fda2..6bbfde35e1 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs
@@ -1,8 +1,5 @@
-#nullable enable
using System;
-using System.Threading;
using Avalonia.OpenGL;
-using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Win32.DirectX;
@@ -15,9 +12,12 @@ namespace Avalonia.Win32.OpenGl.Angle;
internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture
{
private readonly EglContext _context;
- private ID3D11Texture2D _texture2D;
- private EglSurface _eglSurface;
- private IDXGIKeyedMutex _mutex;
+ private ID3D11Texture2D? _texture2D;
+ private EglSurface? _eglSurface;
+ private IDXGIKeyedMutex? _mutex;
+
+ private IDXGIKeyedMutex Mutex
+ => _mutex ?? throw new ObjectDisposedException(nameof(AngleExternalMemoryD3D11Texture2D));
public unsafe AngleExternalMemoryD3D11Texture2D(EglContext context, ID3D11Texture2D texture2D, PlatformGraphicsExternalImageProperties props)
{
@@ -40,14 +40,14 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture
int temp = 0;
gl.GenTextures(1, &temp);
TextureId = temp;
- gl.BindTexture(GlConsts.GL_TEXTURE_2D, TextureId);
+ gl.BindTexture(GL_TEXTURE_2D, TextureId);
if (_context.Display.EglInterface.BindTexImage(_context.Display.Handle, _eglSurface.DangerousGetHandle(),
EGL_BACK_BUFFER) == 0)
throw OpenGlException.GetFormattedException("eglBindTexImage", _context.Display.EglInterface);
}
-
+
public void Dispose()
{
@@ -56,17 +56,15 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture
_context.GlInterface.DeleteTexture(TextureId);
TextureId = 0;
_eglSurface?.Dispose();
- _eglSurface = null!;
+ _eglSurface = null;
_texture2D?.Dispose();
- _texture2D = null!;
+ _texture2D = null;
_mutex?.Dispose();
- _mutex = null!;
+ _mutex = null;
}
-
- public void AcquireKeyedMutex(uint key) => _mutex.AcquireSync(key, int.MaxValue);
-
- public void ReleaseKeyedMutex(uint key) => _mutex.ReleaseSync(key);
+ public void AcquireKeyedMutex(uint key) => Mutex.AcquireSync(key, int.MaxValue);
+ public void ReleaseKeyedMutex(uint key) => Mutex.ReleaseSync(key);
public int TextureId { get; private set; }
public int InternalFormat { get; }
@@ -75,7 +73,7 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture
internal class AngleExternalMemoryD3D11ExportedTexture2D : AngleExternalMemoryD3D11Texture2D, IGlExportableExternalImageTexture
{
- static IPlatformHandle GetHandle(ID3D11Texture2D texture2D)
+ private static IPlatformHandle GetHandle(ID3D11Texture2D texture2D)
{
using var resource = texture2D.QueryInterface();
return new PlatformHandle(resource.SharedHandle,
diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs
index a7b52e953e..4526e0e793 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using Avalonia.Controls.Documents;
+using System.Linq;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
@@ -15,12 +14,14 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
{
private readonly EglContext _context;
private readonly ID3D11Device _device;
+ private readonly ID3D11Device1 _device1;
public AngleExternalObjectsFeature(EglContext context)
{
_context = context;
var angle = (AngleWin32EglDisplay)context.Display;
_device = MicroComRuntime.CreateProxyFor(angle.GetDirect3DDevice(), false).CloneReference();
+ _device1 = _device.QueryInterface();
using var dxgiDevice = _device.QueryInterface();
using var adapter = dxgiDevice.Adapter;
DeviceLuid = BitConverter.GetBytes(adapter.Desc.AdapterLuid);
@@ -28,7 +29,8 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
public IReadOnlyList SupportedImportableExternalImageTypes { get; } = new[]
{
- KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle
+ KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle,
+ KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle,
};
public IReadOnlyList SupportedExportableExternalImageTypes => SupportedImportableExternalImageTypes;
@@ -72,13 +74,17 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
public unsafe IGlExternalImageTexture ImportImage(IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties)
{
- if (handle.HandleDescriptor != KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle)
+ if (!SupportedImportableExternalImageTypes.Contains(handle.HandleDescriptor))
throw new NotSupportedException("Unsupported external memory type");
using (_context.EnsureCurrent())
{
var guid = MicroComRuntime.GetGuidFor(typeof(ID3D11Texture2D));
- using var opened = _device.OpenSharedResource(handle.Handle, &guid);
+ using var opened =
+ handle.HandleDescriptor ==
+ KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle ?
+ _device.OpenSharedResource(handle.Handle, &guid) :
+ _device1.OpenSharedResource1(handle.Handle, &guid);
using var texture = opened.QueryInterface();
return new AngleExternalMemoryD3D11Texture2D(_context, texture, properties);
}
@@ -93,8 +99,8 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
return default;
}
- public byte[] DeviceLuid { get; }
- public byte[] DeviceUuid { get; }
+ public byte[]? DeviceLuid { get; }
+ public byte[]? DeviceUuid => null;
public void Dispose()
{
diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs
index 53bf2fb8b1..770a27386f 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs
@@ -1,4 +1,3 @@
-#nullable enable annotations
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -97,7 +96,7 @@ namespace Avalonia.Win32.OpenGl.Angle
DirectXUnmanagedMethods.D3D11CreateDevice(chosenAdapter?.GetNativeIntPtr() ?? IntPtr.Zero,
D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_UNKNOWN,
IntPtr.Zero, 0, featureLevels, (uint)featureLevels.Length,
- 7, out pD3dDevice, out var featureLevel, null);
+ 7, out pD3dDevice, out _, null);
if (pD3dDevice == IntPtr.Zero)
diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs
index a4d1ea457a..8ee6d286d1 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Logging;
using Avalonia.OpenGL;
@@ -12,11 +13,14 @@ namespace Avalonia.Win32.OpenGl.Angle;
internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphicsOpenGlContextFactory
{
private readonly Win32AngleEglInterface _egl;
- private AngleWin32EglDisplay _sharedDisplay;
- private EglContext _sharedContext;
- public bool UsesSharedContext => PlatformApi == AngleOptions.PlatformApi.DirectX9;
+ private readonly AngleWin32EglDisplay? _sharedDisplay;
+ private EglContext? _sharedContext;
+
+ [MemberNotNullWhen(true, nameof(_sharedDisplay))]
+ public bool UsesSharedContext => _sharedDisplay is not null;
+
+ public AngleOptions.PlatformApi PlatformApi { get; }
- public AngleOptions.PlatformApi PlatformApi { get; } = AngleOptions.PlatformApi.DirectX11;
public IPlatformGraphicsContext CreateContext()
{
if (UsesSharedContext)
@@ -72,7 +76,7 @@ internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphics
}
- public static AngleWin32PlatformGraphics TryCreate(AngleOptions options)
+ public static AngleWin32PlatformGraphics? TryCreate(AngleOptions? options)
{
Win32AngleEglInterface egl;
try
@@ -109,7 +113,7 @@ internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphics
}
else
{
- AngleWin32EglDisplay sharedDisplay = null;
+ AngleWin32EglDisplay? sharedDisplay = null;
try
{
sharedDisplay = AngleWin32EglDisplay.CreateD3D9Display(egl);
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs b/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
index b4002d8bc7..999818d709 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
@@ -7,22 +7,22 @@ using Avalonia.Platform;
using Avalonia.Reactive;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
-using static Avalonia.Win32.OpenGl.WglConsts;
namespace Avalonia.Win32.OpenGl
{
- class WglContext : IGlContext
+ internal class WglContext : IGlContext
{
- private object _lock = new object();
- private readonly WglContext _sharedWith;
+ private readonly object _lock = new();
+ private readonly WglContext? _sharedWith;
private readonly IntPtr _context;
private readonly IntPtr _hWnd;
private readonly IntPtr _dc;
private readonly int _pixelFormat;
private readonly PixelFormatDescriptor _formatDescriptor;
+
public IntPtr Handle => _context;
- public WglContext(WglContext sharedWith, GlVersion version, IntPtr context, IntPtr hWnd, IntPtr dc, int pixelFormat,
+ public WglContext(WglContext? sharedWith, GlVersion version, IntPtr context, IntPtr hWnd, IntPtr dc, int pixelFormat,
PixelFormatDescriptor formatDescriptor)
{
Version = version;
@@ -54,7 +54,7 @@ namespace Avalonia.Win32.OpenGl
public GlVersion Version { get; }
public GlInterface GlInterface { get; }
- public int SampleCount { get; }
+ public int SampleCount => 0;
public int StencilSize { get; }
private bool IsCurrent => wglGetCurrentContext() == _context && wglGetCurrentDC() == _dc;
@@ -97,12 +97,12 @@ namespace Avalonia.Win32.OpenGl
}
public bool CanCreateSharedContext => true;
- public IGlContext CreateSharedContext(IEnumerable preferredVersions = null)
+ public IGlContext? CreateSharedContext(IEnumerable? preferredVersions = null)
{
var versions = preferredVersions?.Append(Version).ToArray() ?? new[] { Version };
return WglDisplay.CreateContext(versions, _sharedWith ?? this);
}
- public object TryGetFeature(Type featureType) => null;
+ public object? TryGetFeature(Type featureType) => null;
}
}
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs
index 9a1963a97a..e207bc23ab 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Avalonia.OpenGL;
using Avalonia.Threading;
@@ -19,29 +20,31 @@ namespace Avalonia.Win32.OpenGl
private static int _defaultPixelFormat;
public static IntPtr OpenGl32Handle = LoadLibrary("opengl32");
- private delegate bool WglChoosePixelFormatARBDelegate(IntPtr hdc, int[] piAttribIList, float[] pfAttribFList,
+ private delegate bool WglChoosePixelFormatARBDelegate(IntPtr hdc, int[]? piAttribIList, float[]? pfAttribFList,
int nMaxFormats, int[] piFormats, out int nNumFormats);
- private static WglChoosePixelFormatARBDelegate WglChoosePixelFormatArb;
+ private static WglChoosePixelFormatARBDelegate? s_wglChoosePixelFormatArb;
- private delegate IntPtr WglCreateContextAttribsARBDelegate(IntPtr hDC, IntPtr hShareContext, int[] attribList);
+ private delegate IntPtr WglCreateContextAttribsARBDelegate(IntPtr hDC, IntPtr hShareContext, int[]? attribList);
- private static WglCreateContextAttribsARBDelegate WglCreateContextAttribsArb;
+ private static WglCreateContextAttribsARBDelegate? s_wglCreateContextAttribsArb;
private delegate void GlDebugMessageCallbackDelegate(IntPtr callback, IntPtr userParam);
- private static GlDebugMessageCallbackDelegate GlDebugMessageCallback;
+ private static GlDebugMessageCallbackDelegate? s_glDebugMessageCallback;
private delegate void DebugCallbackDelegate(int source, int type, int id, int severity, int len, IntPtr message,
IntPtr userParam);
-
- static bool Initialize()
- {
- if (!_initialized.HasValue)
- _initialized = InitializeCore();
- return _initialized.Value;
- }
- static bool InitializeCore()
+
+ [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))]
+ [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))]
+ [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))]
+ private static bool Initialize() => _initialized ??= InitializeCore();
+
+ [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))]
+ [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))]
+ [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))]
+ private static bool InitializeCore()
{
Dispatcher.UIThread.VerifyAccess();
_bootstrapWindow = WglGdiResourceManager.CreateOffscreenWindow();
@@ -64,20 +67,20 @@ namespace Avalonia.Win32.OpenGl
return false;
wglMakeCurrent(_bootstrapDc, _bootstrapContext);
- WglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer(
+ s_wglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer(
wglGetProcAddress("wglCreateContextAttribsARB"));
- WglChoosePixelFormatArb =
+ s_wglChoosePixelFormatArb =
Marshal.GetDelegateForFunctionPointer(
wglGetProcAddress("wglChoosePixelFormatARB"));
- GlDebugMessageCallback =
+ s_glDebugMessageCallback =
Marshal.GetDelegateForFunctionPointer(
wglGetProcAddress("glDebugMessageCallback"));
var formats = new int[1];
- WglChoosePixelFormatArb(_bootstrapDc, new int[]
+ s_wglChoosePixelFormatArb(_bootstrapDc, new int[]
{
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
@@ -106,12 +109,12 @@ namespace Avalonia.Win32.OpenGl
Console.Error.WriteLine(err);
}
- public static WglContext CreateContext(GlVersion[] versions, IGlContext share)
+ public static WglContext? CreateContext(GlVersion[] versions, IGlContext? share)
{
if (!Initialize())
return null;
- var shareContext = (WglContext)share;
+ var shareContext = share as WglContext;
using (new WglRestoreContext(_bootstrapDc, _bootstrapContext, null))
{
@@ -125,7 +128,7 @@ namespace Avalonia.Win32.OpenGl
IntPtr context;
using (shareContext?.Lock())
{
- context = WglCreateContextAttribsArb(dc, shareContext?.Handle ?? IntPtr.Zero,
+ context = s_wglCreateContextAttribsArb(dc, shareContext?.Handle ?? IntPtr.Zero,
new[]
{
// major
@@ -142,7 +145,7 @@ namespace Avalonia.Win32.OpenGl
}
using(new WglRestoreContext(dc, context, null))
- GlDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero);
+ s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero);
if (context != IntPtr.Zero)
return new WglContext(shareContext, version, context, window, dc,
_defaultPixelFormat, _defaultPfd);
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs b/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs
index ed40488c70..86143d078d 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs
@@ -17,45 +17,69 @@ namespace Avalonia.Win32.OpenGl;
internal class WglGdiResourceManager
{
- class GetDCOp
+ private class GetDCOp
{
- public IntPtr Window;
- public TaskCompletionSource Result;
+ public readonly IntPtr Window;
+ public readonly TaskCompletionSource Result;
+
+ public GetDCOp(IntPtr window, TaskCompletionSource result)
+ {
+ Window = window;
+ Result = result;
+ }
}
- class ReleaseDCOp
+ private class ReleaseDCOp
{
- public IntPtr Window;
- public IntPtr DC;
- public TaskCompletionSource Result;
+ public readonly IntPtr Window;
+ public readonly IntPtr DC;
+ public readonly TaskCompletionSource Result;
+
+ public ReleaseDCOp(IntPtr window, IntPtr dc, TaskCompletionSource result)
+ {
+ Window = window;
+ DC = dc;
+ Result = result;
+ }
}
-
- class CreateWindowOp
+
+ private class CreateWindowOp
{
- public TaskCompletionSource Result;
+ public readonly TaskCompletionSource Result;
+
+ public CreateWindowOp(TaskCompletionSource result)
+ {
+ Result = result;
+ }
}
- class DestroyWindowOp
+ private class DestroyWindowOp
{
- public IntPtr Window;
- public TaskCompletionSource Result;
+ public readonly IntPtr Window;
+ public readonly TaskCompletionSource Result;
+
+ public DestroyWindowOp(IntPtr window, TaskCompletionSource result)
+ {
+ Window = window;
+ Result = result;
+ }
}
- private static readonly Queue s_Queue = new();
- private static readonly AutoResetEvent s_Event = new(false);
- private static readonly ushort s_WindowClass;
+ private static readonly Queue s_queue = new();
+ private static readonly AutoResetEvent s_event = new(false);
+ private static readonly ushort s_windowClass;
private static readonly UnmanagedMethods.WndProc s_wndProcDelegate = WndProc;
- static void Worker()
+ private static void Worker()
{
while (true)
{
- s_Event.WaitOne();
- lock (s_Queue)
+ s_event.WaitOne();
+ lock (s_queue)
{
- if(s_Queue.Count == 0)
+ if(s_queue.Count == 0)
continue;
- var job = s_Queue.Dequeue();
+ var job = s_queue.Dequeue();
if (job is GetDCOp getDc)
getDc.Result.TrySetResult(UnmanagedMethods.GetDC(getDc.Window));
else if (job is ReleaseDCOp releaseDc)
@@ -66,7 +90,7 @@ internal class WglGdiResourceManager
else if (job is CreateWindowOp createWindow)
createWindow.Result.TrySetResult(UnmanagedMethods.CreateWindowEx(
0,
- s_WindowClass,
+ s_windowClass,
null,
(int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW,
0,
@@ -97,16 +121,15 @@ internal class WglGdiResourceManager
style = (int)UnmanagedMethods.ClassStyles.CS_OWNDC
};
- s_WindowClass = UnmanagedMethods.RegisterClassEx(ref wndClassEx);
+ s_windowClass = UnmanagedMethods.RegisterClassEx(ref wndClassEx);
var th = new Thread(Worker) { IsBackground = true, Name = "Win32 OpenGL HDC manager" };
// This makes CLR to automatically pump the event queue from WaitOne
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
-
-
-
- static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
+
+
+ private static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
}
@@ -114,53 +137,36 @@ internal class WglGdiResourceManager
public static IntPtr CreateOffscreenWindow()
{
var tcs = new TaskCompletionSource();
- lock(s_Queue)
- s_Queue.Enqueue(new CreateWindowOp()
- {
- Result = tcs
- });
- s_Event.Set();
+ lock (s_queue)
+ s_queue.Enqueue(new CreateWindowOp(tcs));
+ s_event.Set();
return tcs.Task.Result;
}
public static IntPtr GetDC(IntPtr hWnd)
{
var tcs = new TaskCompletionSource();
- lock(s_Queue)
- s_Queue.Enqueue(new GetDCOp
- {
- Window = hWnd,
- Result = tcs
- });
- s_Event.Set();
+ lock (s_queue)
+ s_queue.Enqueue(new GetDCOp(hWnd, tcs));
+ s_event.Set();
return tcs.Task.Result;
}
public static void ReleaseDC(IntPtr hWnd, IntPtr hDC)
{
- var tcs = new TaskCompletionSource();
- lock(s_Queue)
- s_Queue.Enqueue(new ReleaseDCOp()
- {
- Window = hWnd,
- DC = hDC,
- Result = tcs
- });
- s_Event.Set();
+ var tcs = new TaskCompletionSource();
+ lock (s_queue)
+ s_queue.Enqueue(new ReleaseDCOp(hWnd, hDC, tcs));
+ s_event.Set();
tcs.Task.Wait();
}
public static void DestroyWindow(IntPtr hWnd)
{
- var tcs = new TaskCompletionSource();
- lock(s_Queue)
- s_Queue.Enqueue(new DestroyWindowOp()
- {
- Window = hWnd,
- Result = tcs
- });
- s_Event.Set();
+ var tcs = new TaskCompletionSource();
+ lock (s_queue)
+ s_queue.Enqueue(new DestroyWindowOp(hWnd, tcs));
+ s_event.Set();
tcs.Task.Wait();
-
}
}
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs b/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs
index 39dd330d52..61b932e9c7 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs
@@ -6,27 +6,31 @@ using Avalonia.Platform;
namespace Avalonia.Win32.OpenGl
{
- class WglPlatformOpenGlInterface : IPlatformGraphics
+ internal class WglPlatformOpenGlInterface : IPlatformGraphics
{
public WglContext PrimaryContext { get; }
public bool UsesSharedContext => false;
IPlatformGraphicsContext IPlatformGraphics.CreateContext() => CreateContext();
public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException();
-
- public IGlContext CreateContext() => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, null);
- private WglPlatformOpenGlInterface(WglContext primary)
+ public IGlContext CreateContext()
+ => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, null)
+ ?? throw new OpenGlException("Unable to create additional WGL context");
+
+ private WglPlatformOpenGlInterface(WglContext primary)
{
PrimaryContext = primary;
}
- public static WglPlatformOpenGlInterface TryCreate()
+ public static WglPlatformOpenGlInterface? TryCreate()
{
try
{
var opts = AvaloniaLocator.Current.GetService() ?? new Win32PlatformOptions();
- var primary = WglDisplay.CreateContext(opts.WglProfiles.ToArray(), null);
- return new WglPlatformOpenGlInterface(primary);
+ if (WglDisplay.CreateContext(opts.WglProfiles.ToArray(), null) is { } primary)
+ {
+ return new WglPlatformOpenGlInterface(primary);
+ }
}
catch (Exception e)
{
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs b/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs
index b145ffbb37..ee0934af7d 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs
@@ -8,11 +8,11 @@ namespace Avalonia.Win32.OpenGl
{
internal class WglRestoreContext : IDisposable
{
- private readonly object _monitor;
+ private readonly object? _monitor;
private readonly IntPtr _oldDc;
private readonly IntPtr _oldContext;
- public WglRestoreContext(IntPtr gc, IntPtr context, object monitor, bool takeMonitor = true)
+ public WglRestoreContext(IntPtr gc, IntPtr context, object? monitor, bool takeMonitor = true)
{
_monitor = monitor;
_oldDc = wglGetCurrentDC();
diff --git a/src/Windows/Avalonia.Win32/PlatformConstants.cs b/src/Windows/Avalonia.Win32/PlatformConstants.cs
index 9dd4780637..48dd9f45da 100644
--- a/src/Windows/Avalonia.Win32/PlatformConstants.cs
+++ b/src/Windows/Avalonia.Win32/PlatformConstants.cs
@@ -7,7 +7,7 @@ namespace Avalonia.Win32
public const string WindowHandleType = "HWND";
public const string CursorHandleType = "HCURSOR";
- public static readonly Version Windows8 = new Version(6, 2);
- public static readonly Version Windows7 = new Version(6, 1);
+ internal static readonly Version Windows8 = new Version(6, 2);
+ internal static readonly Version Windows7 = new Version(6, 1);
}
}
diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs
index 3a56af12f0..75c1a2d564 100644
--- a/src/Windows/Avalonia.Win32/PopupImpl.cs
+++ b/src/Windows/Avalonia.Win32/PopupImpl.cs
@@ -5,9 +5,9 @@ using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
- class PopupImpl : WindowImpl, IPopupImpl
+ internal class PopupImpl : WindowImpl, IPopupImpl
{
- private readonly IWindowBaseImpl _parent;
+ private readonly IWindowBaseImpl? _parent;
private bool _dropShadowHint = true;
private Size? _maxAutoSize;
@@ -92,7 +92,7 @@ namespace Avalonia.Win32
IntPtr.Zero);
s_parentHandle = IntPtr.Zero;
- PopupImpl.EnableBoxShadow(result, _dropShadowHint);
+ EnableBoxShadow(result, _dropShadowHint);
return result;
}
@@ -113,7 +113,7 @@ namespace Avalonia.Win32
// This is needed because we are calling virtual methods from constructors
// One fabulous design decision leads to another, I guess
- static IWindowBaseImpl SaveParentHandle(IWindowBaseImpl parent)
+ private static IWindowBaseImpl SaveParentHandle(IWindowBaseImpl parent)
{
s_parentHandle = parent.Handle.Handle;
return parent;
@@ -126,7 +126,7 @@ namespace Avalonia.Win32
}
- private PopupImpl(IWindowBaseImpl parent, bool dummy) : base()
+ private PopupImpl(IWindowBaseImpl parent, bool dummy)
{
_parent = parent;
PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(parent, MoveResize));
@@ -159,10 +159,7 @@ namespace Avalonia.Win32
{
_dropShadowHint = enabled;
- if (Handle != null)
- {
- PopupImpl.EnableBoxShadow(Handle.Handle, enabled);
- }
+ EnableBoxShadow(Handle.Handle, enabled);
}
public IPopupPositioner PopupPositioner { get; }
diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs
index f3754cd58f..6154dff307 100644
--- a/src/Windows/Avalonia.Win32/ScreenImpl.cs
+++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs
@@ -3,20 +3,21 @@ using System.Collections.Generic;
using System.Linq;
using Avalonia.Metadata;
using Avalonia.Platform;
-using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
{
- [Unstable]
- public class ScreenImpl : IScreenImpl
+ internal class ScreenImpl : IScreenImpl
{
+ private Screen[]? _allScreens;
+
+ ///
public int ScreenCount
{
get => GetSystemMetrics(SystemMetric.SM_CMONITORS);
}
- private Screen[] _allScreens;
+ ///
public IReadOnlyList AllScreens
{
get
@@ -38,7 +39,7 @@ namespace Avalonia.Win32
if (method != IntPtr.Zero)
{
GetDpiForMonitor(monitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var x, out _);
- dpi = (double)x;
+ dpi = x;
}
else
{
@@ -74,7 +75,8 @@ namespace Avalonia.Win32
_allScreens = null;
}
- public Screen ScreenFromWindow(IWindowBaseImpl window)
+ ///
+ public Screen? ScreenFromWindow(IWindowBaseImpl window)
{
var handle = window.Handle.Handle;
@@ -83,7 +85,8 @@ namespace Avalonia.Win32
return FindScreenByHandle(monitor);
}
- public Screen ScreenFromPoint(PixelPoint point)
+ ///
+ public Screen? ScreenFromPoint(PixelPoint point)
{
var monitor = MonitorFromPoint(new POINT
{
@@ -94,7 +97,8 @@ namespace Avalonia.Win32
return FindScreenByHandle(monitor);
}
- public Screen ScreenFromRect(PixelRect rect)
+ ///
+ public Screen? ScreenFromRect(PixelRect rect)
{
var monitor = MonitorFromRect(new RECT
{
@@ -107,7 +111,7 @@ namespace Avalonia.Win32
return FindScreenByHandle(monitor);
}
- private Screen FindScreenByHandle(IntPtr handle)
+ private Screen? FindScreenByHandle(IntPtr handle)
{
return AllScreens.Cast().FirstOrDefault(m => m.Handle == handle);
}
diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs
index ab70d77a09..c19439c09e 100644
--- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs
+++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs
@@ -11,12 +11,9 @@ using Avalonia.Styling;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
-#nullable enable
-
namespace Avalonia.Win32
{
- [Unstable]
- public class TrayIconImpl : ITrayIconImpl
+ internal class TrayIconImpl : ITrayIconImpl
{
private static readonly IntPtr s_emptyIcon = new System.Drawing.Bitmap(32, 32).GetHicon();
private readonly int _uniqueId;
@@ -25,9 +22,9 @@ namespace Avalonia.Win32
private IconImpl? _icon;
private string? _tooltipText;
private readonly Win32NativeToManagedMenuExporter _exporter;
- private static readonly Dictionary s_trayIcons = new Dictionary();
+ private static readonly Dictionary s_trayIcons = new();
private bool _disposedValue;
- private static readonly uint WM_TASKBARCREATED = UnmanagedMethods.RegisterWindowMessage("TaskbarCreated");
+ private static readonly uint WM_TASKBARCREATED = RegisterWindowMessage("TaskbarCreated");
public TrayIconImpl()
{
@@ -62,17 +59,20 @@ namespace Avalonia.Win32
}
}
+ ///
public void SetIcon(IWindowIconImpl? icon)
{
_icon = icon as IconImpl;
UpdateIcon();
}
+ ///
public void SetIsVisible(bool visible)
{
UpdateIcon(!visible);
}
+ ///
public void SetToolTipText(string? text)
{
_tooltipText = text;
@@ -81,19 +81,18 @@ namespace Avalonia.Win32
private void UpdateIcon(bool remove = false)
{
- var iconData = new NOTIFYICONDATA()
+ var iconData = new NOTIFYICONDATA
{
hWnd = Win32Platform.Instance.Handle,
- uID = _uniqueId,
- uFlags = NIF.TIP | NIF.MESSAGE,
- uCallbackMessage = (int)CustomWindowsMessage.WM_TRAYMOUSE,
- hIcon = _icon?.HIcon ?? s_emptyIcon,
- szTip = _tooltipText ?? ""
+ uID = _uniqueId
};
if (!remove)
{
- iconData.uFlags |= NIF.ICON;
+ iconData.uFlags = NIF.TIP | NIF.MESSAGE | NIF.ICON;
+ iconData.uCallbackMessage = (int)CustomWindowsMessage.WM_TRAYMOUSE;
+ iconData.hIcon = _icon?.HIcon ?? s_emptyIcon;
+ iconData.szTip = _tooltipText ?? "";
if (!_iconAdded)
{
@@ -107,6 +106,7 @@ namespace Avalonia.Win32
}
else
{
+ iconData.uFlags = 0;
Shell_NotifyIcon(NIM.DELETE, iconData);
_iconAdded = false;
}
@@ -209,8 +209,11 @@ namespace Avalonia.Win32
private void MoveResize(PixelPoint position, Size size, double scaling)
{
- PlatformImpl!.Move(position);
- PlatformImpl!.Resize(size, PlatformResizeReason.Layout);
+ if (PlatformImpl is { } platformImpl)
+ {
+ platformImpl.Move(position);
+ platformImpl.Resize(size, PlatformResizeReason.Layout);
+ }
}
protected override void ArrangeCore(Rect finalRect)
@@ -221,7 +224,7 @@ namespace Avalonia.Win32
{
Anchor = PopupAnchor.TopLeft,
Gravity = PopupGravity.BottomRight,
- AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.Scaling, new Size(1, 1)),
+ AnchorRectangle = new Rect(Position.ToPoint(Screens.Primary?.Scaling ?? 1.0), new Size(1, 1)),
Size = finalRect.Size,
ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY,
});
@@ -247,18 +250,22 @@ namespace Avalonia.Win32
{
get
{
- var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft;
- var size = _hiddenWindow.Screens.Primary.Bounds.Size;
- return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.Scaling, size.Height * _hiddenWindow.Screens.Primary.Scaling);
+ if (_hiddenWindow.Screens.Primary is { } screen)
+ {
+ var point = screen.Bounds.TopLeft;
+ var size = screen.Bounds.Size;
+ return new Rect(point.X, point.Y, size.Width * screen.Scaling, size.Height * screen.Scaling);
+ }
+ return default;
}
}
public void MoveAndResize(Point devicePoint, Size virtualSize)
{
- _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.Scaling);
+ _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, Scaling);
}
- public double Scaling => _hiddenWindow.Screens.Primary.Scaling;
+ public double Scaling => _hiddenWindow.Screens.Primary?.Scaling ?? 1.0;
}
}
diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs
index ab6de1a027..c26ce5fd45 100644
--- a/src/Windows/Avalonia.Win32/Win32GlManager.cs
+++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs
@@ -1,6 +1,4 @@
using Avalonia.OpenGL;
-using Avalonia.OpenGL.Angle;
-using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Win32.DirectX;
using Avalonia.Win32.OpenGl;
@@ -11,16 +9,19 @@ namespace Avalonia.Win32
{
static class Win32GlManager
{
-
- public static IPlatformGraphics Initialize()
+ public static IPlatformGraphics? Initialize()
{
var gl = InitializeCore();
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl);
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl);
+
+ if (gl is not null)
+ {
+ AvaloniaLocator.CurrentMutable.Bind