Browse Source

Merge branch 'master' into fast-theme-switching-fluent-theme

pull/7256/head
Max Katz 5 years ago
committed by GitHub
parent
commit
3b22aefb99
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/Avalonia/Avalonia.csproj
  2. 6
      readme.md
  3. 8
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  4. 3
      src/Android/Avalonia.Android/AndroidPlatform.cs
  5. 56
      src/Android/Avalonia.Android/Stubs.cs
  6. 2
      src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
  7. 2
      src/Avalonia.Animation/Avalonia.Animation.csproj
  8. 2
      src/Avalonia.Base/Avalonia.Base.csproj
  9. 10
      src/Avalonia.Base/AvaloniaLocator.cs
  10. 6
      src/Avalonia.Base/Threading/Dispatcher.cs
  11. 2
      src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
  12. 2
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  13. 2
      src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
  14. 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  15. 17
      src/Avalonia.Controls/Button.cs
  16. 68
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  17. 2
      src/Avalonia.Controls/Grid.cs
  18. 9
      src/Avalonia.Controls/SystemDialog.cs
  19. 2
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  20. 2
      src/Avalonia.Desktop/Avalonia.Desktop.csproj
  21. 2
      src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj
  22. 2
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  23. 7
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs
  24. 2
      src/Avalonia.Dialogs/Avalonia.Dialogs.csproj
  25. 2
      src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
  26. 2
      src/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj
  27. 2
      src/Avalonia.Headless/Avalonia.Headless.csproj
  28. 2
      src/Avalonia.Input/AccessKeyHandler.cs
  29. 2
      src/Avalonia.Input/Avalonia.Input.csproj
  30. 4
      src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs
  31. 18
      src/Avalonia.Input/Gestures.cs
  32. 2
      src/Avalonia.Input/InputElement.cs
  33. 2
      src/Avalonia.Input/Pointer.cs
  34. 9
      src/Avalonia.Input/PointerEventArgs.cs
  35. 44
      src/Avalonia.Input/TouchDevice.cs
  36. 2
      src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
  37. 6
      src/Avalonia.Layout/AttachedLayout.cs
  38. 3
      src/Avalonia.Layout/Avalonia.Layout.csproj
  39. 46
      src/Avalonia.Layout/ElementManager.cs
  40. 68
      src/Avalonia.Layout/FlowLayoutAlgorithm.cs
  41. 4
      src/Avalonia.Layout/IFlowLayoutAlgorithmDelegates.cs
  42. 4
      src/Avalonia.Layout/LayoutContext.cs
  43. 2
      src/Avalonia.Layout/LayoutContextAdapter.cs
  44. 2
      src/Avalonia.Layout/LayoutHelper.cs
  45. 1
      src/Avalonia.Layout/LayoutQueue.cs
  46. 2
      src/Avalonia.Layout/Layoutable.cs
  47. 4
      src/Avalonia.Layout/NonVirtualizingLayoutContext.cs
  48. 22
      src/Avalonia.Layout/StackLayout.cs
  49. 26
      src/Avalonia.Layout/UniformGridLayout.cs
  50. 2
      src/Avalonia.Layout/UniformGridLayoutState.cs
  51. 5
      src/Avalonia.Layout/Utils/ListUtils.cs
  52. 4
      src/Avalonia.Layout/VirtualLayoutContextAdapter.cs
  53. 2
      src/Avalonia.Layout/VirtualizingLayoutContext.cs
  54. 2
      src/Avalonia.Layout/WrapLayout/UvMeasure.cs
  55. 2
      src/Avalonia.Layout/WrapLayout/WrapItem.cs
  56. 6
      src/Avalonia.Layout/WrapLayout/WrapLayout.cs
  57. 9
      src/Avalonia.Layout/WrapLayout/WrapLayoutState.cs
  58. 2
      src/Avalonia.Native/Avalonia.Native.csproj
  59. 7
      src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
  60. 5
      src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
  61. 2
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  62. 2
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  63. 2
      src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj
  64. 3
      src/Avalonia.Styling/Avalonia.Styling.csproj
  65. 12
      src/Avalonia.Styling/Controls/ChildNameScope.cs
  66. 4
      src/Avalonia.Styling/Controls/INameScope.cs
  67. 30
      src/Avalonia.Styling/Controls/NameScope.cs
  68. 28
      src/Avalonia.Styling/Controls/NameScopeExtensions.cs
  69. 8
      src/Avalonia.Styling/Controls/NameScopeLocator.cs
  70. 2
      src/Avalonia.Styling/Controls/PseudoClassesExtensions.cs
  71. 2
      src/Avalonia.Styling/Controls/ResourceDictionary.cs
  72. 6
      src/Avalonia.Styling/Controls/ResourceNodeExtensions.cs
  73. 2
      src/Avalonia.Styling/INamed.cs
  74. 16
      src/Avalonia.Styling/LogicalTree/ControlLocator.cs
  75. 6
      src/Avalonia.Styling/LogicalTree/ILogical.cs
  76. 26
      src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs
  77. 7
      src/Avalonia.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs
  78. 18
      src/Avalonia.Styling/StyledElement.cs
  79. 2
      src/Avalonia.Styling/Styling/Activators/NthChildActivator.cs
  80. 2
      src/Avalonia.Styling/Styling/Activators/StyleClassActivator.cs
  81. 6
      src/Avalonia.Styling/Styling/ChildSelector.cs
  82. 2
      src/Avalonia.Styling/Styling/OrSelector.cs
  83. 7
      src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs
  84. 50
      src/Avalonia.Styling/Styling/Selectors.cs
  85. 14
      src/Avalonia.Styling/Styling/Styles.cs
  86. 6
      src/Avalonia.Styling/Styling/TemplateSelector.cs
  87. 2
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  88. 6
      src/Avalonia.Themes.Default/CalendarDatePicker.xaml
  89. 2
      src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj
  90. 6
      src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
  91. 2
      src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs
  92. 4
      src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs
  93. 2
      src/Avalonia.Visuals/Animation/CompositePageTransition.cs
  94. 6
      src/Avalonia.Visuals/Animation/CrossFade.cs
  95. 2
      src/Avalonia.Visuals/Animation/IPageTransition.cs
  96. 10
      src/Avalonia.Visuals/Animation/PageSlide.cs
  97. 2
      src/Avalonia.Visuals/Animation/RenderLoopClock.cs
  98. 4
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  99. 3
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  100. 2
      src/Avalonia.Visuals/CornerRadius.cs

2
packages/Avalonia/Avalonia.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461;netcoreapp2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0;net461;netcoreapp2.0</TargetFrameworks>
<PackageId>Avalonia</PackageId>
</PropertyGroup>

6
readme.md

@ -75,6 +75,12 @@ For more information see the [.NET Foundation Code of Conduct](https://dotnetfou
Avalonia is licenced under the [MIT licence](licence.md).
## Support Avalonia
**BTC**: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx
This will be shared with the community and awarded for significant contributions.
### Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)]

8
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -32,7 +32,7 @@
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<AotAssemblies>False</AotAssemblies>
@ -51,7 +51,7 @@
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidSupportedAbis>armeabi-v7a,x86;x86_64</AndroidSupportedAbis>
<Debugger>Xamarin</Debugger>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
@ -125,6 +125,10 @@
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj">
<Project>{c42d2fc1-a531-4ed4-84b9-89aec7c962fc}</Project>
<Name>Avalonia.Themes.Fluent</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>

3
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -43,11 +43,12 @@ namespace Avalonia.Android
AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToTransient<ClipboardImpl>()
.Bind<ICursorFactory>().ToTransient<CursorFactory>()
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformStub())
.Bind<IKeyboardDevice>().ToSingleton<AndroidKeyboardDevice>()
.Bind<IPlatformSettings>().ToConstant(Instance)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()

56
src/Android/Avalonia.Android/Stubs.cs

@ -0,0 +1,56 @@
using System;
using System.IO;
using Avalonia.Platform;
namespace Avalonia.Android
{
class WindowingPlatformStub : IWindowingPlatform
{
public IWindowImpl CreateWindow() => throw new NotSupportedException();
public IWindowImpl CreateEmbeddableWindow() => throw new NotSupportedException();
public ITrayIconImpl CreateTrayIcon() => null;
}
class PlatformIconLoaderStub : IPlatformIconLoader
{
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
{
using (var stream = new MemoryStream())
{
bitmap.Save(stream);
return LoadIcon(stream);
}
}
public IWindowIconImpl LoadIcon(Stream stream)
{
var ms = new MemoryStream();
stream.CopyTo(ms);
return new IconStub(ms);
}
public IWindowIconImpl LoadIcon(string fileName)
{
using (var file = File.Open(fileName, FileMode.Open))
return LoadIcon(file);
}
}
public class IconStub : IWindowIconImpl
{
private readonly MemoryStream _ms;
public IconStub(MemoryStream stream)
{
_ms = stream;
}
public void Save(Stream outputStream)
{
_ms.Position = 0;
_ms.CopyTo(outputStream);
}
}
}

2
src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs

@ -14,7 +14,7 @@ namespace Avalonia.AndroidTestApplication
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")]
public partial class Resource
{

2
src/Avalonia.Animation/Avalonia.Animation.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />

2
src/Avalonia.Base/Avalonia.Base.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AssemblyName>Avalonia.Base</AssemblyName>
<RootNamespace>Avalonia</RootNamespace>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>

10
src/Avalonia.Base/AvaloniaLocator.cs

@ -125,6 +125,16 @@ namespace Avalonia
{
return (T?) resolver.GetService(typeof (T));
}
public static object GetRequiredService(this IAvaloniaDependencyResolver resolver, Type t)
{
return resolver.GetService(t) ?? throw new InvalidOperationException($"Unable to locate '{t}'.");
}
public static T GetRequiredService<T>(this IAvaloniaDependencyResolver resolver)
{
return (T?)resolver.GetService(typeof(T)) ?? throw new InvalidOperationException($"Unable to locate '{typeof(T)}'.");
}
}
}

6
src/Avalonia.Base/Threading/Dispatcher.cs

@ -56,11 +56,7 @@ namespace Avalonia.Threading
/// </param>
public void MainLoop(CancellationToken cancellationToken)
{
var platform = AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>();
if (platform is null)
throw new InvalidOperationException("Unable to locate IPlatformThreadingInterface");
var platform = AvaloniaLocator.Current.GetRequiredService<IPlatformThreadingInterface>();
cancellationToken.Register(() => platform.Signal(DispatcherPriority.Send));
platform.RunLoop(cancellationToken);
}

2
src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs

@ -180,7 +180,7 @@ namespace Avalonia.Utilities
{
var r = _data[c];
if (r?.TryGetTarget(out var sub) == true)
sub.OnEvent(sender, eventArgs);
sub!.OnEvent(sender, eventArgs);
else
needCompact = true;
}

2
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -6,7 +6,7 @@
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
<DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>
<CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies>
<NoWarn>NU1605</NoWarn>
<NoWarn>NU1605;CS8632</NoWarn>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<PackageId>Avalonia.Controls.DataGrid</PackageId>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />

17
src/Avalonia.Controls/Button.cs

