Browse Source

Nullability fixes for Avalonia.Controls

pull/10256/head
Julien Lebosquain 3 years ago
parent
commit
e1138f2cb6
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 6
      src/Avalonia.Base/Input/Platform/IClipboard.cs
  2. 2
      src/Avalonia.Base/Media/Color.cs
  3. 5
      src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs
  4. 28
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  5. 5
      src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
  6. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  7. 282
      src/Avalonia.Controls/Automation/AutomationProperties.cs
  8. 18
      src/Avalonia.Controls/Calendar/Calendar.cs
  9. 14
      src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs
  10. 112
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  11. 33
      src/Avalonia.Controls/Calendar/DateTimeHelper.cs
  12. 20
      src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
  13. 40
      src/Avalonia.Controls/Chrome/TitleBar.cs
  14. 1
      src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
  15. 90
      src/Avalonia.Controls/DefinitionBase.cs
  16. 9
      src/Avalonia.Controls/DockPanel.cs
  17. 9
      src/Avalonia.Controls/Documents/Inline.cs
  18. 14
      src/Avalonia.Controls/Documents/Span.cs
  19. 230
      src/Avalonia.Controls/Grid.cs
  20. 7
      src/Avalonia.Controls/Image.cs
  21. 12
      src/Avalonia.Controls/ItemsControl.cs
  22. 20
      src/Avalonia.Controls/LayoutTransformControl.cs
  23. 12
      src/Avalonia.Controls/MaskedTextBox.cs
  24. 22
      src/Avalonia.Controls/NativeControlHost.cs
  25. 20
      src/Avalonia.Controls/NativeMenu.Export.cs
  26. 12
      src/Avalonia.Controls/Primitives/AdornerLayer.cs
  27. 12
      src/Avalonia.Controls/Primitives/Popup.cs
  28. 31
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  29. 7
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  30. 8
      src/Avalonia.Controls/Primitives/TextSearch.cs
  31. 19
      src/Avalonia.Controls/Primitives/Track.cs
  32. 16
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  33. 7
      src/Avalonia.Controls/RelativePanel.cs
  34. 44
      src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
  35. 13
      src/Avalonia.Controls/Slider.cs
  36. 9
      src/Avalonia.Controls/StackPanel.cs
  37. 18
      src/Avalonia.Controls/TickBar.cs
  38. 9
      src/Avalonia.Controls/TrayIcon.cs
  39. 16
      src/Avalonia.Controls/TreeView.cs
  40. 36
      src/Avalonia.Controls/Viewbox.cs
  41. 107
      src/Avalonia.Controls/WrapPanel.cs
  42. 10
      src/Browser/Avalonia.Browser/ClipboardImpl.cs

6
src/Avalonia.Base/Input/Platform/IClipboard.cs

@ -6,9 +6,9 @@ namespace Avalonia.Input.Platform
[NotClientImplementable]
public interface IClipboard
{
Task<string> GetTextAsync();
Task<string?> GetTextAsync();
Task SetTextAsync(string text);
Task SetTextAsync(string? text);
Task ClearAsync();
@ -16,6 +16,6 @@ namespace Avalonia.Input.Platform
Task<string[]> GetFormatsAsync();
Task<object> GetDataAsync(string format);
Task<object?> GetDataAsync(string format);
}
}

2
src/Avalonia.Base/Media/Color.cs

@ -331,7 +331,7 @@ namespace Avalonia.Media
/// <summary>
/// Parses the given string representing a CSS color value into a new <see cref="Color"/>.
/// </summary>
private static bool TryParseCssFormat(string s, out Color color)
private static bool TryParseCssFormat(string? s, out Color color)
{
bool prefixMatched = false;

5
src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
@ -18,7 +19,7 @@ internal class AssemblyDescriptor : IAssemblyDescriptor
{
public AssemblyDescriptor(Assembly assembly)
{
Assembly = assembly;
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
Resources = assembly.GetManifestResourceNames()
.ToDictionary(n => n, n => (IAssetDescriptor)new AssemblyResourceDescriptor(assembly, n));
Name = assembly.GetName().Name;

28
src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@ -17,32 +16,34 @@ namespace Avalonia.Controls.ApplicationLifetimes
private int _exitCode;
private CancellationTokenSource? _cts;
private bool _isShuttingDown;
private HashSet<Window> _windows = new HashSet<Window>();
private readonly HashSet<Window> _windows = new();
private static ClassicDesktopStyleApplicationLifetime? s_activeLifetime;
private static ClassicDesktopStyleApplicationLifetime? _activeLifetime;
static ClassicDesktopStyleApplicationLifetime()
{
Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened);
Window.WindowClosedEvent.AddClassHandler(typeof(Window), WindowClosedEvent);
Window.WindowClosedEvent.AddClassHandler(typeof(Window), OnWindowClosed);
}
private static void WindowClosedEvent(object? sender, RoutedEventArgs e)
private static void OnWindowClosed(object? sender, RoutedEventArgs e)
{
_activeLifetime?._windows.Remove((Window)sender!);
_activeLifetime?.HandleWindowClosed((Window)sender!);
var window = (Window)sender!;
s_activeLifetime?._windows.Remove(window);
s_activeLifetime?.HandleWindowClosed(window);
}
private static void OnWindowOpened(object? sender, RoutedEventArgs e)
{
_activeLifetime?._windows.Add((Window)sender!);
s_activeLifetime?._windows.Add((Window)sender!);
}
public ClassicDesktopStyleApplicationLifetime()
{
if (_activeLifetime != null)
if (s_activeLifetime != null)
throw new InvalidOperationException(
"Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed");
_activeLifetime = this;
s_activeLifetime = this;
}
/// <inheritdoc/>
@ -65,9 +66,10 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// <inheritdoc/>
public Window? MainWindow { get; set; }
/// <inheritdoc />
public IReadOnlyList<Window> Windows => _windows.ToArray();
private void HandleWindowClosed(Window window)
private void HandleWindowClosed(Window? window)
{
if (window == null)
return;
@ -130,8 +132,8 @@ namespace Avalonia.Controls.ApplicationLifetimes
public void Dispose()
{
if (_activeLifetime == this)
_activeLifetime = null;
if (s_activeLifetime == this)
s_activeLifetime = null;
}
private bool DoShutdown(

5
src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs

@ -40,7 +40,10 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// The main window.
/// </value>
Window? MainWindow { get; set; }
/// <summary>
/// Gets the list of all open windows in the application.
/// </summary>
IReadOnlyList<Window> Windows { get; }
/// <summary>

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -1711,7 +1711,7 @@ namespace Avalonia.Controls
/// <param name="predicate">The predicate to use for the partial or
/// exact match.</param>
/// <returns>Returns the object or null.</returns>
private object? TryGetMatch(string? searchText, AvaloniaList<object> view, AutoCompleteFilterPredicate<string?>? predicate)
private object? TryGetMatch(string? searchText, AvaloniaList<object>? view, AutoCompleteFilterPredicate<string?>? predicate)
{
if (predicate is null)
return null;

282
src/Avalonia.Controls/Automation/AutomationProperties.cs

@ -38,8 +38,8 @@ namespace Avalonia.Automation
/// <summary>
/// Defines the AutomationProperties.AcceleratorKey attached property.
/// </summary>
public static readonly AttachedProperty<string> AcceleratorKeyProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> AcceleratorKeyProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"AcceleratorKey",
typeof(AutomationProperties));
@ -54,16 +54,16 @@ namespace Avalonia.Automation
/// <summary>
/// Defines the AutomationProperties.AccessKey attached property
/// </summary>
public static readonly AttachedProperty<string> AccessKeyProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> AccessKeyProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"AccessKey",
typeof(AutomationProperties));
/// <summary>
/// Defines the AutomationProperties.AutomationId attached property.
/// </summary>
public static readonly AttachedProperty<string> AutomationIdProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> AutomationIdProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"AutomationId",
typeof(AutomationProperties));
@ -78,8 +78,8 @@ namespace Avalonia.Automation
/// <summary>
/// Defines the AutomationProperties.HelpText attached property.
/// </summary>
public static readonly AttachedProperty<string> HelpTextProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> HelpTextProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"HelpText",
typeof(AutomationProperties));
@ -122,16 +122,16 @@ namespace Avalonia.Automation
/// <summary>
/// Defines the AutomationProperties.ItemStatus attached property.
/// </summary>
public static readonly AttachedProperty<string> ItemStatusProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> ItemStatusProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"ItemStatus",
typeof(AutomationProperties));
/// <summary>
/// Defines the AutomationProperties.ItemType attached property.
/// </summary>
public static readonly AttachedProperty<string> ItemTypeProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> ItemTypeProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"ItemType",
typeof(AutomationProperties));
@ -155,8 +155,8 @@ namespace Avalonia.Automation
/// <summary>
/// Defines the AutomationProperties.Name attached attached property.
/// </summary>
public static readonly AttachedProperty<string> NameProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string>(
public static readonly AttachedProperty<string?> NameProperty =
AvaloniaProperty.RegisterAttached<StyledElement, string?>(
"Name",
typeof(AutomationProperties));
@ -193,25 +193,17 @@ namespace Avalonia.Automation
/// </summary>
public static void SetAcceleratorKey(StyledElement element, string value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AcceleratorKeyProperty, value);
}
/// <summary>
/// Helper for reading AcceleratorKey property from a StyledElement.
/// </summary>
public static string GetAcceleratorKey(StyledElement element)
public static string? GetAcceleratorKey(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((string)element.GetValue(AcceleratorKeyProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(AcceleratorKeyProperty);
}
/// <summary>
@ -219,11 +211,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetAccessibilityView(StyledElement element, AccessibilityView value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AccessibilityViewProperty, value);
}
@ -232,11 +220,7 @@ namespace Avalonia.Automation
/// </summary>
public static AccessibilityView GetAccessibilityView(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(AccessibilityViewProperty);
}
@ -245,50 +229,34 @@ namespace Avalonia.Automation
/// </summary>
public static void SetAccessKey(StyledElement element, string value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AccessKeyProperty, value);
}
/// <summary>
/// Helper for reading AccessKey property from a StyledElement.
/// </summary>
public static string GetAccessKey(StyledElement element)
public static string? GetAccessKey(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((string)element.GetValue(AccessKeyProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(AccessKeyProperty);
}
/// <summary>
/// Helper for setting AutomationId property on a StyledElement.
/// </summary>
public static void SetAutomationId(StyledElement element, string value)
public static void SetAutomationId(StyledElement element, string? value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(AutomationIdProperty, value);
}
/// <summary>
/// Helper for reading AutomationId property from a StyledElement.
/// </summary>
public static string GetAutomationId(StyledElement element)
public static string? GetAutomationId(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(AutomationIdProperty);
}
@ -297,11 +265,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetControlTypeOverride(StyledElement element, AutomationControlType? value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ControlTypeOverrideProperty, value);
}
@ -310,38 +274,26 @@ namespace Avalonia.Automation
/// </summary>
public static AutomationControlType? GetControlTypeOverride(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ControlTypeOverrideProperty);
}
/// <summary>
/// Helper for setting HelpText property on a StyledElement.
/// </summary>
public static void SetHelpText(StyledElement element, string value)
public static void SetHelpText(StyledElement element, string? value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(HelpTextProperty, value);
}
/// <summary>
/// Helper for reading HelpText property from a StyledElement.
/// </summary>
public static string GetHelpText(StyledElement element)
public static string? GetHelpText(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((string)element.GetValue(HelpTextProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(HelpTextProperty);
}
/// <summary>
@ -349,11 +301,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetIsColumnHeader(StyledElement element, bool value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsColumnHeaderProperty, value);
}
@ -362,12 +310,8 @@ namespace Avalonia.Automation
/// </summary>
public static bool GetIsColumnHeader(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((bool)element.GetValue(IsColumnHeaderProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(IsColumnHeaderProperty);
}
/// <summary>
@ -375,11 +319,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetIsRequiredForForm(StyledElement element, bool value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsRequiredForFormProperty, value);
}
@ -388,12 +328,8 @@ namespace Avalonia.Automation
/// </summary>
public static bool GetIsRequiredForForm(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((bool)element.GetValue(IsRequiredForFormProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(IsRequiredForFormProperty);
}
/// <summary>
@ -401,12 +337,8 @@ namespace Avalonia.Automation
/// </summary>
public static bool GetIsRowHeader(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((bool)element.GetValue(IsRowHeaderProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(IsRowHeaderProperty);
}
/// <summary>
@ -414,11 +346,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetIsRowHeader(StyledElement element, bool value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsRowHeaderProperty, value);
}
@ -427,11 +355,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetIsOffscreenBehavior(StyledElement element, IsOffscreenBehavior value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsOffscreenBehaviorProperty, value);
}
@ -440,64 +364,44 @@ namespace Avalonia.Automation
/// </summary>
public static IsOffscreenBehavior GetIsOffscreenBehavior(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((IsOffscreenBehavior)element.GetValue(IsOffscreenBehaviorProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(IsOffscreenBehaviorProperty);
}
/// <summary>
/// Helper for setting ItemStatus property on a StyledElement.
/// </summary>
public static void SetItemStatus(StyledElement element, string value)
public static void SetItemStatus(StyledElement element, string? value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ItemStatusProperty, value);
}
/// <summary>
/// Helper for reading ItemStatus property from a StyledElement.
/// </summary>
public static string GetItemStatus(StyledElement element)
public static string? GetItemStatus(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((string)element.GetValue(ItemStatusProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ItemStatusProperty);
}
/// <summary>
/// Helper for setting ItemType property on a StyledElement.
/// </summary>
public static void SetItemType(StyledElement element, string value)
public static void SetItemType(StyledElement element, string? value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ItemTypeProperty, value);
}
/// <summary>
/// Helper for reading ItemType property from a StyledElement.
/// </summary>
public static string GetItemType(StyledElement element)
public static string? GetItemType(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((string)element.GetValue(ItemTypeProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ItemTypeProperty);
}
/// <summary>
@ -505,11 +409,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetLabeledBy(StyledElement element, Control value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(LabeledByProperty, value);
}
@ -518,11 +418,7 @@ namespace Avalonia.Automation
/// </summary>
public static Control GetLabeledBy(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(LabeledByProperty);
}
@ -531,11 +427,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetLiveSetting(StyledElement element, AutomationLiveSetting value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(LiveSettingProperty, value);
}
@ -544,38 +436,26 @@ namespace Avalonia.Automation
/// </summary>
public static AutomationLiveSetting GetLiveSetting(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((AutomationLiveSetting)element.GetValue(LiveSettingProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(LiveSettingProperty);
}
/// <summary>
/// Helper for setting Name property on a StyledElement.
/// </summary>
public static void SetName(StyledElement element, string value)
public static void SetName(StyledElement element, string? value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(NameProperty, value);
}
/// <summary>
/// Helper for reading Name property from a StyledElement.
/// </summary>
public static string GetName(StyledElement element)
public static string? GetName(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((string)element.GetValue(NameProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(NameProperty);
}
/// <summary>
@ -583,11 +463,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetPositionInSet(StyledElement element, int value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(PositionInSetProperty, value);
}
@ -596,12 +472,8 @@ namespace Avalonia.Automation
/// </summary>
public static int GetPositionInSet(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((int)element.GetValue(PositionInSetProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(PositionInSetProperty);
}
/// <summary>
@ -609,11 +481,7 @@ namespace Avalonia.Automation
/// </summary>
public static void SetSizeOfSet(StyledElement element, int value)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(SizeOfSetProperty, value);
}
@ -622,12 +490,8 @@ namespace Avalonia.Automation
/// </summary>
public static int GetSizeOfSet(StyledElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
return ((int)element.GetValue(SizeOfSetProperty));
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(SizeOfSetProperty);
}
}
}

18
src/Avalonia.Controls/Calendar/Calendar.cs

@ -237,11 +237,11 @@ namespace Avalonia.Controls
private DateTime _selectedYear;
private DateTime _displayDate = DateTime.Today;
private DateTime? _displayDateStart = null;
private DateTime? _displayDateEnd = null;
private DateTime? _displayDateStart;
private DateTime? _displayDateEnd;
private bool _isShiftPressed;
private bool _displayDateIsChanging = false;
private bool _displayDateIsChanging;
internal CalendarDayButton? FocusButton { get; set; }
internal CalendarButton? FocusCalendarButton { get; set; }
@ -291,7 +291,7 @@ namespace Avalonia.Controls
}
else
{
throw new ArgumentOutOfRangeException("d", "Invalid DayOfWeek");
throw new ArgumentOutOfRangeException(nameof(e), "Invalid DayOfWeek");
}
}
@ -346,10 +346,10 @@ namespace Avalonia.Controls
}
}
public static readonly StyledProperty<IBrush> HeaderBackgroundProperty =
AvaloniaProperty.Register<Calendar, IBrush>(nameof(HeaderBackground));
public static readonly StyledProperty<IBrush?> HeaderBackgroundProperty =
AvaloniaProperty.Register<Calendar, IBrush?>(nameof(HeaderBackground));
public IBrush HeaderBackground
public IBrush? HeaderBackground
{
get { return GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); }
@ -478,7 +478,7 @@ namespace Avalonia.Controls
}
else
{
throw new ArgumentOutOfRangeException("d", "Invalid SelectionMode");
throw new ArgumentOutOfRangeException(nameof(e), "Invalid SelectionMode");
}
}
@ -574,7 +574,7 @@ namespace Avalonia.Controls
}
else
{
throw new ArgumentOutOfRangeException("d", "SelectedDate value is not valid.");
throw new ArgumentOutOfRangeException(nameof(e), "SelectedDate value is not valid.");
}
}
else

14
src/Avalonia.Controls/Calendar/CalendarBlackoutDatesCollection.cs

@ -15,7 +15,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// The Calendar whose dates this object represents.
/// </summary>
private Calendar _owner;
private readonly Calendar _owner;
/// <summary>
/// Initializes a new instance of the
@ -79,13 +79,13 @@ namespace Avalonia.Controls.Primitives
if (DateTime.Compare(end, start) > -1)
{
rangeStart = DateTimeHelper.DiscardTime(start).Value;
rangeEnd = DateTimeHelper.DiscardTime(end).Value;
rangeStart = DateTimeHelper.DiscardTime(start);
rangeEnd = DateTimeHelper.DiscardTime(end);
}
else
{
rangeStart = DateTimeHelper.DiscardTime(end).Value;
rangeEnd = DateTimeHelper.DiscardTime(start).Value;
rangeStart = DateTimeHelper.DiscardTime(end);
rangeEnd = DateTimeHelper.DiscardTime(start);
}
int count = Count;
@ -144,7 +144,7 @@ namespace Avalonia.Controls.Primitives
if (!IsValid(item))
{
throw new ArgumentOutOfRangeException("Value is not valid.");
throw new ArgumentOutOfRangeException(nameof(item), "Value is not valid.");
}
base.InsertItem(index, item);
@ -186,7 +186,7 @@ namespace Avalonia.Controls.Primitives
if (!IsValid(item))
{
throw new ArgumentOutOfRangeException("Value is not valid.");
throw new ArgumentOutOfRangeException(nameof(item), "Value is not valid.");
}
base.SetItem(index, item);

112
src/Avalonia.Controls/Calendar/CalendarItem.cs

@ -44,30 +44,30 @@ namespace Avalonia.Controls.Primitives
private ITemplate<Control>? _dayTitleTemplate;
private DateTime _currentMonth;
private bool _isMouseLeftButtonDown = false;
private bool _isMouseLeftButtonDownYearView = false;
private bool _isControlPressed = false;
private bool _isMouseLeftButtonDown;
private bool _isMouseLeftButtonDownYearView;
private bool _isControlPressed;
private System.Globalization.Calendar _calendar = new System.Globalization.GregorianCalendar();
private PointerPressedEventArgs? _downEventArg;
private PointerPressedEventArgs? _downEventArgYearView;
private readonly System.Globalization.Calendar _calendar = new GregorianCalendar();
internal Calendar? Owner { get; set; }
internal CalendarDayButton? CurrentButton { get; set; }
public static readonly StyledProperty<IBrush> HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner<CalendarItem>();
public IBrush HeaderBackground
public static readonly StyledProperty<IBrush?> HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner<CalendarItem>();
public IBrush? HeaderBackground
{
get { return GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); }
}
public static readonly DirectProperty<CalendarItem, ITemplate<Control>?> DayTitleTemplateProperty =
AvaloniaProperty.RegisterDirect<CalendarItem, ITemplate<Control>?>(
nameof(DayTitleTemplate),
o => o.DayTitleTemplate,
(o,v) => o.DayTitleTemplate = v,
defaultBindingMode: BindingMode.OneTime);
public ITemplate<Control>? DayTitleTemplate
{
get { return _dayTitleTemplate; }
@ -178,7 +178,7 @@ namespace Avalonia.Controls.Primitives
{
if (_dayTitleTemplate != null)
{
var cell = (Control) _dayTitleTemplate.Build();
var cell = _dayTitleTemplate.Build();
cell.DataContext = string.Empty;
cell.SetValue(Grid.RowProperty, 0);
cell.SetValue(Grid.ColumnProperty, i);
@ -308,16 +308,13 @@ namespace Avalonia.Controls.Primitives
for (int childIndex = 0; childIndex < Calendar.ColumnsPerMonth; childIndex++)
{
var daytitle = MonthView!.Children[childIndex];
if (daytitle != null)
if (Owner != null)
{
if (Owner != null)
{
daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)Owner.FirstDayOfWeek) % NumberOfDaysPerWeek];
}
else
{
daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek) % NumberOfDaysPerWeek];
}
daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)Owner.FirstDayOfWeek) % NumberOfDaysPerWeek];
}
else
{
daytitle.DataContext = DateTimeHelper.GetCurrentDateFormat().ShortestDayNames[(childIndex + (int)DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek) % NumberOfDaysPerWeek];
}
}
}
@ -527,7 +524,7 @@ namespace Avalonia.Controls.Primitives
childButton.Content = dateToAdd.Day.ToString(DateTimeHelper.GetCurrentDateFormat());
childButton.DataContext = dateToAdd;
if (DateTime.Compare((DateTime)DateTimeHelper.DiscardTime(DateTime.MaxValue), dateToAdd) > 0)
if (DateTime.Compare(DateTimeHelper.DiscardTime(DateTime.MaxValue), dateToAdd) > 0)
{
// Since we are sure DisplayDate is not equal to
// DateTime.MaxValue, it is safe to use AddDays
@ -587,7 +584,7 @@ namespace Avalonia.Controls.Primitives
{
if (Owner != null)
{
_currentMonth = (DateTime)Owner.SelectedMonth;
_currentMonth = Owner.SelectedMonth;
}
else
{
@ -676,7 +673,7 @@ namespace Avalonia.Controls.Primitives
if (Owner != null)
{
selectedYear = Owner.SelectedYear;
_currentMonth = (DateTime)Owner.SelectedMonth;
_currentMonth = Owner.SelectedMonth;
}
else
{
@ -696,9 +693,9 @@ namespace Avalonia.Controls.Primitives
SetYearButtons(decade, decadeEnd);
}
}
internal void UpdateYearViewSelection(CalendarButton calendarButton)
internal void UpdateYearViewSelection(CalendarButton? calendarButton)
{
if (Owner != null && calendarButton != null && calendarButton.DataContext != null)
if (Owner != null && calendarButton?.DataContext is DateTime selectedDate)
{
Owner.FocusCalendarButton!.IsCalendarButtonFocused = false;
Owner.FocusCalendarButton = calendarButton;
@ -706,11 +703,11 @@ namespace Avalonia.Controls.Primitives
if (Owner.DisplayMode == CalendarMode.Year)
{
Owner.SelectedMonth = (DateTime)calendarButton.DataContext;
Owner.SelectedMonth = selectedDate;
}
else
{
Owner.SelectedYear = (DateTime)calendarButton.DataContext;
Owner.SelectedYear = selectedDate;
}
}
}
@ -719,7 +716,7 @@ namespace Avalonia.Controls.Primitives
{
int year;
int count = -1;
foreach (object child in YearView!.Children)
foreach (var child in YearView!.Children)
{
CalendarButton childButton = (CalendarButton)child;
year = decade + count;
@ -859,7 +856,8 @@ namespace Avalonia.Controls.Primitives
{
if (Owner != null)
{
if (_isMouseLeftButtonDown && sender is CalendarDayButton b && b.IsEnabled && !b.IsBlackout)
if (_isMouseLeftButtonDown
&& sender is CalendarDayButton { IsEnabled: true, IsBlackout: false, DataContext: DateTime selectedDate } b)
{
// Update the states of all buttons to be selected starting
// from HoverStart to b
@ -867,7 +865,6 @@ namespace Avalonia.Controls.Primitives
{
case CalendarSelectionMode.SingleDate:
{
DateTime selectedDate = (DateTime)b.DataContext!;
Owner.CalendarDatePickerDisplayDateFlag = true;
if (Owner.SelectedDates.Count == 0)
{
@ -882,10 +879,9 @@ namespace Avalonia.Controls.Primitives
case CalendarSelectionMode.SingleRange:
case CalendarSelectionMode.MultipleRange:
{
Debug.Assert(b.DataContext != null, "The DataContext should not be null!");
Owner.UnHighlightDays();
Owner.HoverEndIndex = b.Index;
Owner.HoverEnd = (DateTime?)b.DataContext;
Owner.HoverEnd = selectedDate;
// Update the States of the buttons
Owner.HighlightDays();
return;
@ -904,22 +900,14 @@ namespace Avalonia.Controls.Primitives
Owner.Focus();
}
bool ctrl, shift;
CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out ctrl, out shift);
CalendarDayButton b = (CalendarDayButton)sender!;
CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out var ctrl, out var shift);
if (b != null)
if (sender is CalendarDayButton b)
{
_isControlPressed = ctrl;
if (b.IsEnabled && !b.IsBlackout)
if (b.IsEnabled && !b.IsBlackout && b.DataContext is DateTime selectedDate)
{
DateTime selectedDate = (DateTime)b.DataContext!;
_isMouseLeftButtonDown = true;
// null check is added for unit tests
if (e != null)
{
_downEventArg = e;
}
switch (Owner.SelectionMode)
{
@ -1010,12 +998,12 @@ namespace Avalonia.Controls.Primitives
}
}
}
private void AddSelection(CalendarDayButton b)
private void AddSelection(CalendarDayButton b, DateTime selectedDate)
{
if (Owner != null)
{
Owner.HoverEndIndex = b.Index;
Owner.HoverEnd = (DateTime)b.DataContext!;
Owner.HoverEnd = selectedDate;
if (Owner.HoverEnd != null && Owner.HoverStart != null)
{
@ -1025,7 +1013,7 @@ namespace Avalonia.Controls.Primitives
// SelectionMode
Owner.IsMouseSelection = true;
Owner.SelectedDates.AddRange(Owner.HoverStart.Value, Owner.HoverEnd.Value);
Owner.OnDayClick((DateTime)b.DataContext);
Owner.OnDayClick(selectedDate);
}
}
}
@ -1039,11 +1027,11 @@ namespace Avalonia.Controls.Primitives
Owner.OnDayButtonMouseUp(e);
}
_isMouseLeftButtonDown = false;
if (b != null && b.DataContext != null)
if (b != null && b.DataContext is DateTime selectedDate)
{
if (Owner.SelectionMode == CalendarSelectionMode.None || Owner.SelectionMode == CalendarSelectionMode.SingleDate)
{
Owner.OnDayClick((DateTime)b.DataContext);
Owner.OnDayClick(selectedDate);
return;
}
if (Owner.HoverStart.HasValue)
@ -1058,14 +1046,14 @@ namespace Avalonia.Controls.Primitives
Owner.RemovedItems.Add(item);
}
Owner.SelectedDates.ClearInternal();
AddSelection(b);
AddSelection(b, selectedDate);
return;
}
case CalendarSelectionMode.MultipleRange:
{
// add the selection (either single day or
// SingleRange day)
AddSelection(b);
AddSelection(b, selectedDate);
return;
}
}
@ -1076,7 +1064,7 @@ namespace Avalonia.Controls.Primitives
// be able to switch months
if (b.IsInactive && b.IsBlackout)
{
Owner.OnDayClick((DateTime)b.DataContext);
Owner.OnDayClick(selectedDate);
}
}
}
@ -1095,9 +1083,9 @@ namespace Avalonia.Controls.Primitives
Owner.HoverStart = null;
_isMouseLeftButtonDown = false;
b.IsSelected = false;
if (b.DataContext != null)
if (b.DataContext is DateTime selectedDate)
{
Owner.SelectedDates.Remove((DateTime)b.DataContext);
Owner.SelectedDates.Remove(selectedDate);
}
}
}
@ -1107,35 +1095,26 @@ namespace Avalonia.Controls.Primitives
private void Month_CalendarButtonMouseDown(object? sender, PointerPressedEventArgs e)
{
CalendarButton b = (CalendarButton)sender!;
_isMouseLeftButtonDownYearView = true;
if (e != null)
{
_downEventArgYearView = e;
}
UpdateYearViewSelection(b);
UpdateYearViewSelection(sender as CalendarButton);
}
internal void Month_CalendarButtonMouseUp(object? sender, PointerReleasedEventArgs e)
{
_isMouseLeftButtonDownYearView = false;
if (Owner != null)
if (Owner != null && (sender as CalendarButton)?.DataContext is DateTime newMonth)
{
DateTime newmonth = (DateTime)((CalendarButton)sender!).DataContext!;
if (Owner.DisplayMode == CalendarMode.Year)
{
Owner.DisplayDate = newmonth;
Owner.DisplayDate = newMonth;
Owner.DisplayMode = CalendarMode.Month;
}
else
{
Debug.Assert(Owner.DisplayMode == CalendarMode.Decade, "The owning Calendar should be in decade mode!");
Owner.SelectedMonth = newmonth;
Owner.SelectedMonth = newMonth;
Owner.DisplayMode = CalendarMode.Year;
}
}
@ -1145,8 +1124,7 @@ namespace Avalonia.Controls.Primitives
{
if (_isMouseLeftButtonDownYearView)
{
CalendarButton b = (CalendarButton)sender!;
UpdateYearViewSelection(b);
UpdateYearViewSelection(sender as CalendarButton);
}
}

33
src/Avalonia.Controls/Calendar/DateTimeHelper.cs

@ -53,7 +53,7 @@ namespace Avalonia.Controls
public static int CompareDays(DateTime dt1, DateTime dt2)
{
return DateTime.Compare(DiscardTime(dt1).Value, DiscardTime(dt2).Value);
return DateTime.Compare(DiscardTime(dt1), DiscardTime(dt2));
}
public static int CompareYearMonth(DateTime dt1, DateTime dt2)
@ -71,14 +71,9 @@ namespace Avalonia.Controls
return new DateTime(d.Year, d.Month, 1, 0, 0, 0);
}
[return: NotNullIfNotNull("d")]
public static DateTime? DiscardTime(DateTime? d)
public static DateTime DiscardTime(DateTime d)
{
if (d == null)
{
return null;
}
return d.Value.Date;
return d.Date;
}
public static int EndOfDecade(DateTime date)
@ -127,28 +122,14 @@ namespace Avalonia.Controls
public static string ToYearMonthPatternString(DateTime date)
{
string result = string.Empty;
DateTimeFormatInfo format = GetCurrentDateFormat();
if (format != null)
{
result = date.ToString(format.YearMonthPattern, format);
}
return result;
var format = GetCurrentDateFormat();
return date.ToString(format.YearMonthPattern, format);
}
public static string ToYearString(DateTime date)
{
string result = string.Empty;
DateTimeFormatInfo format = GetCurrentDateFormat();
if (format != null)
{
result = date.Year.ToString(format);
}
return result;
var format = GetCurrentDateFormat();
return date.Year.ToString(format);
}
}
}