@ -304,15 +304,18 @@ namespace Avalonia.Controls
/// </summary>
protected virtual void OnClick()
{
OpenFlyout();
if (IsEffectivelyEnabled)
{
OpenFlyout();
var e = new RoutedEventArgs(ClickEvent);
RaiseEvent(e);
var e = new RoutedEventArgs(ClickEvent);
RaiseEvent(e);
if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
{
Command.Execute(CommandParameter);
e.Handled = true;
if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
{
Command.Execute(CommandParameter);
e.Handled = true;
}
}
}

68
src/Avalonia.Controls/Calendar/CalendarDatePicker.cs

@ -1,4 +1,4 @@
// (c) Copyright Microsoft Corporation.
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
@ -425,9 +425,6 @@ namespace Avalonia.Controls
{
FocusableProperty.OverrideDefaultValue<CalendarDatePicker>(true);
DisplayDateProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnDisplayDateChanged(e));
DisplayDateStartProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnDisplayDateStartChanged(e));
DisplayDateEndProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnDisplayDateEndChanged(e));
IsDropDownOpenProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnIsDropDownOpenChanged(e));
SelectedDateProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnSelectedDateChanged(e));
SelectedDateFormatProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnSelectedDateFormatChanged(e));
@ -459,18 +456,12 @@ namespace Avalonia.Controls
if (_calendar != null)
{
_calendar.SelectionMode = CalendarSelectionMode.SingleDate;
_calendar.SelectedDate = SelectedDate;
SetCalendarDisplayDate(DisplayDate);
SetCalendarDisplayDateStart(DisplayDateStart);
SetCalendarDisplayDateEnd(DisplayDateEnd);
_calendar.DayButtonMouseUp += Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged += Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
_calendar.PointerReleased += Calendar_PointerReleased;
_calendar.KeyDown += Calendar_KeyDown;
//_calendar.SizeChanged += new SizeChangedEventHandler(Calendar_SizeChanged);
//_calendar.IsTabStop = true;
var currentBlackoutDays = BlackoutDates;
BlackoutDates = _calendar.BlackoutDates;
@ -587,58 +578,6 @@ namespace Avalonia.Controls
SetSelectedDate();
}
private void SetCalendarDisplayDate(DateTime value)
{
if (DateTimeHelper.CompareYearMonth(_calendar.DisplayDate, value) != 0)
{
_calendar.DisplayDate = DisplayDate;
if (DateTime.Compare(_calendar.DisplayDate, DisplayDate) != 0)
{
DisplayDate = _calendar.DisplayDate;
}
}
}
private void OnDisplayDateChanged(AvaloniaPropertyChangedEventArgs e)
{
if (_calendar != null)
{
var value = (DateTime)e.NewValue;
SetCalendarDisplayDate(value);
}
}
private void SetCalendarDisplayDateStart(DateTime? value)
{
_calendar.DisplayDateStart = value;
if (_calendar.DisplayDateStart.HasValue && DisplayDateStart.HasValue && DateTime.Compare(_calendar.DisplayDateStart.Value, DisplayDateStart.Value) != 0)
{
DisplayDateStart = _calendar.DisplayDateStart;
}
}
private void OnDisplayDateStartChanged(AvaloniaPropertyChangedEventArgs e)
{
if (_calendar != null)
{
var value = (DateTime?)e.NewValue;
SetCalendarDisplayDateStart(value);
}
}
private void SetCalendarDisplayDateEnd(DateTime? value)
{
_calendar.DisplayDateEnd = value;
if (_calendar.DisplayDateEnd.HasValue && DisplayDateEnd.HasValue && DateTime.Compare(_calendar.DisplayDateEnd.Value, DisplayDateEnd.Value) != 0)
{
DisplayDateEnd = _calendar.DisplayDateEnd;
}
}
private void OnDisplayDateEndChanged(AvaloniaPropertyChangedEventArgs e)
{
if (_calendar != null)
{
var value = (DateTime?)e.NewValue;
SetCalendarDisplayDateEnd(value);
}
}
private void OnIsDropDownOpenChanged(AvaloniaPropertyChangedEventArgs e)
{
var oldValue = (bool)e.OldValue;
@ -670,11 +609,6 @@ namespace Avalonia.Controls
var addedDate = (DateTime?)e.NewValue;
var removedDate = (DateTime?)e.OldValue;
if (_calendar != null && addedDate != _calendar.SelectedDate)
{
_calendar.SelectedDate = addedDate;
}
if (SelectedDate != null)
{
DateTime day = SelectedDate.Value;

2
src/Avalonia.Controls/Grid.cs

@ -978,7 +978,7 @@ namespace Avalonia.Controls
/// width is not registered in columns.</param>
/// <param name="forceInfinityV">Passed through to MeasureCell.
/// When "true" cells' desired height is not registered in rows.</param>
/// <param name="hasDesiredSizeUChanged">return true when desired size has changed</param>
/// <param name="hasDesiredSizeUChanged">When the method exits, indicates whether the desired size has changed.</param>
private void MeasureCellsGroup(
int cellsHead,
Size referenceSize,

9
src/Avalonia.Controls/SystemDialog.cs

@ -66,8 +66,7 @@ namespace Avalonia.Controls
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
var service = AvaloniaLocator.Current.GetService<ISystemDialogImpl>() ??
throw new InvalidOperationException("Unable to locate ISystemDialogImpl.");
var service = AvaloniaLocator.Current.GetRequiredService<ISystemDialogImpl>();
return (await service.ShowFileDialogAsync(this, parent) ??
Array.Empty<string>()).FirstOrDefault();
}
@ -95,8 +94,7 @@ namespace Avalonia.Controls
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
var service = AvaloniaLocator.Current.GetService<ISystemDialogImpl>() ??
throw new InvalidOperationException("Unable to locate ISystemDialogImpl.");
var service = AvaloniaLocator.Current.GetRequiredService<ISystemDialogImpl>();
return service.ShowFileDialogAsync(this, parent);
}
}
@ -125,8 +123,7 @@ namespace Avalonia.Controls
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
var service = AvaloniaLocator.Current.GetService<ISystemDialogImpl>() ??
throw new InvalidOperationException("Unable to locate ISystemDialogImpl.");
var service = AvaloniaLocator.Current.GetRequiredService<ISystemDialogImpl>();
return service.ShowFolderDialogAsync(this, parent);
}
}

2
src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<!-- WARNING! The designer support version number needs to be frozen
To allow projects that implement designer functionality to still
work with newer versions of Avalonia. This version number only

2
src/Avalonia.Desktop/Avalonia.Desktop.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<PackageId>Avalonia.Desktop</PackageId>
</PropertyGroup>

2
src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;net461;netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia</RootNamespace>
<PackageId>Avalonia.Diagnostics</PackageId>
</PropertyGroup>

7
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs

@ -86,14 +86,15 @@ namespace Avalonia.Diagnostics.ViewModels
public void SelectControl(IControl control)
{
var node = default(TreeNode);
IControl? c = control;
while (node == null && control != null)
while (node == null && c != null)
{
node = FindNode(control);
node = FindNode(c);
if (node == null)
{
control = control.GetVisualParent<IControl>();
c = c.GetVisualParent<IControl>();
}
}

2
src/Avalonia.Dialogs/Avalonia.Dialogs.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.Headless/Avalonia.Headless.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

2
src/Avalonia.Input/AccessKeyHandler.cs

@ -188,7 +188,7 @@ namespace Avalonia.Input
// If the menu is open, only match controls in the menu's visual tree.
if (menuIsOpen)
{
matches = matches.Where(x => MainMenu.IsVisualAncestorOf(x));
matches = matches.Where(x => x is not null && MainMenu!.IsVisualAncestorOf(x));
}
var match = matches.FirstOrDefault();

2
src/Avalonia.Input/Avalonia.Input.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />

4
src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs

@ -71,7 +71,7 @@ namespace Avalonia.Input.GestureRecognizers
EndGesture();
_tracking = e.Pointer;
_gestureId = ScrollGestureEventArgs.GetNextFreeId();;
_trackedRootPoint = e.GetPosition(null);
_trackedRootPoint = e.GetPosition(_target);
}
}
@ -85,7 +85,7 @@ namespace Avalonia.Input.GestureRecognizers
{
if (e.Pointer == _tracking)
{
var rootPoint = e.GetPosition(null);
var rootPoint = e.GetPosition(_target);
if (!_scrolling)
{
if (CanHorizontallyScroll && Math.Abs(_trackedRootPoint.X - rootPoint.X) > ScrollStartDistance)

18
src/Avalonia.Input/Gestures.cs

@ -6,6 +6,7 @@ namespace Avalonia.Input
{
public static class Gestures
{
private static bool s_isDoubleTapped = false;
public static readonly RoutedEvent<TappedEventArgs> TappedEvent = RoutedEvent.Register<TappedEventArgs>(
"Tapped",
RoutingStrategies.Bubble,
@ -81,20 +82,23 @@ namespace Avalonia.Input
var e = (PointerPressedEventArgs)ev;
var visual = (IVisual)ev.Source;
#pragma warning disable CS0618 // Type or member is obsolete
var clickCount = e.ClickCount;
#pragma warning restore CS0618 // Type or member is obsolete
if (clickCount <= 1)
if (e.ClickCount <= 1)
{
s_isDoubleTapped = false;
s_lastPress.SetTarget(ev.Source);
}
else if (clickCount == 2 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
else if (e.ClickCount % 2 == 0 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
if (s_lastPress.TryGetTarget(out var target) && target == e.Source)
{
s_isDoubleTapped = true;
e.Source.RaiseEvent(new TappedEventArgs(DoubleTappedEvent, e));
}
}
else
{
s_isDoubleTapped = false;
}
}
}
@ -112,7 +116,9 @@ namespace Avalonia.Input
{
e.Source.RaiseEvent(new TappedEventArgs(RightTappedEvent, e));
}
else
//s_isDoubleTapped needed here to prevent invoking Tapped event when DoubleTapped is called.
//This behaviour matches UWP behaviour.
else if (s_isDoubleTapped == false)
{
e.Source.RaiseEvent(new TappedEventArgs(TappedEvent, e));
}

2
src/Avalonia.Input/InputElement.cs

@ -675,7 +675,7 @@ namespace Avalonia.Input
/// <see cref="IsEffectivelyEnabled"/>.
/// </summary>
/// <param name="parent">The parent control.</param>
private void UpdateIsEffectivelyEnabled(InputElement parent)
private void UpdateIsEffectivelyEnabled(InputElement? parent)
{
IsEffectivelyEnabled = IsEnabledCore && (parent?.IsEffectivelyEnabled ?? true);

2
src/Avalonia.Input/Pointer.cs

@ -54,7 +54,7 @@ namespace Avalonia.Input
Captured.DetachedFromVisualTree += OnCaptureDetached;
}
IInputElement GetNextCapture(IVisual parent)
IInputElement? GetNextCapture(IVisual parent)
{
return parent as IInputElement ?? parent.FindAncestorOfType<IInputElement>();
}

9
src/Avalonia.Input/PointerEventArgs.cs

@ -114,7 +114,7 @@ namespace Avalonia.Input
public class PointerPressedEventArgs : PointerEventArgs
{
private readonly int _obsoleteClickCount;
private readonly int _clickCount;
public PointerPressedEventArgs(
IInteractive source,
@ -123,15 +123,14 @@ namespace Avalonia.Input
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
int obsoleteClickCount = 1)
int clickCount = 1)
: base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers)
{
_obsoleteClickCount = obsoleteClickCount;
_clickCount = clickCount;
}
[Obsolete("Use DoubleTapped event or Gestures.DoubleRightTapped attached event")]
public int ClickCount => _obsoleteClickCount;
public int ClickCount => _clickCount;
[Obsolete("Use PointerPressedEventArgs.GetCurrentPoint(this).Properties")]
public MouseButton MouseButton => Properties.PointerUpdateKind.GetMouseButton();

44
src/Avalonia.Input/TouchDevice.cs

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Input.Raw;
using Avalonia.VisualTree;
using Avalonia.Platform;
namespace Avalonia.Input
{
@ -16,7 +16,9 @@ namespace Avalonia.Input
{
private readonly Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>();
private bool _disposed;
private int _clickCount;
private Rect _lastClickRect;
private ulong _lastClickTime;
KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) =>
(KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask);
@ -27,10 +29,10 @@ namespace Avalonia.Input
rv |= RawInputModifiers.LeftMouseButton;
return rv;
}
public void ProcessRawEvent(RawInputEventArgs ev)
{
if(_disposed)
if (_disposed)
return;
var args = (RawTouchEventArgs)ev;
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer))
@ -43,16 +45,40 @@ namespace Avalonia.Input
PointerType.Touch, _pointers.Count == 0);
pointer.Capture(hit);
}
var target = pointer.Captured ?? args.Root;
if (args.Type == RawPointerEventType.TouchBegin)
{
if (_pointers.Count > 1)
{
_clickCount = 1;
_lastClickTime = 0;
_lastClickRect = new Rect();
}
else
{
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
if (settings == null)
{
throw new Exception("IPlatformSettings can not be null.");
}
if (!_lastClickRect.Contains(args.Position)
|| ev.Timestamp - _lastClickTime > settings.DoubleClickTime.TotalMilliseconds)
{
_clickCount = 0;
}
++_clickCount;
_lastClickTime = ev.Timestamp;
_lastClickRect = new Rect(args.Position, new Size())
.Inflate(new Thickness(16, 16));
}
target.RaiseEvent(new PointerPressedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, true),
PointerUpdateKind.LeftButtonPressed),
GetKeyModifiers(args.InputModifiers)));
GetKeyModifiers(args.InputModifiers), _clickCount));
}
if (args.Type == RawPointerEventType.TouchEnd)
@ -84,12 +110,12 @@ namespace Avalonia.Input
GetKeyModifiers(args.InputModifiers)));
}
}
public void Dispose()
{
if(_disposed)
if (_disposed)
return;
var values = _pointers.Values.ToList();
_pointers.Clear();
@ -97,6 +123,6 @@ namespace Avalonia.Input
foreach (var p in values)
p.Dispose();
}
}
}