20
src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs

@ -51,11 +51,11 @@ namespace Avalonia.Controls
private bool _isDropDownOpen;
private DateTime? _selectedDate;
private string? _text;
private bool _suspendTextChangeHandler = false;
private bool _isPopupClosing = false;
private bool _ignoreButtonClick = false;
private bool _isFlyoutOpen = false;
private bool _isPressed = false;
private bool _suspendTextChangeHandler;
private bool _isPopupClosing;
private bool _ignoreButtonClick;
private bool _isFlyoutOpen;
private bool _isPressed;
/// <summary>
/// Occurs when the drop-down
@ -185,7 +185,7 @@ namespace Avalonia.Controls
{
_textBox.KeyDown += TextBox_KeyDown;
_textBox.GotFocus += TextBox_GotFocus;
_textBoxTextChangedSubscription = _textBox.GetObservable(TextBox.TextProperty).Subscribe(txt => TextBox_TextChanged());
_textBoxTextChangedSubscription = _textBox.GetObservable(TextBox.TextProperty).Subscribe(_ => TextBox_TextChanged());
if(SelectedDate.HasValue)
{
@ -292,7 +292,7 @@ namespace Avalonia.Controls
// Text
else if (change.Property == TextProperty)
{
var (oldValue, newValue) = change.GetOldAndNewValue<string>();
var (_, newValue) = change.GetOldAndNewValue<string?>();
if (!_suspendTextChangeHandler)
{
@ -595,9 +595,9 @@ namespace Avalonia.Controls
private void Calendar_KeyDown(object? sender, KeyEventArgs e)
{
Calendar? c = sender as Calendar ?? throw new ArgumentException("Sender must be Calendar.", nameof(sender));
if (!e.Handled && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape) && c.DisplayMode == CalendarMode.Month)
if (!e.Handled
&& sender is Calendar { DisplayMode: CalendarMode.Month }
&& (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape))
{
Focus();
IsDropDownOpen = false;

40
src/Avalonia.Controls/Chrome/TitleBar.cs

@ -17,28 +17,26 @@ namespace Avalonia.Controls.Chrome
private void UpdateSize(Window window)
{
if (window != null)
Margin = new Thickness(
window.OffScreenMargin.Left,
window.OffScreenMargin.Top,
window.OffScreenMargin.Right,
window.OffScreenMargin.Bottom);
if (window.WindowState != WindowState.FullScreen)
{
Margin = new Thickness(
window.OffScreenMargin.Left,
window.OffScreenMargin.Top,
window.OffScreenMargin.Right,
window.OffScreenMargin.Bottom);
Height = window.WindowDecorationMargin.Top;
if (window.WindowState != WindowState.FullScreen)
if (_captionButtons != null)
{
Height = window.WindowDecorationMargin.Top;
if (_captionButtons != null)
{
_captionButtons.Height = Height;
}
_captionButtons.Height = Height;
}
IsVisible = window.PlatformImpl?.NeedsManagedDecorations ?? false;
}
IsVisible = window.PlatformImpl?.NeedsManagedDecorations ?? false;
}
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@ -55,6 +53,7 @@ namespace Avalonia.Controls.Chrome
}
}
/// <inheritdoc />
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
@ -64,13 +63,13 @@ namespace Avalonia.Controls.Chrome
_disposables = new CompositeDisposable(6)
{
window.GetObservable(Window.WindowDecorationMarginProperty)
.Subscribe(x => UpdateSize(window)),
.Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
.Subscribe(x => UpdateSize(window)),
.Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.OffScreenMarginProperty)
.Subscribe(x => UpdateSize(window)),
.Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.ExtendClientAreaChromeHintsProperty)
.Subscribe(x => UpdateSize(window)),
.Subscribe(_ => UpdateSize(window)),
window.GetObservable(Window.WindowStateProperty)
.Subscribe(x =>
{
@ -80,11 +79,12 @@ namespace Avalonia.Controls.Chrome
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
}),
window.GetObservable(Window.IsExtendedIntoWindowDecorationsProperty)
.Subscribe(x => UpdateSize(window))
.Subscribe(_ => UpdateSize(window))
};
}
}
/// <inheritdoc />
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);

1
src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs

@ -14,7 +14,6 @@ namespace Avalonia.Controls.Converters
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if (parameter == null ||
values == null ||
values.Count != 4 ||
!(values[0] is ScrollBarVisibility visibility) ||
!(values[1] is double offset) ||

90
src/Avalonia.Controls/DefinitionBase.cs

@ -21,9 +21,9 @@ namespace Avalonia.Controls
/// <summary>
/// SharedSizeGroup property.
/// </summary>
public string SharedSizeGroup
public string? SharedSizeGroup
{
get { return (string)GetValue(SharedSizeGroupProperty); }
get { return GetValue(SharedSizeGroupProperty); }
set { SetValue(SharedSizeGroupProperty, value); }
}
@ -32,20 +32,15 @@ namespace Avalonia.Controls
/// </summary>
internal void OnEnterParentTree()
{
this.InheritanceParent = Parent;
InheritanceParent = Parent;
if (_sharedState == null)
{
// start with getting SharedSizeGroup value.
// this property is NOT inherited which should result in better overall perf.
string sharedSizeGroupId = SharedSizeGroup;
if (sharedSizeGroupId != null)
if (SharedSizeGroup is { } sharedSizeGroupId && PrivateSharedSizeScope is { } privateSharedSizeScope)
{
SharedSizeScope? privateSharedSizeScope = PrivateSharedSizeScope;
if (privateSharedSizeScope != null)
{
_sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
_sharedState.AddMember(this);
}
_sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
_sharedState.AddMember(this);
}
}
@ -321,13 +316,12 @@ namespace Avalonia.Controls
return ((_flags & flags) == flags);
}
private static void OnSharedSizeGroupPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
private static void OnSharedSizeGroupPropertyChanged(DefinitionBase definition,
AvaloniaPropertyChangedEventArgs<string?> e)
{
DefinitionBase definition = (DefinitionBase)d;
if (definition.Parent != null)
{
string sharedSizeGroupId = (string)e.NewValue!;
string? sharedSizeGroupId = e.NewValue.Value;
if (definition._sharedState != null)
{
@ -337,16 +331,14 @@ namespace Avalonia.Controls
definition._sharedState = null;
}
if ((definition._sharedState == null) && (sharedSizeGroupId != null))
if (definition._sharedState == null
&& sharedSizeGroupId != null
&& definition.PrivateSharedSizeScope is { } privateSharedSizeScope)
{
SharedSizeScope? privateSharedSizeScope = definition.PrivateSharedSizeScope;
if (privateSharedSizeScope != null)
{
// if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition.
definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
definition._sharedState.AddMember(definition);
}
// if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition.
definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
definition._sharedState.AddMember(definition);
}
}
}
@ -357,17 +349,15 @@ namespace Avalonia.Controls
/// b) contains only letters, digits and underscore ('_').
/// c) does not start with a digit.
/// </remarks>
private static bool SharedSizeGroupPropertyValueValid(string value)
private static bool SharedSizeGroupPropertyValueValid(string? id)
{
// null is default value
if (value == null)
if (id == null)
{
return true;
}
string id = (string)value;
if (!string.IsNullOrEmpty(id))
if (id.Length > 0)
{
int i = -1;
while (++i < id.Length)
@ -397,14 +387,11 @@ namespace Avalonia.Controls
/// existing scope just left. In both cases if the DefinitionBase object is already registered
/// in SharedSizeState, it should un-register and register itself in a new one.
/// </remark>
private static void OnPrivateSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
private static void OnPrivateSharedSizeScopePropertyChanged(DefinitionBase definition,
AvaloniaPropertyChangedEventArgs<SharedSizeScope?> e)
{
DefinitionBase definition = (DefinitionBase)d;
if (definition.Parent != null)
{
SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue!;
if (definition._sharedState != null)
{
// if definition is already registered And shared size scope is changing,
@ -413,16 +400,14 @@ namespace Avalonia.Controls
definition._sharedState = null;
}
if ((definition._sharedState == null) && (privateSharedSizeScope != null))
if (definition._sharedState == null
&& e.NewValue.Value is { } privateSharedSizeScope
&& definition.SharedSizeGroup is { } sharedSizeGroup)
{
string sharedSizeGroup = definition.SharedSizeGroup;
if (sharedSizeGroup != null)
{
// if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition.
definition._sharedState = privateSharedSizeScope.EnsureSharedState(definition.SharedSizeGroup);
definition._sharedState.AddMember(definition);
}
// if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition.
definition._sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroup);
definition._sharedState.AddMember(definition);
}
}
}
@ -432,7 +417,7 @@ namespace Avalonia.Controls
/// </summary>
private SharedSizeScope? PrivateSharedSizeScope
{
get { return (SharedSizeScope?)GetValue(PrivateSharedSizeScopeProperty); }
get { return GetValue(PrivateSharedSizeScopeProperty); }
}
/// <summary>
@ -465,7 +450,7 @@ namespace Avalonia.Controls
private SharedSizeState? _sharedState; // reference to shared state object this instance is registered with
[System.Flags]
[Flags]
private enum Flags : byte
{
//
@ -520,11 +505,10 @@ namespace Avalonia.Controls
/// </summary>
internal SharedSizeState(SharedSizeScope sharedSizeScope, string sharedSizeGroupId)
{
Debug.Assert(sharedSizeScope != null && sharedSizeGroupId != null);
_sharedSizeScope = sharedSizeScope;
_sharedSizeGroupId = sharedSizeGroupId;
_registry = new List<DefinitionBase>();
_layoutUpdated = new EventHandler(OnLayoutUpdated);
_layoutUpdated = OnLayoutUpdated;
_broadcastInvalidation = true;
}
@ -568,7 +552,7 @@ namespace Avalonia.Controls
{
for (int i = 0, count = _registry.Count; i < count; ++i)
{
Grid parentGrid = (Grid)(_registry[i].Parent!);
Grid parentGrid = _registry[i].Parent!;
parentGrid.Invalidate();
}
_broadcastInvalidation = false;
@ -703,7 +687,7 @@ namespace Avalonia.Controls
// measure is invalid - it used the old shared size,
// which is larger than d's (possibly changed) minSize
measureIsValid = (definitionBase.LayoutWasUpdated &&
MathUtilities.GreaterThanOrClose(definitionBase._minSize, this.MinSize));
MathUtilities.GreaterThanOrClose(definitionBase._minSize, MinSize));
}
if(!measureIsValid)
@ -786,8 +770,8 @@ namespace Avalonia.Controls
/// </description></item>
/// </list>
/// </remarks>
public static readonly AttachedProperty<string> SharedSizeGroupProperty =
AvaloniaProperty.RegisterAttached<DefinitionBase, Control, string>(
public static readonly AttachedProperty<string?> SharedSizeGroupProperty =
AvaloniaProperty.RegisterAttached<DefinitionBase, Control, string?>(
"SharedSizeGroup",
validate: SharedSizeGroupPropertyValueValid);
@ -796,8 +780,8 @@ namespace Avalonia.Controls
/// </summary>
static DefinitionBase()
{
SharedSizeGroupProperty.Changed.AddClassHandler<DefinitionBase>(OnSharedSizeGroupPropertyChanged);
PrivateSharedSizeScopeProperty.Changed.AddClassHandler<DefinitionBase>(OnPrivateSharedSizeScopePropertyChanged);
SharedSizeGroupProperty.Changed.AddClassHandler<DefinitionBase, string?>(OnSharedSizeGroupPropertyChanged);
PrivateSharedSizeScopeProperty.Changed.AddClassHandler<DefinitionBase, SharedSizeScope?>(OnPrivateSharedSizeScopePropertyChanged);
}
/// <summary>

9
src/Avalonia.Controls/DockPanel.cs

@ -101,9 +101,6 @@ namespace Avalonia.Controls
Size childConstraint; // Contains the suggested input constraint for this child.
Size childDesiredSize; // Contains the return size from child measure.
if (child == null)
{ continue; }
// Child constraint is the remaining size; this is total size minus size consumed by previous children.
childConstraint = new Size(Math.Max(0.0, constraint.Width - accumulatedWidth),
Math.Max(0.0, constraint.Height - accumulatedHeight));
@ -122,7 +119,7 @@ namespace Avalonia.Controls
// will deal with computing our minimum size (parentSize) due to that accumulation.
// Therefore, we only need to compute our minimum size (parentSize) in dimensions that this child does
// not accumulate: Width for Top/Bottom, Height for Left/Right.
switch (DockPanel.GetDock((Control)child))
switch (GetDock(child))
{
case Dock.Left:
case Dock.Right:
@ -164,8 +161,6 @@ namespace Avalonia.Controls
for (int i = 0; i < totalChildrenCount; ++i)
{
var child = children[i];
if (child == null)
{ continue; }
Size childDesiredSize = child.DesiredSize;
Rect rcChild = new Rect(
@ -176,7 +171,7 @@ namespace Avalonia.Controls
if (i < nonFillChildrenCount)
{
switch (DockPanel.GetDock((Control)child))
switch (GetDock(child))
{
case Dock.Left:
accumulatedLeft += childDesiredSize.Width;

9
src/Avalonia.Controls/Documents/Inline.cs

@ -13,8 +13,8 @@ namespace Avalonia.Controls.Documents
/// <summary>
/// AvaloniaProperty for <see cref="TextDecorations" /> property.
/// </summary>
public static readonly StyledProperty<TextDecorationCollection> TextDecorationsProperty =
AvaloniaProperty.Register<Inline, TextDecorationCollection>(
public static readonly StyledProperty<TextDecorationCollection?> TextDecorationsProperty =
AvaloniaProperty.Register<Inline, TextDecorationCollection?>(
nameof(TextDecorations));
/// <summary>
@ -28,7 +28,7 @@ namespace Avalonia.Controls.Documents
/// <summary>
/// The TextDecorations property specifies decorations that are added to the text of an element.
/// </summary>
public TextDecorationCollection TextDecorations
public TextDecorationCollection? TextDecorations
{
get { return GetValue(TextDecorationsProperty); }
set { SetValue(TextDecorationsProperty, value); }
@ -83,7 +83,8 @@ namespace Avalonia.Controls.Documents
return new GenericTextRunProperties(new Typeface(FontFamily, fontStyle, fontWeight), FontSize,
textDecorations, Foreground, background, BaselineAlignment);
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

14
src/Avalonia.Controls/Documents/Span.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Media.TextFormatting;
@ -51,6 +52,7 @@ namespace Avalonia.Controls.Documents
}
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@ -68,26 +70,26 @@ namespace Avalonia.Controls.Documents
{
base.OnInlineHostChanged(oldValue, newValue);
if (Inlines is not null)
{
Inlines.InlineHost = newValue;
}
Inlines.InlineHost = newValue;
}
private void OnInlinesChanged(InlineCollection? oldValue, InlineCollection? newValue)
{
void OnInlinesInvalidated(object? sender, EventArgs e)
=> InlineHost?.Invalidate();
if (oldValue is not null)
{
oldValue.LogicalChildren = null;
oldValue.InlineHost = null;
oldValue.Invalidated -= (s, e) => InlineHost?.Invalidate();
oldValue.Invalidated -= OnInlinesInvalidated;
}
if (newValue is not null)
{
newValue.LogicalChildren = LogicalChildren;
newValue.InlineHost = InlineHost;
newValue.Invalidated += (s, e) => InlineHost?.Invalidate();
newValue.Invalidated += OnInlinesInvalidated;
}
}
}

230
src/Avalonia.Controls/Grid.cs

@ -164,20 +164,21 @@ namespace Avalonia.Controls
/// <summary>
/// Returns a ColumnDefinitions of column definitions.
/// </summary>
[MemberNotNull(nameof(_extData))]
public ColumnDefinitions ColumnDefinitions
{
get
{
if (_data == null) { _data = new ExtendedData(); }
if (_data.ColumnDefinitions == null) { _data.ColumnDefinitions = new ColumnDefinitions() { Parent = this }; }
if (_extData == null) { _extData = new ExtendedData(); }
if (_extData.ColumnDefinitions == null) { _extData.ColumnDefinitions = new ColumnDefinitions() { Parent = this }; }
return (_data.ColumnDefinitions);
return (_extData.ColumnDefinitions);
}
set
{
if (_data == null) { _data = new ExtendedData(); }
_data.ColumnDefinitions = value;
_data.ColumnDefinitions.Parent = this;
if (_extData == null) { _extData = new ExtendedData(); }
_extData.ColumnDefinitions = value;
_extData.ColumnDefinitions.Parent = this;
InvalidateMeasure();
}
}
@ -185,20 +186,21 @@ namespace Avalonia.Controls
/// <summary>
/// Returns a RowDefinitions of row definitions.
/// </summary>
[MemberNotNull(nameof(_extData))]
public RowDefinitions RowDefinitions
{
get
{
if (_data == null) { _data = new ExtendedData(); }
if (_data.RowDefinitions == null) { _data.RowDefinitions = new RowDefinitions() { Parent = this }; }
if (_extData == null) { _extData = new ExtendedData(); }
if (_extData.RowDefinitions == null) { _extData.RowDefinitions = new RowDefinitions() { Parent = this }; }
return (_data.RowDefinitions);
return (_extData.RowDefinitions);
}
set
{
if (_data == null) { _data = new ExtendedData(); }
_data.RowDefinitions = value;
_data.RowDefinitions.Parent = this;
if (_extData == null) { _extData = new ExtendedData(); }
_extData.RowDefinitions = value;
_extData.RowDefinitions.Parent = this;
InvalidateMeasure();
}
}
@ -211,7 +213,7 @@ namespace Avalonia.Controls
protected override Size MeasureOverride(Size constraint)
{
Size gridDesiredSize;
ExtendedData extData = ExtData;
var extData = _extData;
try
{
@ -221,17 +223,14 @@ namespace Avalonia.Controls
if (extData == null)
{
gridDesiredSize = new Size();
var children = this.Children;
var children = Children;
for (int i = 0, count = children.Count; i < count; ++i)
{
var child = children[i];
if (child != null)
{
child.Measure(constraint);
gridDesiredSize = new Size(Math.Max(gridDesiredSize.Width, child.DesiredSize.Width),
Math.Max(gridDesiredSize.Height, child.DesiredSize.Height));
}
child.Measure(constraint);
gridDesiredSize = new Size(Math.Max(gridDesiredSize.Width, child.DesiredSize.Width),
Math.Max(gridDesiredSize.Height, child.DesiredSize.Height));
}
}
else
@ -512,17 +511,14 @@ namespace Avalonia.Controls
{
ArrangeOverrideInProgress = true;
if (_data == null)
if (_extData is null)
{
var children = this.Children;
var children = Children;
for (int i = 0, count = children.Count; i < count; ++i)
{
var child = children[i];
if (child != null)
{
child.Arrange(new Rect(arrangeSize));
}
child.Arrange(new Rect(arrangeSize));
}
}
else
@ -532,15 +528,11 @@ namespace Avalonia.Controls
SetFinalSize(DefinitionsU, arrangeSize.Width, true);
SetFinalSize(DefinitionsV, arrangeSize.Height, false);
var children = this.Children;
var children = Children;
for (int currentCell = 0; currentCell < PrivateCells.Length; ++currentCell)
{
var cell = children[currentCell];
if (cell == null)
{
continue;
}
int columnIndex = PrivateCells[currentCell].ColumnIndex;
int rowIndex = PrivateCells[currentCell].RowIndex;
@ -599,7 +591,7 @@ namespace Avalonia.Controls
{
double value = 0.0;
Debug.Assert(_data != null);
Debug.Assert(_extData != null);
// actual value calculations require structure to be up-to-date
if (!ColumnDefinitionsDirty)
@ -621,7 +613,7 @@ namespace Avalonia.Controls
{
double value = 0.0;
Debug.Assert(_data != null);
Debug.Assert(_extData != null);
// actual value calculations require structure to be up-to-date
if (!RowDefinitionsDirty)
@ -654,18 +646,20 @@ namespace Avalonia.Controls
/// <summary>
/// Convenience accessor to ValidDefinitionsUStructure bit flag.
/// </summary>
[MemberNotNull(nameof(_extData))]
internal bool ColumnDefinitionsDirty
{
get => ColumnDefinitions?.IsDirty ?? false;
get => ColumnDefinitions.IsDirty;
set => ColumnDefinitions.IsDirty = value;
}
/// <summary>
/// Convenience accessor to ValidDefinitionsVStructure bit flag.
/// </summary>
[MemberNotNull(nameof(_extData))]
internal bool RowDefinitionsDirty
{
get => RowDefinitions?.IsDirty ?? false;
get => RowDefinitions.IsDirty;
set => RowDefinitions.IsDirty = value;
}
@ -686,8 +680,10 @@ namespace Avalonia.Controls
/// </summary>
private void ValidateCellsCore()
{
var children = this.Children;
ExtendedData extData = ExtData;
Debug.Assert(_extData is not null);
var children = Children;
var extData = _extData!;
extData.CellCachesCollection = new CellCache[children.Count];
extData.CellGroup1 = int.MaxValue;
@ -702,10 +698,6 @@ namespace Avalonia.Controls
for (int i = PrivateCells.Length - 1; i >= 0; --i)
{
var child = children[i];
if (child == null)
{
continue;
}
CellCache cell = new CellCache();
@ -713,19 +705,19 @@ namespace Avalonia.Controls
// Read indices from the corresponding properties:
// clamp to value < number_of_columns
// column >= 0 is guaranteed by property value validation callback
cell.ColumnIndex = Math.Min(GetColumn((Control)child), DefinitionsU.Count - 1);
cell.ColumnIndex = Math.Min(GetColumn(child), DefinitionsU.Count - 1);
// clamp to value < number_of_rows
// row >= 0 is guaranteed by property value validation callback
cell.RowIndex = Math.Min(GetRow((Control)child), DefinitionsV.Count - 1);
cell.RowIndex = Math.Min(GetRow(child), DefinitionsV.Count - 1);
// Read span properties:
// clamp to not exceed beyond right side of the grid
// column_span > 0 is guaranteed by property value validation callback
cell.ColumnSpan = Math.Min(GetColumnSpan((Control)child), DefinitionsU.Count - cell.ColumnIndex);
cell.ColumnSpan = Math.Min(GetColumnSpan(child), DefinitionsU.Count - cell.ColumnIndex);
// clamp to not exceed beyond bottom side of the grid
// row_span > 0 is guaranteed by property value validation callback
cell.RowSpan = Math.Min(GetRowSpan((Control)child), DefinitionsV.Count - cell.RowIndex);
cell.RowSpan = Math.Min(GetRowSpan(child), DefinitionsV.Count - cell.RowIndex);
Debug.Assert(0 <= cell.ColumnIndex && cell.ColumnIndex < DefinitionsU.Count);
Debug.Assert(0 <= cell.RowIndex && cell.RowIndex < DefinitionsV.Count);
@ -792,7 +784,7 @@ namespace Avalonia.Controls
{
if (ColumnDefinitionsDirty)
{
ExtendedData extData = ExtData;
var extData = _extData;
if (extData.ColumnDefinitions == null)
{
@ -818,7 +810,7 @@ namespace Avalonia.Controls
ColumnDefinitionsDirty = false;
}
Debug.Assert(ExtData.DefinitionsU != null && ExtData.DefinitionsU.Count > 0);
Debug.Assert(_extData is { DefinitionsU.Count: > 0 });
}
/// <summary>
@ -833,7 +825,7 @@ namespace Avalonia.Controls
{
if (RowDefinitionsDirty)
{
ExtendedData extData = ExtData;
var extData = _extData;
if (extData.RowDefinitions == null)
{
@ -859,7 +851,7 @@ namespace Avalonia.Controls
RowDefinitionsDirty = false;
}
Debug.Assert(ExtData.DefinitionsV != null && ExtData.DefinitionsV.Count > 0);
Debug.Assert(_extData is { DefinitionsV.Count: > 0 });
}
/// <summary>
@ -965,8 +957,7 @@ namespace Avalonia.Controls
bool ignoreDesiredSizeU,
bool forceInfinityV)
{
bool unusedHasDesiredSizeUChanged;
MeasureCellsGroup(cellsHead, referenceSize, ignoreDesiredSizeU, forceInfinityV, out unusedHasDesiredSizeUChanged);
MeasureCellsGroup(cellsHead, referenceSize, ignoreDesiredSizeU, forceInfinityV, out _);
}
/// <summary>
@ -994,7 +985,7 @@ namespace Avalonia.Controls
return;
}
var children = this.Children;
var children = Children;
Hashtable? spanStore = null;
bool ignoreDesiredSizeV = forceInfinityV;
@ -1101,8 +1092,6 @@ namespace Avalonia.Controls
int cell,
bool forceInfinityV)
{
double cellMeasureWidth;
double cellMeasureHeight;
@ -1144,15 +1133,9 @@ namespace Avalonia.Controls
}
var child = this.Children[cell];
if (child != null)
{
Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight);
child.Measure(childConstraint);
}
var child = Children[cell];
Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight);
child.Measure(childConstraint);
}
/// <summary>
@ -1230,7 +1213,7 @@ namespace Avalonia.Controls
// avoid processing when asked to distribute "0"
if (!MathUtilities.IsZero(requestedSize))
{
DefinitionBase[] tempDefinitions = TempDefinitions; // temp array used to remember definitions for sorting
DefinitionBase?[] tempDefinitions = TempDefinitions; // temp array used to remember definitions for sorting
int end = start + count;
int autoDefinitionsCount = 0;
double rangeMinSize = 0;
@ -1288,20 +1271,24 @@ namespace Avalonia.Controls
Array.Sort(tempDefinitions, 0, count, s_spanPreferredDistributionOrderComparer);
for (i = 0, sizeToDistribute = requestedSize; i < autoDefinitionsCount; ++i)
{
var tempDefinition = tempDefinitions[i]!;
// sanity check: only auto definitions allowed in this loop
Debug.Assert(tempDefinitions[i].UserSize.IsAuto);
Debug.Assert(tempDefinition.UserSize.IsAuto);
// adjust sizeToDistribute value by subtracting auto definition min size
sizeToDistribute -= (tempDefinitions[i].MinSize);
sizeToDistribute -= (tempDefinition.MinSize);
}
for (; i < count; ++i)
{
var tempDefinition = tempDefinitions[i]!;
// sanity check: no auto definitions allowed in this loop
Debug.Assert(!tempDefinitions[i].UserSize.IsAuto);
Debug.Assert(!tempDefinition.UserSize.IsAuto);
double newMinSize = Math.Min(sizeToDistribute / (count - i), tempDefinitions[i].PreferredSize);
if (newMinSize > tempDefinitions[i].MinSize) { tempDefinitions[i].UpdateMinSize(newMinSize); }
double newMinSize = Math.Min(sizeToDistribute / (count - i), tempDefinition.PreferredSize);
if (newMinSize > tempDefinition.MinSize) { tempDefinition.UpdateMinSize(newMinSize); }
sizeToDistribute -= newMinSize;
}
@ -1325,24 +1312,28 @@ namespace Avalonia.Controls
Array.Sort(tempDefinitions, 0, count, s_spanMaxDistributionOrderComparer);
for (i = 0, sizeToDistribute = requestedSize - rangePreferredSize; i < count - autoDefinitionsCount; ++i)
{
var tempDefinition = tempDefinitions[i]!;
// sanity check: no auto definitions allowed in this loop
Debug.Assert(!tempDefinitions[i].UserSize.IsAuto);
Debug.Assert(!tempDefinition.UserSize.IsAuto);
double preferredSize = tempDefinitions[i].PreferredSize;
double preferredSize = tempDefinition.PreferredSize;
double newMinSize = preferredSize + sizeToDistribute / (count - autoDefinitionsCount - i);
tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache));
sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize);
tempDefinition.UpdateMinSize(Math.Min(newMinSize, tempDefinition.SizeCache));
sizeToDistribute -= (tempDefinition.MinSize - preferredSize);
}
for (; i < count; ++i)
{
var tempDefinition = tempDefinitions[i]!;
// sanity check: only auto definitions allowed in this loop
Debug.Assert(tempDefinitions[i].UserSize.IsAuto);
Debug.Assert(tempDefinition.UserSize.IsAuto);
double preferredSize = tempDefinitions[i].MinSize;
double preferredSize = tempDefinition.MinSize;
double newMinSize = preferredSize + sizeToDistribute / (count - i);
tempDefinitions[i].UpdateMinSize(Math.Min(newMinSize, tempDefinitions[i].SizeCache));
sizeToDistribute -= (tempDefinitions[i].MinSize - preferredSize);
tempDefinition.UpdateMinSize(Math.Min(newMinSize, tempDefinition.SizeCache));
sizeToDistribute -= (tempDefinition.MinSize - preferredSize);
}
// sanity check: requested size must all be distributed
@ -1376,8 +1367,10 @@ namespace Avalonia.Controls
for (int i = 0; i < count; ++i)
{
double deltaSize = (maxMaxSize - tempDefinitions[i].SizeCache) * sizeToDistribute / totalRemainingSize;
tempDefinitions[i].UpdateMinSize(tempDefinitions[i].SizeCache + deltaSize);
var tempDefinition = tempDefinitions[i]!;
double deltaSize = (maxMaxSize - tempDefinition.SizeCache) * sizeToDistribute / totalRemainingSize;
tempDefinition.UpdateMinSize(tempDefinition.SizeCache + deltaSize);
}
}
else
@ -1388,7 +1381,7 @@ namespace Avalonia.Controls
//
for (int i = 0; i < count; ++i)
{
tempDefinitions[i].UpdateMinSize(equalSize);
tempDefinitions[i]!.UpdateMinSize(equalSize);
}
}
}
@ -1429,7 +1422,7 @@ namespace Avalonia.Controls
double availableSize)
{
int defCount = definitions.Count;
DefinitionBase[] tempDefinitions = TempDefinitions;
DefinitionBase?[] tempDefinitions = TempDefinitions;
int minCount = 0, maxCount = 0;
double takenSize = 0;
double totalStarWeight = 0.0;
@ -1560,8 +1553,8 @@ namespace Avalonia.Controls
remainingStarWeight = totalStarWeight - takenStarWeight;
}
double minRatio = (minCount > 0) ? tempDefinitions[minCount - 1].MeasureSize : Double.PositiveInfinity;
double maxRatio = (maxCount > 0) ? tempDefinitions[defCount + maxCount - 1].SizeCache : -1.0;
double minRatio = (minCount > 0) ? tempDefinitions[minCount - 1]!.MeasureSize : Double.PositiveInfinity;
double maxRatio = (maxCount > 0) ? tempDefinitions[defCount + maxCount - 1]!.SizeCache : -1.0;
// choose the def with larger ratio to the current proportion ("max discrepancy")
double proportion = remainingStarWeight / remainingAvailableSize;
@ -1579,13 +1572,13 @@ namespace Avalonia.Controls
double resolvedSize;
if (chooseMin == true)
{
resolvedDef = tempDefinitions[minCount - 1];
resolvedDef = tempDefinitions[minCount - 1]!;
resolvedSize = resolvedDef.MinSize;
--minCount;
}
else
{
resolvedDef = tempDefinitions[defCount + maxCount - 1];
resolvedDef = tempDefinitions[defCount + maxCount - 1]!;
resolvedSize = Math.Max(resolvedDef.MinSize, resolvedDef.UserMaxSize);
--maxCount;
}
@ -1603,12 +1596,12 @@ namespace Avalonia.Controls
// advance to the next candidate defs, removing ones that have been resolved.
// Both counts are advanced, as a def might appear in both lists.
while (minCount > 0 && tempDefinitions[minCount - 1].MeasureSize < 0.0)
while (minCount > 0 && tempDefinitions[minCount - 1]!.MeasureSize < 0.0)
{
--minCount;
tempDefinitions[minCount] = null!;
}
while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1].MeasureSize < 0.0)
while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1]!.MeasureSize < 0.0)
{
--maxCount;
tempDefinitions[defCount + maxCount] = null!;
@ -1637,8 +1630,7 @@ namespace Avalonia.Controls
// resolved as 'min'. Their allocation can be increased to make up the gap.
for (int i = minCount; i < minCountPhase2; ++i)
{
DefinitionBase def = tempDefinitions[i];
if (def != null)
if (tempDefinitions[i] is { } def)
{
def.MeasureSize = 1.0; // mark as 'not yet resolved'
++starCount;
@ -1653,8 +1645,7 @@ namespace Avalonia.Controls
// resolved as 'max'. Their allocation can be decreased to make up the gap.
for (int i = maxCount; i < maxCountPhase2; ++i)
{
DefinitionBase def = tempDefinitions[defCount + i];
if (def != null)
if (tempDefinitions[defCount + i] is { } def)
{
def.MeasureSize = 1.0; // mark as 'not yet resolved'
++starCount;
@ -1695,7 +1686,7 @@ namespace Avalonia.Controls
totalStarWeight = 0.0;
for (int i = 0; i < starCount; ++i)
{
DefinitionBase def = tempDefinitions[i];
DefinitionBase def = tempDefinitions[i]!;
totalStarWeight += def.MeasureSize;
def.SizeCache = totalStarWeight;
}
@ -1703,7 +1694,7 @@ namespace Avalonia.Controls
// resolve the defs, in decreasing order of weight
for (int i = starCount - 1; i >= 0; --i)
{
DefinitionBase def = tempDefinitions[i];
DefinitionBase def = tempDefinitions[i]!;
double resolvedSize = (def.MeasureSize > 0.0) ? Math.Max(availableSize - takenSize, 0.0) * (def.MeasureSize / def.SizeCache) : 0.0;
// min and max should have no effect by now, but just in case...
@ -2095,7 +2086,7 @@ namespace Avalonia.Controls
{
// DpiScale dpiScale = GetDpi();
// double dpi = columns ? dpiScale.DpiScaleX : dpiScale.DpiScaleY;
var dpi = (VisualRoot as Layout.ILayoutRoot)?.LayoutScaling ?? 1.0;
var dpi = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
double[] roundingErrors = RoundingErrors;
double roundedTakenSize = 0.0;
@ -2302,8 +2293,7 @@ namespace Avalonia.Controls
/// </summary>
private void SetValid()
{
ExtendedData extData = ExtData;
if (extData != null)
if (_extData is { } extData)
{
// for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid ();
// for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid ();
@ -2330,12 +2320,12 @@ namespace Avalonia.Controls
if (ShowGridLines && (_gridLinesRenderer == null))
{
_gridLinesRenderer = new GridLinesRenderer();
this.VisualChildren.Add(_gridLinesRenderer);
VisualChildren.Add(_gridLinesRenderer);
}
if ((!ShowGridLines) && (_gridLinesRenderer != null))
{
this.VisualChildren.Add(_gridLinesRenderer);
VisualChildren.Add(_gridLinesRenderer);
_gridLinesRenderer = null;
}
@ -2364,7 +2354,7 @@ namespace Avalonia.Controls
{
Grid grid = (Grid)d;
if (grid.ExtData != null // trivial grid is 1 by 1. there is no grid lines anyway
if (grid._extData != null // trivial grid is 1 by 1. there is no grid lines anyway
&& grid.ListenToNotifications)
{
grid.InvalidateVisual();
@ -2375,13 +2365,11 @@ namespace Avalonia.Controls
private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
Visual? child = d as Visual;
if (child != null)
if (d is Visual child)
{
Grid? grid = child.GetVisualParent<Grid>();
if (grid != null
&& grid.ExtData != null
&& grid._extData != null
&& grid.ListenToNotifications)
{
grid.CellsStructureDirty = true;
@ -2427,7 +2415,7 @@ namespace Avalonia.Controls
/// </summary>
private IReadOnlyList<DefinitionBase> DefinitionsU
{
get { return (ExtData.DefinitionsU!); }
get { return _extData!.DefinitionsU!; }
}
/// <summary>
@ -2435,17 +2423,19 @@ namespace Avalonia.Controls
/// </summary>
private IReadOnlyList<DefinitionBase> DefinitionsV
{
get { return (ExtData.DefinitionsV!); }
get { return _extData!.DefinitionsV!; }
}
/// <summary>
/// Helper accessor to layout time array of definitions.
/// </summary>
private DefinitionBase[] TempDefinitions
private DefinitionBase?[] TempDefinitions
{
get
{
ExtendedData extData = ExtData;
Debug.Assert(_extData is not null);
var extData = _extData!;
int requiredLength = Math.Max(DefinitionsU.Count, DefinitionsV.Count) * 2;
if (extData.TempDefinitions == null
@ -2516,7 +2506,7 @@ namespace Avalonia.Controls
/// </summary>
private CellCache[] PrivateCells
{
get { return (ExtData.CellCachesCollection!); }
get { return _extData!.CellCachesCollection!; }
}
/// <summary>
@ -2582,18 +2572,10 @@ namespace Avalonia.Controls
set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); }
}
/// <summary>
/// Returns reference to extended data bag.
/// </summary>
private ExtendedData ExtData
{
get { return (_data!); }
}
/// <summary>
/// Returns *-weight, adjusted for scale computed during Phase 1
/// </summary>
static double StarWeight(DefinitionBase def, double scale)
private static double StarWeight(DefinitionBase def, double scale)
{
if (scale < 0.0)
{
@ -2609,17 +2591,17 @@ namespace Avalonia.Controls
}
// Extended data instantiated on demand, for non-trivial case handling only
private ExtendedData? _data;
private ExtendedData? _extData;
// Grid validity / property caches dirtiness flags
private Flags _flags;
private GridLinesRenderer? _gridLinesRenderer;
// Keeps track of definition indices.
int[]? _definitionIndices;
private int[]? _definitionIndices;
// Stores unrounded values and rounding errors during layout rounding.
double[]? _roundingErrors;
private double[]? _roundingErrors;
// 5 is an arbitrary constant chosen to end the measure loop
private const int c_layoutLoopMaxCount = 5;
@ -2645,14 +2627,14 @@ namespace Avalonia.Controls
internal int CellGroup2; // index of the first cell in second cell group
internal int CellGroup3; // index of the first cell in third cell group
internal int CellGroup4; // index of the first cell in forth cell group
internal DefinitionBase[]? TempDefinitions; // temporary array used during layout for various purposes
internal DefinitionBase?[]? TempDefinitions; // temporary array used during layout for various purposes
// TempDefinitions.Length == Max(definitionsU.Length, definitionsV.Length)
}
/// <summary>
/// Grid validity / property caches dirtiness flags
/// </summary>
[System.Flags]
[Flags]
private enum Flags
{
//
@ -2768,7 +2750,7 @@ namespace Avalonia.Controls
/// <summary>
/// LayoutTimeSizeType is used internally and reflects layout-time size type.
/// </summary>
[System.Flags]
[Flags]
internal enum LayoutTimeSizeType : byte
{
None = 0x00,
@ -3317,7 +3299,7 @@ namespace Avalonia.Controls
internal void UpdateRenderBounds(Size arrangeSize)
{
_lastArrangeSize = arrangeSize;
this.InvalidateVisual();
InvalidateVisual();
}
private static Size _lastArrangeSize;

7
src/Avalonia.Controls/Image.cs

@ -14,8 +14,8 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Source"/> property.
/// </summary>
public static readonly StyledProperty<IImage> SourceProperty =
AvaloniaProperty.Register<Image, IImage>(nameof(Source));
public static readonly StyledProperty<IImage?> SourceProperty =
AvaloniaProperty.Register<Image, IImage?>(nameof(Source));
/// <summary>
/// Defines the <see cref="Stretch"/> property.
@ -42,7 +42,7 @@ namespace Avalonia.Controls
/// Gets or sets the image that will be displayed.
/// </summary>
[Content]
public IImage Source
public IImage? Source
{
get { return GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
@ -66,6 +66,7 @@ namespace Avalonia.Controls
set { SetValue(StretchDirectionProperty, value); }
}
/// <inheritdoc />
protected override bool BypassFlowDirectionPolicies => true;
/// <summary>

12
src/Avalonia.Controls/ItemsControl.cs

@ -2,7 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Automation.Peers;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
@ -17,7 +16,6 @@ using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Styling;
using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@ -106,7 +104,6 @@ namespace Avalonia.Controls
private Tuple<int, Control>? _containerBeingPrepared;
private ScrollViewer? _scrollViewer;
private ItemsPresenter? _itemsPresenter;
private IScrollSnapPointsInfo? _scrolSnapPointInfo;
/// <summary>
/// Initializes a new instance of the <see cref="ItemsControl"/> class.
@ -221,6 +218,7 @@ namespace Avalonia.Controls
}
/// <inheritdoc />
public event EventHandler<RoutedEventArgs> HorizontalSnapPointsChanged
{
add
@ -240,6 +238,7 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc />
public event EventHandler<RoutedEventArgs> VerticalSnapPointsChanged
{
add
@ -424,13 +423,12 @@ namespace Avalonia.Controls
/// <returns>true if the item is (or is eligible to be) its own container; otherwise, false.</returns>
protected internal virtual bool IsItemItsOwnContainerOverride(Control item) => true;
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_scrollViewer = e.NameScope.Find<ScrollViewer>("PART_ScrollViewer");
_itemsPresenter = e.NameScope.Find<ItemsPresenter>("PART_ItemsPresenter");
_scrolSnapPointInfo = _itemsPresenter as IScrollSnapPointsInfo;
}
/// <summary>
@ -477,11 +475,13 @@ namespace Avalonia.Controls
base.OnKeyDown(e);
}
/// <inheritdoc />
protected override AutomationPeer OnCreateAutomationPeer()
{
return new ItemsControlAutomationPeer(this);
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@ -748,11 +748,13 @@ namespace Avalonia.Controls
return true;
}
/// <inheritdoc />
public IReadOnlyList<double> GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment)
{
return _itemsPresenter?.GetIrregularSnapPoints(orientation, snapPointsAlignment) ?? new List<double>();
}
/// <inheritdoc />
public double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset)
{
offset = 0;

20
src/Avalonia.Controls/LayoutTransformControl.cs

@ -28,7 +28,7 @@ namespace Avalonia.Controls
.AddClassHandler<LayoutTransformControl>((x, e) => x.OnLayoutTransformChanged(e));
ChildProperty.Changed
.AddClassHandler<LayoutTransformControl>((x, e) => x.OnChildChanged(e));
.AddClassHandler<LayoutTransformControl>((x, _) => x.OnChildChanged());
UseRenderTransformProperty.Changed
.AddClassHandler<LayoutTransformControl>((x, e) => x.OnUseRenderTransformPropertyChanged(e));
@ -146,7 +146,7 @@ namespace Avalonia.Controls
return transformedDesiredSize;
}
IDisposable? _renderTransformChangedEvent;
private IDisposable? _renderTransformChangedEvent;
private void OnUseRenderTransformPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
@ -167,8 +167,7 @@ namespace Avalonia.Controls
.Subscribe(
(x) =>
{
var target2 = x.Sender as LayoutTransformControl;
if (target2 != null)
if (x.Sender is LayoutTransformControl target2)
{
target2.LayoutTransform = target2.RenderTransform;
}
@ -182,7 +181,7 @@ namespace Avalonia.Controls
}
}
private void OnChildChanged(AvaloniaPropertyChangedEventArgs e)
private void OnChildChanged()
{
if (null != TransformRoot)
{
@ -206,18 +205,18 @@ namespace Avalonia.Controls
/// <summary>
/// Actual DesiredSize of Child element (the value it returned from its MeasureOverride method).
/// </summary>
private Size _childActualSize = default;
private Size _childActualSize;
/// <summary>
/// RenderTransform/MatrixTransform applied to TransformRoot.
/// </summary>
private MatrixTransform _matrixTransform = new MatrixTransform();
private readonly MatrixTransform _matrixTransform = new();
/// <summary>
/// Transformation matrix corresponding to _matrixTransform.
/// </summary>
private Matrix _transformation;
private IDisposable? _transformChangedEvent = null;
private IDisposable? _transformChangedEvent;
/// <summary>
/// Returns true if Size a is smaller than Size b in either dimension.
@ -263,10 +262,7 @@ namespace Avalonia.Controls
// Get the transform matrix and apply it
_transformation = RoundMatrix(LayoutTransform.Value, DecimalsAfterRound);
if (null != _matrixTransform)
{
_matrixTransform.Matrix = _transformation;
}
_matrixTransform.Matrix = _transformation;
// New transform means re-layout is necessary
InvalidateMeasure();

12
src/Avalonia.Controls/MaskedTextBox.cs

@ -178,12 +178,11 @@ namespace Avalonia.Controls
}
}
}
Type IStyleable.StyleKey => typeof(TextBox);
/// <inheritdoc />
protected override void OnGotFocus(GotFocusEventArgs e)
{
if (HidePromptOnLeave == true && MaskProvider != null)
@ -193,6 +192,7 @@ namespace Avalonia.Controls
base.OnGotFocus(e);
}
/// <inheritdoc />
protected override async void OnKeyDown(KeyEventArgs e)
{
if (MaskProvider == null)
@ -271,15 +271,17 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc />
protected override void OnLostFocus(RoutedEventArgs e)
{
if (HidePromptOnLeave == true && MaskProvider != null)
if (HidePromptOnLeave && MaskProvider != null)
{
Text = MaskProvider.ToString(!HidePromptOnLeave, true);
}
base.OnLostFocus(e);
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
void UpdateMaskProvider()
@ -357,6 +359,8 @@ namespace Avalonia.Controls
}
base.OnPropertyChanged(change);
}
/// <inheritdoc />
protected override void OnTextInput(TextInputEventArgs e)
{
_ignoreTextChanges = true;
@ -423,7 +427,7 @@ namespace Avalonia.Controls
return startPosition;
}
private void RefreshText(MaskedTextProvider provider, int position)
private void RefreshText(MaskedTextProvider? provider, int position)
{
if (provider != null)
{

22
src/Avalonia.Controls/NativeControlHost.cs

@ -16,19 +16,17 @@ namespace Avalonia.Controls
private IPlatformHandle? _nativeControlHandle;
private bool _queuedForDestruction;
private bool _queuedForMoveResize;
private readonly List<Visual> _propertyChangedSubscriptions = new List<Visual>();
private readonly List<Visual> _propertyChangedSubscriptions = new();
/// <inheritdoc />
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
_currentRoot = e.Root as TopLevel;
var visual = (Visual)this;
while (visual != null)
{
if (visual is Visual v)
{
v.PropertyChanged += PropertyChangedHandler;
_propertyChangedSubscriptions.Add(v);
}
visual.PropertyChanged += PropertyChangedHandler;
_propertyChangedSubscriptions.Add(visual);
visual = visual.GetVisualParent();
}
@ -42,15 +40,13 @@ namespace Avalonia.Controls
EnqueueForMoveResize();
}
/// <inheritdoc />
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_currentRoot = null;
if (_propertyChangedSubscriptions != null)
{
foreach (var v in _propertyChangedSubscriptions)
v.PropertyChanged -= PropertyChangedHandler;
_propertyChangedSubscriptions.Clear();
}
foreach (var v in _propertyChangedSubscriptions)
v.PropertyChanged -= PropertyChangedHandler;
_propertyChangedSubscriptions.Clear();
UpdateHost();
}
@ -128,7 +124,7 @@ namespace Avalonia.Controls
return new Rect(position.Value, bounds.Size);
}
void EnqueueForMoveResize()
private void EnqueueForMoveResize()
{
if(_queuedForMoveResize)
return;

20
src/Avalonia.Controls/NativeMenu.Export.cs

@ -12,10 +12,10 @@ namespace Avalonia.Controls
public static bool GetIsNativeMenuExported(TopLevel tl) => tl.GetValue(IsNativeMenuExportedProperty);
private static readonly AttachedProperty<NativeMenuInfo> s_nativeMenuInfoProperty =
AvaloniaProperty.RegisterAttached<NativeMenu, TopLevel, NativeMenuInfo>("___NativeMenuInfo");
class NativeMenuInfo
private static readonly AttachedProperty<NativeMenuInfo?> s_nativeMenuInfoProperty =
AvaloniaProperty.RegisterAttached<NativeMenu, TopLevel, NativeMenuInfo?>("___NativeMenuInfo");
private sealed class NativeMenuInfo
{
public bool ChangingIsExported { get; set; }
public ITopLevelNativeMenuExporter? Exporter { get; }
@ -33,7 +33,7 @@ namespace Avalonia.Controls
}
}
static NativeMenuInfo GetInfo(TopLevel target)
private static NativeMenuInfo GetInfo(TopLevel target)
{
var rv = target.GetValue(s_nativeMenuInfoProperty);
if (rv == null)
@ -45,18 +45,18 @@ namespace Avalonia.Controls
return rv;
}
static void SetIsNativeMenuExported(TopLevel tl, bool value)
private static void SetIsNativeMenuExported(TopLevel tl, bool value)
{
GetInfo(tl).ChangingIsExported = true;
tl.SetValue(IsNativeMenuExportedProperty, value);
}
public static readonly AttachedProperty<NativeMenu> MenuProperty
= AvaloniaProperty.RegisterAttached<NativeMenu, AvaloniaObject, NativeMenu>("Menu");
public static readonly AttachedProperty<NativeMenu?> MenuProperty
= AvaloniaProperty.RegisterAttached<NativeMenu, AvaloniaObject, NativeMenu?>("Menu");
public static void SetMenu(AvaloniaObject o, NativeMenu menu) => o.SetValue(MenuProperty, menu);
public static void SetMenu(AvaloniaObject o, NativeMenu? menu) => o.SetValue(MenuProperty, menu);
public static NativeMenu GetMenu(AvaloniaObject o) => o.GetValue(MenuProperty);
public static NativeMenu? GetMenu(AvaloniaObject o) => o.GetValue(MenuProperty);
static NativeMenu()
{

12
src/Avalonia.Controls/Primitives/AdornerLayer.cs

@ -34,8 +34,8 @@ namespace Avalonia.Controls.Primitives
public static readonly AttachedProperty<Control?> AdornerProperty =
AvaloniaProperty.RegisterAttached<AdornerLayer, Visual, Control?>("Adorner");
private static readonly AttachedProperty<AdornedElementInfo> s_adornedElementInfoProperty =
AvaloniaProperty.RegisterAttached<AdornerLayer, Visual, AdornedElementInfo>("AdornedElementInfo");
private static readonly AttachedProperty<AdornedElementInfo?> s_adornedElementInfoProperty =
AvaloniaProperty.RegisterAttached<AdornerLayer, Visual, AdornedElementInfo?>("AdornedElementInfo");
private static readonly AttachedProperty<AdornerLayer?> s_savedAdornerLayerProperty =
AvaloniaProperty.RegisterAttached<Visual, Visual, AdornerLayer?>("SavedAdornerLayer");
@ -159,8 +159,8 @@ namespace Avalonia.Controls.Primitives
return;
}
AdornerLayer.SetAdornedElement(adorner, visual);
AdornerLayer.SetIsClipEnabled(adorner, false);
SetAdornedElement(adorner, visual);
SetIsClipEnabled(adorner, false);
((ISetLogicalParent) adorner).SetParent(visual);
layer.Children.Add(adorner);
@ -177,6 +177,7 @@ namespace Avalonia.Controls.Primitives
((ISetLogicalParent) adorner).SetParent(null);
}
/// <inheritdoc />
protected override Size MeasureOverride(Size availableSize)
{
foreach (var child in Children)
@ -199,6 +200,7 @@ namespace Avalonia.Controls.Primitives
return default;
}
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
foreach (var child in Children)
@ -217,7 +219,7 @@ namespace Avalonia.Controls.Primitives
}
else
{
ArrangeChild((Control) child, finalSize);
ArrangeChild(child, finalSize);
}
}
}

12
src/Avalonia.Controls/Primitives/Popup.cs

@ -120,7 +120,7 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<bool> TopmostProperty =
AvaloniaProperty.Register<Popup, bool>(nameof(Topmost));
private bool _isOpenRequested = false;
private bool _isOpenRequested;
private bool _isOpen;
private bool _ignoreIsOpenChanged;
private PopupOpenState? _openState;
@ -377,9 +377,9 @@ namespace Avalonia.Controls.Primitives
popupHost.SetChild(Child);
((ISetLogicalParent)popupHost).SetParent(this);
if (InheritsTransform && placementTarget is Control c)
if (InheritsTransform)
{
TransformTrackingHelper.Track(c, PlacementTargetTransformChanged)
TransformTrackingHelper.Track(placementTarget, PlacementTargetTransformChanged)
.DisposeWith(handlerCleanup);
}
else
@ -518,6 +518,7 @@ namespace Avalonia.Controls.Primitives
Close();
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@ -579,7 +580,7 @@ namespace Avalonia.Controls.Primitives
var scaleX = 1.0;
var scaleY = 1.0;
if (InheritsTransform && placementTarget.TransformToVisual(topLevel) is Matrix m)
if (InheritsTransform && placementTarget.TransformToVisual(topLevel) is { } m)
{
scaleX = Math.Sqrt(m.M11 * m.M11 + m.M12 * m.M12);
scaleY = Math.Sqrt(m.M11 * m.M11 + m.M12 * m.M12);
@ -623,6 +624,7 @@ namespace Avalonia.Controls.Primitives
}
}
/// <inheritdoc />
protected override AutomationPeer OnCreateAutomationPeer()
{
return new PopupAutomationPeer(this);
@ -850,7 +852,7 @@ namespace Avalonia.Controls.Primitives
var popupHost = _openState.PopupHost;
return popupHost != null && ((Visual)popupHost).IsVisualAncestorOf(visual);
return ((Visual)popupHost).IsVisualAncestorOf(visual);
}
public bool IsPointerOverPopup => ((IInputElement?)_openState?.PopupHost)?.IsPointerOver ?? false;

31
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -3,16 +3,14 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Xml.Linq;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Selection;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
{
@ -255,6 +253,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Gets or sets the model that holds the current selection.
/// </summary>
[AllowNull]
protected ISelectionModel Selection
{
get
@ -399,6 +398,7 @@ namespace Avalonia.Controls.Primitives
return null;
}
/// <inheritdoc />
protected override void ItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.ItemsCollectionChanged(sender!, e);
@ -409,12 +409,14 @@ namespace Avalonia.Controls.Primitives
}
}
/// <inheritdoc />
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
AutoScrollToSelectedItemIfNecessary();
}
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@ -431,6 +433,7 @@ namespace Avalonia.Controls.Primitives
}
}
/// <inheritdoc />
protected internal override void PrepareContainerForItemOverride(Control element, object? item, int index)
{
base.PrepareContainerForItemOverride(element, item, index);
@ -447,12 +450,14 @@ namespace Avalonia.Controls.Primitives
}
}
/// <inheritdoc />
protected override void ContainerIndexChangedOverride(Control container, int oldIndex, int newIndex)
{
base.ContainerIndexChangedOverride(container, oldIndex, newIndex);
MarkContainerSelected(container, Selection.IsSelected(newIndex));
}
/// <inheritdoc />
protected internal override void ClearContainerForItemOverride(Control element)
{
base.ClearContainerForItemOverride(element);
@ -463,7 +468,7 @@ namespace Avalonia.Controls.Primitives
KeyboardNavigation.SetTabOnceActiveElement(panel, null);
}
if (element is ISelectable selectable)
if (element is ISelectable)
MarkContainerSelected(element, false);
}
@ -498,7 +503,8 @@ namespace Avalonia.Controls.Primitives
DataValidationErrors.SetError(this, error);
}
}
/// <inheritdoc />
protected override void OnInitialized()
{
base.OnInitialized();
@ -509,6 +515,7 @@ namespace Avalonia.Controls.Primitives
}
}
/// <inheritdoc />
protected override void OnTextInput(TextInputEventArgs e)
{
if (!e.Handled)
@ -551,6 +558,7 @@ namespace Avalonia.Controls.Primitives
base.OnTextInput(e);
}
/// <inheritdoc />
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
@ -582,6 +590,7 @@ namespace Avalonia.Controls.Primitives
}
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@ -592,7 +601,7 @@ namespace Avalonia.Controls.Primitives
}
if (change.Property == ItemsProperty && _updateState is null && _selection is object)
{
var newValue = change.GetNewValue<IEnumerable>();
var newValue = change.GetNewValue<IEnumerable?>();
_selection.Source = newValue;
if (newValue is null)
@ -695,7 +704,7 @@ namespace Avalonia.Controls.Primitives
{
if (multi)
{
if (Selection.IsSelected(index) == true)
if (Selection.IsSelected(index))
{
Selection.Deselect(index);
}
@ -716,12 +725,10 @@ namespace Avalonia.Controls.Primitives
Selection.Select(index);
}
if (Presenter?.Panel != null)
if (Presenter?.Panel is { } panel)
{
var container = ContainerFromIndex(index);
KeyboardNavigation.SetTabOnceActiveElement(
(InputElement)Presenter.Panel,
container);
KeyboardNavigation.SetTabOnceActiveElement(panel, container);
}
}
@ -940,7 +947,7 @@ namespace Avalonia.Controls.Primitives
private void UpdateContainerSelection()
{
if (Presenter?.Panel is Panel panel)
if (Presenter?.Panel is { } panel)
{
foreach (var container in panel.Children)
{

7
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@ -290,12 +290,6 @@ namespace Avalonia.Controls.Primitives
ApplyTemplatedParent(child, this);
((ISetLogicalParent)child).SetParent(this);
VisualChildren.Add(child);
// Existing code kinda expect to see a NameScope even if it's empty
if (nameScope == null)
{
nameScope = new NameScope();
}
var e = new TemplateAppliedEventArgs(nameScope);
OnApplyTemplate(e);
@ -320,6 +314,7 @@ namespace Avalonia.Controls.Primitives
return this;
}
/// <inheritdoc />
protected sealed override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
var count = VisualChildren.Count;

8
src/Avalonia.Controls/Primitives/TextSearch.cs

@ -11,15 +11,15 @@ namespace Avalonia.Controls.Primitives
/// Defines the Text attached property.
/// This text will be considered during text search in <see cref="SelectingItemsControl"/> (such as <see cref="ComboBox"/>)
/// </summary>
public static readonly AttachedProperty<string> TextProperty
= AvaloniaProperty.RegisterAttached<Interactive, string>("Text", typeof(TextSearch));
public static readonly AttachedProperty<string?> TextProperty
= AvaloniaProperty.RegisterAttached<Interactive, string?>("Text", typeof(TextSearch));
/// <summary>
/// Sets the <see cref="TextProperty"/> for a control.
/// </summary>
/// <param name="control">The control</param>
/// <param name="text">The search text to set</param>
public static void SetText(Control control, string text)
public static void SetText(Control control, string? text)
{
control.SetValue(TextProperty, text);
}
@ -29,7 +29,7 @@ namespace Avalonia.Controls.Primitives
/// </summary>
/// <param name="control">The control</param>
/// <returns>The property value</returns>
public static string GetText(Control control)
public static string? GetText(Control control)
{
return control.GetValue(TextProperty);
}

19
src/Avalonia.Controls/Primitives/Track.cs

@ -5,7 +5,6 @@
using System;
using Avalonia.Controls.Metadata;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Metadata;
@ -31,14 +30,14 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<Orientation> OrientationProperty =
ScrollBar.OrientationProperty.AddOwner<Track>();
public static readonly StyledProperty<Thumb> ThumbProperty =
AvaloniaProperty.Register<Track, Thumb>(nameof(Thumb));
public static readonly StyledProperty<Thumb?> ThumbProperty =
AvaloniaProperty.Register<Track, Thumb?>(nameof(Thumb));
public static readonly StyledProperty<Button> IncreaseButtonProperty =
AvaloniaProperty.Register<Track, Button>(nameof(IncreaseButton));
public static readonly StyledProperty<Button?> IncreaseButtonProperty =
AvaloniaProperty.Register<Track, Button?>(nameof(IncreaseButton));
public static readonly StyledProperty<Button> DecreaseButtonProperty =
AvaloniaProperty.Register<Track, Button>(nameof(DecreaseButton));
public static readonly StyledProperty<Button?> DecreaseButtonProperty =
AvaloniaProperty.Register<Track, Button?>(nameof(DecreaseButton));
public static readonly StyledProperty<bool> IsDirectionReversedProperty =
AvaloniaProperty.Register<Track, bool>(nameof(IsDirectionReversed));
@ -94,19 +93,19 @@ namespace Avalonia.Controls.Primitives
}
[Content]
public Thumb Thumb
public Thumb? Thumb
{
get { return GetValue(ThumbProperty); }
set { SetValue(ThumbProperty, value); }
}
public Button IncreaseButton
public Button? IncreaseButton
{
get { return GetValue(IncreaseButtonProperty); }
set { SetValue(IncreaseButtonProperty, value); }
}
public Button DecreaseButton
public Button? DecreaseButton
{
get { return GetValue(DecreaseButtonProperty); }
set { SetValue(DecreaseButtonProperty, value); }

16
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -1,6 +1,5 @@
using System.Collections.Generic;
using Avalonia.LogicalTree;
using Avalonia.Media;
namespace Avalonia.Controls.Primitives
{
@ -12,10 +11,10 @@ namespace Avalonia.Controls.Primitives
private const int OverlayZIndex = int.MaxValue - 97;
private ILogicalRoot? _logicalRoot;
private readonly List<Control> _layers = new List<Control>();
private readonly List<Control> _layers = new();
public static readonly StyledProperty<ChromeOverlayLayer> ChromeOverlayLayerProperty =
AvaloniaProperty.Register<VisualLayerManager, ChromeOverlayLayer>(nameof(ChromeOverlayLayer));
public static readonly StyledProperty<ChromeOverlayLayer?> ChromeOverlayLayerProperty =
AvaloniaProperty.Register<VisualLayerManager, ChromeOverlayLayer?>(nameof(ChromeOverlayLayer));
public bool IsPopup { get; set; }
@ -81,7 +80,7 @@ namespace Avalonia.Controls.Primitives
}
}
T? FindLayer<T>() where T : class
private T? FindLayer<T>() where T : class
{
foreach (var layer in _layers)
if (layer is T match)
@ -89,7 +88,7 @@ namespace Avalonia.Controls.Primitives
return null;
}
void AddLayer(Control layer, int zindex)
private void AddLayer(Control layer, int zindex)
{
_layers.Add(layer);
((ISetLogicalParent)layer).SetParent(this);
@ -101,6 +100,7 @@ namespace Avalonia.Controls.Primitives
InvalidateArrange();
}
/// <inheritdoc />
protected override void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{
foreach (var l in _layers)
@ -109,6 +109,7 @@ namespace Avalonia.Controls.Primitives
base.NotifyChildResourcesChanged(e);
}
/// <inheritdoc />
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
@ -118,6 +119,7 @@ namespace Avalonia.Controls.Primitives
((ILogical)l).NotifyAttachedToLogicalTree(e);
}
/// <inheritdoc />
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
_logicalRoot = null;
@ -126,6 +128,7 @@ namespace Avalonia.Controls.Primitives
((ILogical)l).NotifyDetachedFromLogicalTree(e);
}
/// <inheritdoc />
protected override Size MeasureOverride(Size availableSize)
{
foreach (var l in _layers)
@ -133,6 +136,7 @@ namespace Avalonia.Controls.Primitives
return base.MeasureOverride(availableSize);
}
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
foreach (var l in _layers)

7
src/Avalonia.Controls/RelativePanel.cs

@ -33,13 +33,8 @@ namespace Avalonia.Controls
protected override Size MeasureOverride(Size availableSize)
{
_childGraph.Clear();
foreach (Layoutable child in Children)
foreach (var child in Children)
{
if (child == null)
{
continue;
}
var node = _childGraph.AddNode(child);
node.AlignLeftWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignLeftWithProperty, child));

44
src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs

@ -14,8 +14,8 @@ using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Rendering;
using Avalonia.Threading;
using Key = Avalonia.Input.Key;
using PixelFormat = Avalonia.Platform.PixelFormat;
using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat;
using ProtocolMouseButton = Avalonia.Remote.Protocol.Input.MouseButton;
namespace Avalonia.Controls.Remote.Server
{
@ -24,7 +24,7 @@ namespace Avalonia.Controls.Remote.Server
{
private readonly IAvaloniaRemoteTransportConnection _transport;
private LockedFramebuffer? _framebuffer;
private object _lock = new object();
private readonly object _lock = new();
private long _lastSentFrame = -1;
private long _lastReceivedFrame = -1;
private long _nextFrameNumber = 1;
@ -50,17 +50,17 @@ namespace Avalonia.Controls.Remote.Server
return r;
}
private static RawPointerEventType GetAvaloniaEventType (Avalonia.Remote.Protocol.Input.MouseButton button, bool pressed)
private static RawPointerEventType GetAvaloniaEventType(ProtocolMouseButton button, bool pressed)
{
switch (button)
{
case Avalonia.Remote.Protocol.Input.MouseButton.Left:
case ProtocolMouseButton.Left:
return pressed ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp;
case Avalonia.Remote.Protocol.Input.MouseButton.Middle:
case ProtocolMouseButton.Middle:
return pressed ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp;
case Avalonia.Remote.Protocol.Input.MouseButton.Right:
case ProtocolMouseButton.Right:
return pressed ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp;
default:
@ -68,11 +68,7 @@ namespace Avalonia.Controls.Remote.Server
}
}
private static RawInputModifiers GetAvaloniaRawInputModifiers(
Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers)
=> (RawInputModifiers)GetAvaloniaInputModifiers(modifiers);
private static RawInputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers)
private static RawInputModifiers GetAvaloniaRawInputModifiers(InputModifiers[]? modifiers)
{
var result = RawInputModifiers.None;
@ -85,31 +81,31 @@ namespace Avalonia.Controls.Remote.Server
{
switch (modifier)
{
case Avalonia.Remote.Protocol.Input.InputModifiers.Control:
case InputModifiers.Control:
result |= RawInputModifiers.Control;
break;
case Avalonia.Remote.Protocol.Input.InputModifiers.Alt:
case InputModifiers.Alt:
result |= RawInputModifiers.Alt;
break;
case Avalonia.Remote.Protocol.Input.InputModifiers.Shift:
case InputModifiers.Shift:
result |= RawInputModifiers.Shift;
break;
case Avalonia.Remote.Protocol.Input.InputModifiers.Windows:
case InputModifiers.Windows:
result |= RawInputModifiers.Meta;
break;
case Avalonia.Remote.Protocol.Input.InputModifiers.LeftMouseButton:
case InputModifiers.LeftMouseButton:
result |= RawInputModifiers.LeftMouseButton;
break;
case Avalonia.Remote.Protocol.Input.InputModifiers.MiddleMouseButton:
case InputModifiers.MiddleMouseButton:
result |= RawInputModifiers.MiddleMouseButton;
break;
case Avalonia.Remote.Protocol.Input.InputModifiers.RightMouseButton:
case InputModifiers.RightMouseButton:
result |= RawInputModifiers.RightMouseButton;
break;
}
@ -187,7 +183,7 @@ namespace Avalonia.Controls.Remote.Server
InputRoot!,
RawPointerEventType.Move,
new Point(pointer.X, pointer.Y),
GetAvaloniaInputModifiers(pointer.Modifiers)));
GetAvaloniaRawInputModifiers(pointer.Modifiers)));
}, DispatcherPriority.Input);
}
if(obj is PointerPressedEventMessage pressed)
@ -200,7 +196,7 @@ namespace Avalonia.Controls.Remote.Server
InputRoot!,
GetAvaloniaEventType(pressed.Button, true),
new Point(pressed.X, pressed.Y),
GetAvaloniaInputModifiers(pressed.Modifiers)));
GetAvaloniaRawInputModifiers(pressed.Modifiers)));
}, DispatcherPriority.Input);
}
if (obj is PointerReleasedEventMessage released)
@ -213,7 +209,7 @@ namespace Avalonia.Controls.Remote.Server
InputRoot!,
GetAvaloniaEventType(released.Button, false),
new Point(released.X, released.Y),
GetAvaloniaInputModifiers(released.Modifiers)));
GetAvaloniaRawInputModifiers(released.Modifiers)));
}, DispatcherPriority.Input);
}
if(obj is ScrollEventMessage scroll)
@ -226,7 +222,7 @@ namespace Avalonia.Controls.Remote.Server
InputRoot!,
new Point(scroll.X, scroll.Y),
new Vector(scroll.DeltaX, scroll.DeltaY),
GetAvaloniaInputModifiers(scroll.Modifiers)));
GetAvaloniaRawInputModifiers(scroll.Modifiers)));
}, DispatcherPriority.Input);
}
if(obj is KeyEventMessage key)
@ -274,8 +270,8 @@ namespace Avalonia.Controls.Remote.Server
}
public override IEnumerable<object> Surfaces => new[] { this };
FrameMessage RenderFrame(int width, int height, ProtocolPixelFormat? format)
private FrameMessage RenderFrame(int width, int height, ProtocolPixelFormat? format)
{
var scalingX = _dpi.X / 96.0;
var scalingY = _dpi.Y / 96.0;

13
src/Avalonia.Controls/Slider.cs

@ -81,11 +81,11 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="TicksProperty"/> property.
/// </summary>
public static readonly StyledProperty<AvaloniaList<double>> TicksProperty =
public static readonly StyledProperty<AvaloniaList<double>?> TicksProperty =
TickBar.TicksProperty.AddOwner<Slider>();
// Slider required parts
private bool _isDragging = false;
private bool _isDragging;
private Track? _track;
private Button? _decreaseButton;
private Button? _increaseButton;
@ -124,7 +124,7 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the ticks to be drawn on the tick bar.
/// </summary>
public AvaloniaList<double> Ticks
public AvaloniaList<double>? Ticks
{
get => GetValue(TicksProperty);
set => SetValue(TicksProperty, value);
@ -215,6 +215,7 @@ namespace Avalonia.Controls
_pointerMovedDispose = this.AddDisposableHandler(PointerMovedEvent, TrackMoved, RoutingStrategies.Tunnel);
}
/// <inheritdoc />
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
@ -350,8 +351,8 @@ namespace Avalonia.Controls
var orient = Orientation == Orientation.Horizontal;
var thumbLength = (orient
? _track.Thumb.Bounds.Width
: _track.Thumb.Bounds.Height) + double.Epsilon;
? _track.Thumb?.Bounds.Width ?? 0.0
: _track.Thumb?.Bounds.Height ?? 0.0) + double.Epsilon;
var trackLength = (orient
? _track.Bounds.Width
: _track.Bounds.Height) - thumbLength;
@ -367,6 +368,7 @@ namespace Avalonia.Controls
Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
}
/// <inheritdoc />
protected override void UpdateDataValidation(
AvaloniaProperty property,
BindingValueType state,
@ -378,6 +380,7 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

9
src/Avalonia.Controls/StackPanel.cs

@ -261,9 +261,6 @@ namespace Avalonia.Controls
// Get next child.
var child = children[i];
if (child == null)
{ continue; }
bool isVisible = child.IsVisible;
if (isVisible && !hasVisibleChild)
@ -319,8 +316,10 @@ namespace Avalonia.Controls
{
var child = children[i];
if (child == null || !child.IsVisible)
{ continue; }
if (!child.IsVisible)
{
continue;
}
if (fHorizontal)
{

18
src/Avalonia.Controls/TickBar.cs

@ -51,20 +51,16 @@ namespace Avalonia.Controls
TicksProperty);
}
public TickBar() : base()
{
}
/// <summary>
/// Defines the <see cref="Fill"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> FillProperty =
AvaloniaProperty.Register<TickBar, IBrush>(nameof(Fill));
public static readonly StyledProperty<IBrush?> FillProperty =
AvaloniaProperty.Register<TickBar, IBrush?>(nameof(Fill));
/// <summary>
/// Brush used to fill the TickBar's Ticks.
/// </summary>
public IBrush Fill
public IBrush? Fill
{
get { return GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
@ -136,15 +132,15 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Ticks"/> property.
/// </summary>
public static readonly StyledProperty<AvaloniaList<double>> TicksProperty =
AvaloniaProperty.Register<TickBar, AvaloniaList<double>>(nameof(Ticks));
public static readonly StyledProperty<AvaloniaList<double>?> TicksProperty =
AvaloniaProperty.Register<TickBar, AvaloniaList<double>?>(nameof(Ticks));
/// <summary>
/// The Ticks property contains collection of value of type Double which
/// are the logical positions use to draw the ticks.
/// The property value is a <see cref="AvaloniaList{T}" />.
/// </summary>
public AvaloniaList<double> Ticks
public AvaloniaList<double>? Ticks
{
get { return GetValue(TicksProperty); }
set { SetValue(TicksProperty, value); }
@ -281,7 +277,7 @@ namespace Avalonia.Controls
endPoint = new Point(0d, halfReservedSpace);
logicalToPhysical = size.Height / range * -1;
break;
};
}
tickLen2 = tickLen * 0.75;

9
src/Avalonia.Controls/TrayIcon.cs

@ -100,8 +100,8 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="TrayIcons"/> attached property.
/// </summary>
public static readonly AttachedProperty<TrayIcons> IconsProperty
= AvaloniaProperty.RegisterAttached<TrayIcon, Application, TrayIcons>("Icons");
public static readonly AttachedProperty<TrayIcons?> IconsProperty
= AvaloniaProperty.RegisterAttached<TrayIcon, Application, TrayIcons?>("Icons");
/// <summary>
/// Defines the <see cref="Menu"/> property.
@ -127,9 +127,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> IsVisibleProperty =
Visual.IsVisibleProperty.AddOwner<TrayIcon>();
public static void SetIcons(Application o, TrayIcons trayIcons) => o.SetValue(IconsProperty, trayIcons);
public static void SetIcons(Application o, TrayIcons? trayIcons) => o.SetValue(IconsProperty, trayIcons);
public static TrayIcons GetIcons(Application o) => o.GetValue(IconsProperty);
public static TrayIcons? GetIcons(Application o) => o.GetValue(IconsProperty);
/// <summary>
/// Gets or sets the <see cref="Command"/> property of a TrayIcon.
@ -213,6 +213,7 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

16
src/Avalonia.Controls/TreeView.cs

@ -3,17 +3,13 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Reactive;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Utils;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
@ -132,6 +128,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the selected items.
/// </summary>
[AllowNull]
public IList SelectedItems
{
get
@ -144,7 +141,6 @@ namespace Avalonia.Controls
return _selectedItems;
}
set
{
if (value?.IsFixedSize == true || value?.IsReadOnly == true)
@ -167,9 +163,9 @@ namespace Avalonia.Controls
{
item.IsExpanded = true;
if (item.Presenter?.Panel != null)
if (item.Presenter?.Panel is { } panel)
{
foreach (var child in item.Presenter.Panel.Children)
foreach (var child in panel.Children)
{
if (child is TreeViewItem treeViewItem)
{
@ -589,7 +585,7 @@ namespace Avalonia.Controls
case NavigationDirection.Right:
if (from?.IsExpanded == true && intoChildren && from.ItemCount > 0)
{
result = (TreeViewItem)from.ItemContainerGenerator.ContainerFromIndex(0)!;
result = (TreeViewItem)from.ContainerFromIndex(0)!;
}
else if (index < parent?.ItemCount - 1)
{
@ -865,7 +861,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="container">The container.</param>
/// <param name="selected">Whether the control is selected</param>
private void MarkContainerSelected(Control container, bool selected)
private void MarkContainerSelected(Control? container, bool selected)
{
if (container == null)
{

36
src/Avalonia.Controls/Viewbox.cs

@ -36,6 +36,9 @@ namespace Avalonia.Controls
AffectsMeasure<Viewbox>(StretchProperty, StretchDirectionProperty);
}
/// <summary>
/// Initializes a new instance of the <see cref="Viewbox"/> class.
/// </summary>
public Viewbox()
{
// The Child control is hosted inside a ViewboxContainer control so that the transform
@ -85,13 +88,14 @@ namespace Avalonia.Controls
set => _containerVisual.RenderTransform = value;
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ChildProperty)
{
var (oldChild, newChild) = change.GetOldAndNewValue<Control>();
var (oldChild, newChild) = change.GetOldAndNewValue<Control?>();
if (oldChild is not null)
{
@ -111,41 +115,33 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc />
protected override Size MeasureOverride(Size availableSize)
{
var child = _containerVisual;
if (child != null)
{
child.Measure(Size.Infinity);
var childSize = child.DesiredSize;
child.Measure(Size.Infinity);
var size = Stretch.CalculateSize(availableSize, childSize, StretchDirection);
var childSize = child.DesiredSize;
return size;
}
var size = Stretch.CalculateSize(availableSize, childSize, StretchDirection);
return new Size();
return size;
}
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
var child = _containerVisual;
if (child != null)
{
var childSize = child.DesiredSize;
var scale = Stretch.CalculateScaling(finalSize, childSize, StretchDirection);
InternalTransform = new ImmutableTransform(Matrix.CreateScale(scale.X, scale.Y));
var childSize = child.DesiredSize;
var scale = Stretch.CalculateScaling(finalSize, childSize, StretchDirection);
child.Arrange(new Rect(childSize));
InternalTransform = new ImmutableTransform(Matrix.CreateScale(scale.X, scale.Y));
return childSize * scale;
}
child.Arrange(new Rect(childSize));
return finalSize;
return childSize * scale;
}
/// <summary>

107
src/Avalonia.Controls/WrapPanel.cs

@ -144,35 +144,32 @@ namespace Avalonia.Controls
for (int i = 0, count = children.Count; i < count; i++)
{
var child = children[i];
if (child != null)
{
// Flow passes its own constraint to children
child.Measure(childConstraint);
// Flow passes its own constraint to children
child.Measure(childConstraint);
// This is the size of the child in UV space
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
// This is the size of the child in UV space
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line
{
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
curLineSize = sz;
if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line
{
panelSize.U = Max(sz.U, panelSize.U);
panelSize.V += sz.V;
curLineSize = new UVSize(orientation);
}
}
else // Continue to accumulate a line
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line
{
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
curLineSize = sz;
if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
panelSize.U = Max(sz.U, panelSize.U);
panelSize.V += sz.V;
curLineSize = new UVSize(orientation);
}
}
else // Continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
}
}
// The last line size, if any should be added
@ -202,34 +199,31 @@ namespace Avalonia.Controls
for (int i = 0; i < children.Count; i++)
{
var child = children[i];
if (child != null)
{
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) // Need to switch to another line
{
ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
accumulatedV += curLineSize.V;
curLineSize = sz;
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) // Need to switch to another line
{
ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) // The element is wider then the constraint - give it a separate line
{
// Switch to next line which only contain one element
ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
accumulatedV += curLineSize.V;
curLineSize = sz;
accumulatedV += sz.V;
curLineSize = new UVSize(orientation);
}
firstInLine = i;
}
else // Continue to accumulate a line
if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) // The element is wider then the constraint - give it a separate line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
// Switch to next line which only contain one element
ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
accumulatedV += sz.V;
curLineSize = new UVSize(orientation);
}
firstInLine = i;
}
else // Continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
}
}
@ -252,17 +246,14 @@ namespace Avalonia.Controls
for (int i = start; i < end; i++)
{
var child = children[i];
if (child != null)
{
var childSize = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height);
double layoutSlotU = useItemU ? itemU : childSize.U;
child.Arrange(new Rect(
isHorizontal ? u : v,
isHorizontal ? v : u,
isHorizontal ? layoutSlotU : lineV,
isHorizontal ? lineV : layoutSlotU));
u += layoutSlotU;
}
var childSize = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height);
double layoutSlotU = useItemU ? itemU : childSize.U;
child.Arrange(new Rect(
isHorizontal ? u : v,
isHorizontal ? v : u,
isHorizontal ? layoutSlotU : lineV,
isHorizontal ? lineV : layoutSlotU));
u += layoutSlotU;
}
}

10
src/Browser/Avalonia.Browser/ClipboardImpl.cs

@ -8,14 +8,14 @@ namespace Avalonia.Browser
{
internal class ClipboardImpl : IClipboard
{
public Task<string> GetTextAsync()
public Task<string?> GetTextAsync()
{
return InputHelper.ReadClipboardTextAsync();
return InputHelper.ReadClipboardTextAsync()!;
}
public Task SetTextAsync(string text)
public Task SetTextAsync(string? text)
{
return InputHelper.WriteClipboardTextAsync(text);
return InputHelper.WriteClipboardTextAsync(text ?? string.Empty);
}
public async Task ClearAsync() => await SetTextAsync("");
@ -24,6 +24,6 @@ namespace Avalonia.Browser
public Task<string[]> GetFormatsAsync() => Task.FromResult(Array.Empty<string>());
public Task<object> GetDataAsync(string format) => Task.FromResult<object>(new());
public Task<object?> GetDataAsync(string format) => Task.FromResult<object?>(new());
}
}

Loading…
Cancel
Save