2
src/Avalonia.Interactivity/Avalonia.Interactivity.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />

6
src/Avalonia.Layout/AttachedLayout.cs

@ -12,17 +12,17 @@ namespace Avalonia.Layout
/// </summary>
public abstract class AttachedLayout : AvaloniaObject
{
public string LayoutId { get; set; }
public string? LayoutId { get; set; }
/// <summary>
/// Occurs when the measurement state (layout) has been invalidated.
/// </summary>
public event EventHandler MeasureInvalidated;
public event EventHandler? MeasureInvalidated;
/// <summary>
/// Occurs when the arrange state (layout) has been invalidated.
/// </summary>
public event EventHandler ArrangeInvalidated;
public event EventHandler? ArrangeInvalidated;
/// <summary>
/// Initializes any per-container state the layout requires when it is attached to an

3
src/Avalonia.Layout/Avalonia.Layout.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />
@ -9,4 +9,5 @@
</ItemGroup>
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project>

46
src/Avalonia.Layout/ElementManager.cs

@ -13,10 +13,10 @@ namespace Avalonia.Layout
{
internal class ElementManager
{
private readonly List<ILayoutable> _realizedElements = new List<ILayoutable>();
private readonly List<ILayoutable?> _realizedElements = new List<ILayoutable?>();
private readonly List<Rect> _realizedElementLayoutBounds = new List<Rect>();
private int _firstRealizedDataIndex;
private VirtualizingLayoutContext _context;
private VirtualizingLayoutContext? _context;
private bool IsVirtualizingContext
{
@ -58,7 +58,7 @@ namespace Avalonia.Layout
// Make sure there is enough space for the bounds.
// Note: We could optimize when the count becomes smaller, but keeping
// it always up to date is the simplest option for now.
_realizedElementLayoutBounds.Resize(count);
_realizedElementLayoutBounds.Resize(count, default);
}
}
}
@ -66,34 +66,32 @@ namespace Avalonia.Layout
public int GetRealizedElementCount()
{
return IsVirtualizingContext ? _realizedElements.Count : _context.ItemCount;
return IsVirtualizingContext ? _realizedElements.Count : _context!.ItemCount;
}
public ILayoutable GetAt(int realizedIndex)
{
ILayoutable element;
ILayoutable? element;
if (IsVirtualizingContext)
{
if (_realizedElements[realizedIndex] == null)
element = _realizedElements[realizedIndex];
if (element == null)
{
// Sentinel. Create the element now since we need it.
int dataIndex = GetDataIndexFromRealizedRangeIndex(realizedIndex);
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "Creating element for sentinal with data index {Index}", dataIndex);
element = _context.GetOrCreateElementAt(
element = _context!.GetOrCreateElementAt(
dataIndex,
ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
_realizedElements[realizedIndex] = element;
}
else
{
element = _realizedElements[realizedIndex];
}
}
else
{
// realizedIndex and dataIndex are the same (everything is realized)
element = _context.GetOrCreateElementAt(
element = _context!.GetOrCreateElementAt(
realizedIndex,
ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
}
@ -112,7 +110,7 @@ namespace Avalonia.Layout
_realizedElementLayoutBounds.Add(default);
}
public void Insert(int realizedIndex, int dataIndex, ILayoutable element)
public void Insert(int realizedIndex, int dataIndex, ILayoutable? element)
{
if (realizedIndex == 0)
{
@ -136,7 +134,7 @@ namespace Avalonia.Layout
if (elementRef != null)
{
_context.RecycleElement(elementRef);
_context!.RecycleElement(elementRef);
}
}
@ -203,26 +201,26 @@ namespace Avalonia.Layout
else
{
// Non virtualized - everything is realized
return index >= 0 && index < _context.ItemCount;
return index >= 0 && index < _context!.ItemCount;
}
}
public bool IsIndexValidInData(int currentIndex) => (uint)currentIndex < _context.ItemCount;
public bool IsIndexValidInData(int currentIndex) => (uint)currentIndex < _context!.ItemCount;
public ILayoutable GetRealizedElement(int dataIndex)
public ILayoutable? GetRealizedElement(int dataIndex)
{
return IsVirtualizingContext ?
GetAt(GetRealizedRangeIndexFromDataIndex(dataIndex)) :
_context.GetOrCreateElementAt(
_context!.GetOrCreateElementAt(
dataIndex,
ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
}
public void EnsureElementRealized(bool forward, int dataIndex, string layoutId)
public void EnsureElementRealized(bool forward, int dataIndex, string? layoutId)
{
if (IsDataIndexRealized(dataIndex) == false)
{
var element = _context.GetOrCreateElementAt(
var element = _context!.GetOrCreateElementAt(
dataIndex,
ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
@ -273,14 +271,14 @@ namespace Avalonia.Layout
{
case NotifyCollectionChangedAction.Add:
{
OnItemsAdded(args.NewStartingIndex, args.NewItems.Count);
OnItemsAdded(args.NewStartingIndex, args.NewItems!.Count);
}
break;
case NotifyCollectionChangedAction.Replace:
{
int oldSize = args.OldItems.Count;
int newSize = args.NewItems.Count;
int oldSize = args.OldItems!.Count;
int newSize = args.NewItems!.Count;
int oldStartIndex = args.OldStartingIndex;
int newStartIndex = args.NewStartingIndex;
@ -301,7 +299,7 @@ namespace Avalonia.Layout
if (elementRef != null)
{
_context.RecycleElement(elementRef);
_context!.RecycleElement(elementRef);
_realizedElements[realizedIndex] = null;
}
}

68
src/Avalonia.Layout/FlowLayoutAlgorithm.cs

@ -16,8 +16,8 @@ namespace Avalonia.Layout
private Size _lastAvailableSize;
private double _lastItemSpacing;
private bool _collectionChangePending;
private VirtualizingLayoutContext _context;
private IFlowLayoutAlgorithmDelegates _algorithmCallbacks;
private VirtualizingLayoutContext? _context;
private IFlowLayoutAlgorithmDelegates? _algorithmCallbacks;
private Rect _lastExtent;
private int _firstRealizedDataIndexInsideRealizationWindow = -1;
private int _lastRealizedDataIndexInsideRealizationWindow = -1;
@ -46,7 +46,7 @@ namespace Avalonia.Layout
}
}
private Rect RealizationRect => IsVirtualizingContext ? _context.RealizationRect : new Rect(Size.Infinity);
private Rect RealizationRect => IsVirtualizingContext ? _context!.RealizationRect : new Rect(Size.Infinity);
public void InitializeForContext(VirtualizingLayoutContext context, IFlowLayoutAlgorithmDelegates callbacks)
{
@ -76,7 +76,7 @@ namespace Avalonia.Layout
int maxItemsPerLine,
ScrollOrientation orientation,
bool disableVirtualization,
string layoutId)
string? layoutId)
{
_orientation.ScrollOrientation = orientation;
@ -87,7 +87,7 @@ namespace Avalonia.Layout
layoutId,
realizationRect);
var suggestedAnchorIndex = _context.RecommendedAnchorIndex;
var suggestedAnchorIndex = _context!.RecommendedAnchorIndex;
if (_elementManager.IsIndexValidInData(suggestedAnchorIndex))
{
var anchorRealized = _elementManager.IsDataIndexRealized(suggestedAnchorIndex);
@ -124,7 +124,7 @@ namespace Avalonia.Layout
VirtualizingLayoutContext context,
bool isWrapping,
LineAlignment lineAlignment,
string layoutId)
string? layoutId)
{
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: ArrangeLayout", layoutId);
ArrangeVirtualizingLayout(finalSize, lineAlignment, isWrapping, layoutId);
@ -149,7 +149,7 @@ namespace Avalonia.Layout
Size availableSize,
VirtualizingLayoutContext context)
{
var measureSize = _algorithmCallbacks.Algorithm_GetMeasureSize(index, availableSize, context);
var measureSize = _algorithmCallbacks!.Algorithm_GetMeasureSize(index, availableSize, context);
element.Measure(measureSize);
var provisionalArrangeSize = _algorithmCallbacks.Algorithm_GetProvisionalArrangeSize(index, measureSize, element.DesiredSize, context);
_algorithmCallbacks.Algorithm_OnElementMeasured(element, index, availableSize, measureSize, element.DesiredSize, provisionalArrangeSize, context);
@ -161,7 +161,7 @@ namespace Avalonia.Layout
Size availableSize,
bool isWrapping,
double minItemSpacing,
string layoutId)
string? layoutId)
{
int anchorIndex = -1;
var anchorPosition= new Point();
@ -170,7 +170,7 @@ namespace Avalonia.Layout
if (!IsVirtualizingContext)
{
// Non virtualizing host, start generating from the element 0
anchorIndex = context.ItemCount > 0 ? 0 : -1;
anchorIndex = context!.ItemCount > 0 ? 0 : -1;
}
else
{
@ -183,7 +183,7 @@ namespace Avalonia.Layout
_lastItemSpacing != minItemSpacing ||
_collectionChangePending);
var suggestedAnchorIndex = _context.RecommendedAnchorIndex;
var suggestedAnchorIndex = _context!.RecommendedAnchorIndex;
var isAnchorSuggestionValid = suggestedAnchorIndex >= 0 &&
_elementManager.IsDataIndexRealized(suggestedAnchorIndex);
@ -191,10 +191,10 @@ namespace Avalonia.Layout
if (isAnchorSuggestionValid)
{
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId}: Using suggested anchor {Anchor}", layoutId, suggestedAnchorIndex);
anchorIndex = _algorithmCallbacks.Algorithm_GetAnchorForTargetElement(
anchorIndex = _algorithmCallbacks!.Algorithm_GetAnchorForTargetElement(
suggestedAnchorIndex,
availableSize,
context).Index;
context!).Index;
if (_elementManager.IsDataIndexRealized(anchorIndex))
{
@ -235,7 +235,7 @@ namespace Avalonia.Layout
// The anchor is based on the realization window because a connected ItemsRepeater might intersect the realization window
// but not the visible window. In that situation, we still need to produce a valid anchor.
var anchorInfo = _algorithmCallbacks.Algorithm_GetAnchorForRealizationRect(availableSize, context);
var anchorInfo = _algorithmCallbacks!.Algorithm_GetAnchorForRealizationRect(availableSize, context!);
anchorIndex = anchorInfo.Index;
anchorPosition = _orientation.MinorMajorPoint(0, anchorInfo.Offset);
}
@ -259,12 +259,12 @@ namespace Avalonia.Layout
Logger.TryGet(LogEventLevel.Verbose, "Repeater")?.Log(this, "{LayoutId} Disconnected Window - throwing away all realized elements", layoutId);
_elementManager.ClearRealizedRange();
var anchor = _context.GetOrCreateElementAt(anchorIndex, ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
var anchor = _context!.GetOrCreateElementAt(anchorIndex, ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
_elementManager.Add(anchor, anchorIndex);
}
var anchorElement = _elementManager.GetRealizedElement(anchorIndex);
var desiredSize = MeasureElement(anchorElement, anchorIndex, availableSize, _context);
var desiredSize = MeasureElement(anchorElement!, anchorIndex, availableSize, _context!);
var layoutBounds = new Rect(anchorPosition.X, anchorPosition.Y, desiredSize.Width, desiredSize.Height);
_elementManager.SetLayoutBoundsForDataIndex(anchorIndex, layoutBounds);
@ -296,7 +296,7 @@ namespace Avalonia.Layout
double lineSpacing,
int maxItemsPerLine,
bool disableVirtualization,
string layoutId)
string? layoutId)
{
if (anchorIndex != -1)
{
@ -322,7 +322,7 @@ namespace Avalonia.Layout
// Ensure layout element.
_elementManager.EnsureElementRealized(direction == GenerateDirection.Forward, currentIndex, layoutId);
var currentElement = _elementManager.GetRealizedElement(currentIndex);
var desiredSize = MeasureElement(currentElement, currentIndex, availableSize, _context);
var desiredSize = MeasureElement(currentElement!, currentIndex, availableSize, _context!);
++count;
// Lay it out.
@ -333,7 +333,7 @@ namespace Avalonia.Layout
if (direction == GenerateDirection.Forward)
{
double remainingSpace = _orientation.Minor(availableSize) - (_orientation.MinorStart(previousElementBounds) + _orientation.MinorSize(previousElementBounds) + minItemSpacing + _orientation.Minor(desiredSize));
if (countInLine >= maxItemsPerLine || _algorithmCallbacks.Algorithm_ShouldBreakLine(currentIndex, remainingSpace))
if (countInLine >= maxItemsPerLine || _algorithmCallbacks!.Algorithm_ShouldBreakLine(currentIndex, remainingSpace))
{
// No more space in this row. wrap to next row.
_orientation.SetMinorStart(ref currentBounds, 0);
@ -371,7 +371,7 @@ namespace Avalonia.Layout
{
// Backward
double remainingSpace = _orientation.MinorStart(previousElementBounds) - (_orientation.Minor(desiredSize) + minItemSpacing);
if (countInLine >= maxItemsPerLine || _algorithmCallbacks.Algorithm_ShouldBreakLine(currentIndex, remainingSpace))
if (countInLine >= maxItemsPerLine || _algorithmCallbacks!.Algorithm_ShouldBreakLine(currentIndex, remainingSpace))
{
// Does not fit, wrap to the previous row
var availableSizeMinor = _orientation.Minor(availableSize);
@ -432,13 +432,13 @@ namespace Avalonia.Layout
// account for that element in the indices inside the realization window.
if (direction == GenerateDirection.Forward)
{
int dataCount = _context.ItemCount;
int dataCount = _context!.ItemCount;
_lastRealizedDataIndexInsideRealizationWindow = previousIndex == dataCount - 1 ? dataCount - 1 : previousIndex - 1;
_lastRealizedDataIndexInsideRealizationWindow = Math.Max(0, _lastRealizedDataIndexInsideRealizationWindow);
}
else
{
int dataCount = _context.ItemCount;
int dataCount = _context!.ItemCount;
_firstRealizedDataIndexInsideRealizationWindow = previousIndex == 0 ? 0 : previousIndex + 1;
_firstRealizedDataIndexInsideRealizationWindow = Math.Min(dataCount - 1, _firstRealizedDataIndexInsideRealizationWindow);
}
@ -454,7 +454,7 @@ namespace Avalonia.Layout
{
_elementManager.ClearRealizedRange();
// FlowLayout requires that the anchor is the first element in the row.
var internalAnchor = _algorithmCallbacks.Algorithm_GetAnchorForTargetElement(index, availableSize, context);
var internalAnchor = _algorithmCallbacks!.Algorithm_GetAnchorForTargetElement(index, availableSize, context);
// No need to set the position of the anchor.
// (0,0) is fine for now since the extent can
@ -487,7 +487,7 @@ namespace Avalonia.Layout
}
else
{
var realizationRect = _context.RealizationRect;
var realizationRect = _context!.RealizationRect;
var elementBounds = _elementManager.GetLayoutBoundsForDataIndex(index);
var elementMajorStart = _orientation.MajorStart(elementBounds);
@ -510,11 +510,11 @@ namespace Avalonia.Layout
return shouldContinue;
}
private Rect EstimateExtent(Size availableSize, string layoutId)
private Rect EstimateExtent(Size availableSize, string? layoutId)
{
ILayoutable firstRealizedElement = null;
ILayoutable? firstRealizedElement = null;
Rect firstBounds = new Rect();
ILayoutable lastRealizedElement = null;
ILayoutable? lastRealizedElement = null;
Rect lastBounds = new Rect();
int firstDataIndex = -1;
int lastDataIndex = -1;
@ -531,9 +531,9 @@ namespace Avalonia.Layout
lastBounds = _elementManager.GetLayoutBoundsForRealizedIndex(last);
}
Rect extent = _algorithmCallbacks.Algorithm_GetExtent(
Rect extent = _algorithmCallbacks!.Algorithm_GetExtent(
availableSize,
_context,
_context!,
firstRealizedElement,
firstDataIndex,
firstBounds,
@ -563,7 +563,7 @@ namespace Avalonia.Layout
if (_orientation.MajorStart(currentBounds) != currentLineOffset)
{
// Staring a new line
_algorithmCallbacks.Algorithm_OnLineArranged(currentDataIndex - countInLine, countInLine, currentLineSize, _context);
_algorithmCallbacks!.Algorithm_OnLineArranged(currentDataIndex - countInLine, countInLine, currentLineSize, _context!);
countInLine = 0;
currentLineOffset = _orientation.MajorStart(currentBounds);
currentLineSize = 0;
@ -575,7 +575,7 @@ namespace Avalonia.Layout
}
// Raise for the last line.
_algorithmCallbacks.Algorithm_OnLineArranged(_lastRealizedDataIndexInsideRealizationWindow - countInLine + 1, countInLine, currentLineSize, _context);
_algorithmCallbacks!.Algorithm_OnLineArranged(_lastRealizedDataIndexInsideRealizationWindow - countInLine + 1, countInLine, currentLineSize, _context!);
}
}
}
@ -584,7 +584,7 @@ namespace Avalonia.Layout
Size finalSize,
LineAlignment lineAlignment,
bool isWrapping,
string layoutId)
string? layoutId)
{
// Walk through the realized elements one line at a time and
// align them, Then call element.Arrange with the arranged bounds.
@ -636,7 +636,7 @@ namespace Avalonia.Layout
LineAlignment lineAlignment,
bool isWrapping,
Size finalSize,
string layoutId)
string? layoutId)
{
for (int rangeIndex = lineStartIndex; rangeIndex < lineStartIndex + countInLine; ++rangeIndex)
{
@ -723,11 +723,11 @@ namespace Avalonia.Layout
{
if (IsVirtualizingContext)
{
_context.LayoutOrigin = new Point(_lastExtent.X, _lastExtent.Y);
_context!.LayoutOrigin = new Point(_lastExtent.X, _lastExtent.Y);
}
}
public ILayoutable GetElementIfRealized(int dataIndex)
public ILayoutable? GetElementIfRealized(int dataIndex)
{
if (_elementManager.IsDataIndexRealized(dataIndex))
{

4
src/Avalonia.Layout/IFlowLayoutAlgorithmDelegates.cs

@ -21,10 +21,10 @@ namespace Avalonia.Layout
Rect Algorithm_GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable firstRealized,
ILayoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable lastRealized,
ILayoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds);
void Algorithm_OnElementMeasured(

4
src/Avalonia.Layout/LayoutContext.cs

@ -14,7 +14,7 @@ namespace Avalonia.Layout
/// <summary>
/// Gets or sets an object that represents the state of a layout.
/// </summary>
public object LayoutState
public object? LayoutState
{
get => LayoutStateCore;
set => LayoutStateCore = value;
@ -23,6 +23,6 @@ namespace Avalonia.Layout
/// <summary>
/// Implements the behavior of <see cref="LayoutState"/> in a derived or custom LayoutContext.
/// </summary>
protected virtual object LayoutStateCore { get; set; }
protected virtual object? LayoutStateCore { get; set; }
}
}

2
src/Avalonia.Layout/LayoutContextAdapter.cs

@ -16,7 +16,7 @@ namespace Avalonia.Layout
_nonVirtualizingContext = nonVirtualizingContext;
}
protected override object LayoutStateCore
protected override object? LayoutStateCore
{
get => _nonVirtualizingContext.LayoutState;
set => _nonVirtualizingContext.LayoutState = value;

2
src/Avalonia.Layout/LayoutHelper.cs

@ -101,7 +101,7 @@ namespace Avalonia.Layout
if (result == 0 || double.IsNaN(result) || double.IsInfinity(result))
{
throw new Exception($"Invalid LayoutScaling returned from {visualRoot.GetType()}");
throw new Exception($"Invalid LayoutScaling returned from {visualRoot!.GetType()}");
}
return result;

1
src/Avalonia.Layout/LayoutQueue.cs

@ -5,6 +5,7 @@ using System.Collections.Generic;
namespace Avalonia.Layout
{
internal class LayoutQueue<T> : IReadOnlyCollection<T>, IDisposable
where T : notnull
{
private struct Info
{

2
src/Avalonia.Layout/Layoutable.cs

@ -794,7 +794,7 @@ namespace Avalonia.Layout
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void LayoutManagedLayoutUpdated(object sender, EventArgs e) => _layoutUpdated?.Invoke(this, e);
private void LayoutManagedLayoutUpdated(object? sender, EventArgs e) => _layoutUpdated?.Invoke(this, e);
/// <summary>
/// Tests whether any of a <see cref="Rect"/>'s properties include negative values,

4
src/Avalonia.Layout/NonVirtualizingLayoutContext.cs

@ -12,7 +12,7 @@ namespace Avalonia.Layout
/// </summary>
public abstract class NonVirtualizingLayoutContext : LayoutContext
{
private VirtualizingLayoutContext _contextAdapter;
private VirtualizingLayoutContext? _contextAdapter;
/// <summary>
/// Gets the collection of child controls from the container that provides the context.
@ -26,6 +26,6 @@ namespace Avalonia.Layout
protected abstract IReadOnlyList<ILayoutable> ChildrenCore { get; }
internal VirtualizingLayoutContext GetVirtualizingContextAdapter() =>
_contextAdapter ?? (_contextAdapter = new LayoutContextAdapter(this));
_contextAdapter ??= new LayoutContextAdapter(this);
}
}

22
src/Avalonia.Layout/StackLayout.cs

@ -78,10 +78,10 @@ namespace Avalonia.Layout
internal Rect GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable firstRealized,
ILayoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable lastRealized,
ILayoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds)
{
@ -89,7 +89,7 @@ namespace Avalonia.Layout
// Constants
int itemsCount = context.ItemCount;
var stackState = (StackLayoutState)context.LayoutState;
var stackState = (StackLayoutState)context.LayoutState!;
double averageElementSize = GetAverageElementSize(availableSize, context, stackState) + Spacing;
_orientation.SetMinorSize(ref extent, stackState.MaxArrangeBounds);
@ -131,7 +131,7 @@ namespace Avalonia.Layout
{
if (context is VirtualizingLayoutContext virtualContext)
{
var stackState = (StackLayoutState)virtualContext.LayoutState;
var stackState = (StackLayoutState)virtualContext.LayoutState!;
var provisionalArrangeSizeWinRt = provisionalArrangeSize;
stackState.OnElementMeasured(
index,
@ -177,7 +177,7 @@ namespace Avalonia.Layout
if (targetIndex >= 0 && targetIndex < itemsCount)
{
index = targetIndex;
var state = (StackLayoutState)context.LayoutState;
var state = (StackLayoutState)context.LayoutState!;
double averageElementSize = GetAverageElementSize(availableSize, context, state) + Spacing;
offset = index * averageElementSize + _orientation.MajorStart(state.FlowAlgorithm.LastExtent);
}
@ -188,10 +188,10 @@ namespace Avalonia.Layout
Rect IFlowLayoutAlgorithmDelegates.Algorithm_GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable firstRealized,
ILayoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable lastRealized,
ILayoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds)
{
@ -234,7 +234,7 @@ namespace Avalonia.Layout
if (itemsCount > 0)
{
var realizationRect = context.RealizationRect;
var state = (StackLayoutState)context.LayoutState;
var state = (StackLayoutState)context.LayoutState!;
var lastExtent = state.FlowAlgorithm.LastExtent;
double averageElementSize = GetAverageElementSize(availableSize, context, state) + Spacing;
@ -279,13 +279,13 @@ namespace Avalonia.Layout
protected internal override void UninitializeForContextCore(VirtualizingLayoutContext context)
{
var stackState = (StackLayoutState)context.LayoutState;
var stackState = (StackLayoutState)context.LayoutState!;
stackState.UninitializeForContext(context);
}
protected internal override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
{
((StackLayoutState)context.LayoutState).OnMeasureStart();
((StackLayoutState)context.LayoutState!).OnMeasureStart();
var desiredSize = GetFlowAlgorithm(context).Measure(
availableSize,
@ -358,6 +358,6 @@ namespace Avalonia.Layout
private void InvalidateLayout() => InvalidateMeasure();
private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((StackLayoutState)context.LayoutState).FlowAlgorithm;
private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((StackLayoutState)context.LayoutState!).FlowAlgorithm;
}
}

26
src/Avalonia.Layout/UniformGridLayout.cs

@ -258,7 +258,7 @@ namespace Avalonia.Layout
Size availableSize,
VirtualizingLayoutContext context)
{
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
return new Size(gridState.EffectiveItemWidth, gridState.EffectiveItemHeight);
}
@ -268,7 +268,7 @@ namespace Avalonia.Layout
Size desiredSize,
VirtualizingLayoutContext context)
{
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
return new Size(gridState.EffectiveItemWidth, gridState.EffectiveItemHeight);
}
@ -285,7 +285,7 @@ namespace Avalonia.Layout
var realizationRect = context.RealizationRect;
if (itemsCount > 0 && _orientation.MajorSize(realizationRect) > 0)
{
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
var lastExtent = gridState.FlowAlgorithm.LastExtent;
var itemsPerLine = Math.Min( // note use of unsigned ints
Math.Max(1u, (uint)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))),
@ -324,7 +324,7 @@ namespace Avalonia.Layout
Math.Max(1u, _maximumRowsOrColumns));
int indexOfFirstInLine = (targetIndex / itemsPerLine) * itemsPerLine;
index = indexOfFirstInLine;
var state = context.LayoutState as UniformGridLayoutState;
var state = (UniformGridLayoutState)context.LayoutState!;
offset = _orientation.MajorStart(GetLayoutRectForDataIndex(availableSize, indexOfFirstInLine, state.FlowAlgorithm.LastExtent, context));
}
@ -338,10 +338,10 @@ namespace Avalonia.Layout
Rect IFlowLayoutAlgorithmDelegates.Algorithm_GetExtent(
Size availableSize,
VirtualizingLayoutContext context,
ILayoutable firstRealized,
ILayoutable? firstRealized,
int firstRealizedItemIndex,
Rect firstRealizedLayoutBounds,
ILayoutable lastRealized,
ILayoutable? lastRealized,
int lastRealizedItemIndex,
Rect lastRealizedLayoutBounds)
{
@ -421,7 +421,7 @@ namespace Avalonia.Layout
protected internal override void UninitializeForContextCore(VirtualizingLayoutContext context)
{
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
gridState.UninitializeForContext(context);
}
@ -429,7 +429,7 @@ namespace Avalonia.Layout
{
// Set the width and height on the grid state. If the user already set them then use the preset.
// If not, we have to measure the first element and get back a size which we're going to be using for the rest of the items.
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
gridState.EnsureElementSize(availableSize, context, _minItemWidth, _minItemHeight, _itemsStretch, Orientation, MinRowSpacing, MinColumnSpacing, _maximumRowsOrColumns);
var desiredSize = GetFlowAlgorithm(context).Measure(
@ -467,7 +467,7 @@ namespace Avalonia.Layout
// Always invalidate layout to keep the view accurate.
InvalidateLayout();
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
gridState.ClearElementOnDataSourceChange(context, args);
}
@ -517,7 +517,7 @@ namespace Avalonia.Layout
private double GetMinorSizeWithSpacing(VirtualizingLayoutContext context)
{
var minItemSpacing = MinItemSpacing;
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
return _orientation.ScrollOrientation == ScrollOrientation.Vertical?
gridState.EffectiveItemWidth + minItemSpacing :
gridState.EffectiveItemHeight + minItemSpacing;
@ -526,7 +526,7 @@ namespace Avalonia.Layout
private double GetMajorSizeWithSpacing(VirtualizingLayoutContext context)
{
var lineSpacing = LineSpacing;
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
return _orientation.ScrollOrientation == ScrollOrientation.Vertical ?
gridState.EffectiveItemHeight + lineSpacing :
gridState.EffectiveItemWidth + lineSpacing;
@ -544,7 +544,7 @@ namespace Avalonia.Layout
int rowIndex = (int)(index / itemsPerLine);
int indexInRow = index - (rowIndex * itemsPerLine);
var gridState = (UniformGridLayoutState)context.LayoutState;
var gridState = (UniformGridLayoutState)context.LayoutState!;
Rect bounds = _orientation.MinorMajorRect(
indexInRow * GetMinorSizeWithSpacing(context) + _orientation.MinorStart(lastExtent),
rowIndex * GetMajorSizeWithSpacing(context) + _orientation.MajorStart(lastExtent),
@ -556,6 +556,6 @@ namespace Avalonia.Layout
private void InvalidateLayout() => InvalidateMeasure();
private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((UniformGridLayoutState)context.LayoutState).FlowAlgorithm;
private FlowLayoutAlgorithm GetFlowAlgorithm(VirtualizingLayoutContext context) => ((UniformGridLayoutState)context.LayoutState!).FlowAlgorithm;
}
}

2
src/Avalonia.Layout/UniformGridLayoutState.cs

@ -18,7 +18,7 @@ namespace Avalonia.Layout
// If it does not, then we need to do context.GetElement(0) at which point we have requested an element and are on point to clear it.
// If we are responsible for clearing element 0 we keep m_cachedFirstElement valid.
// If we are not (because FlowLayoutAlgorithm is holding it for us) then we just null out this field and use the one from FlowLayoutAlgorithm.
private ILayoutable _cachedFirstElement;
private ILayoutable? _cachedFirstElement;
internal FlowLayoutAlgorithm FlowAlgorithm { get; } = new FlowLayoutAlgorithm();
internal double EffectiveItemWidth { get; private set; }

5
src/Avalonia.Layout/Utils/ListUtils.cs

@ -23,10 +23,5 @@ namespace Avalonia.Layout.Utils
list.AddRange(Enumerable.Repeat(value, size - cur));
}
}
public static void Resize<T>(this List<T> list, int count)
{
Resize(list, count, default);
}
}
}

4
src/Avalonia.Layout/VirtualLayoutContextAdapter.cs

@ -6,14 +6,14 @@ namespace Avalonia.Layout
public class VirtualLayoutContextAdapter : NonVirtualizingLayoutContext
{
private readonly VirtualizingLayoutContext _virtualizingContext;
private ChildrenCollection _children;
private ChildrenCollection? _children;
public VirtualLayoutContextAdapter(VirtualizingLayoutContext virtualizingContext)
{
_virtualizingContext = virtualizingContext;
}
protected override object LayoutStateCore
protected override object? LayoutStateCore
{
get => _virtualizingContext.LayoutState;
set => _virtualizingContext.LayoutState = value;

2
src/Avalonia.Layout/VirtualizingLayoutContext.cs

@ -43,7 +43,7 @@ namespace Avalonia.Layout
/// </summary>
public abstract class VirtualizingLayoutContext : LayoutContext
{
private NonVirtualizingLayoutContext _contextAdapter;
private NonVirtualizingLayoutContext? _contextAdapter;
/// <summary>
/// Gets the number of items in the data.

2
src/Avalonia.Layout/WrapLayout/UvMeasure.cs

@ -27,7 +27,7 @@ namespace Avalonia.Layout
}
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is UvMeasure measure)
{

2
src/Avalonia.Layout/WrapLayout/WrapItem.cs

@ -20,6 +20,6 @@ namespace Avalonia.Layout
public UvMeasure? Position { get; internal set; }
public ILayoutable Element { get; internal set; }
public ILayoutable? Element { get; internal set; }
}
}

6
src/Avalonia.Layout/WrapLayout/WrapLayout.cs

@ -88,7 +88,7 @@ namespace Avalonia.Layout
/// <inheritdoc />
protected internal override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args)
{
var state = (WrapLayoutState)context.LayoutState;
var state = (WrapLayoutState)context.LayoutState!;
switch (args.Action)
{
@ -126,7 +126,7 @@ namespace Avalonia.Layout
var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
var position = UvMeasure.Zero;
var state = (WrapLayoutState)context.LayoutState;
var state = (WrapLayoutState)context.LayoutState!;
if (state.Orientation != Orientation)
{
state.SetOrientation(Orientation);
@ -261,7 +261,7 @@ namespace Avalonia.Layout
var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
var state = (WrapLayoutState)context.LayoutState;
var state = (WrapLayoutState)context.LayoutState!;
bool Arrange(WrapItem item, bool isLast = false)
{
if (item.Measure.HasValue == false)

9
src/Avalonia.Layout/WrapLayout/WrapLayoutState.cs

@ -62,8 +62,11 @@ namespace Avalonia.Layout
internal void SetOrientation(Orientation orientation)
{
foreach (var item in _items.Where(i => i.Measure.HasValue))
foreach (var item in _items)
{
if (!item.Measure.HasValue)
continue;
UvMeasure measure = item.Measure.Value;
double v = measure.V;
measure.V = measure.U;
@ -120,10 +123,10 @@ namespace Avalonia.Layout
}
lastPosition = item.Position;
maxV = Math.Max(maxV, item.Measure.Value.V);
maxV = Math.Max(maxV, item.Measure!.Value.V);
}
double totalHeight = lastPosition.Value.V + maxV;
double totalHeight = lastPosition!.Value.V + maxV;
if (calculateAverage)
{
return (totalHeight / itemCount) * _context.ItemCount;

2
src/Avalonia.Native/Avalonia.Native.csproj

@ -4,7 +4,7 @@
<PackAvaloniaNative Condition="'$(PackAvaloniaNative)' == ''">$([MSBuild]::IsOSPlatform(OSX))</PackAvaloniaNative>
<IsPackable>$(PackAvaloniaNative)</IsPackable>
<IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

7
src/Avalonia.Native/AvaloniaNativeMenuExporter.cs

@ -142,6 +142,13 @@ namespace Avalonia.Native
private void DoLayoutReset(bool forceUpdate = false)
{
var macOpts = AvaloniaLocator.Current.GetService<MacOSPlatformOptions>();
if (macOpts != null && macOpts.DisableNativeMenus)
{
return;
}
if (_resetQueued || forceUpdate)
{
_resetQueued = false;

5
src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs

@ -73,5 +73,10 @@ namespace Avalonia
/// You can prevent Avalonia from adding those items to the OSX Application Menu with this property. The default value is false.
/// </summary>
public bool DisableDefaultApplicationMenuItems { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the native macOS menu bar will be enabled for the application.
/// </summary>
public bool DisableNativeMenus { get; set; }
}
}

2
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

2
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<PackageId>Avalonia.ReactiveUI</PackageId>
<SignAssembly>false</SignAssembly>
</PropertyGroup>

2
src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<DefineConstants>AVALONIA_REMOTE_PROTOCOL;$(DefineConstants)</DefineConstants>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>

3
src/Avalonia.Styling/Avalonia.Styling.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AssemblyName>Avalonia.Styling</AssemblyName>
<RootNamespace>Avalonia</RootNamespace>
</PropertyGroup>
@ -9,4 +9,5 @@
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
</ItemGroup>
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project>

12
src/Avalonia.Styling/Controls/ChildNameScope.cs

@ -15,20 +15,20 @@ namespace Avalonia.Controls
public void Register(string name, object element) => _inner.Register(name, element);
public SynchronousCompletionAsyncResult<object> FindAsync(string name)
public SynchronousCompletionAsyncResult<object?> FindAsync(string name)
{
var found = Find(name);
if (found != null)
return new SynchronousCompletionAsyncResult<object>(found);
return new SynchronousCompletionAsyncResult<object?>(found);
// Not found and both current and parent scope are in completed state
if(IsCompleted)
return new SynchronousCompletionAsyncResult<object>(null);
return new SynchronousCompletionAsyncResult<object?>(null);
return DoFindAsync(name);
}
public SynchronousCompletionAsyncResult<object> DoFindAsync(string name)
public SynchronousCompletionAsyncResult<object?> DoFindAsync(string name)
{
var src = new SynchronousCompletionAsyncResultSource<object>();
var src = new SynchronousCompletionAsyncResultSource<object?>();
void ParentSearch()
{
@ -56,7 +56,7 @@ namespace Avalonia.Controls
return src.AsyncResult;
}
public object Find(string name)
public object? Find(string name)
{
var found = _inner.Find(name);
if (found != null)

4
src/Avalonia.Styling/Controls/INameScope.cs

@ -22,14 +22,14 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="name">The name.</param>
/// <returns>The element, or null if the name was not found.</returns>
SynchronousCompletionAsyncResult<object> FindAsync(string name);
SynchronousCompletionAsyncResult<object?> FindAsync(string name);
/// <summary>
/// Finds a named element in the name scope, returns immediately, doesn't traverse the name scope stack
/// </summary>
/// <param name="name">The name.</param>
/// <returns>The element, or null if the name was not found.</returns>
object Find(string name);
object? Find(string name);
/// <summary>
/// Marks the name scope as completed, no further registrations will be allowed

30
src/Avalonia.Styling/Controls/NameScope.cs

@ -22,8 +22,8 @@ namespace Avalonia.Controls
private readonly Dictionary<string, object> _inner = new Dictionary<string, object>();
private readonly Dictionary<string, SynchronousCompletionAsyncResultSource<object>> _pendingSearches =
new Dictionary<string, SynchronousCompletionAsyncResultSource<object>>();
private readonly Dictionary<string, SynchronousCompletionAsyncResultSource<object?>> _pendingSearches =
new Dictionary<string, SynchronousCompletionAsyncResultSource<object?>>();
/// <summary>
/// Gets the value of the attached <see cref="NameScopeProperty"/> on a styled element.
@ -32,7 +32,7 @@ namespace Avalonia.Controls
/// <returns>The value of the NameScope attached property.</returns>
public static INameScope GetNameScope(StyledElement styled)
{
Contract.Requires<ArgumentNullException>(styled != null);
_ = styled ?? throw new ArgumentNullException(nameof(styled));
return styled.GetValue(NameScopeProperty);
}
@ -44,7 +44,7 @@ namespace Avalonia.Controls
/// <param name="value">The value to set.</param>
public static void SetNameScope(StyledElement styled, INameScope value)
{
Contract.Requires<ArgumentNullException>(styled != null);
_ = styled ?? throw new ArgumentNullException(nameof(styled));
styled.SetValue(NameScopeProperty, value);
}
@ -54,12 +54,11 @@ namespace Avalonia.Controls
{
if (IsCompleted)
throw new InvalidOperationException("NameScope is completed, no further registrations are allowed");
Contract.Requires<ArgumentNullException>(name != null);
Contract.Requires<ArgumentNullException>(element != null);
object existing;
_ = name ?? throw new ArgumentNullException(nameof(name));
_ = element ?? throw new ArgumentNullException(nameof(element));
if (_inner.TryGetValue(name, out existing))
if (_inner.TryGetValue(name, out var existing))
{
if (existing != element)
{
@ -77,27 +76,26 @@ namespace Avalonia.Controls
}
}
public SynchronousCompletionAsyncResult<object> FindAsync(string name)
public SynchronousCompletionAsyncResult<object?> FindAsync(string name)
{
var found = Find(name);
if (found != null)
return new SynchronousCompletionAsyncResult<object>(found);
return new SynchronousCompletionAsyncResult<object?>(found);
if (IsCompleted)
return new SynchronousCompletionAsyncResult<object>((object)null);
return new SynchronousCompletionAsyncResult<object?>(null);
if (!_pendingSearches.TryGetValue(name, out var tcs))
// We are intentionally running continuations synchronously here
_pendingSearches[name] = tcs = new SynchronousCompletionAsyncResultSource<object>();
_pendingSearches[name] = tcs = new SynchronousCompletionAsyncResultSource<object?>();
return tcs.AsyncResult;
}
/// <inheritdoc />
public object Find(string name)
public object? Find(string name)
{
Contract.Requires<ArgumentNullException>(name != null);
_ = name ?? throw new ArgumentNullException(nameof(name));
object result;
_inner.TryGetValue(name, out result);
_inner.TryGetValue(name, out var result);
return result;
}

28
src/Avalonia.Styling/Controls/NameScopeExtensions.cs

@ -17,11 +17,11 @@ namespace Avalonia.Controls
/// <param name="nameScope">The name scope.</param>
/// <param name="name">The name.</param>
/// <returns>The named element or null if not found.</returns>
public static T Find<T>(this INameScope nameScope, string name)
public static T? Find<T>(this INameScope nameScope, string name)
where T : class
{
Contract.Requires<ArgumentNullException>(nameScope != null);
Contract.Requires<ArgumentNullException>(name != null);
_ = nameScope ?? throw new ArgumentNullException(nameof(nameScope));
_ = name ?? throw new ArgumentNullException(nameof(name));
var result = nameScope.Find(name);
@ -31,7 +31,7 @@ namespace Avalonia.Controls
$"Expected control '{name}' to be '{typeof(T)} but it was '{result.GetType()}'.");
}
return (T)result;
return (T?)result;
}
/// <summary>
@ -41,11 +41,11 @@ namespace Avalonia.Controls
/// <param name="anchor">The control to take the name scope from.</param>
/// <param name="name">The name.</param>
/// <returns>The named element or null if not found.</returns>
public static T Find<T>(this ILogical anchor, string name)
public static T? Find<T>(this ILogical anchor, string name)
where T : class
{
Contract.Requires<ArgumentNullException>(anchor != null);
Contract.Requires<ArgumentNullException>(name != null);
_ = anchor ?? throw new ArgumentNullException(nameof(anchor));
_ = name ?? throw new ArgumentNullException(nameof(name));
var styledAnchor = anchor as StyledElement;
if (styledAnchor == null)
return null;
@ -64,8 +64,8 @@ namespace Avalonia.Controls
public static T Get<T>(this INameScope nameScope, string name)
where T : class
{
Contract.Requires<ArgumentNullException>(nameScope != null);
Contract.Requires<ArgumentNullException>(name != null);
_ = nameScope ?? throw new ArgumentNullException(nameof(nameScope));
_ = name ?? throw new ArgumentNullException(nameof(name));
var result = nameScope.Find(name);
@ -94,9 +94,9 @@ namespace Avalonia.Controls
public static T Get<T>(this ILogical anchor, string name)
where T : class
{
Contract.Requires<ArgumentNullException>(anchor != null);
Contract.Requires<ArgumentNullException>(name != null);
_ = anchor ?? throw new ArgumentNullException(nameof(anchor));
_ = name ?? throw new ArgumentNullException(nameof(name));
var nameScope = (anchor as INameScope) ?? NameScope.GetNameScope((StyledElement)anchor);
if (nameScope == null)
throw new InvalidOperationException(
@ -105,9 +105,9 @@ namespace Avalonia.Controls
return nameScope.Get<T>(name);
}
public static INameScope FindNameScope(this ILogical control)
public static INameScope? FindNameScope(this ILogical control)
{
Contract.Requires<ArgumentNullException>(control != null);
_ = control ?? throw new ArgumentNullException(nameof(control));
var scope = control.GetSelfAndLogicalAncestors()
.OfType<StyledElement>()

8
src/Avalonia.Styling/Controls/NameScopeLocator.cs

@ -11,9 +11,9 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="scope">The scope relative from which the object should be resolved.</param>
/// <param name="name">The name of the object to find.</param>
public static IObservable<object> Track(INameScope scope, string name)
public static IObservable<object?> Track(INameScope scope, string name)
{
return new NeverEndingSynchronousCompletionAsyncResultObservable<object>(scope.FindAsync(name));
return new NeverEndingSynchronousCompletionAsyncResultObservable<object?>(scope.FindAsync(name));
}
// This class is implemented in such weird way because for some reason
@ -22,7 +22,7 @@ namespace Avalonia.Controls
private class NeverEndingSynchronousCompletionAsyncResultObservable<T> : IObservable<T>
{
private T _value;
private T? _value;
private SynchronousCompletionAsyncResult<T>? _asyncResult;
public NeverEndingSynchronousCompletionAsyncResultObservable(SynchronousCompletionAsyncResult<T> task)
@ -47,7 +47,7 @@ namespace Avalonia.Controls
observer.OnNext(_asyncResult.Value.GetResult());
});
else
observer.OnNext(_value);
observer.OnNext(_value!);
return Disposable.Empty;
}

2
src/Avalonia.Styling/Controls/PseudoClassesExtensions.cs

@ -12,7 +12,7 @@ namespace Avalonia.Controls
/// <param name="value">True to add the pseudoclass or false to remove.</param>
public static void Set(this IPseudoClasses classes, string name, bool value)
{
Contract.Requires<ArgumentNullException>(classes != null);
_ = classes ?? throw new ArgumentNullException(nameof(classes));
if (value)
{

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

@ -177,7 +177,7 @@ namespace Avalonia.Controls
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}

6
src/Avalonia.Styling/Controls/ResourceNodeExtensions.cs

@ -109,7 +109,7 @@ namespace Avalonia.Controls
observer.OnNext(Convert(_target.FindResource(_key)));
}
private void ResourcesChanged(object sender, ResourcesChangedEventArgs e)
private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e)
{
PublishNext(Convert(_target.FindResource(_key)));
}
@ -159,7 +159,7 @@ namespace Avalonia.Controls
}
}
private void OwnerChanged(object sender, EventArgs e)
private void OwnerChanged(object? sender, EventArgs e)
{
if (_owner is object)
{
@ -176,7 +176,7 @@ namespace Avalonia.Controls
PublishNext();
}
private void ResourcesChanged(object sender, ResourcesChangedEventArgs e)
private void ResourcesChanged(object? sender, ResourcesChangedEventArgs e)
{
PublishNext();
}

2
src/Avalonia.Styling/INamed.cs

@ -8,6 +8,6 @@ namespace Avalonia
/// <summary>
/// Gets the element name.
/// </summary>
string Name { get; }
string? Name { get; }
}
}

16
src/Avalonia.Styling/LogicalTree/ControlLocator.cs

@ -9,19 +9,19 @@ namespace Avalonia.LogicalTree
/// </summary>
public static class ControlLocator
{
public static IObservable<ILogical> Track(ILogical relativeTo, int ancestorLevel, Type ancestorType = null)
public static IObservable<ILogical?> Track(ILogical relativeTo, int ancestorLevel, Type? ancestorType = null)
{
return new ControlTracker(relativeTo, ancestorLevel, ancestorType);
}
private class ControlTracker : LightweightObservableBase<ILogical>
private class ControlTracker : LightweightObservableBase<ILogical?>
{
private readonly ILogical _relativeTo;
private readonly int _ancestorLevel;
private readonly Type _ancestorType;
private ILogical _value;
private readonly Type? _ancestorType;
private ILogical? _value;
public ControlTracker(ILogical relativeTo, int ancestorLevel, Type ancestorType)
public ControlTracker(ILogical relativeTo, int ancestorLevel, Type? ancestorType)
{
_relativeTo = relativeTo;
_ancestorLevel = ancestorLevel;
@ -43,18 +43,18 @@ namespace Avalonia.LogicalTree
_value = null;
}
protected override void Subscribed(IObserver<ILogical> observer, bool first)
protected override void Subscribed(IObserver<ILogical?> observer, bool first)
{
observer.OnNext(_value);
}
private void Attached(object sender, LogicalTreeAttachmentEventArgs e)
private void Attached(object? sender, LogicalTreeAttachmentEventArgs e)
{
Update();
PublishNext(_value);
}
private void Detached(object sender, LogicalTreeAttachmentEventArgs e)
private void Detached(object? sender, LogicalTreeAttachmentEventArgs e)
{
_value = null;
PublishNext(null);

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

@ -12,12 +12,12 @@ namespace Avalonia.LogicalTree
/// <summary>
/// Raised when the control is attached to a rooted logical tree.
/// </summary>
event EventHandler<LogicalTreeAttachmentEventArgs> AttachedToLogicalTree;
event EventHandler<LogicalTreeAttachmentEventArgs>? AttachedToLogicalTree;
/// <summary>
/// Raised when the control is detached from a rooted logical tree.
/// </summary>
event EventHandler<LogicalTreeAttachmentEventArgs> DetachedFromLogicalTree;
event EventHandler<LogicalTreeAttachmentEventArgs>? DetachedFromLogicalTree;
/// <summary>
/// Gets a value indicating whether the element is attached to a rooted logical tree.
@ -27,7 +27,7 @@ namespace Avalonia.LogicalTree
/// <summary>
/// Gets the logical parent.
/// </summary>
ILogical LogicalParent { get; }
ILogical? LogicalParent { get; }
/// <summary>
/// Gets the logical children.

26
src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs

@ -15,14 +15,14 @@ namespace Avalonia.LogicalTree
/// <returns>The logical's ancestors.</returns>
public static IEnumerable<ILogical> GetLogicalAncestors(this ILogical logical)
{
Contract.Requires<ArgumentNullException>(logical != null);
_ = logical ?? throw new ArgumentNullException(nameof(logical));
logical = logical.LogicalParent;
ILogical? l = logical.LogicalParent;
while (logical != null)
while (l != null)
{
yield return logical;
logical = logical.LogicalParent;
yield return l;
l = l.LogicalParent;
}
}
@ -48,14 +48,14 @@ namespace Avalonia.LogicalTree
/// <param name="logical">The logical.</param>
/// <param name="includeSelf">If given logical should be included in search.</param>
/// <returns>First ancestor of given type.</returns>
public static T FindLogicalAncestorOfType<T>(this ILogical logical, bool includeSelf = false) where T : class
public static T? FindLogicalAncestorOfType<T>(this ILogical logical, bool includeSelf = false) where T : class
{
if (logical is null)
{
return null;
}
ILogical parent = includeSelf ? logical : logical.LogicalParent;
var parent = includeSelf ? logical : logical.LogicalParent;
while (parent != null)
{
@ -120,7 +120,7 @@ namespace Avalonia.LogicalTree
/// <param name="logical">The logical.</param>
/// <param name="includeSelf">If given logical should be included in search.</param>
/// <returns>First descendant of given type.</returns>
public static T FindLogicalDescendantOfType<T>(this ILogical logical, bool includeSelf = false) where T : class
public static T? FindLogicalDescendantOfType<T>(this ILogical logical, bool includeSelf = false) where T : class
{
if (logical is null)
{
@ -140,7 +140,7 @@ namespace Avalonia.LogicalTree
/// </summary>
/// <param name="logical">The logical.</param>
/// <returns>The parent, or null if the logical is unparented.</returns>
public static ILogical GetLogicalParent(this ILogical logical)
public static ILogical? GetLogicalParent(this ILogical logical)
{
return logical.LogicalParent;
}
@ -153,7 +153,7 @@ namespace Avalonia.LogicalTree
/// <returns>
/// The parent, or null if the logical is unparented or its parent is not of type <typeparamref name="T"/>.
/// </returns>
public static T GetLogicalParent<T>(this ILogical logical) where T : class
public static T? GetLogicalParent<T>(this ILogical logical) where T : class
{
return logical.LogicalParent as T;
}
@ -165,7 +165,7 @@ namespace Avalonia.LogicalTree
/// <returns>The logical siblings.</returns>
public static IEnumerable<ILogical> GetLogicalSiblings(this ILogical logical)
{
ILogical parent = logical.LogicalParent;
var parent = logical.LogicalParent;
if (parent != null)
{
@ -187,7 +187,7 @@ namespace Avalonia.LogicalTree
/// </returns>
public static bool IsLogicalAncestorOf(this ILogical logical, ILogical target)
{
ILogical current = target?.LogicalParent;
var current = target?.LogicalParent;
while (current != null)
{
@ -202,7 +202,7 @@ namespace Avalonia.LogicalTree
return false;
}
private static T FindDescendantOfTypeCore<T>(ILogical logical) where T : class
private static T? FindDescendantOfTypeCore<T>(ILogical logical) where T : class
{
var logicalChildren = logical.LogicalChildren;
var logicalChildrenCount = logicalChildren.Count;

7
src/Avalonia.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs

@ -19,11 +19,8 @@ namespace Avalonia.LogicalTree
ILogical source,
ILogical parent)
{
Contract.Requires<ArgumentNullException>(root != null);
Contract.Requires<ArgumentNullException>(source != null);
Root = root;
Source = source;
Root = root ?? throw new ArgumentNullException(nameof(root));
Source = source ?? throw new ArgumentNullException(nameof(source));
Parent = parent;
}

18
src/Avalonia.Styling/StyledElement.cs

@ -427,7 +427,7 @@ namespace Avalonia
if (_logicalRoot != null)
{
var e = new LogicalTreeAttachmentEventArgs(_logicalRoot, this, old);
var e = new LogicalTreeAttachmentEventArgs(_logicalRoot, this, old!);
OnDetachedFromLogicalTreeCore(e);
}
@ -435,7 +435,7 @@ namespace Avalonia
if (newRoot is object)
{
var e = new LogicalTreeAttachmentEventArgs(newRoot, this, parent);
var e = new LogicalTreeAttachmentEventArgs(newRoot, this, parent!);
OnAttachedToLogicalTreeCore(e);
}
else if (parent is null)
@ -495,21 +495,21 @@ namespace Avalonia
DetachStylesFromThisAndDescendents(allStyles);
}
protected virtual void LogicalChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
protected virtual void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
SetLogicalParent(e.NewItems);
SetLogicalParent(e.NewItems!);
break;
case NotifyCollectionChangedAction.Remove:
ClearLogicalParent(e.OldItems);
ClearLogicalParent(e.OldItems!);
break;
case NotifyCollectionChangedAction.Replace:
ClearLogicalParent(e.OldItems);
SetLogicalParent(e.NewItems);
ClearLogicalParent(e.OldItems!);
SetLogicalParent(e.NewItems!);
break;
case NotifyCollectionChangedAction.Reset:
@ -729,7 +729,7 @@ namespace Avalonia
for (var i = 0; i < count; i++)
{
var logical = (ILogical) children[i];
var logical = (ILogical) children[i]!;
if (logical.LogicalParent is null)
{
@ -744,7 +744,7 @@ namespace Avalonia
for (var i = 0; i < count; i++)
{
var logical = (ILogical) children[i];
var logical = (ILogical) children[i]!;
if (logical.LogicalParent == this)
{

2
src/Avalonia.Styling/Styling/Activators/NthChildActivator.cs

@ -37,7 +37,7 @@ namespace Avalonia.Styling.Activators
_provider.ChildIndexChanged -= ChildIndexChanged;
}
private void ChildIndexChanged(object sender, ChildIndexChangedEventArgs e)
private void ChildIndexChanged(object? sender, ChildIndexChangedEventArgs e)
{
// Run matching again if:
// 1. Selector is reversed, so other item insertion/deletion might affect total count without changing subscribed item index.

2
src/Avalonia.Styling/Styling/Activators/StyleClassActivator.cs

@ -66,7 +66,7 @@ namespace Avalonia.Styling.Activators
_classes.CollectionChanged -= ClassesChangedHandler;
}
private void ClassesChanged(object sender, NotifyCollectionChangedEventArgs e)
private void ClassesChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Move)
{

6
src/Avalonia.Styling/Styling/ChildSelector.cs

@ -6,7 +6,7 @@ namespace Avalonia.Styling
internal class ChildSelector : Selector
{
private readonly Selector _parent;
private string _selectorString;
private string? _selectorString;
public ChildSelector(Selector parent)
{
@ -25,7 +25,7 @@ namespace Avalonia.Styling
public override bool IsCombinator => true;
/// <inheritdoc/>
public override Type TargetType => null;
public override Type? TargetType => null;
public override string ToString()
{
@ -64,6 +64,6 @@ namespace Avalonia.Styling
}
}
protected override Selector MovePrevious() => null;
protected override Selector? MovePrevious() => null;
}
}

2
src/Avalonia.Styling/Styling/OrSelector.cs

@ -120,7 +120,7 @@ namespace Avalonia.Styling
}
else
{
while (!result.IsAssignableFrom(selector.TargetType))
while (result is not null && !result.IsAssignableFrom(selector.TargetType))
{
result = result.BaseType;
}

7
src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs

@ -53,11 +53,16 @@ namespace Avalonia.Styling
if (_property.IsAttached)
{
builder.Append('(');
builder.Append(_property.OwnerType.Name);
builder.Append('.');
}
builder.Append(_property.Name);
if (_property.IsAttached)
{
builder.Append(')');
}
builder.Append('=');
builder.Append(_value ?? string.Empty);
builder.Append(']');
@ -104,7 +109,7 @@ namespace Avalonia.Styling
var converter = TypeDescriptor.GetConverter(propertyType);
if (converter?.CanConvertFrom(valueType) == true)
{
return Equals(propertyValue, converter.ConvertFrom(null, CultureInfo.InvariantCulture, value));
return Equals(propertyValue, converter.ConvertFrom(null, CultureInfo.InvariantCulture, value!));
}
return false;

50
src/Avalonia.Styling/Styling/Selectors.cs

@ -25,10 +25,14 @@ namespace Avalonia.Styling
/// <param name="previous">The previous selector.</param>
/// <param name="name">The name of the style class.</param>
/// <returns>The selector.</returns>
public static Selector Class(this Selector previous, string name)
public static Selector Class(this Selector? previous, string name)
{
Contract.Requires<ArgumentNullException>(name != null);
Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(name));
_ = name ?? throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("Name may not be empty", nameof(name));
}
var tac = previous as TypeNameAndClassSelector;
@ -48,7 +52,7 @@ namespace Avalonia.Styling
/// </summary>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector Descendant(this Selector previous)
public static Selector Descendant(this Selector? previous)
{
return new DescendantSelector(previous);
}
@ -59,9 +63,9 @@ namespace Avalonia.Styling
/// <param name="previous">The previous selector.</param>
/// <param name="type">The type.</param>
/// <returns>The selector.</returns>
public static Selector Is(this Selector previous, Type type)
public static Selector Is(this Selector? previous, Type type)
{
Contract.Requires<ArgumentNullException>(type != null);
_ = type ?? throw new ArgumentNullException(nameof(type));
return TypeNameAndClassSelector.Is(previous, type);
}
@ -72,7 +76,7 @@ namespace Avalonia.Styling
/// <typeparam name="T">The type.</typeparam>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector Is<T>(this Selector previous) where T : IStyleable
public static Selector Is<T>(this Selector? previous) where T : IStyleable
{
return previous.Is(typeof(T));
}
@ -83,10 +87,14 @@ namespace Avalonia.Styling
/// <param name="previous">The previous selector.</param>
/// <param name="name">The name.</param>
/// <returns>The selector.</returns>
public static Selector Name(this Selector previous, string name)
public static Selector Name(this Selector? previous, string name)
{
Contract.Requires<ArgumentNullException>(name != null);
Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(name));
_ = name ?? throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("Name may not be empty", nameof(name));
}
var tac = previous as TypeNameAndClassSelector;
@ -107,7 +115,7 @@ namespace Avalonia.Styling
/// <param name="previous">The previous selector.</param>
/// <param name="argument">The selector to be not-ed.</param>
/// <returns>The selector.</returns>
public static Selector Not(this Selector previous, Func<Selector, Selector> argument)
public static Selector Not(this Selector? previous, Func<Selector?, Selector> argument)
{
return new NotSelector(previous, argument(null));
}
@ -118,7 +126,7 @@ namespace Avalonia.Styling
/// <param name="previous">The previous selector.</param>
/// <param name="argument">The selector to be not-ed.</param>
/// <returns>The selector.</returns>
public static Selector Not(this Selector previous, Selector argument)
public static Selector Not(this Selector? previous, Selector argument)
{
return new NotSelector(previous, argument);
}
@ -126,7 +134,7 @@ namespace Avalonia.Styling
/// <inheritdoc cref="NthChildSelector"/>
/// <inheritdoc cref="NthChildSelector(Selector?, int, int)"/>
/// <returns>The selector.</returns>
public static Selector NthChild(this Selector previous, int step, int offset)
public static Selector NthChild(this Selector? previous, int step, int offset)
{
return new NthChildSelector(previous, step, offset);
}
@ -134,7 +142,7 @@ namespace Avalonia.Styling
/// <inheritdoc cref="NthLastChildSelector"/>
/// <inheritdoc cref="NthLastChildSelector(Selector?, int, int)"/>
/// <returns>The selector.</returns>
public static Selector NthLastChild(this Selector previous, int step, int offset)
public static Selector NthLastChild(this Selector? previous, int step, int offset)
{
return new NthLastChildSelector(previous, step, offset);
}
@ -145,9 +153,9 @@ namespace Avalonia.Styling
/// <param name="previous">The previous selector.</param>
/// <param name="type">The type.</param>
/// <returns>The selector.</returns>
public static Selector OfType(this Selector previous, Type type)
public static Selector OfType(this Selector? previous, Type type)
{
Contract.Requires<ArgumentNullException>(type != null);
_ = type ?? throw new ArgumentNullException(nameof(type));
return TypeNameAndClassSelector.OfType(previous, type);
}
@ -158,7 +166,7 @@ namespace Avalonia.Styling
/// <typeparam name="T">The type.</typeparam>
/// <param name="previous">The previous selector.</param>
/// <returns>The selector.</returns>
public static Selector OfType<T>(this Selector previous) where T : IStyleable
public static Selector OfType<T>(this Selector? previous) where T : IStyleable
{
return previous.OfType(typeof(T));
}
@ -191,9 +199,9 @@ namespace Avalonia.Styling
/// <param name="property">The property.</param>
/// <param name="value">The property value.</param>
/// <returns>The selector.</returns>
public static Selector PropertyEquals<T>(this Selector previous, AvaloniaProperty<T> property, object value)
public static Selector PropertyEquals<T>(this Selector? previous, AvaloniaProperty<T> property, object? value)
{
Contract.Requires<ArgumentNullException>(property != null);
_ = property ?? throw new ArgumentNullException(nameof(property));
return new PropertyEqualsSelector(previous, property, value);
}
@ -205,9 +213,9 @@ namespace Avalonia.Styling
/// <param name="property">The property.</param>
/// <param name="value">The property value.</param>
/// <returns>The selector.</returns>
public static Selector PropertyEquals(this Selector previous, AvaloniaProperty property, object value)
public static Selector PropertyEquals(this Selector? previous, AvaloniaProperty property, object? value)
{
Contract.Requires<ArgumentNullException>(property != null);
_ = property ?? throw new ArgumentNullException(nameof(property));
return new PropertyEqualsSelector(previous, property, value);
}

14
src/Avalonia.Styling/Styling/Styles.cs

@ -262,7 +262,7 @@ namespace Avalonia.Styling
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
static IReadOnlyList<T> ToReadOnlyList<T>(IList list)
{
@ -282,7 +282,7 @@ namespace Avalonia.Styling
{
for (var i = 0; i < items.Count; ++i)
{
var style = (IStyle)items[i];
var style = (IStyle)items[i]!;
if (Owner is object && style is IResourceProvider resourceProvider)
{
@ -299,7 +299,7 @@ namespace Avalonia.Styling
{
for (var i = 0; i < items.Count; ++i)
{
var style = (IStyle)items[i];
var style = (IStyle)items[i]!;
if (Owner is object && style is IResourceProvider resourceProvider)
{
@ -315,14 +315,14 @@ namespace Avalonia.Styling
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
Add(e.NewItems);
Add(e.NewItems!);
break;
case NotifyCollectionChangedAction.Remove:
Remove(e.OldItems);
Remove(e.OldItems!);
break;
case NotifyCollectionChangedAction.Replace:
Remove(e.OldItems);
Add(e.NewItems);
Remove(e.OldItems!);
Add(e.NewItems!);
break;
case NotifyCollectionChangedAction.Reset:
throw new InvalidOperationException("Reset should not be called on Styles.");

6
src/Avalonia.Styling/Styling/TemplateSelector.cs

@ -5,7 +5,7 @@ namespace Avalonia.Styling
internal class TemplateSelector : Selector
{
private readonly Selector _parent;
private string _selectorString;
private string? _selectorString;
public TemplateSelector(Selector parent)
{
@ -24,7 +24,7 @@ namespace Avalonia.Styling
public override bool IsCombinator => true;
/// <inheritdoc/>
public override Type TargetType => null;
public override Type? TargetType => null;
public override string ToString()
{
@ -48,6 +48,6 @@ namespace Avalonia.Styling
return _parent.Match(templatedParent, subscribe);
}
protected override Selector MovePrevious() => null;
protected override Selector? MovePrevious() => null;
}
}

2
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />

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

@ -115,7 +115,11 @@
StaysOpen="False">
<Calendar Name="PART_Calendar"
FirstDayOfWeek="{TemplateBinding FirstDayOfWeek}"
IsTodayHighlighted="{TemplateBinding IsTodayHighlighted}"/>
IsTodayHighlighted="{TemplateBinding IsTodayHighlighted}"
SelectedDate="{TemplateBinding SelectedDate, Mode=TwoWay}"
DisplayDate="{TemplateBinding DisplayDate}"
DisplayDateStart="{TemplateBinding DisplayDateStart}"
DisplayDateEnd="{TemplateBinding DisplayDateEnd}" />
</Popup>
</Grid>
</ControlTemplate>

2
src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />

6
src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml

@ -129,7 +129,11 @@
IsLightDismissEnabled="True">
<Calendar Name="PART_Calendar"
FirstDayOfWeek="{TemplateBinding FirstDayOfWeek}"
IsTodayHighlighted="{TemplateBinding IsTodayHighlighted}"/>
IsTodayHighlighted="{TemplateBinding IsTodayHighlighted}"
SelectedDate="{TemplateBinding SelectedDate, Mode=TwoWay}"
DisplayDate="{TemplateBinding DisplayDate}"
DisplayDateStart="{TemplateBinding DisplayDateStart}"
DisplayDateEnd="{TemplateBinding DisplayDateEnd}" />
</Popup>
</Grid>
</ControlTemplate>

2
src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs

@ -143,7 +143,7 @@ namespace Avalonia.Animation.Animators
if (!match(firstKeyType))
continue;
animator = (IAnimator)Activator.CreateInstance(animatorType);
animator = (IAnimator?)Activator.CreateInstance(animatorType);
if (animator != null)
{
animator.Property = Property;

4
src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs

@ -11,10 +11,10 @@ namespace Avalonia.Animation.Animators
/// </summary>
public class TransformAnimator : Animator<double>
{
DoubleAnimator _doubleAnimator;
DoubleAnimator? _doubleAnimator;
/// <inheritdoc/>
public override IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> obsMatch, Action onComplete)
public override IDisposable? Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> obsMatch, Action onComplete)
{
var ctrl = (Visual)control;

2
src/Avalonia.Visuals/Animation/CompositePageTransition.cs

@ -37,7 +37,7 @@ namespace Avalonia.Animation
public List<IPageTransition> PageTransitions { get; set; } = new List<IPageTransition>();
/// <inheritdoc />
public Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
public Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
var transitionTasks = PageTransitions
.Select(transition => transition.Start(from, to, forward, cancellationToken))

6
src/Avalonia.Visuals/Animation/CrossFade.cs

@ -100,7 +100,7 @@ namespace Avalonia.Animation
}
/// <inheritdoc cref="Start(Visual, Visual, CancellationToken)" />
public async Task Start(Visual from, Visual to, CancellationToken cancellationToken)
public async Task Start(Visual? from, Visual? to, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
@ -112,7 +112,7 @@ namespace Avalonia.Animation
{
if (to != null)
{
disposables.Add(to.SetValue(Visual.OpacityProperty, 0, Data.BindingPriority.Animation));
disposables.Add(to.SetValue(Visual.OpacityProperty, 0, Data.BindingPriority.Animation)!);
}
if (from != null)
@ -151,7 +151,7 @@ namespace Avalonia.Animation
/// <returns>
/// A <see cref="Task"/> that tracks the progress of the animation.
/// </returns>
Task IPageTransition.Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
Task IPageTransition.Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
return Start(from, to, cancellationToken);
}

2
src/Avalonia.Visuals/Animation/IPageTransition.cs

@ -26,6 +26,6 @@ namespace Avalonia.Animation
/// <returns>
/// A <see cref="Task"/> that tracks the progress of the animation.
/// </returns>
Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken);
Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken);
}
}

10
src/Avalonia.Visuals/Animation/PageSlide.cs

@ -62,7 +62,7 @@ namespace Avalonia.Animation
public Easing SlideOutEasing { get; set; } = new LinearEasing();
/// <inheritdoc />
public async Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
@ -155,17 +155,17 @@ namespace Avalonia.Animation
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
private static IVisual GetVisualParent(IVisual from, IVisual to)
private static IVisual GetVisualParent(IVisual? from, IVisual? to)
{
var p1 = (from ?? to).VisualParent;
var p2 = (to ?? from).VisualParent;
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;
if (p1 != null && p2 != null && p1 != p2)
{
throw new ArgumentException("Controls for PageSlide must have same parent.");
}
return p1;
return p1 ?? throw new InvalidOperationException("Cannot determine visual parent.");
}
}
}

2
src/Avalonia.Visuals/Animation/RenderLoopClock.cs

@ -9,7 +9,7 @@ namespace Avalonia.Animation
{
protected override void Stop()
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Remove(this);
AvaloniaLocator.Current.GetRequiredService<IRenderLoop>().Remove(this);
}
bool IRenderLoopTask.NeedsUpdate => HasSubscriptions;

4
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -5,6 +5,8 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Task
MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.IPageTransition.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IPageTransition.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean, System.Threading.CancellationToken)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.PageSlide.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.GlyphRun..ctor()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.GlyphRun.GlyphTypeface.set(Avalonia.Media.GlyphTypeface)' does not exist in the implementation but it does exist in the contract.
TypeCannotChangeClassification : Type 'Avalonia.Media.Immutable.ImmutableSolidColorBrush' is a 'class' in the implementation but is a 'struct' in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' is abstract in the implementation but is missing in the contract.
@ -77,4 +79,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWr
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmap(System.String)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmapToHeight(System.IO.Stream, System.Int32, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmapToWidth(System.IO.Stream, System.Int32, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the implementation but not in the contract.
Total Issues: 78
Total Issues: 79

3
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
@ -15,4 +15,5 @@
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\System.Memory.props" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project>

2
src/Avalonia.Visuals/CornerRadius.cs

@ -91,7 +91,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this corner radius; False otherwise.</returns>
public override bool Equals(object obj) => obj is CornerRadius other && Equals(other);
public override bool Equals(object? obj) => obj is CornerRadius other && Equals(other);
public override int GetHashCode()
{

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

Loading…
Cancel
Save