Browse Source

Merge pull request #7477 from AvaloniaUI/fixes/avalonia-controls-nullability

Added nullable annotations to Avalonia.Controls.
pull/7508/head
Max Katz 5 years ago
committed by GitHub
parent
commit
2c7ae3a50f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      src/Avalonia.Controls/AppBuilderBase.cs
  2. 5
      src/Avalonia.Controls/Application.cs
  3. 26
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  4. 6
      src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
  5. 2
      src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs
  6. 309
      src/Avalonia.Controls/AutoCompleteBox.cs
  7. 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  8. 12
      src/Avalonia.Controls/Border.cs
  9. 28
      src/Avalonia.Controls/Button.cs
  10. 14
      src/Avalonia.Controls/ButtonSpinner.cs
  11. 76
      src/Avalonia.Controls/Calendar/Calendar.cs
  12. 6
      src/Avalonia.Controls/Calendar/CalendarButton.cs
  13. 87
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  14. 2
      src/Avalonia.Controls/Calendar/CalendarDateRange.cs
  15. 6
      src/Avalonia.Controls/Calendar/CalendarDayButton.cs
  16. 100
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  17. 2
      src/Avalonia.Controls/Calendar/DateTimeHelper.cs
  18. 4
      src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
  19. 2
      src/Avalonia.Controls/Canvas.cs
  20. 2
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  21. 4
      src/Avalonia.Controls/Chrome/TitleBar.cs
  22. 40
      src/Avalonia.Controls/ComboBox.cs
  23. 14
      src/Avalonia.Controls/ContentControl.cs
  24. 14
      src/Avalonia.Controls/ContextMenu.cs
  25. 2
      src/Avalonia.Controls/ContextRequestedEventArgs.cs
  26. 4
      src/Avalonia.Controls/Control.cs
  27. 35
      src/Avalonia.Controls/ControlExtensions.cs
  28. 3
      src/Avalonia.Controls/Converters/CornerRadiusFilterConverter.cs
  29. 4
      src/Avalonia.Controls/Converters/MarginMultiplierConverter.cs
  30. 2
      src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
  31. 4
      src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs
  32. 29
      src/Avalonia.Controls/DataValidationErrors.cs
  33. 60
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  34. 103
      src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
  35. 28
      src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs
  36. 6
      src/Avalonia.Controls/DateTimePickers/PickerPresenterBase.cs
  37. 56
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  38. 75
      src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs
  39. 10
      src/Avalonia.Controls/Decorator.cs
  40. 40
      src/Avalonia.Controls/DefinitionBase.cs
  41. 6
      src/Avalonia.Controls/DefinitionList.cs
  42. 2
      src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs
  43. 4
      src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs
  44. 20
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  45. 3
      src/Avalonia.Controls/Expander.cs
  46. 7
      src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
  47. 2
      src/Avalonia.Controls/Flyouts/Flyout.cs
  48. 20
      src/Avalonia.Controls/Flyouts/FlyoutBase.cs
  49. 8
      src/Avalonia.Controls/Flyouts/MenuFlyout.cs
  50. 12
      src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
  51. 2
      src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs
  52. 26
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  53. 11
      src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
  54. 2
      src/Avalonia.Controls/Generators/MenuItemContainerGenerator.cs
  55. 12
      src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
  56. 8
      src/Avalonia.Controls/Generators/TreeContainerIndex.cs
  57. 23
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  58. 165
      src/Avalonia.Controls/Grid.cs
  59. 2
      src/Avalonia.Controls/GridLength.cs
  60. 62
      src/Avalonia.Controls/GridSplitter.cs
  61. 40
      src/Avalonia.Controls/HotkeyManager.cs
  62. 6
      src/Avalonia.Controls/IContentControl.cs
  63. 2
      src/Avalonia.Controls/IControl.cs
  64. 2
      src/Avalonia.Controls/IHeadered.cs
  65. 2
      src/Avalonia.Controls/IMenuElement.cs
  66. 4
      src/Avalonia.Controls/IMenuItem.cs
  67. 4
      src/Avalonia.Controls/IScrollAnchorProvider.cs
  68. 2
      src/Avalonia.Controls/IVirtualizingPanel.cs
  69. 56
      src/Avalonia.Controls/ItemsControl.cs
  70. 8
      src/Avalonia.Controls/ItemsSourceView.cs
  71. 8
      src/Avalonia.Controls/Label.cs
  72. 14
      src/Avalonia.Controls/LayoutTransformControl.cs
  73. 12
      src/Avalonia.Controls/ListBox.cs
  74. 10
      src/Avalonia.Controls/MaskedTextBox.cs
  75. 2
      src/Avalonia.Controls/Menu.cs
  76. 13
      src/Avalonia.Controls/MenuBase.cs
  77. 44
      src/Avalonia.Controls/MenuItem.cs
  78. 8
      src/Avalonia.Controls/MenuItemAccessKeyHandler.cs
  79. 2
      src/Avalonia.Controls/Mixins/SelectableMixin.cs
  80. 19
      src/Avalonia.Controls/NativeControlHost.cs
  81. 2
      src/Avalonia.Controls/NativeMenu.Export.cs
  82. 16
      src/Avalonia.Controls/NativeMenu.cs
  83. 4
      src/Avalonia.Controls/NativeMenuBar.cs
  84. 48
      src/Avalonia.Controls/NativeMenuItem.cs
  85. 8
      src/Avalonia.Controls/NativeMenuItemBase.cs
  86. 8
      src/Avalonia.Controls/Notifications/INotification.cs
  87. 16
      src/Avalonia.Controls/Notifications/Notification.cs
  88. 15
      src/Avalonia.Controls/Notifications/NotificationCard.cs
  89. 8
      src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
  90. 94
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  91. 24
      src/Avalonia.Controls/Panel.cs
  92. 37
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  93. 4
      src/Avalonia.Controls/Platform/ExportWindowingSubsystemAttribute.cs
  94. 6
      src/Avalonia.Controls/Platform/INativeControlHostImpl.cs
  95. 2
      src/Avalonia.Controls/Platform/ISystemDialogImpl.cs
  96. 18
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs
  97. 2
      src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs
  98. 4
      src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs
  99. 2
      src/Avalonia.Controls/Platform/ITrayIconImpl.cs
  100. 6
      src/Avalonia.Controls/Platform/IWindowBaseImpl.cs

35
src/Avalonia.Controls/AppBuilderBase.cs

@ -14,9 +14,9 @@ namespace Avalonia.Controls
public abstract class AppBuilderBase<TAppBuilder> where TAppBuilder : AppBuilderBase<TAppBuilder>, new() public abstract class AppBuilderBase<TAppBuilder> where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
{ {
private static bool s_setupWasAlreadyCalled; private static bool s_setupWasAlreadyCalled;
private Action _optionsInitializers; private Action? _optionsInitializers;
private Func<Application> _appFactory; private Func<Application>? _appFactory;
private IApplicationLifetime _lifetime; private IApplicationLifetime? _lifetime;
/// <summary> /// <summary>
/// Gets or sets the <see cref="IRuntimePlatform"/> instance. /// Gets or sets the <see cref="IRuntimePlatform"/> instance.
@ -31,32 +31,32 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the <see cref="Application"/> instance being initialized. /// Gets the <see cref="Application"/> instance being initialized.
/// </summary> /// </summary>
public Application Instance { get; private set; } public Application? Instance { get; private set; }
/// <summary> /// <summary>
/// Gets the type of the Instance (even if it's not created yet) /// Gets the type of the Instance (even if it's not created yet)
/// </summary> /// </summary>
public Type ApplicationType { get; private set; } public Type? ApplicationType { get; private set; }
/// <summary> /// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem. /// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary> /// </summary>
public Action WindowingSubsystemInitializer { get; private set; } public Action? WindowingSubsystemInitializer { get; private set; }
/// <summary> /// <summary>
/// Gets the name of the currently selected windowing subsystem. /// Gets the name of the currently selected windowing subsystem.
/// </summary> /// </summary>
public string WindowingSubsystemName { get; private set; } public string? WindowingSubsystemName { get; private set; }
/// <summary> /// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem. /// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary> /// </summary>
public Action RenderingSubsystemInitializer { get; private set; } public Action? RenderingSubsystemInitializer { get; private set; }
/// <summary> /// <summary>
/// Gets the name of the currently selected rendering subsystem. /// Gets the name of the currently selected rendering subsystem.
/// </summary> /// </summary>
public string RenderingSubsystemName { get; private set; } public string? RenderingSubsystemName { get; private set; }
/// <summary> /// <summary>
/// Gets or sets a method to call after the <see cref="Application"/> is setup. /// Gets or sets a method to call after the <see cref="Application"/> is setup.
@ -126,7 +126,7 @@ namespace Avalonia.Controls
/// <typeparam name="TMainWindow">The window type.</typeparam> /// <typeparam name="TMainWindow">The window type.</typeparam>
/// <param name="dataContextProvider">A delegate that will be called to create a data context for the window (optional).</param> /// <param name="dataContextProvider">A delegate that will be called to create a data context for the window (optional).</param>
[Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")] [Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")]
public void Start<TMainWindow>(Func<object> dataContextProvider = null) public void Start<TMainWindow>(Func<object>? dataContextProvider = null)
where TMainWindow : Window, new() where TMainWindow : Window, new()
{ {
AfterSetup(builder => AfterSetup(builder =>
@ -134,7 +134,7 @@ namespace Avalonia.Controls
var window = new TMainWindow(); var window = new TMainWindow();
if (dataContextProvider != null) if (dataContextProvider != null)
window.DataContext = dataContextProvider(); window.DataContext = dataContextProvider();
((IClassicDesktopStyleApplicationLifetime)builder.Instance.ApplicationLifetime) ((IClassicDesktopStyleApplicationLifetime)builder.Instance!.ApplicationLifetime!)
.MainWindow = window; .MainWindow = window;
}); });
@ -155,7 +155,7 @@ namespace Avalonia.Controls
public void Start(AppMainDelegate main, string[] args) public void Start(AppMainDelegate main, string[] args)
{ {
Setup(); Setup();
main(Instance, args); main(Instance!, args);
} }
/// <summary> /// <summary>
@ -226,8 +226,8 @@ namespace Avalonia.Controls
var platformClassName = assemblyName.Replace("Avalonia.", string.Empty) + "Platform"; var platformClassName = assemblyName.Replace("Avalonia.", string.Empty) + "Platform";
var platformClassFullName = assemblyName + "." + platformClassName; var platformClassFullName = assemblyName + "." + platformClassName;
var platformClass = assembly.GetType(platformClassFullName); var platformClass = assembly.GetType(platformClassFullName);
var init = platformClass.GetRuntimeMethod("Initialize", Type.EmptyTypes); var init = platformClass!.GetRuntimeMethod("Initialize", Type.EmptyTypes);
init.Invoke(null, null); init!.Invoke(null, null);
}; };
public TAppBuilder UseAvaloniaModules() => AfterSetup(builder => SetupAvaloniaModules()); public TAppBuilder UseAvaloniaModules() => AfterSetup(builder => SetupAvaloniaModules());
@ -251,7 +251,7 @@ namespace Avalonia.Controls
where constructor.GetParameters().Length == 0 && !constructor.IsStatic where constructor.GetParameters().Length == 0 && !constructor.IsStatic
select constructor).Single() into constructor select constructor).Single() into constructor
select (Action)(() => constructor.Invoke(Array.Empty<object>())); select (Action)(() => constructor.Invoke(Array.Empty<object>()));
Delegate.Combine(moduleInitializers.ToArray()).DynamicInvoke(); Delegate.Combine(moduleInitializers.ToArray())!.DynamicInvoke();
} }
/// <summary> /// <summary>
@ -292,6 +292,11 @@ namespace Avalonia.Controls
throw new InvalidOperationException("No rendering system configured."); throw new InvalidOperationException("No rendering system configured.");
} }
if (_appFactory == null)
{
throw new InvalidOperationException("No Application factory configured.");
}
if (s_setupWasAlreadyCalled && CheckSetup) if (s_setupWasAlreadyCalled && CheckSetup)
{ {
throw new InvalidOperationException("Setup was already called on one of AppBuilder instances"); throw new InvalidOperationException("Setup was already called on one of AppBuilder instances");

5
src/Avalonia.Controls/Application.cs

@ -13,7 +13,6 @@ using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Threading; using Avalonia.Threading;
#nullable enable
namespace Avalonia namespace Avalonia
{ {
@ -177,13 +176,13 @@ namespace Avalonia
/// </summary> /// </summary>
public IApplicationLifetime? ApplicationLifetime { get; set; } public IApplicationLifetime? ApplicationLifetime { get; set; }
event Action<IReadOnlyList<IStyle>> IGlobalStyles.GlobalStylesAdded event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesAdded
{ {
add => _stylesAdded += value; add => _stylesAdded += value;
remove => _stylesAdded -= value; remove => _stylesAdded -= value;
} }
event Action<IReadOnlyList<IStyle>> IGlobalStyles.GlobalStylesRemoved event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesRemoved
{ {
add => _stylesRemoved += value; add => _stylesRemoved += value;
remove => _stylesRemoved -= value; remove => _stylesRemoved -= value;

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

@ -15,26 +15,26 @@ namespace Avalonia.Controls.ApplicationLifetimes
public class ClassicDesktopStyleApplicationLifetime : IClassicDesktopStyleApplicationLifetime, IDisposable public class ClassicDesktopStyleApplicationLifetime : IClassicDesktopStyleApplicationLifetime, IDisposable
{ {
private int _exitCode; private int _exitCode;
private CancellationTokenSource _cts; private CancellationTokenSource? _cts;
private bool _isShuttingDown; private bool _isShuttingDown;
private HashSet<Window> _windows = new HashSet<Window>(); private HashSet<Window> _windows = new HashSet<Window>();
private static ClassicDesktopStyleApplicationLifetime _activeLifetime; private static ClassicDesktopStyleApplicationLifetime? _activeLifetime;
static ClassicDesktopStyleApplicationLifetime() static ClassicDesktopStyleApplicationLifetime()
{ {
Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened); Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened);
Window.WindowClosedEvent.AddClassHandler(typeof(Window), WindowClosedEvent); Window.WindowClosedEvent.AddClassHandler(typeof(Window), WindowClosedEvent);
} }
private static void WindowClosedEvent(object sender, RoutedEventArgs e) private static void WindowClosedEvent(object? sender, RoutedEventArgs e)
{ {
_activeLifetime?._windows.Remove((Window)sender); _activeLifetime?._windows.Remove((Window)sender!);
_activeLifetime?.HandleWindowClosed((Window)sender); _activeLifetime?.HandleWindowClosed((Window)sender!);
} }
private static void OnWindowOpened(object sender, RoutedEventArgs e) private static void OnWindowOpened(object? sender, RoutedEventArgs e)
{ {
_activeLifetime?._windows.Add((Window)sender); _activeLifetime?._windows.Add((Window)sender!);
} }
public ClassicDesktopStyleApplicationLifetime() public ClassicDesktopStyleApplicationLifetime()
@ -46,24 +46,24 @@ namespace Avalonia.Controls.ApplicationLifetimes
} }
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup; public event EventHandler<ControlledApplicationLifetimeStartupEventArgs>? Startup;
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested; public event EventHandler<ShutdownRequestedEventArgs>? ShutdownRequested;
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit; public event EventHandler<ControlledApplicationLifetimeExitEventArgs>? Exit;
/// <summary> /// <summary>
/// Gets the arguments passed to the AppBuilder Start method. /// Gets the arguments passed to the AppBuilder Start method.
/// </summary> /// </summary>
public string[] Args { get; set; } public string[]? Args { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public ShutdownMode ShutdownMode { get; set; } public ShutdownMode ShutdownMode { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public Window MainWindow { get; set; } public Window? MainWindow { get; set; }
public IReadOnlyList<Window> Windows => _windows.ToList(); public IReadOnlyList<Window> Windows => _windows.ToList();
@ -183,7 +183,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
return true; return true;
} }
private void OnShutdownRequested(object sender, ShutdownRequestedEventArgs e) => DoShutdown(e); private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e) => DoShutdown(e);
} }
public class ClassicDesktopStyleApplicationLifetimeOptions public class ClassicDesktopStyleApplicationLifetimeOptions

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

@ -20,7 +20,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// <see cref="ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime{T}(T, string[], ShutdownMode)"/> /// <see cref="ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime{T}(T, string[], ShutdownMode)"/>
/// method. /// method.
/// </summary> /// </summary>
string[] Args { get; } string[]? Args { get; }
/// <summary> /// <summary>
/// Gets or sets the <see cref="ShutdownMode"/>. This property indicates whether the application is shutdown explicitly or implicitly. /// Gets or sets the <see cref="ShutdownMode"/>. This property indicates whether the application is shutdown explicitly or implicitly.
@ -38,7 +38,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// <value> /// <value>
/// The main window. /// The main window.
/// </value> /// </value>
Window MainWindow { get; set; } Window? MainWindow { get; set; }
IReadOnlyList<Window> Windows { get; } IReadOnlyList<Window> Windows { get; }
@ -58,6 +58,6 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// will try to close each non-owned open window, invoking the <see cref="Window.Closing"/> event on each and allowing /// will try to close each non-owned open window, invoking the <see cref="Window.Closing"/> event on each and allowing
/// each window to cancel the shutdown of the application. Windows cannot however prevent OS shutdown. /// each window to cancel the shutdown of the application. Windows cannot however prevent OS shutdown.
/// </remarks> /// </remarks>
event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested; event EventHandler<ShutdownRequestedEventArgs>? ShutdownRequested;
} }
} }

2
src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs

@ -2,6 +2,6 @@ namespace Avalonia.Controls.ApplicationLifetimes
{ {
public interface ISingleViewApplicationLifetime : IApplicationLifetime public interface ISingleViewApplicationLifetime : IApplicationLifetime
{ {
Control MainView { get; set; } Control? MainView { get; set; }
} }
} }

309
src/Avalonia.Controls/AutoCompleteBox.cs

@ -69,7 +69,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <value>The text that is used to determine which items to display in /// <value>The text that is used to determine which items to display in
/// the <see cref="T:Avalonia.Controls.AutoCompleteBox" />.</value> /// the <see cref="T:Avalonia.Controls.AutoCompleteBox" />.</value>
public string Parameter { get; private set; } public string? Parameter { get; private set; }
/// <summary> /// <summary>
/// Initializes a new instance of the /// Initializes a new instance of the
@ -79,7 +79,7 @@ namespace Avalonia.Controls
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.SearchText" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.SearchText" />
/// property, which is used to filter items for the /// property, which is used to filter items for the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</param> /// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</param>
public PopulatingEventArgs(string parameter) public PopulatingEventArgs(string? parameter)
{ {
Parameter = parameter; Parameter = parameter;
} }
@ -98,7 +98,7 @@ namespace Avalonia.Controls
/// <typeparam name="T">The type used for filtering the /// <typeparam name="T">The type used for filtering the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />. This type can /// <see cref="T:Avalonia.Controls.AutoCompleteBox" />. This type can
/// be either a string or an object.</typeparam> /// be either a string or an object.</typeparam>
public delegate bool AutoCompleteFilterPredicate<T>(string search, T item); public delegate bool AutoCompleteFilterPredicate<T>(string? search, T item);
/// <summary> /// <summary>
/// Specifies how text in the text box portion of the /// Specifies how text in the text box portion of the
@ -245,7 +245,7 @@ namespace Avalonia.Controls
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />. /// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// This type can be either a string or an object. /// This type can be either a string or an object.
/// </typeparam> /// </typeparam>
public delegate string AutoCompleteSelector<T>(string search, T item); public delegate string AutoCompleteSelector<T>(string? search, T item);
/// <summary> /// <summary>
/// Represents a control that provides a text box for user input and a /// Represents a control that provides a text box for user input and a
@ -275,19 +275,19 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private const string ElementTextBox = "PART_TextBox"; private const string ElementTextBox = "PART_TextBox";
private IEnumerable _itemsEnumerable; private IEnumerable? _itemsEnumerable;
/// <summary> /// <summary>
/// Gets or sets a local cached copy of the items data. /// Gets or sets a local cached copy of the items data.
/// </summary> /// </summary>
private List<object> _items; private List<object>? _items;
/// <summary> /// <summary>
/// Gets or sets the observable collection that contains references to /// Gets or sets the observable collection that contains references to
/// all of the items in the generated view of data that is provided to /// all of the items in the generated view of data that is provided to
/// the selection-style control adapter. /// the selection-style control adapter.
/// </summary> /// </summary>
private AvaloniaList<object> _view; private AvaloniaList<object>? _view;
/// <summary> /// <summary>
/// Gets or sets a value to ignore a number of pending change handlers. /// Gets or sets a value to ignore a number of pending change handlers.
@ -338,7 +338,7 @@ namespace Avalonia.Controls
/// Gets or sets the DispatcherTimer used for the MinimumPopulateDelay /// Gets or sets the DispatcherTimer used for the MinimumPopulateDelay
/// condition for auto completion. /// condition for auto completion.
/// </summary> /// </summary>
private DispatcherTimer _delayTimer; private DispatcherTimer? _delayTimer;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether a read-only dependency /// Gets or sets a value indicating whether a read-only dependency
@ -351,47 +351,47 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// The TextBox template part. /// The TextBox template part.
/// </summary> /// </summary>
private TextBox _textBox; private TextBox? _textBox;
private IDisposable _textBoxSubscriptions; private IDisposable? _textBoxSubscriptions;
/// <summary> /// <summary>
/// The SelectionAdapter. /// The SelectionAdapter.
/// </summary> /// </summary>
private ISelectionAdapter _adapter; private ISelectionAdapter? _adapter;
/// <summary> /// <summary>
/// A control that can provide updated string values from a binding. /// A control that can provide updated string values from a binding.
/// </summary> /// </summary>
private BindingEvaluator<string> _valueBindingEvaluator; private BindingEvaluator<string>? _valueBindingEvaluator;
/// <summary> /// <summary>
/// A weak subscription for the collection changed event. /// A weak subscription for the collection changed event.
/// </summary> /// </summary>
private IDisposable _collectionChangeSubscription; private IDisposable? _collectionChangeSubscription;
private Func<string, CancellationToken, Task<IEnumerable<object>>> _asyncPopulator; private Func<string?, CancellationToken, Task<IEnumerable<object>>>? _asyncPopulator;
private CancellationTokenSource _populationCancellationTokenSource; private CancellationTokenSource? _populationCancellationTokenSource;
private bool _itemTemplateIsFromValueMemberBinding = true; private bool _itemTemplateIsFromValueMemberBinding = true;
private bool _settingItemTemplateFromValueMemberBinding; private bool _settingItemTemplateFromValueMemberBinding;
private object _selectedItem; private object? _selectedItem;
private bool _isDropDownOpen; private bool _isDropDownOpen;
private bool _isFocused = false; private bool _isFocused = false;
private string _text = string.Empty; private string? _text = string.Empty;
private string _searchText = string.Empty; private string? _searchText = string.Empty;
private AutoCompleteFilterPredicate<object> _itemFilter; private AutoCompleteFilterPredicate<object?>? _itemFilter;
private AutoCompleteFilterPredicate<string> _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith); private AutoCompleteFilterPredicate<string?>? _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith);
private AutoCompleteSelector<object> _itemSelector; private AutoCompleteSelector<object>? _itemSelector;
private AutoCompleteSelector<string> _textSelector; private AutoCompleteSelector<string?>? _textSelector;
public static readonly RoutedEvent<SelectionChangedEventArgs> SelectionChangedEvent = public static readonly RoutedEvent<SelectionChangedEventArgs> SelectionChangedEvent =
RoutedEvent.Register<SelectionChangedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox)); RoutedEvent.Register<SelectionChangedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox));
public static readonly StyledProperty<string> WatermarkProperty = public static readonly StyledProperty<string?> WatermarkProperty =
TextBox.WatermarkProperty.AddOwner<AutoCompleteBox>(); TextBox.WatermarkProperty.AddOwner<AutoCompleteBox>();
/// <summary> /// <summary>
@ -479,8 +479,8 @@ namespace Avalonia.Controls
/// <value>The identifier the /// <value>The identifier the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.SelectedItem" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.SelectedItem" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, object> SelectedItemProperty = public static readonly DirectProperty<AutoCompleteBox, object?> SelectedItemProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, object>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, object?>(
nameof(SelectedItem), nameof(SelectedItem),
o => o.SelectedItem, o => o.SelectedItem,
(o, v) => o.SelectedItem = v, (o, v) => o.SelectedItem = v,
@ -495,7 +495,7 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, string> TextProperty = public static readonly DirectProperty<AutoCompleteBox, string?> TextProperty =
TextBlock.TextProperty.AddOwnerWithDataValidation<AutoCompleteBox>( TextBlock.TextProperty.AddOwnerWithDataValidation<AutoCompleteBox>(
o => o.Text, o => o.Text,
(o, v) => o.Text = v, (o, v) => o.Text = v,
@ -510,8 +510,8 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.SearchText" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.SearchText" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, string> SearchTextProperty = public static readonly DirectProperty<AutoCompleteBox, string?> SearchTextProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, string>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, string?>(
nameof(SearchText), nameof(SearchText),
o => o.SearchText, o => o.SearchText,
unsetValue: string.Empty); unsetValue: string.Empty);
@ -535,8 +535,8 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemFilter" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemFilter" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteFilterPredicate<object>> ItemFilterProperty = public static readonly DirectProperty<AutoCompleteBox, AutoCompleteFilterPredicate<object?>?> ItemFilterProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteFilterPredicate<object>>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteFilterPredicate<object?>?>(
nameof(ItemFilter), nameof(ItemFilter),
o => o.ItemFilter, o => o.ItemFilter,
(o, v) => o.ItemFilter = v); (o, v) => o.ItemFilter = v);
@ -549,8 +549,8 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextFilter" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextFilter" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteFilterPredicate<string>> TextFilterProperty = public static readonly DirectProperty<AutoCompleteBox, AutoCompleteFilterPredicate<string?>?> TextFilterProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteFilterPredicate<string>>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteFilterPredicate<string?>?>(
nameof(TextFilter), nameof(TextFilter),
o => o.TextFilter, o => o.TextFilter,
(o, v) => o.TextFilter = v, (o, v) => o.TextFilter = v,
@ -564,8 +564,8 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemSelector" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemSelector" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<object>> ItemSelectorProperty = public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<object>?> ItemSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<object>>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<object>?>(
nameof(ItemSelector), nameof(ItemSelector),
o => o.ItemSelector, o => o.ItemSelector,
(o, v) => o.ItemSelector = v); (o, v) => o.ItemSelector = v);
@ -578,8 +578,8 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<string>> TextSelectorProperty = public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<string?>?> TextSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<string>>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<string?>?>(
nameof(TextSelector), nameof(TextSelector),
o => o.TextSelector, o => o.TextSelector,
(o, v) => o.TextSelector = v); (o, v) => o.TextSelector = v);
@ -592,14 +592,14 @@ namespace Avalonia.Controls
/// <value>The identifier for the /// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, IEnumerable> ItemsProperty = public static readonly DirectProperty<AutoCompleteBox, IEnumerable?> ItemsProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, IEnumerable>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, IEnumerable?>(
nameof(Items), nameof(Items),
o => o.Items, o => o.Items,
(o, v) => o.Items = v); (o, v) => o.Items = v);
public static readonly DirectProperty<AutoCompleteBox, Func<string, CancellationToken, Task<IEnumerable<object>>>> AsyncPopulatorProperty = public static readonly DirectProperty<AutoCompleteBox, Func<string?, CancellationToken, Task<IEnumerable<object>>>?> AsyncPopulatorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, Func<string, CancellationToken, Task<IEnumerable<object>>>>( AvaloniaProperty.RegisterDirect<AutoCompleteBox, Func<string?, CancellationToken, Task<IEnumerable<object>>>?>(
nameof(AsyncPopulator), nameof(AsyncPopulator),
o => o.AsyncPopulator, o => o.AsyncPopulator,
(o, v) => o.AsyncPopulator = v); (o, v) => o.AsyncPopulator = v);
@ -640,7 +640,7 @@ namespace Avalonia.Controls
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void OnControlIsEnabledChanged(AvaloniaPropertyChangedEventArgs e) private void OnControlIsEnabledChanged(AvaloniaPropertyChangedEventArgs e)
{ {
bool isEnabled = (bool)e.NewValue; bool isEnabled = (bool)e.NewValue!;
if (!isEnabled) if (!isEnabled)
{ {
IsDropDownOpen = false; IsDropDownOpen = false;
@ -655,7 +655,7 @@ namespace Avalonia.Controls
/// <param name="e">Event arguments.</param> /// <param name="e">Event arguments.</param>
private void OnMinimumPopulateDelayChanged(AvaloniaPropertyChangedEventArgs e) private void OnMinimumPopulateDelayChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var newValue = (TimeSpan)e.NewValue; var newValue = (TimeSpan)e.NewValue!;
// Stop any existing timer // Stop any existing timer
if (_delayTimer != null) if (_delayTimer != null)
@ -695,8 +695,8 @@ namespace Avalonia.Controls
return; return;
} }
bool oldValue = (bool)e.OldValue; bool oldValue = (bool)e.OldValue!;
bool newValue = (bool)e.NewValue; bool newValue = (bool)e.NewValue!;
if (newValue) if (newValue)
{ {
@ -750,7 +750,7 @@ namespace Avalonia.Controls
/// <param name="e">Event arguments.</param> /// <param name="e">Event arguments.</param>
private void OnTextPropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnTextPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
TextUpdated((string)e.NewValue, false); TextUpdated((string?)e.NewValue, false);
} }
private void OnSearchTextPropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnSearchTextPropertyChanged(AvaloniaPropertyChangedEventArgs e)
@ -778,7 +778,7 @@ namespace Avalonia.Controls
/// <param name="e">Event arguments.</param> /// <param name="e">Event arguments.</param>
private void OnFilterModePropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnFilterModePropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
AutoCompleteFilterMode mode = (AutoCompleteFilterMode)e.NewValue; AutoCompleteFilterMode mode = (AutoCompleteFilterMode)e.NewValue!;
// Sets the filter predicate for the new value // Sets the filter predicate for the new value
TextFilter = AutoCompleteSearch.GetFilter(mode); TextFilter = AutoCompleteSearch.GetFilter(mode);
@ -790,7 +790,7 @@ namespace Avalonia.Controls
/// <param name="e">Event arguments.</param> /// <param name="e">Event arguments.</param>
private void OnItemFilterPropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnItemFilterPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
AutoCompleteFilterPredicate<object> value = e.NewValue as AutoCompleteFilterPredicate<object>; var value = e.NewValue as AutoCompleteFilterPredicate<object>;
// If null, revert to the "None" predicate // If null, revert to the "None" predicate
if (value == null) if (value == null)
@ -810,7 +810,7 @@ namespace Avalonia.Controls
/// <param name="e">Event arguments.</param> /// <param name="e">Event arguments.</param>
private void OnItemsPropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnItemsPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
OnItemsChanged((IEnumerable)e.NewValue); OnItemsChanged((IEnumerable?)e.NewValue);
} }
private void OnItemTemplatePropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnItemTemplatePropertyChanged(AvaloniaPropertyChangedEventArgs e)
@ -818,7 +818,7 @@ namespace Avalonia.Controls
if (!_settingItemTemplateFromValueMemberBinding) if (!_settingItemTemplateFromValueMemberBinding)
_itemTemplateIsFromValueMemberBinding = false; _itemTemplateIsFromValueMemberBinding = false;
} }
private void OnValueMemberBindingChanged(IBinding value) private void OnValueMemberBindingChanged(IBinding? value)
{ {
if(_itemTemplateIsFromValueMemberBinding) if(_itemTemplateIsFromValueMemberBinding)
{ {
@ -828,7 +828,8 @@ namespace Avalonia.Controls
(o, _) => (o, _) =>
{ {
var control = new ContentControl(); var control = new ContentControl();
control.Bind(ContentControl.ContentProperty, value); if (value is not null)
control.Bind(ContentControl.ContentProperty, value);
return control; return control;
}); });
@ -975,7 +976,7 @@ namespace Avalonia.Controls
/// <value>The <see cref="T:Avalonia.Data.IBinding" /> object used /// <value>The <see cref="T:Avalonia.Data.IBinding" /> object used
/// when binding to a collection property.</value> /// when binding to a collection property.</value>
[AssignBinding] [AssignBinding]
public IBinding ValueMemberBinding public IBinding? ValueMemberBinding
{ {
get { return _valueBindingEvaluator?.ValueBinding; } get { return _valueBindingEvaluator?.ValueBinding; }
set set
@ -998,7 +999,7 @@ namespace Avalonia.Controls
/// then displayed in the text box, the SelectedItem property will be /// then displayed in the text box, the SelectedItem property will be
/// a null reference. /// a null reference.
/// </remarks> /// </remarks>
public object SelectedItem public object? SelectedItem
{ {
get { return _selectedItem; } get { return _selectedItem; }
set { SetAndRaise(SelectedItemProperty, ref _selectedItem, value); } set { SetAndRaise(SelectedItemProperty, ref _selectedItem, value); }
@ -1010,7 +1011,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <value>The text in the text box portion of the /// <value>The text in the text box portion of the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</value> /// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</value>
public string Text public string? Text
{ {
get { return _text; } get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); } set { SetAndRaise(TextProperty, ref _text, value); }
@ -1029,7 +1030,7 @@ namespace Avalonia.Controls
/// Text property, but is set after the TextChanged event occurs /// Text property, but is set after the TextChanged event occurs
/// and before the Populating event. /// and before the Populating event.
/// </remarks> /// </remarks>
public string SearchText public string? SearchText
{ {
get { return _searchText; } get { return _searchText; }
private set private set
@ -1071,7 +1072,7 @@ namespace Avalonia.Controls
set { SetValue(FilterModeProperty, value); } set { SetValue(FilterModeProperty, value); }
} }
public string Watermark public string? Watermark
{ {
get { return GetValue(WatermarkProperty); } get { return GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); } set { SetValue(WatermarkProperty, value); }
@ -1091,7 +1092,7 @@ namespace Avalonia.Controls
/// The filter mode is automatically set to Custom if you set the /// The filter mode is automatically set to Custom if you set the
/// ItemFilter property. /// ItemFilter property.
/// </remarks> /// </remarks>
public AutoCompleteFilterPredicate<object> ItemFilter public AutoCompleteFilterPredicate<object?>? ItemFilter
{ {
get { return _itemFilter; } get { return _itemFilter; }
set { SetAndRaise(ItemFilterProperty, ref _itemFilter, value); } set { SetAndRaise(ItemFilterProperty, ref _itemFilter, value); }
@ -1111,7 +1112,7 @@ namespace Avalonia.Controls
/// The search mode is automatically set to Custom if you set the /// The search mode is automatically set to Custom if you set the
/// TextFilter property. /// TextFilter property.
/// </remarks> /// </remarks>
public AutoCompleteFilterPredicate<string> TextFilter public AutoCompleteFilterPredicate<string?>? TextFilter
{ {
get { return _textFilter; } get { return _textFilter; }
set { SetAndRaise(TextFilterProperty, ref _textFilter, value); } set { SetAndRaise(TextFilterProperty, ref _textFilter, value); }
@ -1127,7 +1128,7 @@ namespace Avalonia.Controls
/// text and one of the items specified by the /// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />. /// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </value> /// </value>
public AutoCompleteSelector<object> ItemSelector public AutoCompleteSelector<object>? ItemSelector
{ {
get { return _itemSelector; } get { return _itemSelector; }
set { SetAndRaise(ItemSelectorProperty, ref _itemSelector, value); } set { SetAndRaise(ItemSelectorProperty, ref _itemSelector, value); }
@ -1145,13 +1146,13 @@ namespace Avalonia.Controls
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
/// in a text-based way. /// in a text-based way.
/// </value> /// </value>
public AutoCompleteSelector<string> TextSelector public AutoCompleteSelector<string?>? TextSelector
{ {
get { return _textSelector; } get { return _textSelector; }
set { SetAndRaise(TextSelectorProperty, ref _textSelector, value); } set { SetAndRaise(TextSelectorProperty, ref _textSelector, value); }
} }
public Func<string, CancellationToken, Task<IEnumerable<object>>> AsyncPopulator public Func<string?, CancellationToken, Task<IEnumerable<object>>>? AsyncPopulator
{ {
get { return _asyncPopulator; } get { return _asyncPopulator; }
set { SetAndRaise(AsyncPopulatorProperty, ref _asyncPopulator, value); } set { SetAndRaise(AsyncPopulatorProperty, ref _asyncPopulator, value); }
@ -1165,7 +1166,7 @@ namespace Avalonia.Controls
/// <value>The collection that is used to generate the items of the /// <value>The collection that is used to generate the items of the
/// drop-down portion of the /// drop-down portion of the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</value> /// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</value>
public IEnumerable Items public IEnumerable? Items
{ {
get { return _itemsEnumerable; } get { return _itemsEnumerable; }
set { SetAndRaise(ItemsProperty, ref _itemsEnumerable, value); } set { SetAndRaise(ItemsProperty, ref _itemsEnumerable, value); }
@ -1174,12 +1175,12 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the drop down popup control. /// Gets or sets the drop down popup control.
/// </summary> /// </summary>
private Popup DropDownPopup { get; set; } private Popup? DropDownPopup { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Text template part. /// Gets or sets the Text template part.
/// </summary> /// </summary>
private TextBox TextBox private TextBox? TextBox
{ {
get { return _textBox; } get { return _textBox; }
set set
@ -1243,7 +1244,7 @@ namespace Avalonia.Controls
/// use with AutoCompleteBox or deriving from AutoCompleteBox to /// use with AutoCompleteBox or deriving from AutoCompleteBox to
/// create a custom control. /// create a custom control.
/// </remarks> /// </remarks>
protected ISelectionAdapter SelectionAdapter protected ISelectionAdapter? SelectionAdapter
{ {
get { return _adapter; } get { return _adapter; }
set set
@ -1279,10 +1280,10 @@ namespace Avalonia.Controls
/// A <see cref="T:Avalonia.Controls.ISelectionAdapter" /> object, /// A <see cref="T:Avalonia.Controls.ISelectionAdapter" /> object,
/// if possible. Otherwise, null. /// if possible. Otherwise, null.
/// </returns> /// </returns>
protected virtual ISelectionAdapter GetSelectionAdapterPart(INameScope nameScope) protected virtual ISelectionAdapter? GetSelectionAdapterPart(INameScope nameScope)
{ {
ISelectionAdapter adapter = null; ISelectionAdapter? adapter = null;
SelectingItemsControl selector = nameScope.Find<SelectingItemsControl>(ElementSelector); SelectingItemsControl? selector = nameScope.Find<SelectingItemsControl>(ElementSelector);
if (selector != null) if (selector != null)
{ {
// Check if it is already an IItemsSelector // Check if it is already an IItemsSelector
@ -1316,7 +1317,7 @@ namespace Avalonia.Controls
// Set the template parts. Individual part setters remove and add // Set the template parts. Individual part setters remove and add
// any event handlers. // any event handlers.
Popup popup = e.NameScope.Find<Popup>(ElementPopup); Popup? popup = e.NameScope.Find<Popup>(ElementPopup);
if (popup != null) if (popup != null)
{ {
DropDownPopup = popup; DropDownPopup = popup;
@ -1358,7 +1359,7 @@ namespace Avalonia.Controls
/// that contains the event data.</param> /// that contains the event data.</param>
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
Contract.Requires<ArgumentNullException>(e != null); _ = e ?? throw new ArgumentNullException(nameof(e));
base.OnKeyDown(e); base.OnKeyDown(e);
@ -1453,7 +1454,7 @@ namespace Avalonia.Controls
/// otherwise, false.</returns> /// otherwise, false.</returns>
protected bool HasFocus() protected bool HasFocus()
{ {
IVisual focused = FocusManager.Instance.Current; IVisual? focused = FocusManager.Instance?.Current;
while (focused != null) while (focused != null)
{ {
@ -1464,11 +1465,11 @@ namespace Avalonia.Controls
// This helps deal with popups that may not be in the same // This helps deal with popups that may not be in the same
// visual tree // visual tree
IVisual parent = focused.GetVisualParent(); IVisual? parent = focused.GetVisualParent();
if (parent == null) if (parent == null)
{ {
// Try the logical parent. // Try the logical parent.
IControl element = focused as IControl; IControl? element = focused as IControl;
if (element != null) if (element != null)
{ {
parent = element.Parent; parent = element.Parent;
@ -1519,7 +1520,7 @@ namespace Avalonia.Controls
/// Occurs when the text in the text box portion of the /// Occurs when the text in the text box portion of the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> changes. /// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> changes.
/// </summary> /// </summary>
public event EventHandler TextChanged; public event EventHandler? TextChanged;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
@ -1535,7 +1536,7 @@ namespace Avalonia.Controls
/// In this case, if you want possible matches to appear, you must /// In this case, if you want possible matches to appear, you must
/// provide the logic for populating the selection adapter. /// provide the logic for populating the selection adapter.
/// </remarks> /// </remarks>
public event EventHandler<PopulatingEventArgs> Populating; public event EventHandler<PopulatingEventArgs>? Populating;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
@ -1544,35 +1545,35 @@ namespace Avalonia.Controls
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" />
/// property. /// property.
/// </summary> /// </summary>
public event EventHandler<PopulatedEventArgs> Populated; public event EventHandler<PopulatedEventArgs>? Populated;
/// <summary> /// <summary>
/// Occurs when the value of the /// Occurs when the value of the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" />
/// property is changing from false to true. /// property is changing from false to true.
/// </summary> /// </summary>
public event EventHandler<CancelEventArgs> DropDownOpening; public event EventHandler<CancelEventArgs>? DropDownOpening;
/// <summary> /// <summary>
/// Occurs when the value of the /// Occurs when the value of the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" />
/// property has changed from false to true and the drop-down is open. /// property has changed from false to true and the drop-down is open.
/// </summary> /// </summary>
public event EventHandler DropDownOpened; public event EventHandler? DropDownOpened;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" />
/// property is changing from true to false. /// property is changing from true to false.
/// </summary> /// </summary>
public event EventHandler<CancelEventArgs> DropDownClosing; public event EventHandler<CancelEventArgs>? DropDownClosing;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.IsDropDownOpen" />
/// property was changed from true to false and the drop-down is open. /// property was changed from true to false and the drop-down is open.
/// </summary> /// </summary>
public event EventHandler DropDownClosed; public event EventHandler? DropDownClosed;
/// <summary> /// <summary>
/// Occurs when the selected item in the drop-down portion of the /// Occurs when the selected item in the drop-down portion of the
@ -1740,7 +1741,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The source object.</param> /// <param name="sender">The source object.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void DropDownPopup_Closed(object sender, EventArgs e) private void DropDownPopup_Closed(object? sender, EventArgs e)
{ {
// Force the drop down dependency property to be false. // Force the drop down dependency property to be false.
if (IsDropDownOpen) if (IsDropDownOpen)
@ -1760,7 +1761,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The source object.</param> /// <param name="sender">The source object.</param>
/// <param name="e">The event arguments.</param> /// <param name="e">The event arguments.</param>
private void PopulateDropDown(object sender, EventArgs e) private void PopulateDropDown(object? sender, EventArgs e)
{ {
if (_delayTimer != null) if (_delayTimer != null)
{ {
@ -1786,7 +1787,7 @@ namespace Avalonia.Controls
PopulateComplete(); PopulateComplete();
} }
} }
private bool TryPopulateAsync(string searchText) private bool TryPopulateAsync(string? searchText)
{ {
_populationCancellationTokenSource?.Cancel(false); _populationCancellationTokenSource?.Cancel(false);
_populationCancellationTokenSource?.Dispose(); _populationCancellationTokenSource?.Dispose();
@ -1804,12 +1805,12 @@ namespace Avalonia.Controls
return true; return true;
} }
private async Task PopulateAsync(string searchText, CancellationToken cancellationToken) private async Task PopulateAsync(string? searchText, CancellationToken cancellationToken)
{ {
try try
{ {
IEnumerable<object> result = await _asyncPopulator.Invoke(searchText, cancellationToken); IEnumerable<object> result = await _asyncPopulator!.Invoke(searchText, cancellationToken);
var resultList = result.ToList(); var resultList = result.ToList();
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
@ -1878,9 +1879,9 @@ namespace Avalonia.Controls
/// <param name="clearDataContext">A value indicating whether to clear /// <param name="clearDataContext">A value indicating whether to clear
/// the data context after the lookup is performed.</param> /// the data context after the lookup is performed.</param>
/// <returns>Formatted Value.</returns> /// <returns>Formatted Value.</returns>
private string FormatValue(object value, bool clearDataContext) private string? FormatValue(object? value, bool clearDataContext)
{ {
string result = FormatValue(value); string? result = FormatValue(value);
if(clearDataContext && _valueBindingEvaluator != null) if(clearDataContext && _valueBindingEvaluator != null)
{ {
_valueBindingEvaluator.ClearDataContext(); _valueBindingEvaluator.ClearDataContext();
@ -1902,7 +1903,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// Override this method to provide a custom string conversion. /// Override this method to provide a custom string conversion.
/// </remarks> /// </remarks>
protected virtual string FormatValue(object value) protected virtual string? FormatValue(object? value)
{ {
if (_valueBindingEvaluator != null) if (_valueBindingEvaluator != null)
{ {
@ -1923,7 +1924,7 @@ namespace Avalonia.Controls
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
// Call the central updated text method as a user-initiated action // Call the central updated text method as a user-initiated action
TextUpdated(_textBox.Text, true); TextUpdated(_textBox!.Text, true);
}); });
} }
@ -1933,7 +1934,7 @@ namespace Avalonia.Controls
/// text changed events when there is a change. /// text changed events when there is a change.
/// </summary> /// </summary>
/// <param name="value">The new string value.</param> /// <param name="value">The new string value.</param>
private void UpdateTextValue(string value) private void UpdateTextValue(string? value)
{ {
UpdateTextValue(value, null); UpdateTextValue(value, null);
} }
@ -1949,7 +1950,7 @@ namespace Avalonia.Controls
/// underlying text dependency property is updated. In a non-user /// underlying text dependency property is updated. In a non-user
/// interaction, the text box value is updated. When user initiated is /// interaction, the text box value is updated. When user initiated is
/// null, all values are updated.</param> /// null, all values are updated.</param>
private void UpdateTextValue(string value, bool? userInitiated) private void UpdateTextValue(string? value, bool? userInitiated)
{ {
bool callTextChanged = false; bool callTextChanged = false;
// Update the Text dependency property // Update the Text dependency property
@ -1987,7 +1988,7 @@ namespace Avalonia.Controls
/// <param name="userInitiated">A value indicating whether the update /// <param name="userInitiated">A value indicating whether the update
/// is a user-initiated action. This should be a True value when the /// is a user-initiated action. This should be a True value when the
/// TextUpdated method is called from a TextBox event handler.</param> /// TextUpdated method is called from a TextBox event handler.</param>
private void TextUpdated(string newText, bool userInitiated) private void TextUpdated(string? newText, bool userInitiated)
{ {
// Only process this event if it is coming from someone outside // Only process this event if it is coming from someone outside
// setting the Text dependency property directly. // setting the Text dependency property directly.
@ -2087,7 +2088,7 @@ namespace Avalonia.Controls
bool objectFiltering = FilterMode == AutoCompleteFilterMode.Custom && TextFilter == null; bool objectFiltering = FilterMode == AutoCompleteFilterMode.Custom && TextFilter == null;
int view_index = 0; int view_index = 0;
int view_count = _view.Count; int view_count = _view!.Count;
List<object> items = _items; List<object> items = _items;
foreach (object item in items) foreach (object item in items)
{ {
@ -2096,7 +2097,7 @@ namespace Avalonia.Controls
{ {
if (stringFiltering) if (stringFiltering)
{ {
inResults = TextFilter(text, FormatValue(item)); inResults = TextFilter!(text, FormatValue(item));
} }
else else
{ {
@ -2166,7 +2167,7 @@ namespace Avalonia.Controls
/// adapter's ItemsSource to the view if appropriate. /// adapter's ItemsSource to the view if appropriate.
/// </summary> /// </summary>
/// <param name="newValue">The new enumerable reference.</param> /// <param name="newValue">The new enumerable reference.</param>
private void OnItemsChanged(IEnumerable newValue) private void OnItemsChanged(IEnumerable? newValue)
{ {
// Remove handler for oldValue.CollectionChanged (if present) // Remove handler for oldValue.CollectionChanged (if present)
_collectionChangeSubscription?.Dispose(); _collectionChangeSubscription?.Dispose();
@ -2198,28 +2199,28 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The object that raised the event.</param> /// <param name="sender">The object that raised the event.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void ItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
// Update the cache // Update the cache
if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems != null) if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems != null)
{ {
for (int index = 0; index < e.OldItems.Count; index++) for (int index = 0; index < e.OldItems.Count; index++)
{ {
_items.RemoveAt(e.OldStartingIndex); _items!.RemoveAt(e.OldStartingIndex);
} }
} }
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null && _items.Count >= e.NewStartingIndex) if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null && _items!.Count >= e.NewStartingIndex)
{ {
for (int index = 0; index < e.NewItems.Count; index++) for (int index = 0; index < e.NewItems.Count; index++)
{ {
_items.Insert(e.NewStartingIndex + index, e.NewItems[index]); _items.Insert(e.NewStartingIndex + index, e.NewItems[index]!);
} }
} }
if (e.Action == NotifyCollectionChangedAction.Replace && e.NewItems != null && e.OldItems != null) if (e.Action == NotifyCollectionChangedAction.Replace && e.NewItems != null && e.OldItems != null)
{ {
for (int index = 0; index < e.NewItems.Count; index++) for (int index = 0; index < e.NewItems.Count; index++)
{ {
_items[e.NewStartingIndex] = e.NewItems[index]; _items![e.NewStartingIndex] = e.NewItems[index]!;
} }
} }
@ -2228,7 +2229,7 @@ namespace Avalonia.Controls
{ {
for (int index = 0; index < e.OldItems.Count; index++) for (int index = 0; index < e.OldItems.Count; index++)
{ {
_view.Remove(e.OldItems[index]); _view!.Remove(e.OldItems[index]!);
} }
} }
@ -2270,7 +2271,7 @@ namespace Avalonia.Controls
RefreshView(); RefreshView();
// Fire the Populated event containing the read-only view data. // Fire the Populated event containing the read-only view data.
PopulatedEventArgs populated = new PopulatedEventArgs(new ReadOnlyCollection<object>(_view)); PopulatedEventArgs populated = new PopulatedEventArgs(new ReadOnlyCollection<object>(_view!));
OnPopulated(populated); OnPopulated(populated);
if (SelectionAdapter != null && SelectionAdapter.Items != _view) if (SelectionAdapter != null && SelectionAdapter.Items != _view)
@ -2278,7 +2279,7 @@ namespace Avalonia.Controls
SelectionAdapter.Items = _view; SelectionAdapter.Items = _view;
} }
bool isDropDownOpen = _userCalledPopulate && (_view.Count > 0); bool isDropDownOpen = _userCalledPopulate && (_view!.Count > 0);
if (isDropDownOpen != IsDropDownOpen) if (isDropDownOpen != IsDropDownOpen)
{ {
_ignorePropertyChange = true; _ignorePropertyChange = true;
@ -2306,20 +2307,20 @@ namespace Avalonia.Controls
private void UpdateTextCompletion(bool userInitiated) private void UpdateTextCompletion(bool userInitiated)
{ {
// By default this method will clear the selected value // By default this method will clear the selected value
object newSelectedItem = null; object? newSelectedItem = null;
string text = Text; string? text = Text;
// Text search is StartsWith explicit and only when enabled, in // Text search is StartsWith explicit and only when enabled, in
// line with WPF's ComboBox lookup. When in use it will associate // line with WPF's ComboBox lookup. When in use it will associate
// a Value with the Text if it is found in ItemsSource. This is // a Value with the Text if it is found in ItemsSource. This is
// only valid when there is data and the user initiated the action. // only valid when there is data and the user initiated the action.
if (_view.Count > 0) if (_view!.Count > 0)
{ {
if (IsTextCompletionEnabled && TextBox != null && userInitiated) if (IsTextCompletionEnabled && TextBox != null && userInitiated)
{ {
int currentLength = TextBox.Text?.Length ?? 0; int currentLength = TextBox.Text?.Length ?? 0;
int selectionStart = TextBoxSelectionStart; int selectionStart = TextBoxSelectionStart;
if (selectionStart == text.Length && selectionStart > _textSelectionStart) if (selectionStart == text?.Length && selectionStart > _textSelectionStart)
{ {
// When the FilterMode dependency property is set to // When the FilterMode dependency property is set to
// either StartsWith or StartsWithCaseSensitive, the // either StartsWith or StartsWithCaseSensitive, the
@ -2327,7 +2328,7 @@ namespace Avalonia.Controls
// performance on the lookup. It assumes that the // performance on the lookup. It assumes that the
// FilterMode the user has selected is an acceptable // FilterMode the user has selected is an acceptable
// case sensitive matching function for their scenario. // case sensitive matching function for their scenario.
object top = FilterMode == AutoCompleteFilterMode.StartsWith || FilterMode == AutoCompleteFilterMode.StartsWithCaseSensitive object? top = FilterMode == AutoCompleteFilterMode.StartsWith || FilterMode == AutoCompleteFilterMode.StartsWithCaseSensitive
? _view[0] ? _view[0]
: TryGetMatch(text, _view, AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith)); : TryGetMatch(text, _view, AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith));
@ -2335,18 +2336,18 @@ namespace Avalonia.Controls
if (top != null) if (top != null)
{ {
newSelectedItem = top; newSelectedItem = top;
string topString = FormatValue(top, true); string? topString = FormatValue(top, true);
// Only replace partially when the two words being the same // Only replace partially when the two words being the same
int minLength = Math.Min(topString.Length, Text.Length); int minLength = Math.Min(topString?.Length ?? 0, Text?.Length ?? 0);
if (AutoCompleteSearch.Equals(Text.Substring(0, minLength), topString.Substring(0, minLength))) if (AutoCompleteSearch.Equals(Text?.Substring(0, minLength), topString?.Substring(0, minLength)))
{ {
// Update the text // Update the text
UpdateTextValue(topString); UpdateTextValue(topString);
// Select the text past the user's caret // Select the text past the user's caret
TextBox.SelectionStart = currentLength; TextBox.SelectionStart = currentLength;
TextBox.SelectionEnd = topString.Length; TextBox.SelectionEnd = topString?.Length ?? 0;
} }
} }
} }
@ -2392,8 +2393,11 @@ namespace Avalonia.Controls
/// <param name="predicate">The predicate to use for the partial or /// <param name="predicate">The predicate to use for the partial or
/// exact match.</param> /// exact match.</param>
/// <returns>Returns the object or null.</returns> /// <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;
if (view != null && view.Count > 0) if (view != null && view.Count > 0)
{ {
foreach (object o in view) foreach (object o in view)
@ -2428,9 +2432,9 @@ namespace Avalonia.Controls
/// that is displayed in the text box part. /// that is displayed in the text box part.
/// </summary> /// </summary>
/// <param name="newItem">The new item.</param> /// <param name="newItem">The new item.</param>
private void OnSelectedItemChanged(object newItem) private void OnSelectedItemChanged(object? newItem)
{ {
string text; string? text;
if (newItem == null) if (newItem == null)
{ {
@ -2461,9 +2465,9 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The source object.</param> /// <param name="sender">The source object.</param>
/// <param name="e">The selection changed event data.</param> /// <param name="e">The selection changed event data.</param>
private void OnAdapterSelectionChanged(object sender, SelectionChangedEventArgs e) private void OnAdapterSelectionChanged(object? sender, SelectionChangedEventArgs e)
{ {
SelectedItem = _adapter.SelectedItem; SelectedItem = _adapter!.SelectedItem;
} }
//TODO Check UpdateTextCompletion //TODO Check UpdateTextCompletion
@ -2472,7 +2476,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The source object.</param> /// <param name="sender">The source object.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void OnAdapterSelectionComplete(object sender, RoutedEventArgs e) private void OnAdapterSelectionComplete(object? sender, RoutedEventArgs e)
{ {
IsDropDownOpen = false; IsDropDownOpen = false;
@ -2482,7 +2486,7 @@ namespace Avalonia.Controls
// Text should not be selected // Text should not be selected
ClearTextBoxSelection(); ClearTextBoxSelection();
TextBox.Focus(); TextBox!.Focus();
} }
/// <summary> /// <summary>
@ -2490,7 +2494,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The source object.</param> /// <param name="sender">The source object.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void OnAdapterSelectionCanceled(object sender, RoutedEventArgs e) private void OnAdapterSelectionCanceled(object? sender, RoutedEventArgs e)
{ {
UpdateTextValue(SearchText); UpdateTextValue(SearchText);
@ -2510,7 +2514,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="FilterMode">The built-in search mode.</param> /// <param name="FilterMode">The built-in search mode.</param>
/// <returns>Returns the string-based comparison function.</returns> /// <returns>Returns the string-based comparison function.</returns>
public static AutoCompleteFilterPredicate<string> GetFilter(AutoCompleteFilterMode FilterMode) public static AutoCompleteFilterPredicate<string?>? GetFilter(AutoCompleteFilterMode FilterMode)
{ {
switch (FilterMode) switch (FilterMode)
{ {
@ -2566,9 +2570,11 @@ namespace Avalonia.Controls
/// <param name="value">The string value to search for.</param> /// <param name="value">The string value to search for.</param>
/// <param name="comparison">The string comparison type.</param> /// <param name="comparison">The string comparison type.</param>
/// <returns>Returns true when the substring is found.</returns> /// <returns>Returns true when the substring is found.</returns>
private static bool Contains(string s, string value, StringComparison comparison) private static bool Contains(string? s, string? value, StringComparison comparison)
{ {
return s.IndexOf(value, comparison) >= 0; if (s is not null && value is not null)
return s.IndexOf(value, comparison) >= 0;
return false;
} }
/// <summary> /// <summary>
@ -2577,9 +2583,11 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool StartsWith(string text, string value) public static bool StartsWith(string? text, string? value)
{ {
return value.StartsWith(text, StringComparison.CurrentCultureIgnoreCase); if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.CurrentCultureIgnoreCase);
return false;
} }
/// <summary> /// <summary>
@ -2588,9 +2596,11 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool StartsWithCaseSensitive(string text, string value) public static bool StartsWithCaseSensitive(string? text, string? value)
{ {
return value.StartsWith(text, StringComparison.CurrentCulture); if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.CurrentCulture);
return false;
} }
/// <summary> /// <summary>
@ -2599,9 +2609,11 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool StartsWithOrdinal(string text, string value) public static bool StartsWithOrdinal(string? text, string? value)
{ {
return value.StartsWith(text, StringComparison.OrdinalIgnoreCase); if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.OrdinalIgnoreCase);
return false;
} }
/// <summary> /// <summary>
@ -2610,9 +2622,11 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool StartsWithOrdinalCaseSensitive(string text, string value) public static bool StartsWithOrdinalCaseSensitive(string? text, string? value)
{ {
return value.StartsWith(text, StringComparison.Ordinal); if (value is not null && text is not null)
return value.StartsWith(text, StringComparison.Ordinal);
return false;
} }
/// <summary> /// <summary>
@ -2622,7 +2636,7 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool Contains(string text, string value) public static bool Contains(string? text, string? value)
{ {
return Contains(value, text, StringComparison.CurrentCultureIgnoreCase); return Contains(value, text, StringComparison.CurrentCultureIgnoreCase);
} }
@ -2633,7 +2647,7 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool ContainsCaseSensitive(string text, string value) public static bool ContainsCaseSensitive(string? text, string? value)
{ {
return Contains(value, text, StringComparison.CurrentCulture); return Contains(value, text, StringComparison.CurrentCulture);
} }
@ -2644,7 +2658,7 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool ContainsOrdinal(string text, string value) public static bool ContainsOrdinal(string? text, string? value)
{ {
return Contains(value, text, StringComparison.OrdinalIgnoreCase); return Contains(value, text, StringComparison.OrdinalIgnoreCase);
} }
@ -2655,7 +2669,7 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool ContainsOrdinalCaseSensitive(string text, string value) public static bool ContainsOrdinalCaseSensitive(string? text, string? value)
{ {
return Contains(value, text, StringComparison.Ordinal); return Contains(value, text, StringComparison.Ordinal);
} }
@ -2666,9 +2680,9 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool Equals(string text, string value) public static bool Equals(string? text, string? value)
{ {
return value.Equals(text, StringComparison.CurrentCultureIgnoreCase); return string.Equals(value, text, StringComparison.CurrentCultureIgnoreCase);
} }
/// <summary> /// <summary>
@ -2677,9 +2691,9 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool EqualsCaseSensitive(string text, string value) public static bool EqualsCaseSensitive(string? text, string? value)
{ {
return value.Equals(text, StringComparison.CurrentCulture); return string.Equals(value, text, StringComparison.CurrentCulture);
} }
/// <summary> /// <summary>
@ -2688,9 +2702,9 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool EqualsOrdinal(string text, string value) public static bool EqualsOrdinal(string? text, string? value)
{ {
return value.Equals(text, StringComparison.OrdinalIgnoreCase); return string.Equals(value, text, StringComparison.OrdinalIgnoreCase);
} }
/// <summary> /// <summary>
@ -2699,9 +2713,9 @@ namespace Avalonia.Controls
/// <param name="text">The AutoCompleteBox prefix text.</param> /// <param name="text">The AutoCompleteBox prefix text.</param>
/// <param name="value">The item's string value.</param> /// <param name="value">The item's string value.</param>
/// <returns>Returns true if the condition is met.</returns> /// <returns>Returns true if the condition is met.</returns>
public static bool EqualsOrdinalCaseSensitive(string text, string value) public static bool EqualsOrdinalCaseSensitive(string? text, string? value)
{ {
return value.Equals(text, StringComparison.Ordinal); return string.Equals(value, text, StringComparison.Ordinal);
} }
} }
@ -2715,7 +2729,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the string value binding used by the control. /// Gets or sets the string value binding used by the control.
/// </summary> /// </summary>
private IBinding _binding; private IBinding? _binding;
#region public T Value #region public T Value
@ -2739,13 +2753,14 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the value binding. /// Gets or sets the value binding.
/// </summary> /// </summary>
public IBinding ValueBinding public IBinding? ValueBinding
{ {
get { return _binding; } get { return _binding; }
set set
{ {
_binding = value; _binding = value;
AvaloniaObjectExtensions.Bind(this, ValueProperty, value); if (value is not null)
AvaloniaObjectExtensions.Bind(this, ValueProperty, value);
} }
} }
@ -2760,7 +2775,7 @@ namespace Avalonia.Controls
/// setting the initial binding to the provided parameter. /// setting the initial binding to the provided parameter.
/// </summary> /// </summary>
/// <param name="binding">The initial string value binding.</param> /// <param name="binding">The initial string value binding.</param>
public BindingEvaluator(IBinding binding) public BindingEvaluator(IBinding? binding)
: this() : this()
{ {
ValueBinding = binding; ValueBinding = binding;
@ -2802,7 +2817,7 @@ namespace Avalonia.Controls
/// <param name="o">The object to use as the data context.</param> /// <param name="o">The object to use as the data context.</param>
/// <returns>Returns the evaluated T value of the bound dependency /// <returns>Returns the evaluated T value of the bound dependency
/// property.</returns> /// property.</returns>
public T GetDynamicValue(object o) public T GetDynamicValue(object? o)
{ {
DataContext = o; DataContext = o;
return Value; return Value;

1
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -18,4 +18,5 @@
<Import Project="..\..\build\Rx.props" /> <Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\JetBrains.Annotations.props" /> <Import Project="..\..\build\JetBrains.Annotations.props" />
<Import Project="..\..\build\ApiDiff.props" /> <Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project> </Project>

12
src/Avalonia.Controls/Border.cs

@ -17,14 +17,14 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Background"/> property. /// Defines the <see cref="Background"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IBrush> BackgroundProperty = public static readonly StyledProperty<IBrush?> BackgroundProperty =
AvaloniaProperty.Register<Border, IBrush>(nameof(Background)); AvaloniaProperty.Register<Border, IBrush?>(nameof(Background));
/// <summary> /// <summary>
/// Defines the <see cref="BorderBrush"/> property. /// Defines the <see cref="BorderBrush"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IBrush> BorderBrushProperty = public static readonly StyledProperty<IBrush?> BorderBrushProperty =
AvaloniaProperty.Register<Border, IBrush>(nameof(BorderBrush)); AvaloniaProperty.Register<Border, IBrush?>(nameof(BorderBrush));
/// <summary> /// <summary>
/// Defines the <see cref="BorderThickness"/> property. /// Defines the <see cref="BorderThickness"/> property.
@ -91,7 +91,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets a brush with which to paint the background. /// Gets or sets a brush with which to paint the background.
/// </summary> /// </summary>
public IBrush Background public IBrush? Background
{ {
get { return GetValue(BackgroundProperty); } get { return GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); } set { SetValue(BackgroundProperty, value); }
@ -100,7 +100,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets a brush with which to paint the border. /// Gets or sets a brush with which to paint the border.
/// </summary> /// </summary>
public IBrush BorderBrush public IBrush? BorderBrush
{ {
get { return GetValue(BorderBrushProperty); } get { return GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); } set { SetValue(BorderBrushProperty, value); }

28
src/Avalonia.Controls/Button.cs

@ -42,21 +42,21 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Command"/> property. /// Defines the <see cref="Command"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<Button, ICommand> CommandProperty = public static readonly DirectProperty<Button, ICommand?> CommandProperty =
AvaloniaProperty.RegisterDirect<Button, ICommand>(nameof(Command), AvaloniaProperty.RegisterDirect<Button, ICommand?>(nameof(Command),
button => button.Command, (button, command) => button.Command = command, enableDataValidation: true); button => button.Command, (button, command) => button.Command = command, enableDataValidation: true);
/// <summary> /// <summary>
/// Defines the <see cref="HotKey"/> property. /// Defines the <see cref="HotKey"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<KeyGesture> HotKeyProperty = public static readonly StyledProperty<KeyGesture?> HotKeyProperty =
HotKeyManager.HotKeyProperty.AddOwner<Button>(); HotKeyManager.HotKeyProperty.AddOwner<Button>();
/// <summary> /// <summary>
/// Defines the <see cref="CommandParameter"/> property. /// Defines the <see cref="CommandParameter"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<object> CommandParameterProperty = public static readonly StyledProperty<object?> CommandParameterProperty =
AvaloniaProperty.Register<Button, object>(nameof(CommandParameter)); AvaloniaProperty.Register<Button, object?>(nameof(CommandParameter));
/// <summary> /// <summary>
/// Defines the <see cref="IsDefault"/> property. /// Defines the <see cref="IsDefault"/> property.
@ -88,9 +88,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<FlyoutBase> FlyoutProperty = public static readonly StyledProperty<FlyoutBase> FlyoutProperty =
AvaloniaProperty.Register<Button, FlyoutBase>(nameof(Flyout)); AvaloniaProperty.Register<Button, FlyoutBase>(nameof(Flyout));
private ICommand _command; private ICommand? _command;
private bool _commandCanExecute = true; private bool _commandCanExecute = true;
private KeyGesture _hotkey; private KeyGesture? _hotkey;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="Button"/> class. /// Initializes static members of the <see cref="Button"/> class.
@ -112,7 +112,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Raised when the user clicks the button. /// Raised when the user clicks the button.
/// </summary> /// </summary>
public event EventHandler<RoutedEventArgs> Click public event EventHandler<RoutedEventArgs>? Click
{ {
add => AddHandler(ClickEvent, value); add => AddHandler(ClickEvent, value);
remove => RemoveHandler(ClickEvent, value); remove => RemoveHandler(ClickEvent, value);
@ -130,7 +130,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets an <see cref="ICommand"/> to be invoked when the button is clicked. /// Gets or sets an <see cref="ICommand"/> to be invoked when the button is clicked.
/// </summary> /// </summary>
public ICommand Command public ICommand? Command
{ {
get => _command; get => _command;
set => SetAndRaise(CommandProperty, ref _command, value); set => SetAndRaise(CommandProperty, ref _command, value);
@ -139,7 +139,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets an <see cref="KeyGesture"/> associated with this control /// Gets or sets an <see cref="KeyGesture"/> associated with this control
/// </summary> /// </summary>
public KeyGesture HotKey public KeyGesture? HotKey
{ {
get => GetValue(HotKeyProperty); get => GetValue(HotKeyProperty);
set => SetValue(HotKeyProperty, value); set => SetValue(HotKeyProperty, value);
@ -148,7 +148,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets a parameter to be passed to the <see cref="Command"/>. /// Gets or sets a parameter to be passed to the <see cref="Command"/>.
/// </summary> /// </summary>
public object CommandParameter public object? CommandParameter
{ {
get => GetValue(CommandParameterProperty); get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value); set => SetValue(CommandParameterProperty, value);
@ -477,7 +477,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void CanExecuteChanged(object sender, EventArgs e) private void CanExecuteChanged(object? sender, EventArgs e)
{ {
var canExecute = Command == null || Command.CanExecute(CommandParameter); var canExecute = Command == null || Command.CanExecute(CommandParameter);
@ -529,7 +529,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void RootDefaultKeyDown(object sender, KeyEventArgs e) private void RootDefaultKeyDown(object? sender, KeyEventArgs e)
{ {
if (e.Key == Key.Enter && IsVisible && IsEnabled) if (e.Key == Key.Enter && IsVisible && IsEnabled)
{ {
@ -542,7 +542,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void RootCancelKeyDown(object sender, KeyEventArgs e) private void RootCancelKeyDown(object? sender, KeyEventArgs e)
{ {
if (e.Key == Key.Escape && IsVisible && IsEnabled) if (e.Key == Key.Escape && IsVisible && IsEnabled)
{ {

14
src/Avalonia.Controls/ButtonSpinner.cs

@ -42,11 +42,11 @@ namespace Avalonia.Controls
UpdatePseudoClasses(ButtonSpinnerLocation); UpdatePseudoClasses(ButtonSpinnerLocation);
} }
private Button _decreaseButton; private Button? _decreaseButton;
/// <summary> /// <summary>
/// Gets or sets the DecreaseButton template part. /// Gets or sets the DecreaseButton template part.
/// </summary> /// </summary>
private Button DecreaseButton private Button? DecreaseButton
{ {
get { return _decreaseButton; } get { return _decreaseButton; }
set set
@ -63,11 +63,11 @@ namespace Avalonia.Controls
} }
} }
private Button _increaseButton; private Button? _increaseButton;
/// <summary> /// <summary>
/// Gets or sets the IncreaseButton template part. /// Gets or sets the IncreaseButton template part.
/// </summary> /// </summary>
private Button IncreaseButton private Button? IncreaseButton
{ {
get get
{ {
@ -241,8 +241,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is ButtonSpinner spinner) if (e.Sender is ButtonSpinner spinner)
{ {
var oldValue = (bool)e.OldValue; var oldValue = (bool)e.OldValue!;
var newValue = (bool)e.NewValue; var newValue = (bool)e.NewValue!;
spinner.OnAllowSpinChanged(oldValue, newValue); spinner.OnAllowSpinChanged(oldValue, newValue);
} }
} }
@ -268,7 +268,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void OnButtonClick(object sender, RoutedEventArgs e) private void OnButtonClick(object? sender, RoutedEventArgs e)
{ {
if (AllowSpin) if (AllowSpin)
{ {

76
src/Avalonia.Controls/Calendar/Calendar.cs

@ -240,11 +240,11 @@ namespace Avalonia.Controls
private bool _isShiftPressed; private bool _isShiftPressed;
private bool _displayDateIsChanging = false; private bool _displayDateIsChanging = false;
internal CalendarDayButton FocusButton { get; set; } internal CalendarDayButton? FocusButton { get; set; }
internal CalendarButton FocusCalendarButton { get; set; } internal CalendarButton? FocusCalendarButton { get; set; }
internal Panel Root { get; set; } internal Panel? Root { get; set; }
internal CalendarItem MonthControl internal CalendarItem? MonthControl
{ {
get get
{ {
@ -280,7 +280,7 @@ namespace Avalonia.Controls
private void OnFirstDayOfWeekChanged(AvaloniaPropertyChangedEventArgs e) private void OnFirstDayOfWeekChanged(AvaloniaPropertyChangedEventArgs e)
{ {
if (IsValidFirstDayOfWeek(e.NewValue)) if (IsValidFirstDayOfWeek(e.NewValue!))
{ {
UpdateMonths(); UpdateMonths();
} }
@ -373,9 +373,9 @@ namespace Avalonia.Controls
/// <param name="e">The DependencyPropertyChangedEventArgs.</param> /// <param name="e">The DependencyPropertyChangedEventArgs.</param>
private void OnDisplayModePropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnDisplayModePropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
CalendarMode mode = (CalendarMode)e.NewValue; CalendarMode mode = (CalendarMode)e.NewValue!;
CalendarMode oldMode = (CalendarMode)e.OldValue; CalendarMode oldMode = (CalendarMode)e.OldValue!;
CalendarItem monthControl = MonthControl; CalendarItem? monthControl = MonthControl;
if (monthControl != null) if (monthControl != null)
{ {
@ -459,7 +459,7 @@ namespace Avalonia.Controls
} }
private void OnSelectionModeChanged(AvaloniaPropertyChangedEventArgs e) private void OnSelectionModeChanged(AvaloniaPropertyChangedEventArgs e)
{ {
if (IsValidSelectionMode(e.NewValue)) if (IsValidSelectionMode(e.NewValue!))
{ {
_displayDateIsChanging = true; _displayDateIsChanging = true;
SelectedDate = null; SelectedDate = null;
@ -656,7 +656,7 @@ namespace Avalonia.Controls
{ {
FocusButton.IsCurrent = false; FocusButton.IsCurrent = false;
} }
FocusButton = FindDayButtonFromDay(LastSelectedDate.Value); FocusButton = FindDayButtonFromDay(LastSelectedDate!.Value);
if (FocusButton != null) if (FocusButton != null)
{ {
FocusButton.IsCurrent = HasFocusInternal; FocusButton.IsCurrent = HasFocusInternal;
@ -754,11 +754,11 @@ namespace Avalonia.Controls
private void OnDisplayDateChanged(AvaloniaPropertyChangedEventArgs e) private void OnDisplayDateChanged(AvaloniaPropertyChangedEventArgs e)
{ {
UpdateDisplayDate(this, (DateTime)e.NewValue, (DateTime)e.OldValue); UpdateDisplayDate(this, (DateTime)e.NewValue!, (DateTime)e.OldValue!);
} }
private static void UpdateDisplayDate(Calendar c, DateTime addedDate, DateTime removedDate) private static void UpdateDisplayDate(Calendar c, DateTime addedDate, DateTime removedDate)
{ {
Contract.Requires<ArgumentNullException>(c != null); _ = c ?? throw new ArgumentNullException(nameof(c));
// If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart // If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart
if (DateTime.Compare(addedDate, c.DisplayDateRangeStart) < 0) if (DateTime.Compare(addedDate, c.DisplayDateRangeStart) < 0)
@ -871,7 +871,7 @@ namespace Avalonia.Controls
if (cal.SelectedDates.Count > 0) if (cal.SelectedDates.Count > 0)
{ {
selectedDateMin = cal.SelectedDates[0]; selectedDateMin = cal.SelectedDates[0];
Debug.Assert(DateTime.Compare(cal.SelectedDate.Value, selectedDateMin) == 0, "The SelectedDate should be the minimum selected date!"); Debug.Assert(DateTime.Compare(cal.SelectedDate!.Value, selectedDateMin) == 0, "The SelectedDate should be the minimum selected date!");
} }
else else
{ {
@ -959,7 +959,7 @@ namespace Avalonia.Controls
if (cal.SelectedDates.Count > 0) if (cal.SelectedDates.Count > 0)
{ {
selectedDateMax = cal.SelectedDates[0]; selectedDateMax = cal.SelectedDates[0];
Debug.Assert(DateTime.Compare(cal.SelectedDate.Value, selectedDateMax) == 0, "The SelectedDate should be the maximum SelectedDate!"); Debug.Assert(DateTime.Compare(cal.SelectedDate!.Value, selectedDateMax) == 0, "The SelectedDate should be the maximum SelectedDate!");
} }
else else
{ {
@ -1003,9 +1003,9 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
internal bool CalendarDatePickerDisplayDateFlag { get; set; } internal bool CalendarDatePickerDisplayDateFlag { get; set; }
internal CalendarDayButton FindDayButtonFromDay(DateTime day) internal CalendarDayButton? FindDayButtonFromDay(DateTime day)
{ {
CalendarItem monthControl = MonthControl; CalendarItem? monthControl = MonthControl;
// REMOVE_RTM: should be updated if we support MultiCalendar // REMOVE_RTM: should be updated if we support MultiCalendar
int count = RowsPerMonth * ColumnsPerMonth; int count = RowsPerMonth * ColumnsPerMonth;
@ -1054,7 +1054,7 @@ namespace Avalonia.Controls
internal void OnHeaderClick() internal void OnHeaderClick()
{ {
Debug.Assert(DisplayMode == CalendarMode.Year || DisplayMode == CalendarMode.Decade, "The DisplayMode should be Year or Decade"); Debug.Assert(DisplayMode == CalendarMode.Year || DisplayMode == CalendarMode.Decade, "The DisplayMode should be Year or Decade");
CalendarItem monthControl = MonthControl; CalendarItem? monthControl = MonthControl;
if (monthControl != null && monthControl.MonthView != null && monthControl.YearView != null) if (monthControl != null && monthControl.MonthView != null && monthControl.YearView != null)
{ {
monthControl.MonthView.IsVisible = false; monthControl.MonthView.IsVisible = false;
@ -1065,7 +1065,7 @@ namespace Avalonia.Controls
internal void ResetStates() internal void ResetStates()
{ {
CalendarItem monthControl = MonthControl; CalendarItem? monthControl = MonthControl;
int count = RowsPerMonth * ColumnsPerMonth; int count = RowsPerMonth * ColumnsPerMonth;
if (monthControl != null) if (monthControl != null)
{ {
@ -1083,7 +1083,7 @@ namespace Avalonia.Controls
internal void UpdateMonths() internal void UpdateMonths()
{ {
CalendarItem monthControl = MonthControl; CalendarItem? monthControl = MonthControl;
if (monthControl != null) if (monthControl != null)
{ {
switch (DisplayMode) switch (DisplayMode)
@ -1163,6 +1163,8 @@ namespace Avalonia.Controls
{ {
if (HoverEnd != null && HoverStart != null) if (HoverEnd != null && HoverStart != null)
{ {
Debug.Assert(MonthControl is not null);
int startIndex, endIndex, i; int startIndex, endIndex, i;
CalendarItem monthControl = MonthControl; CalendarItem monthControl = MonthControl;
@ -1173,7 +1175,7 @@ namespace Avalonia.Controls
for (i = startIndex; i <= endIndex; i++) for (i = startIndex; i <= endIndex; i++)
{ {
if (monthControl.MonthView.Children[i] is CalendarDayButton b) if (monthControl.MonthView!.Children[i] is CalendarDayButton b)
{ {
b.IsSelected = true; b.IsSelected = true;
var d = b.DataContext as DateTime?; var d = b.DataContext as DateTime?;
@ -1201,6 +1203,8 @@ namespace Avalonia.Controls
{ {
if (HoverEnd != null && HoverStart != null) if (HoverEnd != null && HoverStart != null)
{ {
Debug.Assert(MonthControl is not null);
CalendarItem monthControl = MonthControl; CalendarItem monthControl = MonthControl;
if (HoverEndIndex != null && HoverStartIndex != null) if (HoverEndIndex != null && HoverStartIndex != null)
@ -1212,7 +1216,7 @@ namespace Avalonia.Controls
{ {
for (i = startIndex; i <= endIndex; i++) for (i = startIndex; i <= endIndex; i++)
{ {
if (monthControl.MonthView.Children[i] is CalendarDayButton b) if (monthControl.MonthView!.Children[i] is CalendarDayButton b)
{ {
var d = b.DataContext as DateTime?; var d = b.DataContext as DateTime?;
@ -1231,7 +1235,7 @@ namespace Avalonia.Controls
// It is SingleRange // It is SingleRange
for (i = startIndex; i <= endIndex; i++) for (i = startIndex; i <= endIndex; i++)
{ {
((CalendarDayButton)monthControl.MonthView.Children[i]).IsSelected = false; ((CalendarDayButton)monthControl.MonthView!.Children[i]).IsSelected = false;
} }
} }
} }
@ -1239,6 +1243,11 @@ namespace Avalonia.Controls
} }
internal void SortHoverIndexes(out int startIndex, out int endIndex) internal void SortHoverIndexes(out int startIndex, out int endIndex)
{ {
Debug.Assert(HoverStart.HasValue);
Debug.Assert(HoverEnd.HasValue);
Debug.Assert(HoverStartIndex.HasValue);
Debug.Assert(HoverEndIndex.HasValue);
if (DateTimeHelper.CompareDays(HoverEnd.Value, HoverStart.Value) > 0) if (DateTimeHelper.CompareDays(HoverEnd.Value, HoverStart.Value) > 0)
{ {
startIndex = HoverStartIndex.Value; startIndex = HoverStartIndex.Value;
@ -1373,6 +1382,8 @@ namespace Avalonia.Controls
} }
private void OnMonthClick() private void OnMonthClick()
{ {
Debug.Assert(MonthControl is not null);
CalendarItem monthControl = MonthControl; CalendarItem monthControl = MonthControl;
if (monthControl != null && monthControl.YearView != null && monthControl.MonthView != null) if (monthControl != null && monthControl.YearView != null && monthControl.MonthView != null)
{ {
@ -1400,7 +1411,7 @@ namespace Avalonia.Controls
} }
} }
public event EventHandler<SelectionChangedEventArgs> SelectedDatesChanged; public event EventHandler<SelectionChangedEventArgs>? SelectedDatesChanged;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
@ -1410,19 +1421,19 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// This event occurs after DisplayDate is assigned its new value. /// This event occurs after DisplayDate is assigned its new value.
/// </remarks> /// </remarks>
public event EventHandler<CalendarDateChangedEventArgs> DisplayDateChanged; public event EventHandler<CalendarDateChangedEventArgs>? DisplayDateChanged;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
/// <see cref="P:System.Windows.Controls.Calendar.DisplayMode" /> /// <see cref="P:System.Windows.Controls.Calendar.DisplayMode" />
/// property is changed. /// property is changed.
/// </summary> /// </summary>
public event EventHandler<CalendarModeChangedEventArgs> DisplayModeChanged; public event EventHandler<CalendarModeChangedEventArgs>? DisplayModeChanged;
/// <summary> /// <summary>
/// Inherited code: Requires comment. /// Inherited code: Requires comment.
/// </summary> /// </summary>
internal event EventHandler<PointerReleasedEventArgs> DayButtonMouseUp; internal event EventHandler<PointerReleasedEventArgs>? DayButtonMouseUp;
/// <summary> /// <summary>
/// This method adds the days that were selected by Keyboard to the /// This method adds the days that were selected by Keyboard to the
@ -1461,7 +1472,7 @@ namespace Avalonia.Controls
SelectedDates.ClearInternal(); SelectedDates.ClearInternal();
if (shift) if (shift)
{ {
CalendarDayButton b; CalendarDayButton? b;
_isShiftPressed = true; _isShiftPressed = true;
if (HoverStart == null) if (HoverStart == null)
{ {
@ -1513,6 +1524,8 @@ namespace Avalonia.Controls
} }
else else
{ {
Debug.Assert(HoverEndInternal is not null);
// For Home, End, PageUp and PageDown Keys there // For Home, End, PageUp and PageDown Keys there
// is no easy way to predict the index value // is no easy way to predict the index value
b = FindDayButtonFromDay(HoverEndInternal.Value); b = FindDayButtonFromDay(HoverEndInternal.Value);
@ -1524,6 +1537,7 @@ namespace Avalonia.Controls
} }
} }
Debug.Assert(HoverEnd is not null);
OnDayClick(HoverEnd.Value); OnDayClick(HoverEnd.Value);
HighlightDays(); HighlightDays();
} }
@ -1557,7 +1571,7 @@ namespace Avalonia.Controls
base.OnPointerReleased(e); base.OnPointerReleased(e);
if (!HasFocusInternal && e.InitialPressMouseButton == MouseButton.Left) if (!HasFocusInternal && e.InitialPressMouseButton == MouseButton.Left)
{ {
FocusManager.Instance.Focus(this); FocusManager.Instance?.Focus(this);
} }
} }
@ -1876,8 +1890,8 @@ namespace Avalonia.Controls
// since DisplayDate is not equal to // since DisplayDate is not equal to
// DateTime.MaxValue we are sure selectedDate is\ // DateTime.MaxValue we are sure selectedDate is\
// not null // not null
selectedDate = DateTimeHelper.AddMonths(selectedDate.Value, 1).Value; selectedDate = DateTimeHelper.AddMonths(selectedDate.Value, 1)!.Value;
selectedDate = DateTimeHelper.AddDays(selectedDate.Value, -1).Value; selectedDate = DateTimeHelper.AddDays(selectedDate.Value, -1)!.Value;
} }
else else
{ {
@ -2098,7 +2112,7 @@ namespace Avalonia.Controls
if (Root != null) if (Root != null)
{ {
CalendarItem month = e.NameScope.Find<CalendarItem>(PART_ElementMonth); CalendarItem? month = e.NameScope.Find<CalendarItem>(PART_ElementMonth);
if (month != null) if (month != null)
{ {

6
src/Avalonia.Controls/Calendar/CalendarButton.cs

@ -45,7 +45,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Gets or sets the Calendar associated with this button. /// Gets or sets the Calendar associated with this button.
/// </summary> /// </summary>
internal Calendar Owner { get; set; } internal Calendar? Owner { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the button is focused. /// Gets or sets a value indicating whether the button is focused.
@ -120,7 +120,7 @@ namespace Avalonia.Controls.Primitives
/// stylus touches the tablet PC) while the mouse pointer is over a /// stylus touches the tablet PC) while the mouse pointer is over a
/// UIElement. /// UIElement.
/// </summary> /// </summary>
public event EventHandler<PointerPressedEventArgs> CalendarLeftMouseButtonDown; public event EventHandler<PointerPressedEventArgs>? CalendarLeftMouseButtonDown;
/// <summary> /// <summary>
/// Occurs when the left mouse button is released (or the tip of the /// Occurs when the left mouse button is released (or the tip of the
@ -128,7 +128,7 @@ namespace Avalonia.Controls.Primitives
/// stylus) is over a UIElement (or while a UIElement holds mouse /// stylus) is over a UIElement (or while a UIElement holds mouse
/// capture). /// capture).
/// </summary> /// </summary>
public event EventHandler<PointerReleasedEventArgs> CalendarLeftMouseButtonUp; public event EventHandler<PointerReleasedEventArgs>? CalendarLeftMouseButtonUp;
/// <summary> /// <summary>
/// Provides class handling for the MouseLeftButtonDown event that /// Provides class handling for the MouseLeftButtonDown event that

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

@ -123,15 +123,15 @@ namespace Avalonia.Controls
private const string ElementPopup = "PART_Popup"; private const string ElementPopup = "PART_Popup";
private const string ElementCalendar = "PART_Calendar"; private const string ElementCalendar = "PART_Calendar";
private Calendar _calendar; private Calendar? _calendar;
private string _defaultText; private string _defaultText;
private Button _dropDownButton; private Button? _dropDownButton;
//private Canvas _outsideCanvas; //private Canvas _outsideCanvas;
//private Canvas _outsidePopupCanvas; //private Canvas _outsidePopupCanvas;
private Popup _popUp; private Popup? _popUp;
private TextBox _textBox; private TextBox? _textBox;
private IDisposable _textBoxTextChangedSubscription; private IDisposable? _textBoxTextChangedSubscription;
private IDisposable _buttonPointerPressedSubscription; private IDisposable? _buttonPointerPressedSubscription;
private DateTime? _onOpenSelectedDate; private DateTime? _onOpenSelectedDate;
private bool _settingSelectedDate; private bool _settingSelectedDate;
@ -141,7 +141,7 @@ namespace Avalonia.Controls
private DateTime? _displayDateEnd; private DateTime? _displayDateEnd;
private bool _isDropDownOpen; private bool _isDropDownOpen;
private DateTime? _selectedDate; private DateTime? _selectedDate;
private string _text; private string? _text;
private bool _suspendTextChangeHandler = false; private bool _suspendTextChangeHandler = false;
private bool _isPopupClosing = false; private bool _isPopupClosing = false;
private bool _ignoreButtonClick = false; private bool _ignoreButtonClick = false;
@ -153,7 +153,7 @@ namespace Avalonia.Controls
/// A collection of dates that cannot be selected. The default value is /// A collection of dates that cannot be selected. The default value is
/// an empty collection. /// an empty collection.
/// </value> /// </value>
public CalendarBlackoutDatesCollection BlackoutDates { get; private set; } public CalendarBlackoutDatesCollection? BlackoutDates { get; private set; }
public static readonly DirectProperty<CalendarDatePicker, DateTime> DisplayDateProperty = public static readonly DirectProperty<CalendarDatePicker, DateTime> DisplayDateProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, DateTime>( AvaloniaProperty.RegisterDirect<CalendarDatePicker, DateTime>(
@ -200,12 +200,12 @@ namespace Avalonia.Controls
defaultValue: "d", defaultValue: "d",
validate: IsValidDateFormatString); validate: IsValidDateFormatString);
public static readonly DirectProperty<CalendarDatePicker, string> TextProperty = public static readonly DirectProperty<CalendarDatePicker, string?> TextProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, string>( AvaloniaProperty.RegisterDirect<CalendarDatePicker, string?>(
nameof(Text), nameof(Text),
o => o.Text, o => o.Text,
(o, v) => o.Text = v); (o, v) => o.Text = v);
public static readonly StyledProperty<string> WatermarkProperty = public static readonly StyledProperty<string?> WatermarkProperty =
TextBox.WatermarkProperty.AddOwner<CalendarDatePicker>(); TextBox.WatermarkProperty.AddOwner<CalendarDatePicker>();
public static readonly StyledProperty<bool> UseFloatingWatermarkProperty = public static readonly StyledProperty<bool> UseFloatingWatermarkProperty =
TextBox.UseFloatingWatermarkProperty.AddOwner<CalendarDatePicker>(); TextBox.UseFloatingWatermarkProperty.AddOwner<CalendarDatePicker>();
@ -361,13 +361,13 @@ namespace Avalonia.Controls
/// <exception cref="T:System.ArgumentOutOfRangeException"> /// <exception cref="T:System.ArgumentOutOfRangeException">
/// The text entered parses to a date that is not selectable. /// The text entered parses to a date that is not selectable.
/// </exception> /// </exception>
public string Text public string? Text
{ {
get { return _text; } get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); } set { SetAndRaise(TextProperty, ref _text, value); }
} }
public string Watermark public string? Watermark
{ {
get { return GetValue(WatermarkProperty); } get { return GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); } set { SetValue(WatermarkProperty, value); }
@ -401,26 +401,26 @@ namespace Avalonia.Controls
/// Occurs when the drop-down /// Occurs when the drop-down
/// <see cref="T:Avalonia.Controls.Calendar" /> is closed. /// <see cref="T:Avalonia.Controls.Calendar" /> is closed.
/// </summary> /// </summary>
public event EventHandler CalendarClosed; public event EventHandler? CalendarClosed;
/// <summary> /// <summary>
/// Occurs when the drop-down /// Occurs when the drop-down
/// <see cref="T:Avalonia.Controls.Calendar" /> is opened. /// <see cref="T:Avalonia.Controls.Calendar" /> is opened.
/// </summary> /// </summary>
public event EventHandler CalendarOpened; public event EventHandler? CalendarOpened;
/// <summary> /// <summary>
/// Occurs when <see cref="P:Avalonia.Controls.DatePicker.Text" /> /// Occurs when <see cref="P:Avalonia.Controls.DatePicker.Text" />
/// is assigned a value that cannot be interpreted as a date. /// is assigned a value that cannot be interpreted as a date.
/// </summary> /// </summary>
public event EventHandler<CalendarDatePickerDateValidationErrorEventArgs> DateValidationError; public event EventHandler<CalendarDatePickerDateValidationErrorEventArgs>? DateValidationError;
/// <summary> /// <summary>
/// Occurs when the /// Occurs when the
/// <see cref="P:Avalonia.Controls.CalendarDatePicker.SelectedDate" /> /// <see cref="P:Avalonia.Controls.CalendarDatePicker.SelectedDate" />
/// property is changed. /// property is changed.
/// </summary> /// </summary>
public event EventHandler<SelectionChangedEventArgs> SelectedDateChanged; public event EventHandler<SelectionChangedEventArgs>? SelectedDateChanged;
static CalendarDatePicker() static CalendarDatePicker()
{ {
@ -579,14 +579,14 @@ namespace Avalonia.Controls
private void OnIsDropDownOpenChanged(AvaloniaPropertyChangedEventArgs e) private void OnIsDropDownOpenChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var oldValue = (bool)e.OldValue; var oldValue = (bool)e.OldValue!;
var value = (bool)e.NewValue; var value = (bool)e.NewValue!;
if (_popUp != null && _popUp.Child != null) if (_popUp != null && _popUp.Child != null)
{ {
if (value != oldValue) if (value != oldValue)
{ {
if (_calendar.DisplayMode != CalendarMode.Month) if (_calendar!.DisplayMode != CalendarMode.Month)
{ {
_calendar.DisplayMode = CalendarMode.Month; _calendar.DisplayMode = CalendarMode.Month;
} }
@ -660,7 +660,7 @@ namespace Avalonia.Controls
if (date != null) if (date != null)
{ {
string s = DateTimeToString((DateTime)date); string? s = DateTimeToString((DateTime)date);
Text = s; Text = s;
} }
} }
@ -679,8 +679,8 @@ namespace Avalonia.Controls
} }
private void OnTextChanged(AvaloniaPropertyChangedEventArgs e) private void OnTextChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var oldValue = (string)e.OldValue; var oldValue = (string?)e.OldValue;
var value = (string)e.NewValue; var value = (string?)e.NewValue;
if (!_suspendTextChangeHandler) if (!_suspendTextChangeHandler)
{ {
@ -731,7 +731,7 @@ namespace Avalonia.Controls
} }
private void OnDateSelected(DateTime? addedDate, DateTime? removedDate) private void OnDateSelected(DateTime? addedDate, DateTime? removedDate)
{ {
EventHandler<SelectionChangedEventArgs> handler = this.SelectedDateChanged; EventHandler<SelectionChangedEventArgs>? handler = this.SelectedDateChanged;
if (null != handler) if (null != handler)
{ {
Collection<DateTime> addedItems = new Collection<DateTime>(); Collection<DateTime> addedItems = new Collection<DateTime>();
@ -759,23 +759,23 @@ namespace Avalonia.Controls
CalendarOpened?.Invoke(this, e); CalendarOpened?.Invoke(this, e);
} }
private void Calendar_DayButtonMouseUp(object sender, PointerReleasedEventArgs e) private void Calendar_DayButtonMouseUp(object? sender, PointerReleasedEventArgs e)
{ {
Focus(); Focus();
IsDropDownOpen = false; IsDropDownOpen = false;
} }
private void Calendar_DisplayDateChanged(object sender, CalendarDateChangedEventArgs e) private void Calendar_DisplayDateChanged(object? sender, CalendarDateChangedEventArgs e)
{ {
if (e.AddedDate != this.DisplayDate) if (e.AddedDate != this.DisplayDate)
{ {
SetValue(DisplayDateProperty, (DateTime) e.AddedDate); SetValue(DisplayDateProperty, (DateTime) e.AddedDate!);
} }
} }
private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e) private void Calendar_SelectedDatesChanged(object? sender, SelectionChangedEventArgs e)
{ {
Debug.Assert(e.AddedItems.Count < 2, "There should be less than 2 AddedItems!"); Debug.Assert(e.AddedItems.Count < 2, "There should be less than 2 AddedItems!");
if (e.AddedItems.Count > 0 && SelectedDate.HasValue && DateTime.Compare((DateTime)e.AddedItems[0], SelectedDate.Value) != 0) if (e.AddedItems.Count > 0 && SelectedDate.HasValue && DateTime.Compare((DateTime)e.AddedItems[0]!, SelectedDate.Value) != 0)
{ {
SelectedDate = (DateTime?)e.AddedItems[0]; SelectedDate = (DateTime?)e.AddedItems[0];
} }
@ -796,7 +796,7 @@ namespace Avalonia.Controls
} }
} }
} }
private void Calendar_PointerReleased(object sender, PointerReleasedEventArgs e) private void Calendar_PointerReleased(object? sender, PointerReleasedEventArgs e)
{ {
if (e.InitialPressMouseButton == MouseButton.Left) if (e.InitialPressMouseButton == MouseButton.Left)
@ -804,10 +804,9 @@ namespace Avalonia.Controls
e.Handled = true; e.Handled = true;
} }
} }
private void Calendar_KeyDown(object sender, KeyEventArgs e) private void Calendar_KeyDown(object? sender, KeyEventArgs e)
{ {
Calendar c = sender as Calendar; Calendar? c = sender as Calendar ?? throw new ArgumentException("Sender must be Calendar.", nameof(sender));
Contract.Requires<ArgumentNullException>(c != null);
if (!e.Handled && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape) && c.DisplayMode == CalendarMode.Month) if (!e.Handled && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape) && c.DisplayMode == CalendarMode.Month)
{ {
@ -820,11 +819,11 @@ namespace Avalonia.Controls
} }
} }
} }
private void TextBox_GotFocus(object sender, RoutedEventArgs e) private void TextBox_GotFocus(object? sender, RoutedEventArgs e)
{ {
IsDropDownOpen = false; IsDropDownOpen = false;
} }
private void TextBox_KeyDown(object sender, KeyEventArgs e) private void TextBox_KeyDown(object? sender, KeyEventArgs e)
{ {
if (!e.Handled) if (!e.Handled)
{ {
@ -840,11 +839,11 @@ namespace Avalonia.Controls
_suspendTextChangeHandler = false; _suspendTextChangeHandler = false;
} }
} }
private void DropDownButton_PointerPressed(object sender, PointerPressedEventArgs e) private void DropDownButton_PointerPressed(object? sender, PointerPressedEventArgs e)
{ {
_ignoreButtonClick = _isPopupClosing; _ignoreButtonClick = _isPopupClosing;
} }
private void DropDownButton_Click(object sender, RoutedEventArgs e) private void DropDownButton_Click(object? sender, RoutedEventArgs e)
{ {
if (!_ignoreButtonClick) if (!_ignoreButtonClick)
{ {
@ -855,7 +854,7 @@ namespace Avalonia.Controls
_ignoreButtonClick = false; _ignoreButtonClick = false;
} }
} }
private void PopUp_Closed(object sender, EventArgs e) private void PopUp_Closed(object? sender, EventArgs e)
{ {
IsDropDownOpen = false; IsDropDownOpen = false;
@ -891,7 +890,7 @@ namespace Avalonia.Controls
private void OpenPopUp() private void OpenPopUp()
{ {
_onOpenSelectedDate = SelectedDate; _onOpenSelectedDate = SelectedDate;
_popUp.IsOpen = true; _popUp!.IsOpen = true;
} }
/// <summary> /// <summary>
@ -914,7 +913,7 @@ namespace Avalonia.Controls
{ {
newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetCurrentDateFormat()); newSelectedDate = DateTime.Parse(text, DateTimeHelper.GetCurrentDateFormat());
if (Calendar.IsValidDateSelection(this._calendar, newSelectedDate)) if (Calendar.IsValidDateSelection(this._calendar!, newSelectedDate))
{ {
return newSelectedDate; return newSelectedDate;
} }
@ -941,7 +940,7 @@ namespace Avalonia.Controls
} }
return null; return null;
} }
private string DateTimeToString(DateTime d) private string? DateTimeToString(DateTime d)
{ {
DateTimeFormatInfo dtfi = DateTimeHelper.GetCurrentDateFormat(); DateTimeFormatInfo dtfi = DateTimeHelper.GetCurrentDateFormat();
@ -982,7 +981,7 @@ namespace Avalonia.Controls
{ {
SetSelectedDate(); SetSelectedDate();
IsDropDownOpen = true; IsDropDownOpen = true;
_calendar.Focus(); _calendar!.Focus();
} }
private void SetSelectedDate() private void SetSelectedDate()
{ {
@ -1001,7 +1000,7 @@ namespace Avalonia.Controls
// ex: SelectedDate = DateTime(1008,12,19) but when // ex: SelectedDate = DateTime(1008,12,19) but when
// "12/19/08" is parsed it is interpreted as // "12/19/08" is parsed it is interpreted as
// DateTime(2008,12,19) // DateTime(2008,12,19)
string selectedDate = DateTimeToString(SelectedDate.Value); string? selectedDate = DateTimeToString(SelectedDate.Value);
if (selectedDate == s) if (selectedDate == s)
{ {
return; return;
@ -1053,7 +1052,7 @@ namespace Avalonia.Controls
// SelectedDate value: // SelectedDate value:
if (SelectedDate != null) if (SelectedDate != null)
{ {
string newtext = this.DateTimeToString(SelectedDate.Value); string? newtext = this.DateTimeToString(SelectedDate.Value);
SetValue(TextProperty, newtext); SetValue(TextProperty, newtext);
return SelectedDate; return SelectedDate;
} }

2
src/Avalonia.Controls/Calendar/CalendarDateRange.cs

@ -65,7 +65,7 @@ namespace Avalonia.Controls
/// <returns>Inherited code: Requires comment 2.</returns> /// <returns>Inherited code: Requires comment 2.</returns>
internal bool ContainsAny(CalendarDateRange range) internal bool ContainsAny(CalendarDateRange range)
{ {
Contract.Requires<ArgumentNullException>(range != null); _ = range ?? throw new ArgumentNullException(nameof(range));
int start = DateTime.Compare(Start, range.Start); int start = DateTime.Compare(Start, range.Start);

6
src/Avalonia.Controls/Calendar/CalendarDayButton.cs

@ -40,7 +40,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Gets or sets the Calendar associated with this button. /// Gets or sets the Calendar associated with this button.
/// </summary> /// </summary>
internal Calendar Owner { get; set; } internal Calendar? Owner { get; set; }
internal int Index { get; set; } internal int Index { get; set; }
/// <summary> /// <summary>
@ -177,7 +177,7 @@ namespace Avalonia.Controls.Primitives
/// stylus touches the tablet PC) while the mouse pointer is over a /// stylus touches the tablet PC) while the mouse pointer is over a
/// UIElement. /// UIElement.
/// </summary> /// </summary>
public event EventHandler<PointerPressedEventArgs> CalendarDayButtonMouseDown; public event EventHandler<PointerPressedEventArgs>? CalendarDayButtonMouseDown;
/// <summary> /// <summary>
/// Occurs when the left mouse button is released (or the tip of the /// Occurs when the left mouse button is released (or the tip of the
@ -185,7 +185,7 @@ namespace Avalonia.Controls.Primitives
/// stylus) is over a UIElement (or while a UIElement holds mouse /// stylus) is over a UIElement (or while a UIElement holds mouse
/// capture). /// capture).
/// </summary> /// </summary>
public event EventHandler<PointerReleasedEventArgs> CalendarDayButtonMouseUp; public event EventHandler<PointerReleasedEventArgs>? CalendarDayButtonMouseUp;
/// <summary> /// <summary>
/// Provides class handling for the MouseLeftButtonDown event that /// Provides class handling for the MouseLeftButtonDown event that

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

@ -33,10 +33,10 @@ namespace Avalonia.Controls.Primitives
private const string PART_ElementMonthView = "MonthView"; private const string PART_ElementMonthView = "MonthView";
private const string PART_ElementYearView = "YearView"; private const string PART_ElementYearView = "YearView";
private Button _headerButton; private Button? _headerButton;
private Button _nextButton; private Button? _nextButton;
private Button _previousButton; private Button? _previousButton;
private ITemplate<IControl> _dayTitleTemplate; private ITemplate<IControl>? _dayTitleTemplate;
private DateTime _currentMonth; private DateTime _currentMonth;
private bool _isMouseLeftButtonDown = false; private bool _isMouseLeftButtonDown = false;
@ -45,11 +45,11 @@ namespace Avalonia.Controls.Primitives
private System.Globalization.Calendar _calendar = new System.Globalization.GregorianCalendar(); private System.Globalization.Calendar _calendar = new System.Globalization.GregorianCalendar();
private PointerPressedEventArgs _downEventArg; private PointerPressedEventArgs? _downEventArg;
private PointerPressedEventArgs _downEventArgYearView; private PointerPressedEventArgs? _downEventArgYearView;
internal Calendar Owner { get; set; } internal Calendar? Owner { get; set; }
internal CalendarDayButton CurrentButton { get; set; } internal CalendarDayButton? CurrentButton { get; set; }
public static readonly StyledProperty<IBrush> HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner<CalendarItem>(); public static readonly StyledProperty<IBrush> HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner<CalendarItem>();
public IBrush HeaderBackground public IBrush HeaderBackground
@ -57,13 +57,13 @@ namespace Avalonia.Controls.Primitives
get { return GetValue(HeaderBackgroundProperty); } get { return GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); } set { SetValue(HeaderBackgroundProperty, value); }
} }
public static readonly DirectProperty<CalendarItem, ITemplate<IControl>> DayTitleTemplateProperty = public static readonly DirectProperty<CalendarItem, ITemplate<IControl>?> DayTitleTemplateProperty =
AvaloniaProperty.RegisterDirect<CalendarItem, ITemplate<IControl>>( AvaloniaProperty.RegisterDirect<CalendarItem, ITemplate<IControl>?>(
nameof(DayTitleTemplate), nameof(DayTitleTemplate),
o => o.DayTitleTemplate, o => o.DayTitleTemplate,
(o,v) => o.DayTitleTemplate = v, (o,v) => o.DayTitleTemplate = v,
defaultBindingMode: BindingMode.OneTime); defaultBindingMode: BindingMode.OneTime);
public ITemplate<IControl> DayTitleTemplate public ITemplate<IControl>? DayTitleTemplate
{ {
get { return _dayTitleTemplate; } get { return _dayTitleTemplate; }
set { SetAndRaise(DayTitleTemplateProperty, ref _dayTitleTemplate, value); } set { SetAndRaise(DayTitleTemplateProperty, ref _dayTitleTemplate, value); }
@ -73,7 +73,7 @@ namespace Avalonia.Controls.Primitives
/// Gets the button that allows switching between month mode, year mode, /// Gets the button that allows switching between month mode, year mode,
/// and decade mode. /// and decade mode.
/// </summary> /// </summary>
internal Button HeaderButton internal Button? HeaderButton
{ {
get { return _headerButton; } get { return _headerButton; }
private set private set
@ -94,7 +94,7 @@ namespace Avalonia.Controls.Primitives
/// Gets the button that displays the next page of the calendar when it /// Gets the button that displays the next page of the calendar when it
/// is clicked. /// is clicked.
/// </summary> /// </summary>
internal Button NextButton internal Button? NextButton
{ {
get { return _nextButton; } get { return _nextButton; }
private set private set
@ -125,7 +125,7 @@ namespace Avalonia.Controls.Primitives
/// Gets the button that displays the previous page of the calendar when /// Gets the button that displays the previous page of the calendar when
/// it is clicked. /// it is clicked.
/// </summary> /// </summary>
internal Button PreviousButton internal Button? PreviousButton
{ {
get { return _previousButton; } get { return _previousButton; }
private set private set
@ -156,11 +156,11 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Gets the Grid that hosts the content when in month mode. /// Gets the Grid that hosts the content when in month mode.
/// </summary> /// </summary>
internal Grid MonthView { get; set; } internal Grid? MonthView { get; set; }
/// <summary> /// <summary>
/// Gets the Grid that hosts the content when in year or decade mode. /// Gets the Grid that hosts the content when in year or decade mode.
/// </summary> /// </summary>
internal Grid YearView { get; set; } internal Grid? YearView { get; set; }
private void PopulateGrids() private void PopulateGrids()
{ {
@ -294,7 +294,7 @@ namespace Avalonia.Controls.Primitives
{ {
for (int childIndex = 0; childIndex < Calendar.ColumnsPerMonth; childIndex++) for (int childIndex = 0; childIndex < Calendar.ColumnsPerMonth; childIndex++)
{ {
var daytitle = MonthView.Children[childIndex]; var daytitle = MonthView!.Children[childIndex];
if (daytitle != null) if (daytitle != null)
{ {
if (Owner != null) if (Owner != null)
@ -495,8 +495,7 @@ namespace Avalonia.Controls.Primitives
for (int childIndex = Calendar.ColumnsPerMonth; childIndex < count; childIndex++) for (int childIndex = Calendar.ColumnsPerMonth; childIndex < count; childIndex++)
{ {
CalendarDayButton childButton = MonthView.Children[childIndex] as CalendarDayButton; CalendarDayButton childButton = (CalendarDayButton)MonthView!.Children[childIndex];
Contract.Requires<ArgumentNullException>(childButton != null);
childButton.Index = childIndex; childButton.Index = childIndex;
SetButtonState(childButton, dateToAdd); SetButtonState(childButton, dateToAdd);
@ -532,8 +531,7 @@ namespace Avalonia.Controls.Primitives
childIndex++; childIndex++;
for (int i = childIndex; i < count; i++) for (int i = childIndex; i < count; i++)
{ {
childButton = MonthView.Children[i] as CalendarDayButton; childButton = (CalendarDayButton)MonthView.Children[i];
Contract.Requires<ArgumentNullException>(childButton != null);
// button needs a content to occupy the necessary space // button needs a content to occupy the necessary space
// for the content presenter // for the content presenter
childButton.Content = i.ToString(DateTimeHelper.GetCurrentDateFormat()); childButton.Content = i.ToString(DateTimeHelper.GetCurrentDateFormat());
@ -626,10 +624,9 @@ namespace Avalonia.Controls.Primitives
private void SetMonthButtonsForYearMode() private void SetMonthButtonsForYearMode()
{ {
int count = 0; int count = 0;
foreach (object child in YearView.Children) foreach (object child in YearView!.Children)
{ {
CalendarButton childButton = child as CalendarButton; CalendarButton childButton = (CalendarButton)child;
Contract.Requires<ArgumentNullException>(childButton != null);
// There should be no time component. Time is 12:00 AM // There should be no time component. Time is 12:00 AM
DateTime day = new DateTime(_currentMonth.Year, count + 1, 1); DateTime day = new DateTime(_currentMonth.Year, count + 1, 1);
childButton.DataContext = day; childButton.DataContext = day;
@ -703,7 +700,7 @@ namespace Avalonia.Controls.Primitives
{ {
if (Owner != null && calendarButton != null && calendarButton.DataContext != null) if (Owner != null && calendarButton != null && calendarButton.DataContext != null)
{ {
Owner.FocusCalendarButton.IsCalendarButtonFocused = false; Owner.FocusCalendarButton!.IsCalendarButtonFocused = false;
Owner.FocusCalendarButton = calendarButton; Owner.FocusCalendarButton = calendarButton;
calendarButton.IsCalendarButtonFocused = Owner.HasFocusInternal; calendarButton.IsCalendarButtonFocused = Owner.HasFocusInternal;
@ -722,10 +719,9 @@ namespace Avalonia.Controls.Primitives
{ {
int year; int year;
int count = -1; int count = -1;
foreach (object child in YearView.Children) foreach (object child in YearView!.Children)
{ {
CalendarButton childButton = child as CalendarButton; CalendarButton childButton = (CalendarButton)child;
Contract.Requires<ArgumentNullException>(childButton != null);
year = decade + count; year = decade + count;
if (year <= DateTime.MaxValue.Year && year >= DateTime.MinValue.Year) if (year <= DateTime.MaxValue.Year && year >= DateTime.MinValue.Year)
@ -797,7 +793,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
internal void HeaderButton_Click(object sender, RoutedEventArgs e) internal void HeaderButton_Click(object? sender, RoutedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
@ -805,7 +801,7 @@ namespace Avalonia.Controls.Primitives
{ {
Owner.Focus(); Owner.Focus();
} }
Button b = (Button)sender; Button b = (Button)sender!;
DateTime d; DateTime d;
if (b.IsEnabled) if (b.IsEnabled)
@ -833,7 +829,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
} }
internal void PreviousButton_Click(object sender, RoutedEventArgs e) internal void PreviousButton_Click(object? sender, RoutedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
@ -842,14 +838,14 @@ namespace Avalonia.Controls.Primitives
Owner.Focus(); Owner.Focus();
} }
Button b = (Button)sender; Button b = (Button)sender!;
if (b.IsEnabled) if (b.IsEnabled)
{ {
Owner.OnPreviousClick(); Owner.OnPreviousClick();
} }
} }
} }
internal void NextButton_Click(object sender, RoutedEventArgs e) internal void NextButton_Click(object? sender, RoutedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
@ -857,7 +853,7 @@ namespace Avalonia.Controls.Primitives
{ {
Owner.Focus(); Owner.Focus();
} }
Button b = (Button)sender; Button b = (Button)sender!;
if (b.IsEnabled) if (b.IsEnabled)
{ {
@ -866,7 +862,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
internal void Cell_MouseEnter(object sender, PointerEventArgs e) internal void Cell_MouseEnter(object? sender, PointerEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
@ -878,7 +874,7 @@ namespace Avalonia.Controls.Primitives
{ {
case CalendarSelectionMode.SingleDate: case CalendarSelectionMode.SingleDate:
{ {
DateTime selectedDate = (DateTime)b.DataContext; DateTime selectedDate = (DateTime)b.DataContext!;
Owner.CalendarDatePickerDisplayDateFlag = true; Owner.CalendarDatePickerDisplayDateFlag = true;
if (Owner.SelectedDates.Count == 0) if (Owner.SelectedDates.Count == 0)
{ {
@ -906,7 +902,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
internal void Cell_MouseLeftButtonDown(object sender, PointerPressedEventArgs e) internal void Cell_MouseLeftButtonDown(object? sender, PointerPressedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
@ -917,15 +913,14 @@ namespace Avalonia.Controls.Primitives
bool ctrl, shift; bool ctrl, shift;
CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out ctrl, out shift); CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out ctrl, out shift);
CalendarDayButton b = sender as CalendarDayButton; CalendarDayButton b = (CalendarDayButton)sender!;
if (b != null) if (b != null)
{ {
_isControlPressed = ctrl; _isControlPressed = ctrl;
if (b.IsEnabled && !b.IsBlackout) if (b.IsEnabled && !b.IsBlackout)
{ {
DateTime selectedDate = (DateTime)b.DataContext; DateTime selectedDate = (DateTime)b.DataContext!;
Contract.Requires<ArgumentNullException>(selectedDate != null);
_isMouseLeftButtonDown = true; _isMouseLeftButtonDown = true;
// null check is added for unit tests // null check is added for unit tests
if (e != null) if (e != null)
@ -1027,7 +1022,7 @@ namespace Avalonia.Controls.Primitives
if (Owner != null) if (Owner != null)
{ {
Owner.HoverEndIndex = b.Index; Owner.HoverEndIndex = b.Index;
Owner.HoverEnd = (DateTime)b.DataContext; Owner.HoverEnd = (DateTime)b.DataContext!;
if (Owner.HoverEnd != null && Owner.HoverStart != null) if (Owner.HoverEnd != null && Owner.HoverStart != null)
{ {
@ -1041,11 +1036,11 @@ namespace Avalonia.Controls.Primitives
} }
} }
} }
internal void Cell_MouseLeftButtonUp(object sender, PointerReleasedEventArgs e) internal void Cell_MouseLeftButtonUp(object? sender, PointerReleasedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
CalendarDayButton b = sender as CalendarDayButton; CalendarDayButton? b = sender as CalendarDayButton;
if (b != null && !b.IsBlackout) if (b != null && !b.IsBlackout)
{ {
Owner.OnDayButtonMouseUp(e); Owner.OnDayButtonMouseUp(e);
@ -1094,14 +1089,13 @@ namespace Avalonia.Controls.Primitives
} }
} }
} }
private void Cell_Click(object sender, RoutedEventArgs e) private void Cell_Click(object? sender, RoutedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
{ {
if (_isControlPressed && Owner.SelectionMode == CalendarSelectionMode.MultipleRange) if (_isControlPressed && Owner.SelectionMode == CalendarSelectionMode.MultipleRange)
{ {
CalendarDayButton b = sender as CalendarDayButton; CalendarDayButton b = (CalendarDayButton)sender!;
Contract.Requires<ArgumentNullException>(b != null);
if (b.IsSelected) if (b.IsSelected)
{ {
@ -1118,10 +1112,9 @@ namespace Avalonia.Controls.Primitives
_isControlPressed = false; _isControlPressed = false;
} }
private void Month_CalendarButtonMouseDown(object sender, PointerPressedEventArgs e) private void Month_CalendarButtonMouseDown(object? sender, PointerPressedEventArgs e)
{ {
CalendarButton b = sender as CalendarButton; CalendarButton b = (CalendarButton)sender!;
Contract.Requires<ArgumentNullException>(b != null);
_isMouseLeftButtonDownYearView = true; _isMouseLeftButtonDownYearView = true;
@ -1133,13 +1126,13 @@ namespace Avalonia.Controls.Primitives
UpdateYearViewSelection(b); UpdateYearViewSelection(b);
} }
internal void Month_CalendarButtonMouseUp(object sender, PointerReleasedEventArgs e) internal void Month_CalendarButtonMouseUp(object? sender, PointerReleasedEventArgs e)
{ {
_isMouseLeftButtonDownYearView = false; _isMouseLeftButtonDownYearView = false;
if (Owner != null) if (Owner != null)
{ {
DateTime newmonth = (DateTime)((CalendarButton)sender).DataContext; DateTime newmonth = (DateTime)((CalendarButton)sender!).DataContext!;
if (Owner.DisplayMode == CalendarMode.Year) if (Owner.DisplayMode == CalendarMode.Year)
{ {
@ -1155,12 +1148,11 @@ namespace Avalonia.Controls.Primitives
} }
} }
private void Month_MouseEnter(object sender, PointerEventArgs e) private void Month_MouseEnter(object? sender, PointerEventArgs e)
{ {
if (_isMouseLeftButtonDownYearView) if (_isMouseLeftButtonDownYearView)
{ {
CalendarButton b = sender as CalendarButton; CalendarButton b = (CalendarButton)sender!;
Contract.Requires<ArgumentNullException>(b != null);
UpdateYearViewSelection(b); UpdateYearViewSelection(b);
} }
} }

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

@ -5,6 +5,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
namespace Avalonia.Controls namespace Avalonia.Controls
@ -73,6 +74,7 @@ namespace Avalonia.Controls
return newD; return newD;
} }
[return: NotNullIfNotNull("d")]
public static DateTime? DiscardTime(DateTime? d) public static DateTime? DiscardTime(DateTime? d)
{ {
if (d == null) if (d == null)

4
src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs

@ -49,7 +49,7 @@ namespace Avalonia.Controls.Primitives
private void InvokeCollectionChanged(System.Collections.IList removedItems, System.Collections.IList addedItems) private void InvokeCollectionChanged(System.Collections.IList removedItems, System.Collections.IList addedItems)
{ {
_owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, removedItems, addedItems)); _owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(SelectingItemsControl.SelectionChangedEvent, removedItems, addedItems));
} }
/// <summary> /// <summary>
@ -119,7 +119,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
_owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, _owner.RemovedItems, _addedItems)); _owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(SelectingItemsControl.SelectionChangedEvent, _owner.RemovedItems, _addedItems));
_owner.RemovedItems.Clear(); _owner.RemovedItems.Clear();
_owner.UpdateMonths(); _owner.UpdateMonths();
_isRangeAdded = false; _isRangeAdded = false;

2
src/Avalonia.Controls/Canvas.cs

@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// <param name="from">The control from which movement begins.</param> /// <param name="from">The control from which movement begins.</param>
/// <param name="wrap">Whether to wrap around when the first or last item is reached.</param> /// <param name="wrap">Whether to wrap around when the first or last item is reached.</param>
/// <returns>The control.</returns> /// <returns>The control.</returns>
IInputElement INavigableContainer.GetControl(NavigationDirection direction, IInputElement from, bool wrap) IInputElement? INavigableContainer.GetControl(NavigationDirection direction, IInputElement? from, bool wrap)
{ {
// TODO: Implement this // TODO: Implement this
return null; return null;

2
src/Avalonia.Controls/Chrome/CaptionButtons.cs

@ -3,8 +3,6 @@ using System.Reactive.Disposables;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
#nullable enable
namespace Avalonia.Controls.Chrome namespace Avalonia.Controls.Chrome
{ {
/// <summary> /// <summary>

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

@ -3,8 +3,6 @@ using System.Reactive.Disposables;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
#nullable enable
namespace Avalonia.Controls.Chrome namespace Avalonia.Controls.Chrome
{ {
/// <summary> /// <summary>
@ -36,7 +34,7 @@ namespace Avalonia.Controls.Chrome
} }
} }
IsVisible = window.PlatformImpl.NeedsManagedDecorations; IsVisible = window.PlatformImpl?.NeedsManagedDecorations ?? false;
} }
} }

40
src/Avalonia.Controls/ComboBox.cs

@ -46,8 +46,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="SelectionBoxItem"/> property. /// Defines the <see cref="SelectionBoxItem"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<ComboBox, object> SelectionBoxItemProperty = public static readonly DirectProperty<ComboBox, object?> SelectionBoxItemProperty =
AvaloniaProperty.RegisterDirect<ComboBox, object>(nameof(SelectionBoxItem), o => o.SelectionBoxItem); AvaloniaProperty.RegisterDirect<ComboBox, object?>(nameof(SelectionBoxItem), o => o.SelectionBoxItem);
/// <summary> /// <summary>
/// Defines the <see cref="VirtualizationMode"/> property. /// Defines the <see cref="VirtualizationMode"/> property.
@ -58,14 +58,14 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="PlaceholderText"/> property. /// Defines the <see cref="PlaceholderText"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<string> PlaceholderTextProperty = public static readonly StyledProperty<string?> PlaceholderTextProperty =
AvaloniaProperty.Register<ComboBox, string>(nameof(PlaceholderText)); AvaloniaProperty.Register<ComboBox, string?>(nameof(PlaceholderText));
/// <summary> /// <summary>
/// Defines the <see cref="PlaceholderForeground"/> property. /// Defines the <see cref="PlaceholderForeground"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IBrush> PlaceholderForegroundProperty = public static readonly StyledProperty<IBrush?> PlaceholderForegroundProperty =
AvaloniaProperty.Register<ComboBox, IBrush>(nameof(PlaceholderForeground)); AvaloniaProperty.Register<ComboBox, IBrush?>(nameof(PlaceholderForeground));
/// <summary> /// <summary>
/// Defines the <see cref="HorizontalContentAlignment"/> property. /// Defines the <see cref="HorizontalContentAlignment"/> property.
@ -80,8 +80,8 @@ namespace Avalonia.Controls
ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>(); ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>();
private bool _isDropDownOpen; private bool _isDropDownOpen;
private Popup _popup; private Popup? _popup;
private object _selectionBoxItem; private object? _selectionBoxItem;
private readonly CompositeDisposable _subscriptionsOnOpen = new CompositeDisposable(); private readonly CompositeDisposable _subscriptionsOnOpen = new CompositeDisposable();
/// <summary> /// <summary>
@ -117,7 +117,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the item to display as the control's content. /// Gets or sets the item to display as the control's content.
/// </summary> /// </summary>
protected object SelectionBoxItem protected object? SelectionBoxItem
{ {
get { return _selectionBoxItem; } get { return _selectionBoxItem; }
set { SetAndRaise(SelectionBoxItemProperty, ref _selectionBoxItem, value); } set { SetAndRaise(SelectionBoxItemProperty, ref _selectionBoxItem, value); }
@ -126,7 +126,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the PlaceHolder text. /// Gets or sets the PlaceHolder text.
/// </summary> /// </summary>
public string PlaceholderText public string? PlaceholderText
{ {
get { return GetValue(PlaceholderTextProperty); } get { return GetValue(PlaceholderTextProperty); }
set { SetValue(PlaceholderTextProperty, value); } set { SetValue(PlaceholderTextProperty, value); }
@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the Brush that renders the placeholder text. /// Gets or sets the Brush that renders the placeholder text.
/// </summary> /// </summary>
public IBrush PlaceholderForeground public IBrush? PlaceholderForeground
{ {
get { return GetValue(PlaceholderForegroundProperty); } get { return GetValue(PlaceholderForegroundProperty); }
set { SetValue(PlaceholderForegroundProperty, value); } set { SetValue(PlaceholderForegroundProperty, value); }
@ -262,9 +262,9 @@ namespace Avalonia.Controls
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnPointerReleased(PointerReleasedEventArgs e) protected override void OnPointerReleased(PointerReleasedEventArgs e)
{ {
if (!e.Handled) if (!e.Handled && e.Source is IVisual source)
{ {
if (_popup?.IsInsidePopup((IVisual)e.Source) == true) if (_popup?.IsInsidePopup(source) == true)
{ {
if (UpdateSelectionFromEventSource(e.Source)) if (UpdateSelectionFromEventSource(e.Source))
{ {
@ -304,7 +304,7 @@ namespace Avalonia.Controls
} }
} }
private void PopupClosed(object sender, EventArgs e) private void PopupClosed(object? sender, EventArgs e)
{ {
_subscriptionsOnOpen.Clear(); _subscriptionsOnOpen.Clear();
@ -314,7 +314,7 @@ namespace Avalonia.Controls
} }
} }
private void PopupOpened(object sender, EventArgs e) private void PopupOpened(object? sender, EventArgs e)
{ {
TryFocusSelectedItem(); TryFocusSelectedItem();
@ -326,7 +326,7 @@ namespace Avalonia.Controls
toplevel.AddDisposableHandler(PointerWheelChangedEvent, (s, ev) => toplevel.AddDisposableHandler(PointerWheelChangedEvent, (s, ev) =>
{ {
//eat wheel scroll event outside dropdown popup while it's open //eat wheel scroll event outside dropdown popup while it's open
if (IsDropDownOpen && (ev.Source as IVisual).GetVisualRoot() == toplevel) if (IsDropDownOpen && (ev.Source as IVisual)?.GetVisualRoot() == toplevel)
{ {
ev.Handled = true; ev.Handled = true;
} }
@ -360,12 +360,12 @@ namespace Avalonia.Controls
var selectedIndex = SelectedIndex; var selectedIndex = SelectedIndex;
if (IsDropDownOpen && selectedIndex != -1) if (IsDropDownOpen && selectedIndex != -1)
{ {
var container = ItemContainerGenerator.ContainerFromIndex(selectedIndex); var container = ItemContainerGenerator!.ContainerFromIndex(selectedIndex);
if (container == null && SelectedIndex != -1) if (container == null && SelectedIndex != -1)
{ {
ScrollIntoView(Selection.SelectedIndex); ScrollIntoView(Selection.SelectedIndex);
container = ItemContainerGenerator.ContainerFromIndex(selectedIndex); container = ItemContainerGenerator!.ContainerFromIndex(selectedIndex);
} }
if (container != null && CanFocus(container)) if (container != null && CanFocus(container))
@ -377,7 +377,7 @@ namespace Avalonia.Controls
private bool CanFocus(IControl control) => control.Focusable && control.IsEffectivelyEnabled && control.IsVisible; private bool CanFocus(IControl control) => control.Focusable && control.IsEffectivelyEnabled && control.IsVisible;
private void UpdateSelectionBoxItem(object item) private void UpdateSelectionBoxItem(object? item)
{ {
var contentControl = item as IContentControl; var contentControl = item as IContentControl;
@ -415,7 +415,7 @@ namespace Avalonia.Controls
private void SelectFocusedItem() private void SelectFocusedItem()
{ {
foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator.Containers) foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator!.Containers)
{ {
if (dropdownItem.ContainerControl.IsFocused) if (dropdownItem.ContainerControl.IsFocused)
{ {

14
src/Avalonia.Controls/ContentControl.cs

@ -17,14 +17,14 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Content"/> property. /// Defines the <see cref="Content"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<object> ContentProperty = public static readonly StyledProperty<object?> ContentProperty =
AvaloniaProperty.Register<ContentControl, object>(nameof(Content)); AvaloniaProperty.Register<ContentControl, object?>(nameof(Content));
/// <summary> /// <summary>
/// Defines the <see cref="ContentTemplate"/> property. /// Defines the <see cref="ContentTemplate"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IDataTemplate> ContentTemplateProperty = public static readonly StyledProperty<IDataTemplate?> ContentTemplateProperty =
AvaloniaProperty.Register<ContentControl, IDataTemplate>(nameof(ContentTemplate)); AvaloniaProperty.Register<ContentControl, IDataTemplate?>(nameof(ContentTemplate));
/// <summary> /// <summary>
/// Defines the <see cref="HorizontalContentAlignment"/> property. /// Defines the <see cref="HorizontalContentAlignment"/> property.
@ -48,7 +48,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
[Content] [Content]
[DependsOn(nameof(ContentTemplate))] [DependsOn(nameof(ContentTemplate))]
public object Content public object? Content
{ {
get { return GetValue(ContentProperty); } get { return GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); } set { SetValue(ContentProperty, value); }
@ -57,7 +57,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the data template used to display the content of the control. /// Gets or sets the data template used to display the content of the control.
/// </summary> /// </summary>
public IDataTemplate ContentTemplate public IDataTemplate? ContentTemplate
{ {
get { return GetValue(ContentTemplateProperty); } get { return GetValue(ContentTemplateProperty); }
set { SetValue(ContentTemplateProperty, value); } set { SetValue(ContentTemplateProperty, value); }
@ -66,7 +66,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the presenter from the control's template. /// Gets the presenter from the control's template.
/// </summary> /// </summary>
public IContentPresenter Presenter public IContentPresenter? Presenter
{ {
get; get;
private set; private set;

14
src/Avalonia.Controls/ContextMenu.cs

@ -14,8 +14,6 @@ using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Styling; using Avalonia.Styling;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
@ -368,7 +366,7 @@ namespace Avalonia.Controls
}); });
} }
private void PopupOpened(object sender, EventArgs e) private void PopupOpened(object? sender, EventArgs e)
{ {
_previousFocus = FocusManager.Instance?.Current; _previousFocus = FocusManager.Instance?.Current;
Focus(); Focus();
@ -376,12 +374,12 @@ namespace Avalonia.Controls
_popupHostChangedHandler?.Invoke(_popup!.Host); _popupHostChangedHandler?.Invoke(_popup!.Host);
} }
private void PopupClosing(object sender, CancelEventArgs e) private void PopupClosing(object? sender, CancelEventArgs e)
{ {
e.Cancel = CancelClosing(); e.Cancel = CancelClosing();
} }
private void PopupClosed(object sender, EventArgs e) private void PopupClosed(object? sender, EventArgs e)
{ {
foreach (var i in LogicalChildren) foreach (var i in LogicalChildren)
{ {
@ -411,7 +409,7 @@ namespace Avalonia.Controls
_popupHostChangedHandler?.Invoke(null); _popupHostChangedHandler?.Invoke(null);
} }
private void PopupKeyUp(object sender, KeyEventArgs e) private void PopupKeyUp(object? sender, KeyEventArgs e)
{ {
if (IsOpen) if (IsOpen)
{ {
@ -426,7 +424,7 @@ namespace Avalonia.Controls
} }
} }
private static void ControlContextRequested(object sender, ContextRequestedEventArgs e) private static void ControlContextRequested(object? sender, ContextRequestedEventArgs e)
{ {
if (sender is Control control if (sender is Control control
&& control.ContextMenu is ContextMenu contextMenu && control.ContextMenu is ContextMenu contextMenu
@ -439,7 +437,7 @@ namespace Avalonia.Controls
} }
} }
private static void ControlDetachedFromVisualTree(object sender, VisualTreeAttachmentEventArgs e) private static void ControlDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{ {
if (sender is Control control if (sender is Control control
&& control.ContextMenu is ContextMenu contextMenu) && control.ContextMenu is ContextMenu contextMenu)

2
src/Avalonia.Controls/ContextRequestedEventArgs.cs

@ -1,8 +1,6 @@
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>

4
src/Avalonia.Controls/Control.cs

@ -11,8 +11,6 @@ using Avalonia.Rendering;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.VisualTree; using Avalonia.VisualTree;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
@ -129,7 +127,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Occurs when the user has completed a context input gesture, such as a right-click. /// Occurs when the user has completed a context input gesture, such as a right-click.
/// </summary> /// </summary>
public event EventHandler<ContextRequestedEventArgs> ContextRequested public event EventHandler<ContextRequestedEventArgs>? ContextRequested
{ {
add => AddHandler(ContextRequestedEvent, value); add => AddHandler(ContextRequestedEvent, value);
remove => RemoveHandler(ContextRequestedEvent, value); remove => RemoveHandler(ContextRequestedEvent, value);

35
src/Avalonia.Controls/ControlExtensions.cs

@ -17,7 +17,7 @@ namespace Avalonia.Controls
/// <param name="control">The control.</param> /// <param name="control">The control.</param>
public static void BringIntoView(this IControl control) public static void BringIntoView(this IControl control)
{ {
Contract.Requires<ArgumentNullException>(control != null); _ = control ?? throw new ArgumentNullException(nameof(control));
control.BringIntoView(new Rect(control.Bounds.Size)); control.BringIntoView(new Rect(control.Bounds.Size));
} }
@ -29,7 +29,7 @@ namespace Avalonia.Controls
/// <param name="rect">The area of the control to being into view.</param> /// <param name="rect">The area of the control to being into view.</param>
public static void BringIntoView(this IControl control, Rect rect) public static void BringIntoView(this IControl control, Rect rect)
{ {
Contract.Requires<ArgumentNullException>(control != null); _ = control ?? throw new ArgumentNullException(nameof(control));
if (control.IsEffectivelyVisible) if (control.IsEffectivelyVisible)
{ {
@ -51,10 +51,10 @@ namespace Avalonia.Controls
/// <param name="control">The control to look in.</param> /// <param name="control">The control to look in.</param>
/// <param name="name">The name of the control to find.</param> /// <param name="name">The name of the control to find.</param>
/// <returns>The control or null if not found.</returns> /// <returns>The control or null if not found.</returns>
public static T FindControl<T>(this IControl control, string name) where T : class, IControl public static T? FindControl<T>(this IControl control, string name) where T : class, IControl
{ {
Contract.Requires<ArgumentNullException>(control != null); _ = control ?? throw new ArgumentNullException(nameof(control));
Contract.Requires<ArgumentNullException>(name != null); _ = name ?? throw new ArgumentNullException(nameof(name));
var nameScope = control.FindNameScope(); var nameScope = control.FindNameScope();
@ -66,6 +66,29 @@ namespace Avalonia.Controls
return nameScope.Find<T>(name); return nameScope.Find<T>(name);
} }
/// <summary>
/// Finds the named control in the scope of the specified control and throws if not found.
/// </summary>
/// <typeparam name="T">The type of the control to find.</typeparam>
/// <param name="control">The control to look in.</param>
/// <param name="name">The name of the control to find.</param>
/// <returns>The control.</returns>
public static T GetControl<T>(this IControl control, string name) where T : class, IControl
{
_ = control ?? throw new ArgumentNullException(nameof(control));
_ = name ?? throw new ArgumentNullException(nameof(name));
var nameScope = control.FindNameScope();
if (nameScope == null)
{
throw new InvalidOperationException("Could not find parent name scope.");
}
return nameScope.Find<T>(name) ??
throw new ArgumentException($"Could not find control named '{name}'.");
}
/// <summary> /// <summary>
/// Sets a pseudoclass depending on an observable trigger. /// Sets a pseudoclass depending on an observable trigger.
/// </summary> /// </summary>
@ -75,7 +98,7 @@ namespace Avalonia.Controls
/// <returns>A disposable used to cancel the subscription.</returns> /// <returns>A disposable used to cancel the subscription.</returns>
public static IDisposable Set(this IPseudoClasses classes, string name, IObservable<bool> trigger) public static IDisposable Set(this IPseudoClasses classes, string name, IObservable<bool> trigger)
{ {
Contract.Requires<ArgumentNullException>(classes != null); _ = classes ?? throw new ArgumentNullException(nameof(classes));
return trigger.Subscribe(x => classes.Set(name, x)); return trigger.Subscribe(x => classes.Set(name, x));
} }

3
src/Avalonia.Controls/Converters/CornerRadiusFilterConverter.cs

@ -1,5 +1,4 @@
#nullable enable using System;
using System;
using System.Globalization; using System.Globalization;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;

4
src/Avalonia.Controls/Converters/MarginMultiplierConverter.cs

@ -16,7 +16,7 @@ namespace Avalonia.Controls.Converters
public bool Bottom { get; set; } = false; public bool Bottom { get; set; } = false;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
if (value is int scalarDepth) if (value is int scalarDepth)
{ {
@ -38,7 +38,7 @@ namespace Avalonia.Controls.Converters
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }

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

@ -11,7 +11,7 @@ namespace Avalonia.Controls.Converters
{ {
public static readonly MenuScrollingVisibilityConverter Instance = new MenuScrollingVisibilityConverter(); public static readonly MenuScrollingVisibilityConverter Instance = new MenuScrollingVisibilityConverter();
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture) public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{ {
if (parameter == null || if (parameter == null ||
values == null || values == null ||

4
src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs

@ -13,7 +13,7 @@ namespace Avalonia.Controls.Converters
/// </summary> /// </summary>
public class PlatformKeyGestureConverter : IValueConverter public class PlatformKeyGestureConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
if (value is null) if (value is null)
{ {
@ -29,7 +29,7 @@ namespace Avalonia.Controls.Converters
} }
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

29
src/Avalonia.Controls/DataValidationErrors.cs

@ -21,8 +21,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the DataValidationErrors.Errors attached property. /// Defines the DataValidationErrors.Errors attached property.
/// </summary> /// </summary>
public static readonly AttachedProperty<IEnumerable<object>> ErrorsProperty = public static readonly AttachedProperty<IEnumerable<object>?> ErrorsProperty =
AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, IEnumerable<object>>("Errors"); AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, IEnumerable<object>?>("Errors");
/// <summary> /// <summary>
/// Defines the DataValidationErrors.HasErrors attached property. /// Defines the DataValidationErrors.HasErrors attached property.
@ -34,15 +34,15 @@ namespace Avalonia.Controls
AvaloniaProperty.Register<DataValidationErrors, IDataTemplate>(nameof(ErrorTemplate)); AvaloniaProperty.Register<DataValidationErrors, IDataTemplate>(nameof(ErrorTemplate));
private Control _owner; private Control? _owner;
public static readonly DirectProperty<DataValidationErrors, Control> OwnerProperty = public static readonly DirectProperty<DataValidationErrors, Control?> OwnerProperty =
AvaloniaProperty.RegisterDirect<DataValidationErrors, Control>( AvaloniaProperty.RegisterDirect<DataValidationErrors, Control?>(
nameof(Owner), nameof(Owner),
o => o.Owner, o => o.Owner,
(o, v) => o.Owner = v); (o, v) => o.Owner = v);
public Control Owner public Control? Owner
{ {
get { return _owner; } get { return _owner; }
set { SetAndRaise(OwnerProperty, ref _owner, value); } set { SetAndRaise(OwnerProperty, ref _owner, value); }
@ -75,7 +75,7 @@ namespace Avalonia.Controls
private static void ErrorsChanged(AvaloniaPropertyChangedEventArgs e) private static void ErrorsChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var control = (Control)e.Sender; var control = (Control)e.Sender;
var errors = (IEnumerable<object>)e.NewValue; var errors = (IEnumerable<object>?)e.NewValue;
var hasErrors = false; var hasErrors = false;
if (errors != null && errors.Any()) if (errors != null && errors.Any())
@ -87,18 +87,18 @@ namespace Avalonia.Controls
{ {
var control = (Control)e.Sender; var control = (Control)e.Sender;
var classes = (IPseudoClasses)control.Classes; var classes = (IPseudoClasses)control.Classes;
classes.Set(":error", (bool)e.NewValue); classes.Set(":error", (bool)e.NewValue!);
} }
public static IEnumerable<object> GetErrors(Control control) public static IEnumerable<object>? GetErrors(Control control)
{ {
return control.GetValue(ErrorsProperty); return control.GetValue(ErrorsProperty);
} }
public static void SetErrors(Control control, IEnumerable<object> errors) public static void SetErrors(Control control, IEnumerable<object>? errors)
{ {
control.SetValue(ErrorsProperty, errors); control.SetValue(ErrorsProperty, errors);
} }
public static void SetError(Control control, Exception error) public static void SetError(Control control, Exception? error)
{ {
SetErrors(control, UnpackException(error)); SetErrors(control, UnpackException(error));
} }
@ -111,7 +111,7 @@ namespace Avalonia.Controls
return control.GetValue(HasErrorsProperty); return control.GetValue(HasErrorsProperty);
} }
private static IEnumerable<object> UnpackException(Exception exception) private static IEnumerable<object>? UnpackException(Exception? exception)
{ {
if (exception != null) if (exception != null)
{ {
@ -132,8 +132,9 @@ namespace Avalonia.Controls
private static object GetExceptionData(Exception exception) private static object GetExceptionData(Exception exception)
{ {
if (exception is DataValidationException dataValidationException) if (exception is DataValidationException dataValidationException &&
return dataValidationException.ErrorData; dataValidationException.ErrorData is object data)
return data;
return exception; return exception;
} }

60
src/Avalonia.Controls/DateTimePickers/DatePicker.cs

@ -93,15 +93,15 @@ namespace Avalonia.Controls
defaultBindingMode: BindingMode.TwoWay); defaultBindingMode: BindingMode.TwoWay);
// Template Items // Template Items
private Button _flyoutButton; private Button? _flyoutButton;
private TextBlock _dayText; private TextBlock? _dayText;
private TextBlock _monthText; private TextBlock? _monthText;
private TextBlock _yearText; private TextBlock? _yearText;
private Grid _container; private Grid? _container;
private Rectangle _spacer1; private Rectangle? _spacer1;
private Rectangle _spacer2; private Rectangle? _spacer2;
private Popup _popup; private Popup? _popup;
private DatePickerPresenter _presenter; private DatePickerPresenter? _presenter;
private bool _areControlsAvailable; private bool _areControlsAvailable;
@ -256,7 +256,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Raised when the <see cref="SelectedDate"/> changes /// Raised when the <see cref="SelectedDate"/> changes
/// </summary> /// </summary>
public event EventHandler<DatePickerSelectedValueChangedEventArgs> SelectedDateChanged; public event EventHandler<DatePickerSelectedValueChangedEventArgs>? SelectedDateChanged;
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
@ -307,16 +307,16 @@ namespace Avalonia.Controls
} }
} }
private void OnDismissPicker(object sender, EventArgs e) private void OnDismissPicker(object? sender, EventArgs e)
{ {
_popup.Close(); _popup!.Close();
Focus(); Focus();
} }
private void OnConfirmed(object sender, EventArgs e) private void OnConfirmed(object? sender, EventArgs e)
{ {
_popup.Close(); _popup!.Close();
SelectedDate = _presenter.Date; SelectedDate = _presenter!.Date;
} }
private void SetGrid() private void SetGrid()
@ -325,7 +325,7 @@ namespace Avalonia.Controls
return; return;
var fmt = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern; var fmt = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
var columns = new List<(TextBlock, int)> var columns = new List<(TextBlock?, int)>
{ {
(_monthText, MonthVisible ? fmt.IndexOf("m", StringComparison.OrdinalIgnoreCase) : -1), (_monthText, MonthVisible ? fmt.IndexOf("m", StringComparison.OrdinalIgnoreCase) : -1),
(_yearText, YearVisible ? fmt.IndexOf("y", StringComparison.OrdinalIgnoreCase) : -1), (_yearText, YearVisible ? fmt.IndexOf("y", StringComparison.OrdinalIgnoreCase) : -1),
@ -366,11 +366,11 @@ namespace Avalonia.Controls
var isSpacer1Visible = columnIndex > 1; var isSpacer1Visible = columnIndex > 1;
var isSpacer2Visible = columnIndex > 2; var isSpacer2Visible = columnIndex > 2;
// ternary conditional operator is used to make sure grid cells will be validated // ternary conditional operator is used to make sure grid cells will be validated
Grid.SetColumn(_spacer1, isSpacer1Visible ? 1 : 0); Grid.SetColumn(_spacer1!, isSpacer1Visible ? 1 : 0);
Grid.SetColumn(_spacer2, isSpacer2Visible ? 3 : 0); Grid.SetColumn(_spacer2!, isSpacer2Visible ? 3 : 0);
_spacer1.IsVisible = isSpacer1Visible; _spacer1!.IsVisible = isSpacer1Visible;
_spacer2.IsVisible = isSpacer2Visible; _spacer2!.IsVisible = isSpacer2Visible;
} }
private void SetSelectedDateText() private void SetSelectedDateText()
@ -382,37 +382,37 @@ namespace Avalonia.Controls
{ {
PseudoClasses.Set(":hasnodate", false); PseudoClasses.Set(":hasnodate", false);
var selDate = SelectedDate.Value; var selDate = SelectedDate.Value;
_monthText.Text = selDate.ToString(MonthFormat); _monthText!.Text = selDate.ToString(MonthFormat);
_yearText.Text = selDate.ToString(YearFormat); _yearText!.Text = selDate.ToString(YearFormat);
_dayText.Text = selDate.ToString(DayFormat); _dayText!.Text = selDate.ToString(DayFormat);
} }
else else
{ {
PseudoClasses.Set(":hasnodate", true); PseudoClasses.Set(":hasnodate", true);
_monthText.Text = "month"; _monthText!.Text = "month";
_yearText.Text = "year"; _yearText!.Text = "year";
_dayText.Text = "day"; _dayText!.Text = "day";
} }
} }
private void OnFlyoutButtonClicked(object sender, RoutedEventArgs e) private void OnFlyoutButtonClicked(object? sender, RoutedEventArgs e)
{ {
if (_presenter == null) if (_presenter == null)
throw new InvalidOperationException("No DatePickerPresenter found"); throw new InvalidOperationException("No DatePickerPresenter found");
_presenter.Date = SelectedDate ?? DateTimeOffset.Now; _presenter.Date = SelectedDate ?? DateTimeOffset.Now;
_popup.IsOpen = true; _popup!.IsOpen = true;
var deltaY = _presenter.GetOffsetForPopup(); var deltaY = _presenter.GetOffsetForPopup();
// The extra 5 px I think is related to default popup placement behavior // The extra 5 px I think is related to default popup placement behavior
_popup.Host.ConfigurePosition(_popup.PlacementTarget, PlacementMode.AnchorAndGravity, new Point(0, deltaY + 5), _popup!.Host!.ConfigurePosition(_popup.PlacementTarget!, PlacementMode.AnchorAndGravity, new Point(0, deltaY + 5),
Primitives.PopupPositioning.PopupAnchor.Bottom, Primitives.PopupPositioning.PopupGravity.Bottom, Primitives.PopupPositioning.PopupAnchor.Bottom, Primitives.PopupPositioning.PopupGravity.Bottom,
Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY); Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY);
} }
protected virtual void OnSelectedDateChanged(object sender, DatePickerSelectedValueChangedEventArgs e) protected virtual void OnSelectedDateChanged(object? sender, DatePickerSelectedValueChangedEventArgs e)
{ {
SelectedDateChanged?.Invoke(sender, e); SelectedDateChanged?.Invoke(sender, e);
} }

103
src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs

@ -78,23 +78,23 @@ namespace Avalonia.Controls
x.YearVisible, (x, v) => x.YearVisible = v); x.YearVisible, (x, v) => x.YearVisible = v);
// Template Items // Template Items
private Grid _pickerContainer; private Grid? _pickerContainer;
private Button _acceptButton; private Button? _acceptButton;
private Button _dismissButton; private Button? _dismissButton;
private Rectangle _spacer1; private Rectangle? _spacer1;
private Rectangle _spacer2; private Rectangle? _spacer2;
private Panel _monthHost; private Panel? _monthHost;
private Panel _yearHost; private Panel? _yearHost;
private Panel _dayHost; private Panel? _dayHost;
private DateTimePickerPanel _monthSelector; private DateTimePickerPanel? _monthSelector;
private DateTimePickerPanel _yearSelector; private DateTimePickerPanel? _yearSelector;
private DateTimePickerPanel _daySelector; private DateTimePickerPanel? _daySelector;
private Button _monthUpButton; private Button? _monthUpButton;
private Button _dayUpButton; private Button? _dayUpButton;
private Button _yearUpButton; private Button? _yearUpButton;
private Button _monthDownButton; private Button? _monthDownButton;
private Button _dayDownButton; private Button? _dayDownButton;
private Button _yearDownButton; private Button? _yearDownButton;
private DateTimeOffset _date; private DateTimeOffset _date;
private string _dayFormat = "%d"; private string _dayFormat = "%d";
@ -308,9 +308,12 @@ namespace Avalonia.Controls
e.Handled = true; e.Handled = true;
break; break;
case Key.Tab: case Key.Tab:
var nextFocus = KeyboardNavigationHandler.GetNext(FocusManager.Instance.Current, NavigationDirection.Next); if (FocusManager.Instance?.Current is IInputElement focus)
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None); {
e.Handled = true; var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
e.Handled = true;
}
break; break;
case Key.Enter: case Key.Enter:
Date = _syncDate; Date = _syncDate;
@ -332,13 +335,13 @@ namespace Avalonia.Controls
_suppressUpdateSelection = true; _suppressUpdateSelection = true;
_monthSelector.MaximumValue = 12; _monthSelector!.MaximumValue = 12;
_monthSelector.MinimumValue = 1; _monthSelector.MinimumValue = 1;
_monthSelector.ItemFormat = MonthFormat; _monthSelector.ItemFormat = MonthFormat;
_daySelector.ItemFormat = DayFormat; _daySelector!.ItemFormat = DayFormat;
_yearSelector.MaximumValue = MaxYear.Year; _yearSelector!.MaximumValue = MaxYear.Year;
_yearSelector.MinimumValue = MinYear.Year; _yearSelector.MinimumValue = MinYear.Year;
_yearSelector.ItemFormat = YearFormat; _yearSelector.ItemFormat = YearFormat;
@ -375,7 +378,7 @@ namespace Avalonia.Controls
private void SetGrid() private void SetGrid()
{ {
var fmt = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern; var fmt = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
var columns = new List<(Panel, int)> var columns = new List<(Panel?, int)>
{ {
(_monthHost, MonthVisible ? fmt.IndexOf("m", StringComparison.OrdinalIgnoreCase) : -1), (_monthHost, MonthVisible ? fmt.IndexOf("m", StringComparison.OrdinalIgnoreCase) : -1),
(_yearHost, YearVisible ? fmt.IndexOf("y", StringComparison.OrdinalIgnoreCase) : -1), (_yearHost, YearVisible ? fmt.IndexOf("y", StringComparison.OrdinalIgnoreCase) : -1),
@ -383,7 +386,7 @@ namespace Avalonia.Controls
}; };
columns.Sort((x, y) => x.Item2 - y.Item2); columns.Sort((x, y) => x.Item2 - y.Item2);
_pickerContainer.ColumnDefinitions.Clear(); _pickerContainer!.ColumnDefinitions.Clear();
var columnIndex = 0; var columnIndex = 0;
@ -416,18 +419,18 @@ namespace Avalonia.Controls
var isSpacer1Visible = columnIndex > 1; var isSpacer1Visible = columnIndex > 1;
var isSpacer2Visible = columnIndex > 2; var isSpacer2Visible = columnIndex > 2;
// ternary conditional operator is used to make sure grid cells will be validated // ternary conditional operator is used to make sure grid cells will be validated
Grid.SetColumn(_spacer1, isSpacer1Visible ? 1 : 0); Grid.SetColumn(_spacer1!, isSpacer1Visible ? 1 : 0);
Grid.SetColumn(_spacer2, isSpacer2Visible ? 3 : 0); Grid.SetColumn(_spacer2!, isSpacer2Visible ? 3 : 0);
_spacer1.IsVisible = isSpacer1Visible; _spacer1!.IsVisible = isSpacer1Visible;
_spacer2.IsVisible = isSpacer2Visible; _spacer2!.IsVisible = isSpacer2Visible;
} }
private void SetInitialFocus() private void SetInitialFocus()
{ {
int monthCol = MonthVisible ? Grid.GetColumn(_monthHost) : int.MaxValue; int monthCol = MonthVisible ? Grid.GetColumn(_monthHost!) : int.MaxValue;
int dayCol = DayVisible ? Grid.GetColumn(_dayHost) : int.MaxValue; int dayCol = DayVisible ? Grid.GetColumn(_dayHost!) : int.MaxValue;
int yearCol = YearVisible ? Grid.GetColumn(_yearHost) : int.MaxValue; int yearCol = YearVisible ? Grid.GetColumn(_yearHost!) : int.MaxValue;
if (monthCol < dayCol && monthCol < yearCol) if (monthCol < dayCol && monthCol < yearCol)
{ {
@ -443,39 +446,39 @@ namespace Avalonia.Controls
} }
} }
private void OnDismissButtonClicked(object sender, RoutedEventArgs e) private void OnDismissButtonClicked(object? sender, RoutedEventArgs e)
{ {
OnDismiss(); OnDismiss();
} }
private void OnAcceptButtonClicked(object sender, RoutedEventArgs e) private void OnAcceptButtonClicked(object? sender, RoutedEventArgs e)
{ {
Date = _syncDate; Date = _syncDate;
OnConfirmed(); OnConfirmed();
} }
private void OnSelectorButtonClick(object sender, RoutedEventArgs e) private void OnSelectorButtonClick(object? sender, RoutedEventArgs e)
{ {
if (sender == _monthUpButton) if (sender == _monthUpButton)
_monthSelector.ScrollUp(); _monthSelector!.ScrollUp();
else if (sender == _monthDownButton) else if (sender == _monthDownButton)
_monthSelector.ScrollDown(); _monthSelector!.ScrollDown();
else if (sender == _yearUpButton) else if (sender == _yearUpButton)
_yearSelector.ScrollUp(); _yearSelector!.ScrollUp();
else if (sender == _yearDownButton) else if (sender == _yearDownButton)
_yearSelector.ScrollDown(); _yearSelector!.ScrollDown();
else if (sender == _dayUpButton) else if (sender == _dayUpButton)
_daySelector.ScrollUp(); _daySelector!.ScrollUp();
else if (sender == _dayDownButton) else if (sender == _dayDownButton)
_daySelector.ScrollDown(); _daySelector!.ScrollDown();
} }
private void OnYearChanged(object sender, EventArgs e) private void OnYearChanged(object? sender, EventArgs e)
{ {
if (_suppressUpdateSelection) if (_suppressUpdateSelection)
return; return;
int maxDays = _calendar.GetDaysInMonth(_yearSelector.SelectedValue, _syncDate.Month); int maxDays = _calendar.GetDaysInMonth(_yearSelector!.SelectedValue, _syncDate.Month);
var newDate = new DateTimeOffset(_yearSelector.SelectedValue, _syncDate.Month, var newDate = new DateTimeOffset(_yearSelector.SelectedValue, _syncDate.Month,
_syncDate.Day > maxDays ? maxDays : _syncDate.Day, 0, 0, 0, _syncDate.Offset); _syncDate.Day > maxDays ? maxDays : _syncDate.Day, 0, 0, 0, _syncDate.Offset);
@ -487,7 +490,7 @@ namespace Avalonia.Controls
_suppressUpdateSelection = true; _suppressUpdateSelection = true;
_daySelector.FormatDate = newDate.Date; _daySelector!.FormatDate = newDate.Date;
if (_daySelector.MaximumValue != maxDays) if (_daySelector.MaximumValue != maxDays)
_daySelector.MaximumValue = maxDays; _daySelector.MaximumValue = maxDays;
@ -497,19 +500,19 @@ namespace Avalonia.Controls
_suppressUpdateSelection = false; _suppressUpdateSelection = false;
} }
private void OnDayChanged(object sender, EventArgs e) private void OnDayChanged(object? sender, EventArgs e)
{ {
if (_suppressUpdateSelection) if (_suppressUpdateSelection)
return; return;
_syncDate = new DateTimeOffset(_syncDate.Year, _syncDate.Month, _daySelector.SelectedValue, 0, 0, 0, _syncDate.Offset); _syncDate = new DateTimeOffset(_syncDate.Year, _syncDate.Month, _daySelector!.SelectedValue, 0, 0, 0, _syncDate.Offset);
} }
private void OnMonthChanged(object sender, EventArgs e) private void OnMonthChanged(object? sender, EventArgs e)
{ {
if (_suppressUpdateSelection) if (_suppressUpdateSelection)
return; return;
int maxDays = _calendar.GetDaysInMonth(_syncDate.Year, _monthSelector.SelectedValue); int maxDays = _calendar.GetDaysInMonth(_syncDate.Year, _monthSelector!.SelectedValue);
var newDate = new DateTimeOffset(_syncDate.Year, _monthSelector.SelectedValue, var newDate = new DateTimeOffset(_syncDate.Year, _monthSelector.SelectedValue,
_syncDate.Day > maxDays ? maxDays : _syncDate.Day, 0, 0, 0, _syncDate.Offset); _syncDate.Day > maxDays ? maxDays : _syncDate.Day, 0, 0, 0, _syncDate.Offset);
@ -521,7 +524,7 @@ namespace Avalonia.Controls
_suppressUpdateSelection = true; _suppressUpdateSelection = true;
_daySelector.FormatDate = newDate.Date; _daySelector!.FormatDate = newDate.Date;
_syncDate = newDate; _syncDate = newDate;
if (_daySelector.MaximumValue != maxDays) if (_daySelector.MaximumValue != maxDays)
@ -535,7 +538,7 @@ namespace Avalonia.Controls
internal double GetOffsetForPopup() internal double GetOffsetForPopup()
{ {
var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41; var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41;
return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_monthSelector.ItemHeight / 2); return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_monthSelector!.ItemHeight / 2);
} }
} }
} }

28
src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs

@ -58,7 +58,7 @@ namespace Avalonia.Controls.Primitives
private Vector _offset; private Vector _offset;
private bool _hasInit; private bool _hasInit;
private bool _suppressUpdateOffset; private bool _suppressUpdateOffset;
private ListBoxItem _pressedItem; private ListBoxItem? _pressedItem;
public DateTimePickerPanel() public DateTimePickerPanel()
{ {
@ -271,9 +271,9 @@ namespace Avalonia.Controls.Primitives
public Size Viewport => new Size(0, ItemHeight); public Size Viewport => new Size(0, ItemHeight);
public event EventHandler ScrollInvalidated; public event EventHandler? ScrollInvalidated;
public event EventHandler SelectionChanged; public event EventHandler? SelectionChanged;
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
@ -523,40 +523,44 @@ namespace Avalonia.Controls.Primitives
return newValue; return newValue;
} }
private void OnItemPointerDown(object sender, PointerPressedEventArgs e) private void OnItemPointerDown(object? sender, PointerPressedEventArgs e)
{ {
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed &&
e.Source is IVisual source)
{ {
_pressedItem = GetItemFromSource((IVisual)e.Source); _pressedItem = GetItemFromSource(source);
e.Handled = true; e.Handled = true;
} }
} }
private void OnItemPointerUp(object sender, PointerReleasedEventArgs e) private void OnItemPointerUp(object? sender, PointerReleasedEventArgs e)
{ {
if (e.GetCurrentPoint(this).Properties.PointerUpdateKind == PointerUpdateKind.LeftButtonReleased && if (e.GetCurrentPoint(this).Properties.PointerUpdateKind == PointerUpdateKind.LeftButtonReleased &&
_pressedItem != null) _pressedItem != null &&
e.Source is IVisual source &&
GetItemFromSource(source) is ListBoxItem item &&
item.Tag is int tag)
{ {
SelectedValue = (int)GetItemFromSource((IVisual)e.Source).Tag; SelectedValue = tag;
_pressedItem = null; _pressedItem = null;
e.Handled = true; e.Handled = true;
} }
} }
//Helper to get ListBoxItem from pointerevent source //Helper to get ListBoxItem from pointerevent source
private ListBoxItem GetItemFromSource(IVisual src) private ListBoxItem? GetItemFromSource(IVisual src)
{ {
var item = src; var item = src;
while (item != null && !(item is ListBoxItem)) while (item != null && !(item is ListBoxItem))
{ {
item = item.VisualParent; item = item.VisualParent;
} }
return (ListBoxItem)item; return (ListBoxItem?)item;
} }
public bool BringIntoView(IControl target, Rect targetRect) { return false; } public bool BringIntoView(IControl target, Rect targetRect) { return false; }
public IControl GetControlInDirection(NavigationDirection direction, IControl from) { return null; } public IControl? GetControlInDirection(NavigationDirection direction, IControl from) { return null; }
public void RaiseScrollInvalidated(EventArgs e) public void RaiseScrollInvalidated(EventArgs e)
{ {

6
src/Avalonia.Controls/DateTimePickers/PickerPresenterBase.cs

@ -16,10 +16,10 @@ namespace Avalonia.Controls.Primitives
protected virtual void OnDismiss() protected virtual void OnDismiss()
{ {
Dismissed.Invoke(this, EventArgs.Empty); Dismissed?.Invoke(this, EventArgs.Empty);
} }
public event EventHandler Confirmed; public event EventHandler? Confirmed;
public event EventHandler Dismissed; public event EventHandler? Dismissed;
} }
} }

56
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@ -49,18 +49,18 @@ namespace Avalonia.Controls
defaultBindingMode: BindingMode.TwoWay); defaultBindingMode: BindingMode.TwoWay);
// Template Items // Template Items
private TimePickerPresenter _presenter; private TimePickerPresenter? _presenter;
private Button _flyoutButton; private Button? _flyoutButton;
private Border _firstPickerHost; private Border? _firstPickerHost;
private Border _secondPickerHost; private Border? _secondPickerHost;
private Border _thirdPickerHost; private Border? _thirdPickerHost;
private TextBlock _hourText; private TextBlock? _hourText;
private TextBlock _minuteText; private TextBlock? _minuteText;
private TextBlock _periodText; private TextBlock? _periodText;
private Rectangle _firstSplitter; private Rectangle? _firstSplitter;
private Rectangle _secondSplitter; private Rectangle? _secondSplitter;
private Grid _contentGrid; private Grid? _contentGrid;
private Popup _popup; private Popup? _popup;
private TimeSpan? _selectedTime; private TimeSpan? _selectedTime;
private int _minuteIncrement = 1; private int _minuteIncrement = 1;
@ -142,7 +142,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Raised when the <see cref="SelectedTime"/> property changes /// Raised when the <see cref="SelectedTime"/> property changes
/// </summary> /// </summary>
public event EventHandler<TimePickerSelectedValueChangedEventArgs> SelectedTimeChanged; public event EventHandler<TimePickerSelectedValueChangedEventArgs>? SelectedTimeChanged;
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
@ -200,15 +200,15 @@ namespace Avalonia.Controls
var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *"; var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *";
_contentGrid.ColumnDefinitions = new ColumnDefinitions(columnsD); _contentGrid.ColumnDefinitions = new ColumnDefinitions(columnsD);
_thirdPickerHost.IsVisible = !use24HourClock; _thirdPickerHost!.IsVisible = !use24HourClock;
_secondSplitter.IsVisible = !use24HourClock; _secondSplitter!.IsVisible = !use24HourClock;
Grid.SetColumn(_firstPickerHost, 0); Grid.SetColumn(_firstPickerHost!, 0);
Grid.SetColumn(_secondPickerHost, 2); Grid.SetColumn(_secondPickerHost!, 2);
Grid.SetColumn(_thirdPickerHost, use24HourClock ? 0 : 4); Grid.SetColumn(_thirdPickerHost, use24HourClock ? 0 : 4);
Grid.SetColumn(_firstSplitter, 1); Grid.SetColumn(_firstSplitter!, 1);
Grid.SetColumn(_secondSplitter, use24HourClock ? 0 : 3); Grid.SetColumn(_secondSplitter, use24HourClock ? 0 : 3);
} }
@ -220,7 +220,7 @@ namespace Avalonia.Controls
var time = SelectedTime; var time = SelectedTime;
if (time.HasValue) if (time.HasValue)
{ {
var newTime = SelectedTime.Value; var newTime = SelectedTime!.Value;
if (ClockIdentifier == "12HourClock") if (ClockIdentifier == "12HourClock")
{ {
@ -252,30 +252,30 @@ namespace Avalonia.Controls
SelectedTimeChanged?.Invoke(this, new TimePickerSelectedValueChangedEventArgs(oldTime, newTime)); SelectedTimeChanged?.Invoke(this, new TimePickerSelectedValueChangedEventArgs(oldTime, newTime));
} }
private void OnFlyoutButtonClicked(object sender, Interactivity.RoutedEventArgs e) private void OnFlyoutButtonClicked(object? sender, Interactivity.RoutedEventArgs e)
{ {
_presenter.Time = SelectedTime ?? DateTime.Now.TimeOfDay; _presenter!.Time = SelectedTime ?? DateTime.Now.TimeOfDay;
_popup.IsOpen = true; _popup!.IsOpen = true;
var deltaY = _presenter.GetOffsetForPopup(); var deltaY = _presenter.GetOffsetForPopup();
// The extra 5 px I think is related to default popup placement behavior // The extra 5 px I think is related to default popup placement behavior
_popup.Host.ConfigurePosition(_popup.PlacementTarget, PlacementMode.AnchorAndGravity, new Point(0, deltaY + 5), _popup.Host!.ConfigurePosition(_popup.PlacementTarget!, PlacementMode.AnchorAndGravity, new Point(0, deltaY + 5),
Primitives.PopupPositioning.PopupAnchor.Bottom, Primitives.PopupPositioning.PopupGravity.Bottom, Primitives.PopupPositioning.PopupAnchor.Bottom, Primitives.PopupPositioning.PopupGravity.Bottom,
Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY); Primitives.PopupPositioning.PopupPositionerConstraintAdjustment.SlideY);
} }
private void OnDismissPicker(object sender, EventArgs e) private void OnDismissPicker(object? sender, EventArgs e)
{ {
_popup.Close(); _popup!.Close();
Focus(); Focus();
} }
private void OnConfirmed(object sender, EventArgs e) private void OnConfirmed(object? sender, EventArgs e)
{ {
_popup.Close(); _popup!.Close();
SelectedTime = _presenter.Time; SelectedTime = _presenter!.Time;
} }
} }
} }

75
src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs

@ -40,20 +40,20 @@ namespace Avalonia.Controls
} }
// TemplateItems // TemplateItems
private Grid _pickerContainer; private Grid? _pickerContainer;
private Button _acceptButton; private Button? _acceptButton;
private Button _dismissButton; private Button? _dismissButton;
private Rectangle _spacer2; private Rectangle? _spacer2;
private Panel _periodHost; private Panel? _periodHost;
private DateTimePickerPanel _hourSelector; private DateTimePickerPanel? _hourSelector;
private DateTimePickerPanel _minuteSelector; private DateTimePickerPanel? _minuteSelector;
private DateTimePickerPanel _periodSelector; private DateTimePickerPanel? _periodSelector;
private Button _hourUpButton; private Button? _hourUpButton;
private Button _minuteUpButton; private Button? _minuteUpButton;
private Button _periodUpButton; private Button? _periodUpButton;
private Button _hourDownButton; private Button? _hourDownButton;
private Button _minuteDownButton; private Button? _minuteDownButton;
private Button _periodDownButton; private Button? _periodDownButton;
// Backing Fields // Backing Fields
private TimeSpan _time; private TimeSpan _time;
@ -156,9 +156,12 @@ namespace Avalonia.Controls
e.Handled = true; e.Handled = true;
break; break;
case Key.Tab: case Key.Tab:
var nextFocus = KeyboardNavigationHandler.GetNext(FocusManager.Instance.Current, NavigationDirection.Next); if (FocusManager.Instance?.Current is IInputElement focus)
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None); {
e.Handled = true; var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
e.Handled = true;
}
break; break;
case Key.Enter: case Key.Enter:
OnConfirmed(); OnConfirmed();
@ -170,9 +173,9 @@ namespace Avalonia.Controls
protected override void OnConfirmed() protected override void OnConfirmed()
{ {
var hr = _hourSelector.SelectedValue; var hr = _hourSelector!.SelectedValue;
var min = _minuteSelector.SelectedValue; var min = _minuteSelector!.SelectedValue;
var per = _periodSelector.SelectedValue; var per = _periodSelector!.SelectedValue;
if (ClockIdentifier == "12HourClock") if (ClockIdentifier == "12HourClock")
{ {
@ -190,20 +193,20 @@ namespace Avalonia.Controls
return; return;
bool clock12 = ClockIdentifier == "12HourClock"; bool clock12 = ClockIdentifier == "12HourClock";
_hourSelector.MaximumValue = clock12 ? 12 : 23; _hourSelector!.MaximumValue = clock12 ? 12 : 23;
_hourSelector.MinimumValue = clock12 ? 1 : 0; _hourSelector.MinimumValue = clock12 ? 1 : 0;
_hourSelector.ItemFormat = "%h"; _hourSelector.ItemFormat = "%h";
var hr = Time.Hours; var hr = Time.Hours;
_hourSelector.SelectedValue = !clock12 ? hr : _hourSelector.SelectedValue = !clock12 ? hr :
hr > 12 ? hr - 12 : hr == 0 ? 12 : hr; hr > 12 ? hr - 12 : hr == 0 ? 12 : hr;
_minuteSelector.MaximumValue = 59; _minuteSelector!.MaximumValue = 59;
_minuteSelector.MinimumValue = 0; _minuteSelector.MinimumValue = 0;
_minuteSelector.Increment = MinuteIncrement; _minuteSelector.Increment = MinuteIncrement;
_minuteSelector.SelectedValue = Time.Minutes; _minuteSelector.SelectedValue = Time.Minutes;
_minuteSelector.ItemFormat = "mm"; _minuteSelector.ItemFormat = "mm";
_periodSelector.MaximumValue = 1; _periodSelector!.MaximumValue = 1;
_periodSelector.MinimumValue = 0; _periodSelector.MinimumValue = 0;
_periodSelector.SelectedValue = hr >= 12 ? 1 : 0; _periodSelector.SelectedValue = hr >= 12 ? 1 : 0;
@ -216,45 +219,45 @@ namespace Avalonia.Controls
bool use24HourClock = ClockIdentifier == "24HourClock"; bool use24HourClock = ClockIdentifier == "24HourClock";
var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *"; var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *";
_pickerContainer.ColumnDefinitions = new ColumnDefinitions(columnsD); _pickerContainer!.ColumnDefinitions = new ColumnDefinitions(columnsD);
_spacer2.IsVisible = !use24HourClock; _spacer2!.IsVisible = !use24HourClock;
_periodHost.IsVisible = !use24HourClock; _periodHost!.IsVisible = !use24HourClock;
Grid.SetColumn(_spacer2, use24HourClock ? 0 : 3); Grid.SetColumn(_spacer2, use24HourClock ? 0 : 3);
Grid.SetColumn(_periodHost, use24HourClock ? 0 : 4); Grid.SetColumn(_periodHost, use24HourClock ? 0 : 4);
} }
private void OnDismissButtonClicked(object sender, RoutedEventArgs e) private void OnDismissButtonClicked(object? sender, RoutedEventArgs e)
{ {
OnDismiss(); OnDismiss();
} }
private void OnAcceptButtonClicked(object sender, RoutedEventArgs e) private void OnAcceptButtonClicked(object? sender, RoutedEventArgs e)
{ {
OnConfirmed(); OnConfirmed();
} }
private void OnSelectorButtonClick(object sender, RoutedEventArgs e) private void OnSelectorButtonClick(object? sender, RoutedEventArgs e)
{ {
if (sender == _hourUpButton) if (sender == _hourUpButton)
_hourSelector.ScrollUp(); _hourSelector!.ScrollUp();
else if (sender == _hourDownButton) else if (sender == _hourDownButton)
_hourSelector.ScrollDown(); _hourSelector!.ScrollDown();
else if (sender == _minuteUpButton) else if (sender == _minuteUpButton)
_minuteSelector.ScrollUp(); _minuteSelector!.ScrollUp();
else if (sender == _minuteDownButton) else if (sender == _minuteDownButton)
_minuteSelector.ScrollDown(); _minuteSelector!.ScrollDown();
else if (sender == _periodUpButton) else if (sender == _periodUpButton)
_periodSelector.ScrollUp(); _periodSelector!.ScrollUp();
else if (sender == _periodDownButton) else if (sender == _periodDownButton)
_periodSelector.ScrollDown(); _periodSelector!.ScrollDown();
} }
internal double GetOffsetForPopup() internal double GetOffsetForPopup()
{ {
var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41; var acceptDismissButtonHeight = _acceptButton != null ? _acceptButton.Bounds.Height : 41;
return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_hourSelector.ItemHeight / 2); return -(MaxHeight - acceptDismissButtonHeight) / 2 - (_hourSelector!.ItemHeight / 2);
} }
} }
} }

10
src/Avalonia.Controls/Decorator.cs

@ -11,8 +11,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Child"/> property. /// Defines the <see cref="Child"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IControl> ChildProperty = public static readonly StyledProperty<IControl?> ChildProperty =
AvaloniaProperty.Register<Decorator, IControl>(nameof(Child)); AvaloniaProperty.Register<Decorator, IControl?>(nameof(Child));
/// <summary> /// <summary>
/// Defines the <see cref="Padding"/> property. /// Defines the <see cref="Padding"/> property.
@ -33,7 +33,7 @@ namespace Avalonia.Controls
/// Gets or sets the decorated control. /// Gets or sets the decorated control.
/// </summary> /// </summary>
[Content] [Content]
public IControl Child public IControl? Child
{ {
get { return GetValue(ChildProperty); } get { return GetValue(ChildProperty); }
set { SetValue(ChildProperty, value); } set { SetValue(ChildProperty, value); }
@ -66,8 +66,8 @@ namespace Avalonia.Controls
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void ChildChanged(AvaloniaPropertyChangedEventArgs e) private void ChildChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var oldChild = (Control)e.OldValue; var oldChild = (Control?)e.OldValue;
var newChild = (Control)e.NewValue; var newChild = (Control?)e.NewValue;
if (oldChild != null) if (oldChild != null)
{ {

40
src/Avalonia.Controls/DefinitionBase.cs

@ -39,7 +39,7 @@ namespace Avalonia.Controls
string sharedSizeGroupId = SharedSizeGroup; string sharedSizeGroupId = SharedSizeGroup;
if (sharedSizeGroupId != null) if (sharedSizeGroupId != null)
{ {
SharedSizeScope privateSharedSizeScope = PrivateSharedSizeScope; SharedSizeScope? privateSharedSizeScope = PrivateSharedSizeScope;
if (privateSharedSizeScope != null) if (privateSharedSizeScope != null)
{ {
_sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId); _sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
@ -104,7 +104,7 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
internal static void OnIsSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) internal static void OnIsSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{ {
if ((bool)e.NewValue) if ((bool)e.NewValue!)
{ {
SharedSizeScope sharedStatesCollection = new SharedSizeScope(); SharedSizeScope sharedStatesCollection = new SharedSizeScope();
d.SetValue(PrivateSharedSizeScopeProperty, sharedStatesCollection); d.SetValue(PrivateSharedSizeScopeProperty, sharedStatesCollection);
@ -131,8 +131,8 @@ namespace Avalonia.Controls
} }
else else
{ {
GridUnitType oldUnitType = ((GridLength)e.OldValue).GridUnitType; GridUnitType oldUnitType = ((GridLength)e.OldValue!).GridUnitType;
GridUnitType newUnitType = ((GridLength)e.NewValue).GridUnitType; GridUnitType newUnitType = ((GridLength)e.NewValue!).GridUnitType;
if (oldUnitType != newUnitType) if (oldUnitType != newUnitType)
{ {
@ -300,7 +300,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
internal abstract double UserMaxSizeValueCache { get; } internal abstract double UserMaxSizeValueCache { get; }
internal Grid Parent { get; set; } internal Grid? Parent { get; set; }
/// <summary> /// <summary>
/// SetFlags is used to set or unset one or multiple /// SetFlags is used to set or unset one or multiple
@ -326,7 +326,7 @@ namespace Avalonia.Controls
if (definition.Parent != null) if (definition.Parent != null)
{ {
string sharedSizeGroupId = (string)e.NewValue; string sharedSizeGroupId = (string)e.NewValue!;
if (definition._sharedState != null) if (definition._sharedState != null)
{ {
@ -338,7 +338,7 @@ namespace Avalonia.Controls
if ((definition._sharedState == null) && (sharedSizeGroupId != null)) if ((definition._sharedState == null) && (sharedSizeGroupId != null))
{ {
SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope; SharedSizeScope? privateSharedSizeScope = definition.PrivateSharedSizeScope;
if (privateSharedSizeScope != null) if (privateSharedSizeScope != null)
{ {
// if definition is not registered and both: shared size group id AND private shared scope // if definition is not registered and both: shared size group id AND private shared scope
@ -402,7 +402,7 @@ namespace Avalonia.Controls
if (definition.Parent != null) if (definition.Parent != null)
{ {
SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue; SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue!;
if (definition._sharedState != null) if (definition._sharedState != null)
{ {
@ -429,9 +429,9 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Private getter of shared state collection dynamic property. /// Private getter of shared state collection dynamic property.
/// </summary> /// </summary>
private SharedSizeScope PrivateSharedSizeScope private SharedSizeScope? PrivateSharedSizeScope
{ {
get { return (SharedSizeScope)GetValue(PrivateSharedSizeScopeProperty); } get { return (SharedSizeScope?)GetValue(PrivateSharedSizeScopeProperty); }
} }
/// <summary> /// <summary>
@ -462,7 +462,7 @@ namespace Avalonia.Controls
private double _sizeCache; // cache used for various purposes (sorting, caching, etc) during calculations private double _sizeCache; // cache used for various purposes (sorting, caching, etc) during calculations
private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case) private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case)
private SharedSizeState _sharedState; // reference to shared state object this instance is registered with private SharedSizeState? _sharedState; // reference to shared state object this instance is registered with
[System.Flags] [System.Flags]
private enum Flags : byte private enum Flags : byte
@ -488,7 +488,7 @@ namespace Avalonia.Controls
// check that sharedSizeGroup is not default // check that sharedSizeGroup is not default
Debug.Assert(sharedSizeGroup != null); Debug.Assert(sharedSizeGroup != null);
SharedSizeState sharedState = _registry[sharedSizeGroup] as SharedSizeState; SharedSizeState? sharedState = _registry[sharedSizeGroup] as SharedSizeState;
if (sharedState == null) if (sharedState == null)
{ {
sharedState = new SharedSizeState(this, sharedSizeGroup); sharedState = new SharedSizeState(this, sharedSizeGroup);
@ -567,7 +567,7 @@ namespace Avalonia.Controls
{ {
for (int i = 0, count = _registry.Count; i < count; ++i) for (int i = 0, count = _registry.Count; i < count; ++i)
{ {
Grid parentGrid = (Grid)(_registry[i].Parent); Grid parentGrid = (Grid)(_registry[i].Parent!);
parentGrid.Invalidate(); parentGrid.Invalidate();
} }
_broadcastInvalidation = false; _broadcastInvalidation = false;
@ -645,7 +645,7 @@ namespace Avalonia.Controls
/// OnLayoutUpdated handler. Validates that all participating definitions /// OnLayoutUpdated handler. Validates that all participating definitions
/// have updated min size value. Forces another layout update cycle if needed. /// have updated min size value. Forces another layout update cycle if needed.
/// </summary> /// </summary>
private void OnLayoutUpdated(object sender, EventArgs e) private void OnLayoutUpdated(object? sender, EventArgs e)
{ {
double sharedMinSize = 0; double sharedMinSize = 0;
@ -707,14 +707,14 @@ namespace Avalonia.Controls
if(!measureIsValid) if(!measureIsValid)
{ {
definitionBase.Parent.InvalidateMeasure(); definitionBase.Parent!.InvalidateMeasure();
} }
else if (!MathUtilities.AreClose(sharedMinSize, definitionBase.SizeCache)) else if (!MathUtilities.AreClose(sharedMinSize, definitionBase.SizeCache))
{ {
// if measure is valid then also need to check arrange. // if measure is valid then also need to check arrange.
// Note: definitionBase.SizeCache is volatile but at this point // Note: definitionBase.SizeCache is volatile but at this point
// it contains up-to-date final size // it contains up-to-date final size
definitionBase.Parent.InvalidateArrange(); definitionBase.Parent!.InvalidateArrange();
} }
// now we can restore the invariant, and clear the layout flag // now we can restore the invariant, and clear the layout flag
@ -724,7 +724,7 @@ namespace Avalonia.Controls
_minSize = sharedMinSize; _minSize = sharedMinSize;
_layoutUpdatedHost.LayoutUpdated -= _layoutUpdated; _layoutUpdatedHost!.LayoutUpdated -= _layoutUpdated;
_layoutUpdatedHost = null; _layoutUpdatedHost = null;
_broadcastInvalidation = true; _broadcastInvalidation = true;
@ -743,7 +743,7 @@ namespace Avalonia.Controls
private readonly EventHandler _layoutUpdated; private readonly EventHandler _layoutUpdated;
// Control for which layout updated event handler is registered // Control for which layout updated event handler is registered
private Control _layoutUpdatedHost; private Control? _layoutUpdatedHost;
// "true" when broadcasting of invalidation is needed // "true" when broadcasting of invalidation is needed
private bool _broadcastInvalidation; private bool _broadcastInvalidation;
@ -762,8 +762,8 @@ namespace Avalonia.Controls
/// Private shared size scope property holds a collection of shared state objects for the a given shared size scope. /// Private shared size scope property holds a collection of shared state objects for the a given shared size scope.
/// <see cref="OnIsSharedSizeScopePropertyChanged"/> /// <see cref="OnIsSharedSizeScopePropertyChanged"/>
/// </summary> /// </summary>
internal static readonly AttachedProperty<SharedSizeScope> PrivateSharedSizeScopeProperty = internal static readonly AttachedProperty<SharedSizeScope?> PrivateSharedSizeScopeProperty =
AvaloniaProperty.RegisterAttached<DefinitionBase, Control, SharedSizeScope>( AvaloniaProperty.RegisterAttached<DefinitionBase, Control, SharedSizeScope?>(
"PrivateSharedSizeScope", "PrivateSharedSizeScope",
defaultValue: null, defaultValue: null,
inherits: true); inherits: true);

6
src/Avalonia.Controls/DefinitionList.cs

@ -2,8 +2,6 @@ using System.Collections;
using System.Collections.Specialized; using System.Collections.Specialized;
using Avalonia.Collections; using Avalonia.Collections;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
public abstract class DefinitionList<T> : AvaloniaList<T> where T : DefinitionBase public abstract class DefinitionList<T> : AvaloniaList<T> where T : DefinitionBase
@ -36,7 +34,7 @@ namespace Avalonia.Controls
} }
} }
internal void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) internal void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
var idx = 0; var idx = 0;
@ -62,7 +60,7 @@ namespace Avalonia.Controls
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var definition = (DefinitionBase) items[i]; var definition = (DefinitionBase) items[i]!;
if (wasRemoved) if (wasRemoved)
{ {

2
src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs

@ -1,8 +1,6 @@
using System; using System;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
#nullable enable
namespace Avalonia.Controls.Diagnostics namespace Avalonia.Controls.Diagnostics
{ {
/// <summary> /// <summary>

4
src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs

@ -1,6 +1,4 @@
#nullable enable namespace Avalonia.Controls.Diagnostics
namespace Avalonia.Controls.Diagnostics
{ {
/// <summary> /// <summary>
/// Helper class to provide diagnostics information for <see cref="ToolTip"/>. /// Helper class to provide diagnostics information for <see cref="ToolTip"/>.

20
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -12,7 +12,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
private double _scaling = 1; private double _scaling = 1;
private Size _clientSize; private Size _clientSize;
public IInputRoot InputRoot { get; private set; } public IInputRoot? InputRoot { get; private set; }
public bool IsDisposed { get; private set; } public bool IsDisposed { get; private set; }
public virtual void Dispose() public virtual void Dispose()
@ -47,12 +47,12 @@ namespace Avalonia.Controls.Embedding.Offscreen
} }
} }
public Action<RawInputEventArgs> Input { get; set; } public Action<RawInputEventArgs>? Input { get; set; }
public Action<Rect> Paint { get; set; } public Action<Rect>? Paint { get; set; }
public Action<Size, PlatformResizeReason> Resized { get; set; } public Action<Size, PlatformResizeReason>? Resized { get; set; }
public Action<double> ScalingChanged { get; set; } public Action<double>? ScalingChanged { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; } public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
@ -63,18 +63,18 @@ namespace Avalonia.Controls.Embedding.Offscreen
public virtual PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, 1); public virtual PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, 1);
public virtual void SetCursor(ICursorImpl cursor) public virtual void SetCursor(ICursorImpl? cursor)
{ {
} }
public Action Closed { get; set; } public Action? Closed { get; set; }
public Action LostFocus { get; set; } public Action? LostFocus { get; set; }
public abstract IMouseDevice MouseDevice { get; } public abstract IMouseDevice MouseDevice { get; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { } public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { }
public WindowTransparencyLevel TransparencyLevel { get; private set; } public WindowTransparencyLevel TransparencyLevel { get; private set; }
public IPopupImpl CreatePopup() => null; public IPopupImpl? CreatePopup() => null;
} }
} }

3
src/Avalonia.Controls/Expander.cs

@ -1,11 +1,8 @@
using System.Threading; using System.Threading;
using Avalonia.Animation; using Avalonia.Animation;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>

7
src/Avalonia.Controls/ExperimentalAcrylicBorder.cs

@ -17,7 +17,7 @@ namespace Avalonia.Controls
private readonly BorderRenderHelper _borderRenderHelper = new BorderRenderHelper(); private readonly BorderRenderHelper _borderRenderHelper = new BorderRenderHelper();
private IDisposable _subscription; private IDisposable? _subscription;
static ExperimentalAcrylicBorder() static ExperimentalAcrylicBorder()
{ {
@ -46,11 +46,14 @@ namespace Avalonia.Controls
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
var tl = (e.Root as TopLevel); var tl = (TopLevel)e.Root;
_subscription = tl.GetObservable(TopLevel.ActualTransparencyLevelProperty) _subscription = tl.GetObservable(TopLevel.ActualTransparencyLevelProperty)
.Subscribe(x => .Subscribe(x =>
{ {
if (tl.PlatformImpl is null)
return;
switch (x) switch (x)
{ {
case WindowTransparencyLevel.Transparent: case WindowTransparencyLevel.Transparent:

2
src/Avalonia.Controls/Flyouts/Flyout.cs

@ -1,8 +1,6 @@
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Metadata; using Avalonia.Metadata;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
public class Flyout : FlyoutBase public class Flyout : FlyoutBase

20
src/Avalonia.Controls/Flyouts/FlyoutBase.cs

@ -8,8 +8,6 @@ using Avalonia.Input.Raw;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Logging; using Avalonia.Logging;
#nullable enable
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider
@ -267,7 +265,7 @@ namespace Avalonia.Controls.Primitives
return true; return true;
} }
private void PlacementTarget_DetachedFromVisualTree(object sender, VisualTreeAttachmentEventArgs e) private void PlacementTarget_DetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{ {
_ = HideCore(false); _ = HideCore(false);
} }
@ -335,7 +333,7 @@ namespace Avalonia.Controls.Primitives
protected virtual void OnOpened() protected virtual void OnOpened()
{ {
Opened?.Invoke(this, null); Opened?.Invoke(this, EventArgs.Empty);
} }
protected virtual void OnClosing(CancelEventArgs args) protected virtual void OnClosing(CancelEventArgs args)
@ -345,7 +343,7 @@ namespace Avalonia.Controls.Primitives
protected virtual void OnClosed() protected virtual void OnClosed()
{ {
Closed?.Invoke(this, null); Closed?.Invoke(this, EventArgs.Empty);
} }
/// <summary> /// <summary>
@ -368,14 +366,14 @@ namespace Avalonia.Controls.Primitives
return popup; return popup;
} }
private void OnPopupOpened(object sender, EventArgs e) private void OnPopupOpened(object? sender, EventArgs e)
{ {
IsOpen = true; IsOpen = true;
_popupHostChangedHandler?.Invoke(Popup!.Host); _popupHostChangedHandler?.Invoke(Popup!.Host);
} }
private void OnPopupClosing(object sender, CancelEventArgs e) private void OnPopupClosing(object? sender, CancelEventArgs e)
{ {
if (IsOpen) if (IsOpen)
{ {
@ -383,7 +381,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
private void OnPopupClosed(object sender, EventArgs e) private void OnPopupClosed(object? sender, EventArgs e)
{ {
HideCore(false); HideCore(false);
@ -391,7 +389,7 @@ namespace Avalonia.Controls.Primitives
} }
// This method is handling both popup logical tree and target logical tree. // This method is handling both popup logical tree and target logical tree.
private void OnPlacementTargetOrPopupKeyUp(object sender, KeyEventArgs e) private void OnPlacementTargetOrPopupKeyUp(object? sender, KeyEventArgs e)
{ {
if (!e.Handled if (!e.Handled
&& IsOpen && IsOpen
@ -530,10 +528,10 @@ namespace Avalonia.Controls.Primitives
} }
} }
private static void OnControlContextRequested(object sender, ContextRequestedEventArgs e) private static void OnControlContextRequested(object? sender, ContextRequestedEventArgs e)
{ {
var control = (Control)sender;
if (!e.Handled if (!e.Handled
&& sender is Control control
&& control.ContextFlyout is FlyoutBase flyout) && control.ContextFlyout is FlyoutBase flyout)
{ {
if (control.ContextMenu != null) if (control.ContextMenu != null)

8
src/Avalonia.Controls/Flyouts/MenuFlyout.cs

@ -4,8 +4,6 @@ using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Metadata; using Avalonia.Metadata;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
public class MenuFlyout : FlyoutBase public class MenuFlyout : FlyoutBase
@ -18,7 +16,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Items"/> property /// Defines the <see cref="Items"/> property
/// </summary> /// </summary>
public static readonly DirectProperty<MenuFlyout, IEnumerable> ItemsProperty = public static readonly DirectProperty<MenuFlyout, IEnumerable?> ItemsProperty =
ItemsControl.ItemsProperty.AddOwner<MenuFlyout>(x => x.Items, ItemsControl.ItemsProperty.AddOwner<MenuFlyout>(x => x.Items,
(x, v) => x.Items = v); (x, v) => x.Items = v);
@ -35,7 +33,7 @@ namespace Avalonia.Controls
/// Gets or sets the items of the MenuFlyout /// Gets or sets the items of the MenuFlyout
/// </summary> /// </summary>
[Content] [Content]
public IEnumerable Items public IEnumerable? Items
{ {
get => _items; get => _items;
set => SetAndRaise(ItemsProperty, ref _items, value); set => SetAndRaise(ItemsProperty, ref _items, value);
@ -51,7 +49,7 @@ namespace Avalonia.Controls
} }
private Classes? _classes; private Classes? _classes;
private IEnumerable _items; private IEnumerable? _items;
private IDataTemplate? _itemTemplate; private IDataTemplate? _itemTemplate;
protected override Control CreatePresenter() protected override Control CreatePresenter()

12
src/Avalonia.Controls/Generators/IItemContainerGenerator.cs

@ -17,27 +17,27 @@ namespace Avalonia.Controls.Generators
/// <summary> /// <summary>
/// Gets or sets the data template used to display the items in the control. /// Gets or sets the data template used to display the items in the control.
/// </summary> /// </summary>
IDataTemplate ItemTemplate { get; set; } IDataTemplate? ItemTemplate { get; set; }
/// <summary> /// <summary>
/// Gets the ContainerType, or null if its an untyped ContainerGenerator. /// Gets the ContainerType, or null if its an untyped ContainerGenerator.
/// </summary> /// </summary>
Type ContainerType { get; } Type? ContainerType { get; }
/// <summary> /// <summary>
/// Signaled whenever new containers are materialized. /// Signaled whenever new containers are materialized.
/// </summary> /// </summary>
event EventHandler<ItemContainerEventArgs> Materialized; event EventHandler<ItemContainerEventArgs>? Materialized;
/// <summary> /// <summary>
/// Event raised whenever containers are dematerialized. /// Event raised whenever containers are dematerialized.
/// </summary> /// </summary>
event EventHandler<ItemContainerEventArgs> Dematerialized; event EventHandler<ItemContainerEventArgs>? Dematerialized;
/// <summary> /// <summary>
/// Event raised whenever containers are recycled. /// Event raised whenever containers are recycled.
/// </summary> /// </summary>
event EventHandler<ItemContainerEventArgs> Recycled; event EventHandler<ItemContainerEventArgs>? Recycled;
/// <summary> /// <summary>
/// Creates a container control for an item. /// Creates a container control for an item.
@ -90,7 +90,7 @@ namespace Avalonia.Controls.Generators
/// </summary> /// </summary>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>The container, or null if no container created.</returns> /// <returns>The container, or null if no container created.</returns>
IControl ContainerFromIndex(int index); IControl? ContainerFromIndex(int index);
/// <summary> /// <summary>
/// Gets the index of the specified container control. /// Gets the index of the specified container control.

2
src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs

@ -8,7 +8,7 @@ namespace Avalonia.Controls.Generators
/// <summary> /// <summary>
/// Gets the container index for the tree. /// Gets the container index for the tree.
/// </summary> /// </summary>
TreeContainerIndex Index { get; } TreeContainerIndex? Index { get; }
/// <summary> /// <summary>
/// Updates the index based on the parent <see cref="TreeView"/>. /// Updates the index based on the parent <see cref="TreeView"/>.

26
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@ -20,27 +20,25 @@ namespace Avalonia.Controls.Generators
/// <param name="owner">The owner control.</param> /// <param name="owner">The owner control.</param>
public ItemContainerGenerator(IControl owner) public ItemContainerGenerator(IControl owner)
{ {
Contract.Requires<ArgumentNullException>(owner != null); Owner = owner ?? throw new ArgumentNullException(nameof(owner));
Owner = owner;
} }
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<ItemContainerInfo> Containers => _containers.Values; public IEnumerable<ItemContainerInfo> Containers => _containers.Values;
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ItemContainerEventArgs> Materialized; public event EventHandler<ItemContainerEventArgs>? Materialized;
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ItemContainerEventArgs> Dematerialized; public event EventHandler<ItemContainerEventArgs>? Dematerialized;
/// <inheritdoc/> /// <inheritdoc/>
public event EventHandler<ItemContainerEventArgs> Recycled; public event EventHandler<ItemContainerEventArgs>? Recycled;
/// <summary> /// <summary>
/// Gets or sets the data template used to display the items in the control. /// Gets or sets the data template used to display the items in the control.
/// </summary> /// </summary>
public IDataTemplate ItemTemplate { get; set; } public IDataTemplate? ItemTemplate { get; set; }
/// <summary> /// <summary>
/// Gets the owner control. /// Gets the owner control.
@ -48,12 +46,12 @@ namespace Avalonia.Controls.Generators
public IControl Owner { get; } public IControl Owner { get; }
/// <inheritdoc/> /// <inheritdoc/>
public virtual Type ContainerType => null; public virtual Type? ContainerType => null;
/// <inheritdoc/> /// <inheritdoc/>
public ItemContainerInfo Materialize(int index, object item) public ItemContainerInfo Materialize(int index, object item)
{ {
var container = new ItemContainerInfo(CreateContainer(item), item, index); var container = new ItemContainerInfo(CreateContainer(item)!, item, index);
_containers.Add(container.Index, container); _containers.Add(container.Index, container);
Materialized?.Invoke(this, new ItemContainerEventArgs(container)); Materialized?.Invoke(this, new ItemContainerEventArgs(container));
@ -104,9 +102,7 @@ namespace Avalonia.Controls.Generators
{ {
for (var i = startingIndex; i < startingIndex + count; ++i) for (var i = startingIndex; i < startingIndex + count; ++i)
{ {
ItemContainerInfo found; if (_containers.TryGetValue(i, out var found))
if (_containers.TryGetValue(i, out found))
{ {
result.Add(found); result.Add(found);
} }
@ -154,9 +150,9 @@ namespace Avalonia.Controls.Generators
} }
/// <inheritdoc/> /// <inheritdoc/>
public IControl ContainerFromIndex(int index) public IControl? ContainerFromIndex(int index)
{ {
ItemContainerInfo result; ItemContainerInfo? result;
_containers.TryGetValue(index, out result); _containers.TryGetValue(index, out result);
return result?.ContainerControl; return result?.ContainerControl;
} }
@ -180,7 +176,7 @@ namespace Avalonia.Controls.Generators
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>The created container control.</returns> /// <returns>The created container control.</returns>
protected virtual IControl CreateContainer(object item) protected virtual IControl? CreateContainer(object item)
{ {
var result = item as IControl; var result = item as IControl;

11
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@ -19,13 +19,10 @@ namespace Avalonia.Controls.Generators
public ItemContainerGenerator( public ItemContainerGenerator(
IControl owner, IControl owner,
AvaloniaProperty contentProperty, AvaloniaProperty contentProperty,
AvaloniaProperty contentTemplateProperty) AvaloniaProperty? contentTemplateProperty)
: base(owner) : base(owner)
{ {
Contract.Requires<ArgumentNullException>(owner != null); ContentProperty = contentProperty ?? throw new ArgumentNullException(nameof(contentProperty));
Contract.Requires<ArgumentNullException>(contentProperty != null);
ContentProperty = contentProperty;
ContentTemplateProperty = contentTemplateProperty; ContentTemplateProperty = contentTemplateProperty;
} }
@ -40,10 +37,10 @@ namespace Avalonia.Controls.Generators
/// <summary> /// <summary>
/// Gets the container's ContentTemplate property. /// Gets the container's ContentTemplate property.
/// </summary> /// </summary>
protected AvaloniaProperty ContentTemplateProperty { get; } protected AvaloniaProperty? ContentTemplateProperty { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override IControl CreateContainer(object item) protected override IControl? CreateContainer(object item)
{ {
var container = item as T; var container = item as T;

2
src/Avalonia.Controls/Generators/MenuItemContainerGenerator.cs

@ -12,7 +12,7 @@
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override IControl CreateContainer(object item) protected override IControl? CreateContainer(object item)
{ {
var separator = item as Separator; var separator = item as Separator;
return separator != null ? separator : base.CreateContainer(item); return separator != null ? separator : base.CreateContainer(item);

12
src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs

@ -20,7 +20,7 @@ namespace Avalonia.Controls.Generators
protected override IControl CreateContainer(object item) protected override IControl CreateContainer(object item)
{ {
var tabItem = (TabItem)base.CreateContainer(item); var tabItem = (TabItem)base.CreateContainer(item)!;
tabItem.Bind(TabItem.TabStripPlacementProperty, new OwnerBinding<Dock>( tabItem.Bind(TabItem.TabStripPlacementProperty, new OwnerBinding<Dock>(
tabItem, tabItem,
@ -28,7 +28,7 @@ namespace Avalonia.Controls.Generators
if (tabItem.HeaderTemplate == null) if (tabItem.HeaderTemplate == null)
{ {
tabItem.Bind(TabItem.HeaderTemplateProperty, new OwnerBinding<IDataTemplate>( tabItem.Bind(TabItem.HeaderTemplateProperty, new OwnerBinding<IDataTemplate?>(
tabItem, tabItem,
TabControl.ItemTemplateProperty)); TabControl.ItemTemplateProperty));
} }
@ -50,7 +50,7 @@ namespace Avalonia.Controls.Generators
if (!(tabItem.Content is IControl)) if (!(tabItem.Content is IControl))
{ {
tabItem.Bind(TabItem.ContentTemplateProperty, new OwnerBinding<IDataTemplate>( tabItem.Bind(TabItem.ContentTemplateProperty, new OwnerBinding<IDataTemplate?>(
tabItem, tabItem,
TabControl.ContentTemplateProperty)); TabControl.ContentTemplateProperty));
} }
@ -62,8 +62,8 @@ namespace Avalonia.Controls.Generators
{ {
private readonly TabItem _item; private readonly TabItem _item;
private readonly StyledProperty<T> _ownerProperty; private readonly StyledProperty<T> _ownerProperty;
private IDisposable _ownerSubscription; private IDisposable? _ownerSubscription;
private IDisposable _propertySubscription; private IDisposable? _propertySubscription;
public OwnerBinding(TabItem item, StyledProperty<T> ownerProperty) public OwnerBinding(TabItem item, StyledProperty<T> ownerProperty)
{ {
@ -82,7 +82,7 @@ namespace Avalonia.Controls.Generators
_ownerSubscription = null; _ownerSubscription = null;
} }
private void OwnerChanged(ILogical c) private void OwnerChanged(ILogical? c)
{ {
_propertySubscription?.Dispose(); _propertySubscription?.Dispose();
_propertySubscription = null; _propertySubscription = null;

8
src/Avalonia.Controls/Generators/TreeContainerIndex.cs

@ -21,12 +21,12 @@ namespace Avalonia.Controls.Generators
/// <summary> /// <summary>
/// Signaled whenever new containers are materialized. /// Signaled whenever new containers are materialized.
/// </summary> /// </summary>
public event EventHandler<ItemContainerEventArgs> Materialized; public event EventHandler<ItemContainerEventArgs>? Materialized;
/// <summary> /// <summary>
/// Event raised whenever containers are dematerialized. /// Event raised whenever containers are dematerialized.
/// </summary> /// </summary>
public event EventHandler<ItemContainerEventArgs> Dematerialized; public event EventHandler<ItemContainerEventArgs>? Dematerialized;
/// <summary> /// <summary>
/// Gets the currently materialized containers. /// Gets the currently materialized containers.
@ -92,7 +92,7 @@ namespace Avalonia.Controls.Generators
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>The container, or null of not found.</returns> /// <returns>The container, or null of not found.</returns>
public IControl ContainerFromItem(object item) public IControl? ContainerFromItem(object item)
{ {
if (item != null) if (item != null)
{ {
@ -108,7 +108,7 @@ namespace Avalonia.Controls.Generators
/// </summary> /// </summary>
/// <param name="container">The container.</param> /// <param name="container">The container.</param>
/// <returns>The item, or null of not found.</returns> /// <returns>The item, or null of not found.</returns>
public object ItemFromContainer(IControl container) public object? ItemFromContainer(IControl? container)
{ {
if (container != null) if (container != null)
{ {

23
src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs

@ -14,7 +14,7 @@ namespace Avalonia.Controls.Generators
public class TreeItemContainerGenerator<T> : ItemContainerGenerator<T>, ITreeItemContainerGenerator public class TreeItemContainerGenerator<T> : ItemContainerGenerator<T>, ITreeItemContainerGenerator
where T : class, IControl, new() where T : class, IControl, new()
{ {
private TreeView _treeView; private TreeView? _treeView;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TreeItemContainerGenerator{T}"/> class. /// Initializes a new instance of the <see cref="TreeItemContainerGenerator{T}"/> class.
@ -32,20 +32,15 @@ namespace Avalonia.Controls.Generators
AvaloniaProperty isExpandedProperty) AvaloniaProperty isExpandedProperty)
: base(owner, contentProperty, contentTemplateProperty) : base(owner, contentProperty, contentTemplateProperty)
{ {
Contract.Requires<ArgumentNullException>(owner != null); ItemsProperty = itemsProperty ?? throw new ArgumentNullException(nameof(itemsProperty));
Contract.Requires<ArgumentNullException>(contentProperty != null); IsExpandedProperty = isExpandedProperty ?? throw new ArgumentNullException(nameof(isExpandedProperty));
Contract.Requires<ArgumentNullException>(itemsProperty != null);
Contract.Requires<ArgumentNullException>(isExpandedProperty != null);
ItemsProperty = itemsProperty;
IsExpandedProperty = isExpandedProperty;
UpdateIndex(); UpdateIndex();
} }
/// <summary> /// <summary>
/// Gets the container index for the tree. /// Gets the container index for the tree.
/// </summary> /// </summary>
public TreeContainerIndex Index { get; private set; } public TreeContainerIndex? Index { get; private set; }
/// <summary> /// <summary>
/// Gets the item container's Items property. /// Gets the item container's Items property.
@ -58,7 +53,7 @@ namespace Avalonia.Controls.Generators
protected AvaloniaProperty IsExpandedProperty { get; } protected AvaloniaProperty IsExpandedProperty { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override IControl CreateContainer(object item) protected override IControl? CreateContainer(object? item)
{ {
var container = item as T; var container = item as T;
@ -141,12 +136,12 @@ namespace Avalonia.Controls.Generators
{ {
private readonly IDataTemplate _inner; private readonly IDataTemplate _inner;
public WrapperTreeDataTemplate(IDataTemplate inner) => _inner = inner; public WrapperTreeDataTemplate(IDataTemplate inner) => _inner = inner;
public IControl Build(object param) => _inner.Build(param); public IControl? Build(object? param) => _inner.Build(param);
public bool Match(object data) => _inner.Match(data); public bool Match(object? data) => _inner.Match(data);
public InstancedBinding ItemsSelector(object item) => null; public InstancedBinding? ItemsSelector(object item) => null;
} }
private ITreeDataTemplate GetTreeDataTemplate(object item, IDataTemplate primary) private ITreeDataTemplate GetTreeDataTemplate(object item, IDataTemplate? primary)
{ {
var template = Owner.FindDataTemplate(item, primary) ?? FuncDataTemplate.Default; var template = Owner.FindDataTemplate(item, primary) ?? FuncDataTemplate.Default;
var treeTemplate = template as ITreeDataTemplate ?? new WrapperTreeDataTemplate(template); var treeTemplate = template as ITreeDataTemplate ?? new WrapperTreeDataTemplate(template);

165
src/Avalonia.Controls/Grid.cs

@ -8,6 +8,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading; using System.Threading;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
@ -48,7 +49,7 @@ namespace Avalonia.Controls
/// <param name="value">Column property value.</param> /// <param name="value">Column property value.</param>
public static void SetColumn(Control element, int value) public static void SetColumn(Control element, int value)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ColumnProperty, value); element.SetValue(ColumnProperty, value);
} }
@ -59,7 +60,7 @@ namespace Avalonia.Controls
/// <returns>Column property value.</returns> /// <returns>Column property value.</returns>
public static int GetColumn(Control element) public static int GetColumn(Control element)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ColumnProperty); return element.GetValue(ColumnProperty);
} }
@ -70,7 +71,7 @@ namespace Avalonia.Controls
/// <param name="value">Row property value.</param> /// <param name="value">Row property value.</param>
public static void SetRow(Control element, int value) public static void SetRow(Control element, int value)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(RowProperty, value); element.SetValue(RowProperty, value);
} }
@ -81,7 +82,7 @@ namespace Avalonia.Controls
/// <returns>Row property value.</returns> /// <returns>Row property value.</returns>
public static int GetRow(Control element) public static int GetRow(Control element)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(RowProperty); return element.GetValue(RowProperty);
} }
@ -92,7 +93,7 @@ namespace Avalonia.Controls
/// <param name="value">ColumnSpan property value.</param> /// <param name="value">ColumnSpan property value.</param>
public static void SetColumnSpan(Control element, int value) public static void SetColumnSpan(Control element, int value)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ColumnSpanProperty, value); element.SetValue(ColumnSpanProperty, value);
} }
@ -103,7 +104,7 @@ namespace Avalonia.Controls
/// <returns>ColumnSpan property value.</returns> /// <returns>ColumnSpan property value.</returns>
public static int GetColumnSpan(Control element) public static int GetColumnSpan(Control element)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ColumnSpanProperty); return element.GetValue(ColumnSpanProperty);
} }
@ -114,7 +115,7 @@ namespace Avalonia.Controls
/// <param name="value">RowSpan property value.</param> /// <param name="value">RowSpan property value.</param>
public static void SetRowSpan(Control element, int value) public static void SetRowSpan(Control element, int value)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(RowSpanProperty, value); element.SetValue(RowSpanProperty, value);
} }
@ -125,7 +126,7 @@ namespace Avalonia.Controls
/// <returns>RowSpan property value.</returns> /// <returns>RowSpan property value.</returns>
public static int GetRowSpan(Control element) public static int GetRowSpan(Control element)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(RowSpanProperty); return element.GetValue(RowSpanProperty);
} }
@ -136,7 +137,7 @@ namespace Avalonia.Controls
/// <param name="value">IsSharedSizeScope property value.</param> /// <param name="value">IsSharedSizeScope property value.</param>
public static void SetIsSharedSizeScope(Control element, bool value) public static void SetIsSharedSizeScope(Control element, bool value)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsSharedSizeScopeProperty, value); element.SetValue(IsSharedSizeScopeProperty, value);
} }
@ -147,7 +148,7 @@ namespace Avalonia.Controls
/// <returns>IsSharedSizeScope property value.</returns> /// <returns>IsSharedSizeScope property value.</returns>
public static bool GetIsSharedSizeScope(Control element) public static bool GetIsSharedSizeScope(Control element)
{ {
Contract.Requires<ArgumentNullException>(element != null); _ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(IsSharedSizeScopeProperty); return element.GetValue(IsSharedSizeScopeProperty);
} }
@ -573,7 +574,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// <see cref="Panel.ChildrenChanged"/> /// <see cref="Panel.ChildrenChanged"/>
/// </summary> /// </summary>
protected override void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) protected override void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
CellsStructureDirty = true; CellsStructureDirty = true;
base.ChildrenChanged(sender, e); base.ChildrenChanged(sender, e);
@ -598,7 +599,7 @@ namespace Avalonia.Controls
{ {
double value = 0.0; double value = 0.0;
Contract.Requires<NullReferenceException>(_data != null); Debug.Assert(_data != null);
// actual value calculations require structure to be up-to-date // actual value calculations require structure to be up-to-date
if (!ColumnDefinitionsDirty) if (!ColumnDefinitionsDirty)
@ -620,7 +621,7 @@ namespace Avalonia.Controls
{ {
double value = 0.0; double value = 0.0;
Contract.Requires<NullReferenceException>(_data != null); Debug.Assert(_data != null);
// actual value calculations require structure to be up-to-date // actual value calculations require structure to be up-to-date
if (!RowDefinitionsDirty) if (!RowDefinitionsDirty)
@ -994,7 +995,7 @@ namespace Avalonia.Controls
} }
var children = this.Children; var children = this.Children;
Hashtable spanStore = null; Hashtable? spanStore = null;
bool ignoreDesiredSizeV = forceInfinityV; bool ignoreDesiredSizeV = forceInfinityV;
int i = cellsHead; int i = cellsHead;
@ -1048,7 +1049,7 @@ namespace Avalonia.Controls
foreach (DictionaryEntry e in spanStore) foreach (DictionaryEntry e in spanStore)
{ {
SpanKey key = (SpanKey)e.Key; SpanKey key = (SpanKey)e.Key;
double requestedSize = (double)e.Value; double requestedSize = (double)e.Value!;
EnsureMinSizeInDefinitionRange( EnsureMinSizeInDefinitionRange(
key.U ? DefinitionsU : DefinitionsV, key.U ? DefinitionsU : DefinitionsV,
@ -1069,7 +1070,7 @@ namespace Avalonia.Controls
/// <param name="u"><c>true</c> if this is a column span. <c>false</c> if this is a row span.</param> /// <param name="u"><c>true</c> if this is a column span. <c>false</c> if this is a row span.</param>
/// <param name="value">Value to store. If an entry already exists the biggest value is stored.</param> /// <param name="value">Value to store. If an entry already exists the biggest value is stored.</param>
private static void RegisterSpan( private static void RegisterSpan(
ref Hashtable store, ref Hashtable? store,
int start, int start,
int count, int count,
bool u, bool u,
@ -1081,7 +1082,7 @@ namespace Avalonia.Controls
} }
SpanKey key = new SpanKey(start, count, u); SpanKey key = new SpanKey(start, count, u);
object o = store[key]; object? o = store[key];
if (o == null if (o == null
|| value > (double)o) || value > (double)o)
@ -1605,12 +1606,12 @@ namespace Avalonia.Controls
while (minCount > 0 && tempDefinitions[minCount - 1].MeasureSize < 0.0) while (minCount > 0 && tempDefinitions[minCount - 1].MeasureSize < 0.0)
{ {
--minCount; --minCount;
tempDefinitions[minCount] = null; tempDefinitions[minCount] = null!;
} }
while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1].MeasureSize < 0.0) while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1].MeasureSize < 0.0)
{ {
--maxCount; --maxCount;
tempDefinitions[defCount + maxCount] = null; tempDefinitions[defCount + maxCount] = null!;
} }
} }
@ -2321,7 +2322,7 @@ namespace Avalonia.Controls
/// by adding / removing GridLinesRenderer visual. /// by adding / removing GridLinesRenderer visual.
/// Returns a reference to GridLinesRenderer visual or null. /// Returns a reference to GridLinesRenderer visual or null.
/// </summary> /// </summary>
private GridLinesRenderer EnsureGridLinesRenderer() private GridLinesRenderer? EnsureGridLinesRenderer()
{ {
// //
// synchronize the state // synchronize the state
@ -2369,16 +2370,16 @@ namespace Avalonia.Controls
grid.InvalidateVisual(); grid.InvalidateVisual();
} }
grid.SetFlags((bool)e.NewValue, Flags.ShowGridLinesPropertyValue); grid.SetFlags((bool)e.NewValue!, Flags.ShowGridLinesPropertyValue);
} }
private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{ {
Visual child = d as Visual; Visual? child = d as Visual;
if (child != null) if (child != null)
{ {
Grid grid = child.GetVisualParent<Grid>(); Grid? grid = child.GetVisualParent<Grid>();
if (grid != null if (grid != null
&& grid.ExtData != null && grid.ExtData != null
&& grid.ListenToNotifications) && grid.ListenToNotifications)
@ -2395,7 +2396,7 @@ namespace Avalonia.Controls
/// true if one or both of x and y are null, in which case result holds /// true if one or both of x and y are null, in which case result holds
/// the relative sort order. /// the relative sort order.
/// </returns> /// </returns>
private static bool CompareNullRefs(object x, object y, out int result) private static bool CompareNullRefs([NotNullWhen(false)] object? x, [NotNullWhen(false)] object? y, out int result)
{ {
result = 2; result = 2;
@ -2426,7 +2427,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private IReadOnlyList<DefinitionBase> DefinitionsU private IReadOnlyList<DefinitionBase> DefinitionsU
{ {
get { return (ExtData.DefinitionsU); } get { return (ExtData.DefinitionsU!); }
} }
/// <summary> /// <summary>
@ -2434,7 +2435,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private IReadOnlyList<DefinitionBase> DefinitionsV private IReadOnlyList<DefinitionBase> DefinitionsV
{ {
get { return (ExtData.DefinitionsV); } get { return (ExtData.DefinitionsV!); }
} }
/// <summary> /// <summary>
@ -2450,7 +2451,7 @@ namespace Avalonia.Controls
if (extData.TempDefinitions == null if (extData.TempDefinitions == null
|| extData.TempDefinitions.Length < requiredLength) || extData.TempDefinitions.Length < requiredLength)
{ {
WeakReference tempDefinitionsWeakRef = (WeakReference)Thread.GetData(s_tempDefinitionsDataSlot); WeakReference? tempDefinitionsWeakRef = (WeakReference?)Thread.GetData(s_tempDefinitionsDataSlot);
if (tempDefinitionsWeakRef == null) if (tempDefinitionsWeakRef == null)
{ {
extData.TempDefinitions = new DefinitionBase[requiredLength]; extData.TempDefinitions = new DefinitionBase[requiredLength];
@ -2458,7 +2459,7 @@ namespace Avalonia.Controls
} }
else else
{ {
extData.TempDefinitions = (DefinitionBase[])tempDefinitionsWeakRef.Target; extData.TempDefinitions = (DefinitionBase[]?)tempDefinitionsWeakRef.Target;
if (extData.TempDefinitions == null if (extData.TempDefinitions == null
|| extData.TempDefinitions.Length < requiredLength) || extData.TempDefinitions.Length < requiredLength)
{ {
@ -2515,7 +2516,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private CellCache[] PrivateCells private CellCache[] PrivateCells
{ {
get { return (ExtData.CellCachesCollection); } get { return (ExtData.CellCachesCollection!); }
} }
/// <summary> /// <summary>
@ -2586,7 +2587,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private ExtendedData ExtData private ExtendedData ExtData
{ {
get { return (_data); } get { return (_data!); }
} }
/// <summary> /// <summary>
@ -2608,17 +2609,17 @@ namespace Avalonia.Controls
} }
// Extended data instantiated on demand, for non-trivial case handling only // Extended data instantiated on demand, for non-trivial case handling only
private ExtendedData _data; private ExtendedData? _data;
// Grid validity / property caches dirtiness flags // Grid validity / property caches dirtiness flags
private Flags _flags; private Flags _flags;
private GridLinesRenderer _gridLinesRenderer; private GridLinesRenderer? _gridLinesRenderer;
// Keeps track of definition indices. // Keeps track of definition indices.
int[] _definitionIndices; int[]? _definitionIndices;
// Stores unrounded values and rounding errors during layout rounding. // Stores unrounded values and rounding errors during layout rounding.
double[] _roundingErrors; double[]? _roundingErrors;
// 5 is an arbitrary constant chosen to end the measure loop // 5 is an arbitrary constant chosen to end the measure loop
private const int c_layoutLoopMaxCount = 5; private const int c_layoutLoopMaxCount = 5;
@ -2635,16 +2636,16 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private class ExtendedData private class ExtendedData
{ {
internal ColumnDefinitions ColumnDefinitions; // collection of column definitions (logical tree support) internal ColumnDefinitions? ColumnDefinitions; // collection of column definitions (logical tree support)
internal RowDefinitions RowDefinitions; // collection of row definitions (logical tree support) internal RowDefinitions? RowDefinitions; // collection of row definitions (logical tree support)
internal IReadOnlyList<DefinitionBase> DefinitionsU; // collection of column definitions used during calc internal IReadOnlyList<DefinitionBase>? DefinitionsU; // collection of column definitions used during calc
internal IReadOnlyList<DefinitionBase> DefinitionsV; // collection of row definitions used during calc internal IReadOnlyList<DefinitionBase>? DefinitionsV; // collection of row definitions used during calc
internal CellCache[] CellCachesCollection; // backing store for logical children internal CellCache[]? CellCachesCollection; // backing store for logical children
internal int CellGroup1; // index of the first cell in first cell group internal int CellGroup1; // index of the first cell in first cell group
internal int CellGroup2; // index of the first cell in second cell group 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 CellGroup3; // index of the first cell in third cell group
internal int CellGroup4; // index of the first cell in forth 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) // TempDefinitions.Length == Max(definitionsU.Length, definitionsV.Length)
} }
@ -2831,9 +2832,9 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// <see cref="object.Equals(object)"/> /// <see cref="object.Equals(object)"/>
/// </summary> /// </summary>
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
SpanKey sk = obj as SpanKey; SpanKey? sk = obj as SpanKey;
return (sk != null return (sk != null
&& sk._start == _start && sk._start == _start
&& sk._count == _count && sk._count == _count
@ -2866,10 +2867,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private class SpanPreferredDistributionOrderComparer : IComparer private class SpanPreferredDistributionOrderComparer : IComparer
{ {
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
DefinitionBase definitionX = x as DefinitionBase; DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase; DefinitionBase? definitionY = y as DefinitionBase;
int result; int result;
@ -2908,10 +2909,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private class SpanMaxDistributionOrderComparer : IComparer private class SpanMaxDistributionOrderComparer : IComparer
{ {
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
DefinitionBase definitionX = x as DefinitionBase; DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase; DefinitionBase? definitionY = y as DefinitionBase;
int result; int result;
@ -2954,17 +2955,16 @@ namespace Avalonia.Controls
internal StarDistributionOrderIndexComparer(IReadOnlyList<DefinitionBase> definitions) internal StarDistributionOrderIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{ {
Contract.Requires<NullReferenceException>(definitions != null); this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
this.definitions = definitions;
} }
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
int? indexX = x as int?; int? indexX = x as int?;
int? indexY = y as int?; int? indexY = y as int?;
DefinitionBase definitionX = null; DefinitionBase? definitionX = null;
DefinitionBase definitionY = null; DefinitionBase? definitionY = null;
if (indexX != null) if (indexX != null)
{ {
@ -2995,17 +2995,16 @@ namespace Avalonia.Controls
internal DistributionOrderIndexComparer(IReadOnlyList<DefinitionBase> definitions) internal DistributionOrderIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{ {
Contract.Requires<NullReferenceException>(definitions != null); this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
this.definitions = definitions;
} }
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
int? indexX = x as int?; int? indexX = x as int?;
int? indexY = y as int?; int? indexY = y as int?;
DefinitionBase definitionX = null; DefinitionBase? definitionX = null;
DefinitionBase definitionY = null; DefinitionBase? definitionY = null;
if (indexX != null) if (indexX != null)
{ {
@ -3038,11 +3037,10 @@ namespace Avalonia.Controls
internal RoundingErrorIndexComparer(double[] errors) internal RoundingErrorIndexComparer(double[] errors)
{ {
Contract.Requires<NullReferenceException>(errors != null); this.errors = errors ?? throw new ArgumentNullException(nameof(errors));
this.errors = errors;
} }
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
int? indexX = x as int?; int? indexX = x as int?;
int? indexY = y as int?; int? indexY = y as int?;
@ -3067,10 +3065,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private class MinRatioComparer : IComparer private class MinRatioComparer : IComparer
{ {
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
DefinitionBase definitionX = x as DefinitionBase; DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase; DefinitionBase? definitionY = y as DefinitionBase;
int result; int result;
@ -3090,10 +3088,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private class MaxRatioComparer : IComparer private class MaxRatioComparer : IComparer
{ {
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
DefinitionBase definitionX = x as DefinitionBase; DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase; DefinitionBase? definitionY = y as DefinitionBase;
int result; int result;
@ -3112,10 +3110,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private class StarWeightComparer : IComparer private class StarWeightComparer : IComparer
{ {
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
DefinitionBase definitionX = x as DefinitionBase; DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase; DefinitionBase? definitionY = y as DefinitionBase;
int result; int result;
@ -3137,17 +3135,16 @@ namespace Avalonia.Controls
internal MinRatioIndexComparer(IReadOnlyList<DefinitionBase> definitions) internal MinRatioIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{ {
Contract.Requires<NullReferenceException>(definitions != null); this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
this.definitions = definitions;
} }
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
int? indexX = x as int?; int? indexX = x as int?;
int? indexY = y as int?; int? indexY = y as int?;
DefinitionBase definitionX = null; DefinitionBase? definitionX = null;
DefinitionBase definitionY = null; DefinitionBase? definitionY = null;
if (indexX != null) if (indexX != null)
{ {
@ -3178,17 +3175,16 @@ namespace Avalonia.Controls
internal MaxRatioIndexComparer(IReadOnlyList<DefinitionBase> definitions) internal MaxRatioIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{ {
Contract.Requires<NullReferenceException>(definitions != null); this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
this.definitions = definitions;
} }
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
int? indexX = x as int?; int? indexX = x as int?;
int? indexY = y as int?; int? indexY = y as int?;
DefinitionBase definitionX = null; DefinitionBase? definitionX = null;
DefinitionBase definitionY = null; DefinitionBase? definitionY = null;
if (indexX != null) if (indexX != null)
{ {
@ -3219,17 +3215,16 @@ namespace Avalonia.Controls
internal StarWeightIndexComparer(IReadOnlyList<DefinitionBase> definitions) internal StarWeightIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{ {
Contract.Requires<NullReferenceException>(definitions != null); this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
this.definitions = definitions;
} }
public int Compare(object x, object y) public int Compare(object? x, object? y)
{ {
int? indexX = x as int?; int? indexX = x as int?;
int? indexY = y as int?; int? indexY = y as int?;
DefinitionBase definitionX = null; DefinitionBase? definitionX = null;
DefinitionBase definitionY = null; DefinitionBase? definitionY = null;
if (indexX != null) if (indexX != null)
{ {

2
src/Avalonia.Controls/GridLength.cs

@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="o">The object with which to test equality.</param> /// <param name="o">The object with which to test equality.</param>
/// <returns>True if the objects are equal, otherwise false.</returns> /// <returns>True if the objects are equal, otherwise false.</returns>
public override bool Equals(object o) public override bool Equals(object? o)
{ {
if (o == null) if (o == null)
{ {

62
src/Avalonia.Controls/GridSplitter.cs

@ -59,7 +59,7 @@ namespace Avalonia.Controls
private static readonly Cursor s_columnSplitterCursor = new Cursor(StandardCursorType.SizeWestEast); private static readonly Cursor s_columnSplitterCursor = new Cursor(StandardCursorType.SizeWestEast);
private static readonly Cursor s_rowSplitterCursor = new Cursor(StandardCursorType.SizeNorthSouth); private static readonly Cursor s_rowSplitterCursor = new Cursor(StandardCursorType.SizeNorthSouth);
private ResizeData _resizeData; private ResizeData? _resizeData;
/// <summary> /// <summary>
/// Indicates whether the Splitter resizes the Columns, Rows, or Both. /// Indicates whether the Splitter resizes the Columns, Rows, or Both.
@ -197,9 +197,9 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private void RemovePreviewAdorner() private void RemovePreviewAdorner()
{ {
if (_resizeData.Adorner != null) if (_resizeData?.Adorner != null)
{ {
AdornerLayer layer = AdornerLayer.GetAdornerLayer(this); AdornerLayer layer = AdornerLayer.GetAdornerLayer(this)!;
layer.Children.Remove(_resizeData.Adorner); layer.Children.Remove(_resizeData.Adorner);
} }
} }
@ -242,7 +242,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private bool SetupDefinitionsToResize() private bool SetupDefinitionsToResize()
{ {
int gridSpan = GetValue(_resizeData.ResizeDirection == GridResizeDirection.Columns ? int gridSpan = GetValue(_resizeData!.ResizeDirection == GridResizeDirection.Columns ?
Grid.ColumnSpanProperty : Grid.ColumnSpanProperty :
Grid.RowSpanProperty); Grid.RowSpanProperty);
@ -276,8 +276,8 @@ namespace Avalonia.Controls
// Get count of rows/columns in the resize direction. // Get count of rows/columns in the resize direction.
int count = _resizeData.ResizeDirection == GridResizeDirection.Columns ? int count = _resizeData.ResizeDirection == GridResizeDirection.Columns ?
_resizeData.Grid.ColumnDefinitions.Count : _resizeData.Grid!.ColumnDefinitions.Count :
_resizeData.Grid.RowDefinitions.Count; _resizeData.Grid!.RowDefinitions.Count;
if (index1 >= 0 && index2 < count) if (index1 >= 0 && index2 < count)
{ {
@ -322,10 +322,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private void SetupPreviewAdorner() private void SetupPreviewAdorner()
{ {
if (_resizeData.ShowsPreview) if (_resizeData!.ShowsPreview)
{ {
// Get the adorner layer and add an adorner to it. // Get the adorner layer and add an adorner to it.
var adornerLayer = AdornerLayer.GetAdornerLayer(_resizeData.Grid); var adornerLayer = AdornerLayer.GetAdornerLayer(_resizeData.Grid!);
var previewContent = PreviewContent; var previewContent = PreviewContent;
@ -335,7 +335,7 @@ namespace Avalonia.Controls
return; return;
} }
IControl builtPreviewContent = previewContent?.Build(); IControl? builtPreviewContent = previewContent?.Build();
_resizeData.Adorner = new PreviewAdorner(builtPreviewContent); _resizeData.Adorner = new PreviewAdorner(builtPreviewContent);
@ -409,13 +409,13 @@ namespace Avalonia.Controls
// Set the Translation of the Adorner to the distance from the thumb. // Set the Translation of the Adorner to the distance from the thumb.
if (_resizeData.ResizeDirection == GridResizeDirection.Columns) if (_resizeData.ResizeDirection == GridResizeDirection.Columns)
{ {
_resizeData.Adorner.OffsetX = Math.Min( _resizeData.Adorner!.OffsetX = Math.Min(
Math.Max(horizontalChange, _resizeData.MinChange), Math.Max(horizontalChange, _resizeData.MinChange),
_resizeData.MaxChange); _resizeData.MaxChange);
} }
else else
{ {
_resizeData.Adorner.OffsetY = Math.Min( _resizeData.Adorner!.OffsetY = Math.Min(
Math.Max(verticalChange, _resizeData.MinChange), Math.Max(verticalChange, _resizeData.MinChange),
_resizeData.MaxChange); _resizeData.MaxChange);
} }
@ -437,7 +437,7 @@ namespace Avalonia.Controls
if (_resizeData.ShowsPreview) if (_resizeData.ShowsPreview)
{ {
// Update the grid. // Update the grid.
MoveSplitter(_resizeData.Adorner.OffsetX, _resizeData.Adorner.OffsetY); MoveSplitter(_resizeData.Adorner!.OffsetX, _resizeData.Adorner.OffsetY);
RemovePreviewAdorner(); RemovePreviewAdorner();
} }
@ -481,14 +481,14 @@ namespace Avalonia.Controls
private void CancelResize() private void CancelResize()
{ {
// Restore original column/row lengths. // Restore original column/row lengths.
if (_resizeData.ShowsPreview) if (_resizeData!.ShowsPreview)
{ {
RemovePreviewAdorner(); RemovePreviewAdorner();
} }
else // Reset the columns/rows lengths to the saved values. else // Reset the columns/rows lengths to the saved values.
{ {
SetDefinitionLength(_resizeData.Definition1, _resizeData.OriginalDefinition1Length); SetDefinitionLength(_resizeData.Definition1!, _resizeData.OriginalDefinition1Length);
SetDefinitionLength(_resizeData.Definition2, _resizeData.OriginalDefinition2Length); SetDefinitionLength(_resizeData.Definition2!, _resizeData.OriginalDefinition2Length);
} }
_resizeData = null; _resizeData = null;
@ -536,12 +536,12 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private void GetDeltaConstraints(out double minDelta, out double maxDelta) private void GetDeltaConstraints(out double minDelta, out double maxDelta)
{ {
double definition1Len = GetActualLength(_resizeData.Definition1); double definition1Len = GetActualLength(_resizeData!.Definition1!);
double definition1Min = _resizeData.Definition1.UserMinSizeValueCache; double definition1Min = _resizeData.Definition1!.UserMinSizeValueCache;
double definition1Max = _resizeData.Definition1.UserMaxSizeValueCache; double definition1Max = _resizeData.Definition1.UserMaxSizeValueCache;
double definition2Len = GetActualLength(_resizeData.Definition2); double definition2Len = GetActualLength(_resizeData.Definition2!);
double definition2Min = _resizeData.Definition2.UserMinSizeValueCache; double definition2Min = _resizeData.Definition2!.UserMinSizeValueCache;
double definition2Max = _resizeData.Definition2.UserMaxSizeValueCache; double definition2Max = _resizeData.Definition2.UserMaxSizeValueCache;
// Set MinWidths to be greater than width of splitter. // Set MinWidths to be greater than width of splitter.
@ -565,11 +565,11 @@ namespace Avalonia.Controls
private void SetLengths(double definition1Pixels, double definition2Pixels) private void SetLengths(double definition1Pixels, double definition2Pixels)
{ {
// For the case where both definition1 and 2 are stars, update all star values to match their current pixel values. // For the case where both definition1 and 2 are stars, update all star values to match their current pixel values.
if (_resizeData.SplitBehavior == SplitBehavior.Split) if (_resizeData!.SplitBehavior == SplitBehavior.Split)
{ {
var definitions = _resizeData.ResizeDirection == GridResizeDirection.Columns ? var definitions = _resizeData.ResizeDirection == GridResizeDirection.Columns ?
(IAvaloniaReadOnlyList<DefinitionBase>)_resizeData.Grid.ColumnDefinitions : (IAvaloniaReadOnlyList<DefinitionBase>)_resizeData.Grid!.ColumnDefinitions :
(IAvaloniaReadOnlyList<DefinitionBase>)_resizeData.Grid.RowDefinitions; (IAvaloniaReadOnlyList<DefinitionBase>)_resizeData.Grid!.RowDefinitions;
var definitionsCount = definitions.Count; var definitionsCount = definitions.Count;
@ -595,11 +595,11 @@ namespace Avalonia.Controls
} }
else if (_resizeData.SplitBehavior == SplitBehavior.Resize1) else if (_resizeData.SplitBehavior == SplitBehavior.Resize1)
{ {
SetDefinitionLength(_resizeData.Definition1, new GridLength(definition1Pixels)); SetDefinitionLength(_resizeData.Definition1!, new GridLength(definition1Pixels));
} }
else else
{ {
SetDefinitionLength(_resizeData.Definition2, new GridLength(definition2Pixels)); SetDefinitionLength(_resizeData.Definition2!, new GridLength(definition2Pixels));
} }
} }
@ -623,8 +623,8 @@ namespace Avalonia.Controls
delta = LayoutHelper.RoundLayoutValue(delta, LayoutHelper.GetLayoutScale(this)); delta = LayoutHelper.RoundLayoutValue(delta, LayoutHelper.GetLayoutScale(this));
} }
DefinitionBase definition1 = _resizeData.Definition1; DefinitionBase? definition1 = _resizeData.Definition1;
DefinitionBase definition2 = _resizeData.Definition2; DefinitionBase? definition2 = _resizeData.Definition2;
if (definition1 != null && definition2 != null) if (definition1 != null && definition2 != null)
{ {
@ -691,7 +691,7 @@ namespace Avalonia.Controls
private readonly TranslateTransform _translation; private readonly TranslateTransform _translation;
private readonly Decorator _decorator; private readonly Decorator _decorator;
public PreviewAdorner(IControl previewControl) public PreviewAdorner(IControl? previewControl)
{ {
// Add a decorator to perform translations. // Add a decorator to perform translations.
_translation = new TranslateTransform(); _translation = new TranslateTransform();
@ -762,22 +762,22 @@ namespace Avalonia.Controls
private class ResizeData private class ResizeData
{ {
public bool ShowsPreview; public bool ShowsPreview;
public PreviewAdorner Adorner; public PreviewAdorner? Adorner;
// The constraints to keep the Preview within valid ranges. // The constraints to keep the Preview within valid ranges.
public double MinChange; public double MinChange;
public double MaxChange; public double MaxChange;
// The grid to Resize. // The grid to Resize.
public Grid Grid; public Grid? Grid;
// Cache of Resize Direction and Behavior. // Cache of Resize Direction and Behavior.
public GridResizeDirection ResizeDirection; public GridResizeDirection ResizeDirection;
public GridResizeBehavior ResizeBehavior; public GridResizeBehavior ResizeBehavior;
// The columns/rows to resize. // The columns/rows to resize.
public DefinitionBase Definition1; public DefinitionBase? Definition1;
public DefinitionBase Definition2; public DefinitionBase? Definition2;
// Are the columns/rows star lengths. // Are the columns/rows star lengths.
public SplitBehavior SplitBehavior; public SplitBehavior SplitBehavior;

40
src/Avalonia.Controls/HotkeyManager.cs

@ -7,29 +7,29 @@ namespace Avalonia.Controls
{ {
public class HotKeyManager public class HotKeyManager
{ {
public static readonly AttachedProperty<KeyGesture> HotKeyProperty public static readonly AttachedProperty<KeyGesture?> HotKeyProperty
= AvaloniaProperty.RegisterAttached<Control, KeyGesture>("HotKey", typeof(HotKeyManager)); = AvaloniaProperty.RegisterAttached<Control, KeyGesture?>("HotKey", typeof(HotKeyManager));
class HotkeyCommandWrapper : ICommand class HotkeyCommandWrapper : ICommand
{ {
public HotkeyCommandWrapper(ICommandSource control) public HotkeyCommandWrapper(ICommandSource? control)
{ {
CommandSource = control; CommandSource = control;
} }
public readonly ICommandSource CommandSource; public readonly ICommandSource? CommandSource;
private ICommand GetCommand() => CommandSource.Command; private ICommand? GetCommand() => CommandSource?.Command;
public bool CanExecute(object parameter) => public bool CanExecute(object? parameter) =>
CommandSource.Command?.CanExecute(CommandSource.CommandParameter) == true CommandSource?.Command?.CanExecute(CommandSource.CommandParameter) == true
&& CommandSource.IsEffectivelyEnabled; && CommandSource.IsEffectivelyEnabled;
public void Execute(object parameter) => public void Execute(object? parameter) =>
GetCommand()?.Execute(CommandSource.CommandParameter); GetCommand()?.Execute(CommandSource?.CommandParameter);
#pragma warning disable 67 // Event not used #pragma warning disable 67 // Event not used
public event EventHandler CanExecuteChanged; public event EventHandler? CanExecuteChanged;
#pragma warning restore 67 #pragma warning restore 67
} }
@ -37,12 +37,12 @@ namespace Avalonia.Controls
class Manager class Manager
{ {
private readonly IControl _control; private readonly IControl _control;
private TopLevel _root; private TopLevel? _root;
private IDisposable _parentSub; private IDisposable? _parentSub;
private IDisposable _hotkeySub; private IDisposable? _hotkeySub;
private KeyGesture _hotkey; private KeyGesture? _hotkey;
private readonly HotkeyCommandWrapper _wrapper; private readonly HotkeyCommandWrapper _wrapper;
private KeyBinding _binding; private KeyBinding? _binding;
public Manager(IControl control) public Manager(IControl control)
{ {
@ -56,14 +56,14 @@ namespace Avalonia.Controls
_parentSub = AncestorFinder.Create<TopLevel>(_control).Subscribe(OnParentChanged); _parentSub = AncestorFinder.Create<TopLevel>(_control).Subscribe(OnParentChanged);
} }
private void OnParentChanged(TopLevel control) private void OnParentChanged(TopLevel? control)
{ {
Unregister(); Unregister();
_root = control; _root = control;
Register(); Register();
} }
private void OnHotkeyChanged(KeyGesture hotkey) private void OnHotkeyChanged(KeyGesture? hotkey)
{ {
if (hotkey == null) if (hotkey == null)
//Subscription will be recreated by static property watcher //Subscription will be recreated by static property watcher
@ -95,8 +95,8 @@ namespace Avalonia.Controls
void Stop() void Stop()
{ {
Unregister(); Unregister();
_parentSub.Dispose(); _parentSub?.Dispose();
_hotkeySub.Dispose(); _hotkeySub?.Dispose();
} }
} }
@ -118,6 +118,6 @@ namespace Avalonia.Controls
}); });
} }
public static void SetHotKey(AvaloniaObject target, KeyGesture value) => target.SetValue(HotKeyProperty, value); public static void SetHotKey(AvaloniaObject target, KeyGesture value) => target.SetValue(HotKeyProperty, value);
public static KeyGesture GetHotKey(AvaloniaObject target) => target.GetValue(HotKeyProperty); public static KeyGesture? GetHotKey(AvaloniaObject target) => target.GetValue(HotKeyProperty);
} }
} }

6
src/Avalonia.Controls/IContentControl.cs

@ -12,12 +12,12 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the content to display. /// Gets or sets the content to display.
/// </summary> /// </summary>
object Content { get; set; } object? Content { get; set; }
/// <summary> /// <summary>
/// Gets or sets the data template used to display the content of the control. /// Gets or sets the data template used to display the content of the control.
/// </summary> /// </summary>
IDataTemplate ContentTemplate { get; set; } IDataTemplate? ContentTemplate { get; set; }
/// <summary> /// <summary>
/// Gets or sets the horizontal alignment of the content within the control. /// Gets or sets the horizontal alignment of the content within the control.
@ -29,4 +29,4 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
VerticalAlignment VerticalContentAlignment { get; set; } VerticalAlignment VerticalContentAlignment { get; set; }
} }
} }

2
src/Avalonia.Controls/IControl.cs

@ -3,8 +3,6 @@ using Avalonia.Input;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.VisualTree; using Avalonia.VisualTree;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>

2
src/Avalonia.Controls/IHeadered.cs

@ -8,6 +8,6 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or set the header. /// Gets or set the header.
/// </summary> /// </summary>
object Header { get; set; } object? Header { get; set; }
} }
} }

2
src/Avalonia.Controls/IMenuElement.cs

@ -1,8 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Input; using Avalonia.Input;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>

4
src/Avalonia.Controls/IMenuItem.cs

@ -1,6 +1,4 @@
#nullable enable namespace Avalonia.Controls
namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
/// Represents a <see cref="MenuItem"/>. /// Represents a <see cref="MenuItem"/>.

4
src/Avalonia.Controls/IScrollAnchorProvider.cs

@ -1,6 +1,4 @@
#nullable enable namespace Avalonia.Controls
namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
/// Specifies a contract for a scrolling control that supports scroll anchoring. /// Specifies a contract for a scrolling control that supports scroll anchoring.

2
src/Avalonia.Controls/IVirtualizingPanel.cs

@ -16,7 +16,7 @@ namespace Avalonia.Controls
/// Note that this property may remain null if the panel is added to a control that does /// Note that this property may remain null if the panel is added to a control that does
/// not act as a virtualizing controller. /// not act as a virtualizing controller.
/// </remarks> /// </remarks>
IVirtualizingController Controller { get; set; } IVirtualizingController? Controller { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether the panel is full. /// Gets a value indicating whether the panel is full.

56
src/Avalonia.Controls/ItemsControl.cs

@ -32,8 +32,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Items"/> property. /// Defines the <see cref="Items"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<ItemsControl, IEnumerable> ItemsProperty = public static readonly DirectProperty<ItemsControl, IEnumerable?> ItemsProperty =
AvaloniaProperty.RegisterDirect<ItemsControl, IEnumerable>(nameof(Items), o => o.Items, (o, v) => o.Items = v); AvaloniaProperty.RegisterDirect<ItemsControl, IEnumerable?>(nameof(Items), o => o.Items, (o, v) => o.Items = v);
/// <summary> /// <summary>
/// Defines the <see cref="ItemCount"/> property. /// Defines the <see cref="ItemCount"/> property.
@ -50,13 +50,13 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="ItemTemplate"/> property. /// Defines the <see cref="ItemTemplate"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IDataTemplate> ItemTemplateProperty = public static readonly StyledProperty<IDataTemplate?> ItemTemplateProperty =
AvaloniaProperty.Register<ItemsControl, IDataTemplate>(nameof(ItemTemplate)); AvaloniaProperty.Register<ItemsControl, IDataTemplate?>(nameof(ItemTemplate));
private IEnumerable _items = new AvaloniaList<object>(); private IEnumerable? _items = new AvaloniaList<object>();
private int _itemCount; private int _itemCount;
private IItemContainerGenerator _itemContainerGenerator; private IItemContainerGenerator? _itemContainerGenerator;
private EventHandler<ChildIndexChangedEventArgs> _childIndexChanged; private EventHandler<ChildIndexChangedEventArgs>? _childIndexChanged;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ItemsControl"/> class. /// Initializes static members of the <see cref="ItemsControl"/> class.
@ -79,7 +79,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the <see cref="IItemContainerGenerator"/> for the control. /// Gets the <see cref="IItemContainerGenerator"/> for the control.
/// </summary> /// </summary>
public IItemContainerGenerator ItemContainerGenerator public IItemContainerGenerator? ItemContainerGenerator
{ {
get get
{ {
@ -104,7 +104,7 @@ namespace Avalonia.Controls
/// Gets or sets the items to display. /// Gets or sets the items to display.
/// </summary> /// </summary>
[Content] [Content]
public IEnumerable Items public IEnumerable? Items
{ {
get { return _items; } get { return _items; }
set { SetAndRaise(ItemsProperty, ref _items, value); } set { SetAndRaise(ItemsProperty, ref _items, value); }
@ -131,7 +131,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the data template used to display the items in the control. /// Gets or sets the data template used to display the items in the control.
/// </summary> /// </summary>
public IDataTemplate ItemTemplate public IDataTemplate? ItemTemplate
{ {
get { return GetValue(ItemTemplateProperty); } get { return GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); } set { SetValue(ItemTemplateProperty, value); }
@ -140,13 +140,13 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the items presenter control. /// Gets the items presenter control.
/// </summary> /// </summary>
public IItemsPresenter Presenter public IItemsPresenter? Presenter
{ {
get; get;
protected set; protected set;
} }
event EventHandler<ChildIndexChangedEventArgs> IChildIndexProvider.ChildIndexChanged event EventHandler<ChildIndexChangedEventArgs>? IChildIndexProvider.ChildIndexChanged
{ {
add => _childIndexChanged += value; add => _childIndexChanged += value;
remove => _childIndexChanged -= value; remove => _childIndexChanged -= value;
@ -161,7 +161,7 @@ namespace Avalonia.Controls
} }
Presenter = presenter; Presenter = presenter;
ItemContainerGenerator.Clear(); ItemContainerGenerator?.Clear();
if (Presenter is IChildIndexProvider innerProvider) if (Presenter is IChildIndexProvider innerProvider)
{ {
@ -189,11 +189,11 @@ namespace Avalonia.Controls
/// <param name="items">The collection.</param> /// <param name="items">The collection.</param>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>The item at the given index or null if the index is out of bounds.</returns> /// <returns>The item at the given index or null if the index is out of bounds.</returns>
protected static object ElementAt(IEnumerable items, int index) protected static object? ElementAt(IEnumerable? items, int index)
{ {
if (index != -1 && index < items.Count()) if (index != -1 && index < items.Count())
{ {
return items.ElementAt(index) ?? null; return items!.ElementAt(index) ?? null;
} }
else else
{ {
@ -207,7 +207,7 @@ namespace Avalonia.Controls
/// <param name="items">The collection.</param> /// <param name="items">The collection.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>The index of the item or -1 if the item was not found.</returns> /// <returns>The index of the item or -1 if the item was not found.</returns>
protected static int IndexOf(IEnumerable items, object item) protected static int IndexOf(IEnumerable? items, object item)
{ {
if (items != null && item != null) if (items != null && item != null)
{ {
@ -282,7 +282,7 @@ namespace Avalonia.Controls
{ {
// If the item is its own container, then it will be removed from the logical tree // If the item is its own container, then it will be removed from the logical tree
// when it is removed from the Items collection. // when it is removed from the Items collection.
if (container?.ContainerControl != container?.Item) if (container.ContainerControl != container.Item)
{ {
LogicalChildren.Remove(container.ContainerControl); LogicalChildren.Remove(container.ContainerControl);
} }
@ -311,20 +311,20 @@ namespace Avalonia.Controls
var container = Presenter?.Panel as INavigableContainer; var container = Presenter?.Panel as INavigableContainer;
if (container == null || if (container == null ||
focus.Current == null || focus?.Current == null ||
direction == null || direction == null ||
direction.Value.IsTab()) direction.Value.IsTab())
{ {
return; return;
} }
IVisual current = focus.Current; IVisual? current = focus.Current;
while (current != null) while (current != null)
{ {
if (current.VisualParent == container && current is IInputElement inputElement) if (current.VisualParent == container && current is IInputElement inputElement)
{ {
IInputElement next = GetNextControl(container, direction.Value, inputElement, false); var next = GetNextControl(container, direction.Value, inputElement, false);
if (next != null) if (next != null)
{ {
@ -406,7 +406,7 @@ namespace Avalonia.Controls
/// Given a collection of items, adds those that are controls to the logical children. /// Given a collection of items, adds those that are controls to the logical children.
/// </summary> /// </summary>
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
private void AddControlItemsToLogicalChildren(IEnumerable items) private void AddControlItemsToLogicalChildren(IEnumerable? items)
{ {
var toAdd = new List<ILogical>(); var toAdd = new List<ILogical>();
@ -430,7 +430,7 @@ namespace Avalonia.Controls
/// Given a collection of items, removes those that are controls to from logical children. /// Given a collection of items, removes those that are controls to from logical children.
/// </summary> /// </summary>
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
private void RemoveControlItemsFromLogicalChildren(IEnumerable items) private void RemoveControlItemsFromLogicalChildren(IEnumerable? items)
{ {
var toRemove = new List<ILogical>(); var toRemove = new List<ILogical>();
@ -454,7 +454,7 @@ namespace Avalonia.Controls
/// Subscribes to an <see cref="Items"/> collection. /// Subscribes to an <see cref="Items"/> collection.
/// </summary> /// </summary>
/// <param name="items">The items collection.</param> /// <param name="items">The items collection.</param>
private void SubscribeToItems(IEnumerable items) private void SubscribeToItems(IEnumerable? items)
{ {
if (items is INotifyCollectionChanged incc) if (items is INotifyCollectionChanged incc)
{ {
@ -470,7 +470,7 @@ namespace Avalonia.Controls
{ {
if (_itemContainerGenerator != null) if (_itemContainerGenerator != null)
{ {
_itemContainerGenerator.ItemTemplate = (IDataTemplate)e.NewValue; _itemContainerGenerator.ItemTemplate = (IDataTemplate?)e.NewValue;
// TODO: Rebuild the item containers. // TODO: Rebuild the item containers.
} }
} }
@ -497,13 +497,13 @@ namespace Avalonia.Controls
PseudoClasses.Set(":singleitem", itemCount == 1); PseudoClasses.Set(":singleitem", itemCount == 1);
} }
protected static IInputElement GetNextControl( protected static IInputElement? GetNextControl(
INavigableContainer container, INavigableContainer container,
NavigationDirection direction, NavigationDirection direction,
IInputElement from, IInputElement? from,
bool wrap) bool wrap)
{ {
IInputElement result; IInputElement? result;
var c = from; var c = from;
do do
@ -525,7 +525,7 @@ namespace Avalonia.Controls
return null; return null;
} }
private void PresenterChildIndexChanged(object sender, ChildIndexChangedEventArgs e) private void PresenterChildIndexChanged(object? sender, ChildIndexChangedEventArgs e)
{ {
_childIndexChanged?.Invoke(this, e); _childIndexChanged?.Invoke(this, e);
} }

8
src/Avalonia.Controls/ItemsSourceView.cs

@ -7,12 +7,9 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
@ -196,7 +193,7 @@ namespace Avalonia.Controls
_collectionChanged?.Invoke(this, args); _collectionChanged?.Invoke(this, args);
} }
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
OnItemsSourceChanged(e); OnItemsSourceChanged(e);
} }
@ -239,8 +236,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>The item.</returns> /// <returns>The item.</returns>
[return: MaybeNull] public new T GetAt(int index) => (T)Inner[index]!;
public new T GetAt(int index) => (T)Inner[index];
public IEnumerator<T> GetEnumerator() => Inner.Cast<T>().GetEnumerator(); public IEnumerator<T> GetEnumerator() => Inner.Cast<T>().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Inner.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => Inner.GetEnumerator();

8
src/Avalonia.Controls/Label.cs

@ -18,19 +18,19 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Target"/> Direct property /// Defines the <see cref="Target"/> Direct property
/// </summary> /// </summary>
public static readonly DirectProperty<Label, IInputElement> TargetProperty = public static readonly DirectProperty<Label, IInputElement?> TargetProperty =
AvaloniaProperty.RegisterDirect<Label, IInputElement>(nameof(Target), lbl => lbl.Target, (lbl, inp) => lbl.Target = inp); AvaloniaProperty.RegisterDirect<Label, IInputElement?>(nameof(Target), lbl => lbl.Target, (lbl, inp) => lbl.Target = inp);
/// <summary> /// <summary>
/// Label focus target storage field /// Label focus target storage field
/// </summary> /// </summary>
private IInputElement _target; private IInputElement? _target;
/// <summary> /// <summary>
/// Label focus Target /// Label focus Target
/// </summary> /// </summary>
[ResolveByName] [ResolveByName]
public IInputElement Target public IInputElement? Target
{ {
get => _target; get => _target;
set => SetAndRaise(TargetProperty, ref _target, value); set => SetAndRaise(TargetProperty, ref _target, value);

14
src/Avalonia.Controls/LayoutTransformControl.cs

@ -14,8 +14,8 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public class LayoutTransformControl : Decorator public class LayoutTransformControl : Decorator
{ {
public static readonly StyledProperty<ITransform> LayoutTransformProperty = public static readonly StyledProperty<ITransform?> LayoutTransformProperty =
AvaloniaProperty.Register<LayoutTransformControl, ITransform>(nameof(LayoutTransform)); AvaloniaProperty.Register<LayoutTransformControl, ITransform?>(nameof(LayoutTransform));
public static readonly StyledProperty<bool> UseRenderTransformProperty = public static readonly StyledProperty<bool> UseRenderTransformProperty =
AvaloniaProperty.Register<LayoutTransformControl, bool>(nameof(UseRenderTransform)); AvaloniaProperty.Register<LayoutTransformControl, bool>(nameof(UseRenderTransform));
@ -37,7 +37,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets a graphics transformation that should apply to this element when layout is performed. /// Gets or sets a graphics transformation that should apply to this element when layout is performed.
/// </summary> /// </summary>
public ITransform LayoutTransform public ITransform? LayoutTransform
{ {
get { return GetValue(LayoutTransformProperty); } get { return GetValue(LayoutTransformProperty); }
set { SetValue(LayoutTransformProperty, value); } set { SetValue(LayoutTransformProperty, value); }
@ -52,7 +52,7 @@ namespace Avalonia.Controls
set { SetValue(UseRenderTransformProperty, value); } set { SetValue(UseRenderTransformProperty, value); }
} }
public IControl TransformRoot => Child; public IControl? TransformRoot => Child;
/// <summary> /// <summary>
/// Provides the behavior for the "Arrange" pass of layout. /// Provides the behavior for the "Arrange" pass of layout.
@ -146,7 +146,7 @@ namespace Avalonia.Controls
return transformedDesiredSize; return transformedDesiredSize;
} }
IDisposable _renderTransformChangedEvent; IDisposable? _renderTransformChangedEvent;
private void OnUseRenderTransformPropertyChanged(AvaloniaPropertyChangedEventArgs e) private void OnUseRenderTransformPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{ {
@ -158,7 +158,7 @@ namespace Avalonia.Controls
// workaround. // workaround.
var target = e.Sender as LayoutTransformControl; var target = e.Sender as LayoutTransformControl;
var shouldUseRenderTransform = (bool)e.NewValue; var shouldUseRenderTransform = (bool)e.NewValue!;
if (target != null) if (target != null)
{ {
if (shouldUseRenderTransform) if (shouldUseRenderTransform)
@ -217,7 +217,7 @@ namespace Avalonia.Controls
/// Transformation matrix corresponding to _matrixTransform. /// Transformation matrix corresponding to _matrixTransform.
/// </summary> /// </summary>
private Matrix _transformation; private Matrix _transformation;
private IDisposable _transformChangedEvent = null; private IDisposable? _transformChangedEvent = null;
/// <summary> /// <summary>
/// Returns true if Size a is smaller than Size b in either dimension. /// Returns true if Size a is smaller than Size b in either dimension.

12
src/Avalonia.Controls/ListBox.cs

@ -23,13 +23,13 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Scroll"/> property. /// Defines the <see cref="Scroll"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<ListBox, IScrollable> ScrollProperty = public static readonly DirectProperty<ListBox, IScrollable?> ScrollProperty =
AvaloniaProperty.RegisterDirect<ListBox, IScrollable>(nameof(Scroll), o => o.Scroll); AvaloniaProperty.RegisterDirect<ListBox, IScrollable?>(nameof(Scroll), o => o.Scroll);
/// <summary> /// <summary>
/// Defines the <see cref="SelectedItems"/> property. /// Defines the <see cref="SelectedItems"/> property.
/// </summary> /// </summary>
public static readonly new DirectProperty<SelectingItemsControl, IList> SelectedItemsProperty = public static readonly new DirectProperty<SelectingItemsControl, IList?> SelectedItemsProperty =
SelectingItemsControl.SelectedItemsProperty; SelectingItemsControl.SelectedItemsProperty;
/// <summary> /// <summary>
@ -50,7 +50,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty<ItemVirtualizationMode> VirtualizationModeProperty = public static readonly StyledProperty<ItemVirtualizationMode> VirtualizationModeProperty =
ItemsPresenter.VirtualizationModeProperty.AddOwner<ListBox>(); ItemsPresenter.VirtualizationModeProperty.AddOwner<ListBox>();
private IScrollable _scroll; private IScrollable? _scroll;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ItemsControl"/> class. /// Initializes static members of the <see cref="ItemsControl"/> class.
@ -64,14 +64,14 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the scroll information for the <see cref="ListBox"/>. /// Gets the scroll information for the <see cref="ListBox"/>.
/// </summary> /// </summary>
public IScrollable Scroll public IScrollable? Scroll
{ {
get { return _scroll; } get { return _scroll; }
private set { SetAndRaise(ScrollProperty, ref _scroll, value); } private set { SetAndRaise(ScrollProperty, ref _scroll, value); }
} }
/// <inheritdoc/> /// <inheritdoc/>
public new IList SelectedItems public new IList? SelectedItems
{ {
get => base.SelectedItems; get => base.SelectedItems;
set => base.SelectedItems = value; set => base.SelectedItems = value;

10
src/Avalonia.Controls/MaskedTextBox.cs

@ -8,8 +8,6 @@ using Avalonia.Input.Platform;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Styling; using Avalonia.Styling;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
public class MaskedTextBox : TextBox, IStyleable public class MaskedTextBox : TextBox, IStyleable
@ -241,7 +239,7 @@ namespace Avalonia.Controls
switch (e.Key) switch (e.Key)
{ {
case Key.Delete: case Key.Delete:
if (CaretIndex < Text.Length) if (CaretIndex < Text?.Length)
{ {
if (MaskProvider.RemoveAt(CaretIndex)) if (MaskProvider.RemoveAt(CaretIndex))
{ {
@ -286,7 +284,7 @@ namespace Avalonia.Controls
{ {
void UpdateMaskProvider() void UpdateMaskProvider()
{ {
MaskProvider = new MaskedTextProvider(Mask, Culture, true, PromptChar, PasswordChar, AsciiOnly) { ResetOnSpace = ResetOnSpace, ResetOnPrompt = ResetOnPrompt }; MaskProvider = new MaskedTextProvider(Mask!, Culture, true, PromptChar, PasswordChar, AsciiOnly) { ResetOnSpace = ResetOnSpace, ResetOnPrompt = ResetOnPrompt };
if (Text != null) if (Text != null)
{ {
MaskProvider.Set(Text); MaskProvider.Set(Text);
@ -383,11 +381,11 @@ namespace Avalonia.Controls
} }
} }
if (CaretIndex < Text.Length) if (CaretIndex < Text?.Length)
{ {
CaretIndex = GetNextCharacterPosition(CaretIndex); CaretIndex = GetNextCharacterPosition(CaretIndex);
if (MaskProvider.InsertAt(e.Text, CaretIndex)) if (MaskProvider.InsertAt(e.Text!, CaretIndex))
{ {
CaretIndex++; CaretIndex++;
} }

2
src/Avalonia.Controls/Menu.cs

@ -5,8 +5,6 @@ using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>

13
src/Avalonia.Controls/MenuBase.cs

@ -8,8 +8,6 @@ using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
@ -83,12 +81,13 @@ namespace Avalonia.Controls
{ {
var index = SelectedIndex; var index = SelectedIndex;
return (index != -1) ? return (index != -1) ?
(IMenuItem)ItemContainerGenerator.ContainerFromIndex(index) : (IMenuItem?)ItemContainerGenerator!.ContainerFromIndex(index) :
null; null;
} }
set set
{ {
SelectedIndex = ItemContainerGenerator.IndexFromContainer(value); SelectedIndex = value is not null ?
ItemContainerGenerator!.IndexFromContainer(value) : -1;
} }
} }
@ -97,7 +96,7 @@ namespace Avalonia.Controls
{ {
get get
{ {
return ItemContainerGenerator.Containers return ItemContainerGenerator!.Containers
.Select(x => x.ContainerControl) .Select(x => x.ContainerControl)
.OfType<IMenuItem>(); .OfType<IMenuItem>();
} }
@ -111,7 +110,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Occurs when a <see cref="Menu"/> is opened. /// Occurs when a <see cref="Menu"/> is opened.
/// </summary> /// </summary>
public event EventHandler<RoutedEventArgs> MenuOpened public event EventHandler<RoutedEventArgs>? MenuOpened
{ {
add { AddHandler(MenuOpenedEvent, value); } add { AddHandler(MenuOpenedEvent, value); }
remove { RemoveHandler(MenuOpenedEvent, value); } remove { RemoveHandler(MenuOpenedEvent, value); }
@ -120,7 +119,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Occurs when a <see cref="Menu"/> is closed. /// Occurs when a <see cref="Menu"/> is closed.
/// </summary> /// </summary>
public event EventHandler<RoutedEventArgs> MenuClosed public event EventHandler<RoutedEventArgs>? MenuClosed
{ {
add { AddHandler(MenuClosedEvent, value); } add { AddHandler(MenuClosedEvent, value); }
remove { RemoveHandler(MenuClosedEvent, value); } remove { RemoveHandler(MenuClosedEvent, value); }

44
src/Avalonia.Controls/MenuItem.cs

@ -14,8 +14,6 @@ using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.VisualTree; using Avalonia.VisualTree;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
@ -42,20 +40,20 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="CommandParameter"/> property. /// Defines the <see cref="CommandParameter"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<object> CommandParameterProperty = public static readonly StyledProperty<object?> CommandParameterProperty =
Button.CommandParameterProperty.AddOwner<MenuItem>(); Button.CommandParameterProperty.AddOwner<MenuItem>();
/// <summary> /// <summary>
/// Defines the <see cref="Icon"/> property. /// Defines the <see cref="Icon"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<object> IconProperty = public static readonly StyledProperty<object?> IconProperty =
AvaloniaProperty.Register<MenuItem, object>(nameof(Icon)); AvaloniaProperty.Register<MenuItem, object?>(nameof(Icon));
/// <summary> /// <summary>
/// Defines the <see cref="InputGesture"/> property. /// Defines the <see cref="InputGesture"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<KeyGesture> InputGestureProperty = public static readonly StyledProperty<KeyGesture?> InputGestureProperty =
AvaloniaProperty.Register<MenuItem, KeyGesture>(nameof(InputGesture)); AvaloniaProperty.Register<MenuItem, KeyGesture?>(nameof(InputGesture));
/// <summary> /// <summary>
/// Defines the <see cref="IsSelected"/> property. /// Defines the <see cref="IsSelected"/> property.
@ -164,7 +162,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Occurs when a <see cref="MenuItem"/> without a submenu is clicked. /// Occurs when a <see cref="MenuItem"/> without a submenu is clicked.
/// </summary> /// </summary>
public event EventHandler<RoutedEventArgs> Click public event EventHandler<RoutedEventArgs>? Click
{ {
add { AddHandler(ClickEvent, value); } add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); } remove { RemoveHandler(ClickEvent, value); }
@ -176,7 +174,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// A bubbling version of the <see cref="InputElement.PointerEnter"/> event for menu items. /// A bubbling version of the <see cref="InputElement.PointerEnter"/> event for menu items.
/// </remarks> /// </remarks>
public event EventHandler<PointerEventArgs> PointerEnterItem public event EventHandler<PointerEventArgs>? PointerEnterItem
{ {
add { AddHandler(PointerEnterItemEvent, value); } add { AddHandler(PointerEnterItemEvent, value); }
remove { RemoveHandler(PointerEnterItemEvent, value); } remove { RemoveHandler(PointerEnterItemEvent, value); }
@ -188,7 +186,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// A bubbling version of the <see cref="InputElement.PointerLeave"/> event for menu items. /// A bubbling version of the <see cref="InputElement.PointerLeave"/> event for menu items.
/// </remarks> /// </remarks>
public event EventHandler<PointerEventArgs> PointerLeaveItem public event EventHandler<PointerEventArgs>? PointerLeaveItem
{ {
add { AddHandler(PointerLeaveItemEvent, value); } add { AddHandler(PointerLeaveItemEvent, value); }
remove { RemoveHandler(PointerLeaveItemEvent, value); } remove { RemoveHandler(PointerLeaveItemEvent, value); }
@ -197,7 +195,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Occurs when a <see cref="MenuItem"/>'s submenu is opened. /// Occurs when a <see cref="MenuItem"/>'s submenu is opened.
/// </summary> /// </summary>
public event EventHandler<RoutedEventArgs> SubmenuOpened public event EventHandler<RoutedEventArgs>? SubmenuOpened
{ {
add { AddHandler(SubmenuOpenedEvent, value); } add { AddHandler(SubmenuOpenedEvent, value); }
remove { RemoveHandler(SubmenuOpenedEvent, value); } remove { RemoveHandler(SubmenuOpenedEvent, value); }
@ -225,7 +223,7 @@ namespace Avalonia.Controls
/// Gets or sets the parameter to pass to the <see cref="Command"/> property of a /// Gets or sets the parameter to pass to the <see cref="Command"/> property of a
/// <see cref="MenuItem"/>. /// <see cref="MenuItem"/>.
/// </summary> /// </summary>
public object CommandParameter public object? CommandParameter
{ {
get { return GetValue(CommandParameterProperty); } get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); } set { SetValue(CommandParameterProperty, value); }
@ -234,7 +232,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the icon that appears in a <see cref="MenuItem"/>. /// Gets or sets the icon that appears in a <see cref="MenuItem"/>.
/// </summary> /// </summary>
public object Icon public object? Icon
{ {
get { return GetValue(IconProperty); } get { return GetValue(IconProperty); }
set { SetValue(IconProperty, value); } set { SetValue(IconProperty, value); }
@ -247,7 +245,7 @@ namespace Avalonia.Controls
/// Setting this property does not cause the input gesture to be handled by the menu item, /// Setting this property does not cause the input gesture to be handled by the menu item,
/// it simply displays the gesture text in the menu. /// it simply displays the gesture text in the menu.
/// </remarks> /// </remarks>
public KeyGesture InputGesture public KeyGesture? InputGesture
{ {
get { return GetValue(InputGestureProperty); } get { return GetValue(InputGestureProperty); }
set { SetValue(InputGestureProperty, value); } set { SetValue(InputGestureProperty, value); }
@ -310,12 +308,12 @@ namespace Avalonia.Controls
{ {
var index = SelectedIndex; var index = SelectedIndex;
return (index != -1) ? return (index != -1) ?
(IMenuItem)ItemContainerGenerator.ContainerFromIndex(index) : (IMenuItem?)ItemContainerGenerator!.ContainerFromIndex(index) :
null; null;
} }
set set
{ {
SelectedIndex = ItemContainerGenerator.IndexFromContainer(value); SelectedIndex = value is not null ? ItemContainerGenerator!.IndexFromContainer(value) : -1;
} }
} }
@ -324,7 +322,7 @@ namespace Avalonia.Controls
{ {
get get
{ {
return ItemContainerGenerator.Containers return ItemContainerGenerator!.Containers
.Select(x => x.ContainerControl) .Select(x => x.ContainerControl)
.OfType<IMenuItem>(); .OfType<IMenuItem>();
} }
@ -390,7 +388,7 @@ namespace Avalonia.Controls
parent = parent.Parent; parent = parent.Parent;
} }
_isEmbeddedInMenu = parent.FindLogicalAncestorOfType<IMenu>(true) != null; _isEmbeddedInMenu = parent?.FindLogicalAncestorOfType<IMenu>(true) != null;
} }
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
@ -561,7 +559,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void CanExecuteChanged(object sender, EventArgs e) private void CanExecuteChanged(object? sender, EventArgs e)
{ {
TryUpdateCanExecute(); TryUpdateCanExecute();
} }
@ -655,7 +653,7 @@ namespace Avalonia.Controls
if (value) if (value)
{ {
foreach (var item in Items.OfType<MenuItem>()) foreach (var item in Items!.OfType<MenuItem>())
{ {
item.TryUpdateCanExecute(); item.TryUpdateCanExecute();
} }
@ -677,13 +675,13 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void PopupOpened(object sender, EventArgs e) private void PopupOpened(object? sender, EventArgs e)
{ {
var selected = SelectedIndex; var selected = SelectedIndex;
if (selected != -1) if (selected != -1)
{ {
var container = ItemContainerGenerator.ContainerFromIndex(selected); var container = ItemContainerGenerator?.ContainerFromIndex(selected);
container?.Focus(); container?.Focus();
} }
} }
@ -693,7 +691,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
private void PopupClosed(object sender, EventArgs e) private void PopupClosed(object? sender, EventArgs e)
{ {
SelectedItem = null; SelectedItem = null;
} }

8
src/Avalonia.Controls/MenuItemAccessKeyHandler.cs

@ -19,7 +19,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// The window to which the handler belongs. /// The window to which the handler belongs.
/// </summary> /// </summary>
private IInputRoot _owner; private IInputRoot? _owner;
/// <summary> /// <summary>
/// Gets or sets the window's main menu. /// Gets or sets the window's main menu.
@ -27,7 +27,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// This property is ignored as a menu item cannot have a main menu. /// This property is ignored as a menu item cannot have a main menu.
/// </remarks> /// </remarks>
public IMainMenu MainMenu { get; set; } public IMainMenu? MainMenu { get; set; }
/// <summary> /// <summary>
/// Sets the owner of the access key handler. /// Sets the owner of the access key handler.
@ -38,7 +38,7 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
public void SetOwner(IInputRoot owner) public void SetOwner(IInputRoot owner)
{ {
Contract.Requires<ArgumentNullException>(owner != null); _ = owner ?? throw new ArgumentNullException(nameof(owner));
if (_owner != null) if (_owner != null)
{ {
@ -84,7 +84,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
protected virtual void OnTextInput(object sender, TextInputEventArgs e) protected virtual void OnTextInput(object? sender, TextInputEventArgs e)
{ {
if (!string.IsNullOrWhiteSpace(e.Text)) if (!string.IsNullOrWhiteSpace(e.Text))
{ {

2
src/Avalonia.Controls/Mixins/SelectableMixin.cs

@ -40,7 +40,7 @@ namespace Avalonia.Controls.Mixins
public static void Attach<TControl>(AvaloniaProperty<bool> isSelected) public static void Attach<TControl>(AvaloniaProperty<bool> isSelected)
where TControl : class, IControl where TControl : class, IControl
{ {
Contract.Requires<ArgumentNullException>(isSelected != null); _ = isSelected ?? throw new ArgumentNullException(nameof(isSelected));
isSelected.Changed.Subscribe(x => isSelected.Changed.Subscribe(x =>
{ {

19
src/Avalonia.Controls/NativeControlHost.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
@ -9,10 +10,10 @@ namespace Avalonia.Controls
{ {
public class NativeControlHost : Control public class NativeControlHost : Control
{ {
private TopLevel _currentRoot; private TopLevel? _currentRoot;
private INativeControlHostImpl _currentHost; private INativeControlHostImpl? _currentHost;
private INativeControlHostControlTopLevelAttachment _attachment; private INativeControlHostControlTopLevelAttachment? _attachment;
private IPlatformHandle _nativeControlHandle; private IPlatformHandle? _nativeControlHandle;
private bool _queuedForDestruction; private bool _queuedForDestruction;
private bool _queuedForMoveResize; private bool _queuedForMoveResize;
private readonly List<Visual> _propertyChangedSubscriptions = new List<Visual>(); private readonly List<Visual> _propertyChangedSubscriptions = new List<Visual>();
@ -35,7 +36,7 @@ namespace Avalonia.Controls
UpdateHost(); UpdateHost();
} }
private void PropertyChangedHandler(object sender, AvaloniaPropertyChangedEventArgs e) private void PropertyChangedHandler(object? sender, AvaloniaPropertyChangedEventArgs e)
{ {
if (e.IsEffectiveValueChange && (e.Property == BoundsProperty || e.Property == IsVisibleProperty)) if (e.IsEffectiveValueChange && (e.Property == BoundsProperty || e.Property == IsVisibleProperty))
EnqueueForMoveResize(); EnqueueForMoveResize();
@ -58,9 +59,8 @@ namespace Avalonia.Controls
{ {
_queuedForMoveResize = false; _queuedForMoveResize = false;
_currentHost = (_currentRoot?.PlatformImpl as ITopLevelImplWithNativeControlHost)?.NativeControlHost; _currentHost = (_currentRoot?.PlatformImpl as ITopLevelImplWithNativeControlHost)?.NativeControlHost;
var needsAttachment = _currentHost != null;
if (needsAttachment) if (_currentHost != null)
{ {
// If there is an existing attachment, ensure that we are attached to the proper host or destroy the attachment // If there is an existing attachment, ensure that we are attached to the proper host or destroy the attachment
if (_attachment != null && _attachment.AttachedTo != _currentHost) if (_attachment != null && _attachment.AttachedTo != _currentHost)
@ -119,6 +119,8 @@ namespace Avalonia.Controls
private Rect? GetAbsoluteBounds() private Rect? GetAbsoluteBounds()
{ {
Debug.Assert(_currentRoot is not null);
var bounds = Bounds; var bounds = Bounds;
var position = this.TranslatePoint(default, _currentRoot); var position = this.TranslatePoint(default, _currentRoot);
if (position == null) if (position == null)
@ -140,9 +142,8 @@ namespace Avalonia.Controls
return false; return false;
var bounds = GetAbsoluteBounds(); var bounds = GetAbsoluteBounds();
var needsShow = IsEffectivelyVisible && bounds.HasValue;
if (needsShow) if (IsEffectivelyVisible && bounds.HasValue)
{ {
if (bounds.Value.IsEmpty) if (bounds.Value.IsEmpty)
return false; return false;

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

@ -18,7 +18,7 @@ namespace Avalonia.Controls
class NativeMenuInfo class NativeMenuInfo
{ {
public bool ChangingIsExported { get; set; } public bool ChangingIsExported { get; set; }
public ITopLevelNativeMenuExporter Exporter { get; } public ITopLevelNativeMenuExporter? Exporter { get; }
public NativeMenuInfo(TopLevel target) public NativeMenuInfo(TopLevel target)
{ {

16
src/Avalonia.Controls/NativeMenu.cs

@ -11,7 +11,7 @@ namespace Avalonia.Controls
{ {
private readonly AvaloniaList<NativeMenuItemBase> _items = private readonly AvaloniaList<NativeMenuItemBase> _items =
new AvaloniaList<NativeMenuItemBase> { ResetBehavior = ResetBehavior.Remove }; new AvaloniaList<NativeMenuItemBase> { ResetBehavior = ResetBehavior.Remove };
private NativeMenuItem _parent; private NativeMenuItem? _parent;
[Content] [Content]
public IList<NativeMenuItemBase> Items => _items; public IList<NativeMenuItemBase> Items => _items;
@ -23,7 +23,7 @@ namespace Avalonia.Controls
/// Use this event to add, remove or modify menu items before a menu is /// Use this event to add, remove or modify menu items before a menu is
/// shown or a hotkey is pressed. /// shown or a hotkey is pressed.
/// </remarks> /// </remarks>
public event EventHandler<EventArgs> NeedsUpdate; public event EventHandler<EventArgs>? NeedsUpdate;
/// <summary> /// <summary>
/// Raised before the menu is opened. /// Raised before the menu is opened.
@ -31,7 +31,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// Do not update the menu in this event; use <see cref="NeedsUpdate"/>. /// Do not update the menu in this event; use <see cref="NeedsUpdate"/>.
/// </remarks> /// </remarks>
public event EventHandler<EventArgs> Opening; public event EventHandler<EventArgs>? Opening;
/// <summary> /// <summary>
/// Raised after the menu is closed. /// Raised after the menu is closed.
@ -39,7 +39,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// Do not update the menu in this event; use <see cref="NeedsUpdate"/>. /// Do not update the menu in this event; use <see cref="NeedsUpdate"/>.
/// </remarks> /// </remarks>
public event EventHandler<EventArgs> Closed; public event EventHandler<EventArgs>? Closed;
public NativeMenu() public NativeMenu()
{ {
@ -68,7 +68,7 @@ namespace Avalonia.Controls
throw new InvalidOperationException("NativeMenuItem already has a parent"); throw new InvalidOperationException("NativeMenuItem already has a parent");
} }
private void ItemsChanged(object sender, NotifyCollectionChangedEventArgs e) private void ItemsChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
if (e.OldItems != null) if (e.OldItems != null)
foreach (NativeMenuItemBase i in e.OldItems) foreach (NativeMenuItemBase i in e.OldItems)
@ -78,10 +78,10 @@ namespace Avalonia.Controls
i.Parent = this; i.Parent = this;
} }
public static readonly DirectProperty<NativeMenu, NativeMenuItem> ParentProperty = public static readonly DirectProperty<NativeMenu, NativeMenuItem?> ParentProperty =
AvaloniaProperty.RegisterDirect<NativeMenu, NativeMenuItem>("Parent", o => o.Parent, (o, v) => o.Parent = v); AvaloniaProperty.RegisterDirect<NativeMenu, NativeMenuItem?>("Parent", o => o.Parent, (o, v) => o.Parent = v);
public NativeMenuItem Parent public NativeMenuItem? Parent
{ {
get => _parent; get => _parent;
set => SetAndRaise(ParentProperty, ref _parent, value); set => SetAndRaise(ParentProperty, ref _parent, value);

4
src/Avalonia.Controls/NativeMenuBar.cs

@ -27,9 +27,9 @@ namespace Avalonia.Controls
menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable); menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable);
} }
private static void OnMenuItemClick(object sender, RoutedEventArgs e) private static void OnMenuItemClick(object? sender, RoutedEventArgs e)
{ {
(((MenuItem)sender).DataContext as INativeMenuItemExporterEventsImplBridge)?.RaiseClicked(); (((MenuItem)sender!).DataContext as INativeMenuItemExporterEventsImplBridge)?.RaiseClicked();
} }
} }
} }

48
src/Avalonia.Controls/NativeMenuItem.cs

@ -9,23 +9,23 @@ namespace Avalonia.Controls
{ {
public class NativeMenuItem : NativeMenuItemBase, INativeMenuItemExporterEventsImplBridge public class NativeMenuItem : NativeMenuItemBase, INativeMenuItemExporterEventsImplBridge
{ {
private string _header; private string? _header;
private KeyGesture _gesture; private KeyGesture? _gesture;
private bool _isEnabled = true; private bool _isEnabled = true;
private ICommand _command; private ICommand? _command;
private bool _isChecked = false; private bool _isChecked = false;
private NativeMenuItemToggleType _toggleType; private NativeMenuItemToggleType _toggleType;
private IBitmap _icon; private IBitmap? _icon;
private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber; private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber;
private NativeMenu _menu; private NativeMenu? _menu;
static NativeMenuItem() static NativeMenuItem()
{ {
MenuProperty.Changed.Subscribe(args => MenuProperty.Changed.Subscribe(args =>
{ {
var item = (NativeMenuItem)args.Sender; var item = (NativeMenuItem)args.Sender;
var value = args.NewValue.GetValueOrDefault(); var value = args.NewValue.GetValueOrDefault()!;
if (value.Parent != null && value.Parent != item) if (value.Parent != null && value.Parent != item)
throw new InvalidOperationException("NativeMenu already has a parent"); throw new InvalidOperationException("NativeMenu already has a parent");
value.Parent = item; value.Parent = item;
@ -59,44 +59,44 @@ namespace Avalonia.Controls
Header = header; Header = header;
} }
public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty = public static readonly DirectProperty<NativeMenuItem, NativeMenu?> MenuProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v); AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu?>(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v);
[Content] [Content]
public NativeMenu Menu public NativeMenu? Menu
{ {
get => _menu; get => _menu;
set set
{ {
if (value.Parent != null && value.Parent != this) if (value != null && value.Parent != null && value.Parent != this)
throw new InvalidOperationException("NativeMenu already has a parent"); throw new InvalidOperationException("NativeMenu already has a parent");
SetAndRaise(MenuProperty, ref _menu, value); SetAndRaise(MenuProperty, ref _menu, value);
} }
} }
public static readonly DirectProperty<NativeMenuItem, IBitmap> IconProperty = public static readonly DirectProperty<NativeMenuItem, IBitmap?> IconProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, IBitmap>(nameof(Icon), o => o.Icon, (o, v) => o.Icon = v); AvaloniaProperty.RegisterDirect<NativeMenuItem, IBitmap?>(nameof(Icon), o => o.Icon, (o, v) => o.Icon = v);
public IBitmap Icon public IBitmap? Icon
{ {
get => _icon; get => _icon;
set => SetAndRaise(IconProperty, ref _icon, value); set => SetAndRaise(IconProperty, ref _icon, value);
} }
public static readonly DirectProperty<NativeMenuItem, string> HeaderProperty = public static readonly DirectProperty<NativeMenuItem, string?> HeaderProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, string>(nameof(Header), o => o.Header, (o, v) => o.Header = v); AvaloniaProperty.RegisterDirect<NativeMenuItem, string?>(nameof(Header), o => o.Header, (o, v) => o.Header = v);
public string Header public string? Header
{ {
get => _header; get => _header;
set => SetAndRaise(HeaderProperty, ref _header, value); set => SetAndRaise(HeaderProperty, ref _header, value);
} }
public static readonly DirectProperty<NativeMenuItem, KeyGesture> GestureProperty = public static readonly DirectProperty<NativeMenuItem, KeyGesture?> GestureProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, KeyGesture>(nameof(Gesture), o => o.Gesture, (o, v) => o.Gesture = v); AvaloniaProperty.RegisterDirect<NativeMenuItem, KeyGesture?>(nameof(Gesture), o => o.Gesture, (o, v) => o.Gesture = v);
public KeyGesture Gesture public KeyGesture? Gesture
{ {
get => _gesture; get => _gesture;
set => SetAndRaise(GestureProperty, ref _gesture, value); set => SetAndRaise(GestureProperty, ref _gesture, value);
@ -126,7 +126,7 @@ namespace Avalonia.Controls
set => SetAndRaise(ToggleTypeProperty, ref _toggleType, value); set => SetAndRaise(ToggleTypeProperty, ref _toggleType, value);
} }
public static readonly DirectProperty<NativeMenuItem, ICommand> CommandProperty = public static readonly DirectProperty<NativeMenuItem, ICommand?> CommandProperty =
Button.CommandProperty.AddOwner<NativeMenuItem>( Button.CommandProperty.AddOwner<NativeMenuItem>(
menuItem => menuItem.Command, menuItem => menuItem.Command,
(menuItem, command) => menuItem.Command = command, (menuItem, command) => menuItem.Command = command,
@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="CommandParameter"/> property. /// Defines the <see cref="CommandParameter"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<object> CommandParameterProperty = public static readonly StyledProperty<object?> CommandParameterProperty =
Button.CommandParameterProperty.AddOwner<MenuItem>(); Button.CommandParameterProperty.AddOwner<MenuItem>();
public static readonly DirectProperty<NativeMenuItem, bool> IsEnabledProperty = public static readonly DirectProperty<NativeMenuItem, bool> IsEnabledProperty =
@ -154,7 +154,7 @@ namespace Avalonia.Controls
public bool HasClickHandlers => Click != null; public bool HasClickHandlers => Click != null;
public ICommand Command public ICommand? Command
{ {
get => _command; get => _command;
set set
@ -175,7 +175,7 @@ namespace Avalonia.Controls
/// Gets or sets the parameter to pass to the <see cref="Command"/> property of a /// Gets or sets the parameter to pass to the <see cref="Command"/> property of a
/// <see cref="NativeMenuItem"/>. /// <see cref="NativeMenuItem"/>.
/// </summary> /// </summary>
public object CommandParameter public object? CommandParameter
{ {
get { return GetValue(CommandParameterProperty); } get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); } set { SetValue(CommandParameterProperty, value); }
@ -184,7 +184,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Occurs when a <see cref="NativeMenuItem"/> is clicked. /// Occurs when a <see cref="NativeMenuItem"/> is clicked.
/// </summary> /// </summary>
public event EventHandler Click; public event EventHandler? Click;
[Obsolete("Use Click event.")] [Obsolete("Use Click event.")]
public event EventHandler Clicked public event EventHandler Clicked

8
src/Avalonia.Controls/NativeMenuItemBase.cs

@ -4,17 +4,17 @@ namespace Avalonia.Controls
{ {
public class NativeMenuItemBase : AvaloniaObject public class NativeMenuItemBase : AvaloniaObject
{ {
private NativeMenu _parent; private NativeMenu? _parent;
internal NativeMenuItemBase() internal NativeMenuItemBase()
{ {
} }
public static readonly DirectProperty<NativeMenuItem, NativeMenu> ParentProperty = public static readonly DirectProperty<NativeMenuItem, NativeMenu?> ParentProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>("Parent", o => o.Parent, (o, v) => o.Parent = v); AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu?>("Parent", o => o.Parent, (o, v) => o.Parent = v);
public NativeMenu Parent public NativeMenu? Parent
{ {
get => _parent; get => _parent;
set => SetAndRaise(ParentProperty, ref _parent, value); set => SetAndRaise(ParentProperty, ref _parent, value);

8
src/Avalonia.Controls/Notifications/INotification.cs

@ -10,12 +10,12 @@ namespace Avalonia.Controls.Notifications
/// <summary> /// <summary>
/// Gets the Title of the notification. /// Gets the Title of the notification.
/// </summary> /// </summary>
string Title { get; } string? Title { get; }
/// <summary> /// <summary>
/// Gets the notification message. /// Gets the notification message.
/// </summary> /// </summary>
string Message { get; } string? Message { get; }
/// <summary> /// <summary>
/// Gets the <see cref="NotificationType"/> of the notification. /// Gets the <see cref="NotificationType"/> of the notification.
@ -31,11 +31,11 @@ namespace Avalonia.Controls.Notifications
/// <summary> /// <summary>
/// Gets an Action to be run when the notification is clicked. /// Gets an Action to be run when the notification is clicked.
/// </summary> /// </summary>
Action OnClick { get; } Action? OnClick { get; }
/// <summary> /// <summary>
/// Gets an Action to be run when the notification is closed. /// Gets an Action to be run when the notification is closed.
/// </summary> /// </summary>
Action OnClose { get; } Action? OnClose { get; }
} }
} }

16
src/Avalonia.Controls/Notifications/Notification.cs

@ -21,12 +21,12 @@ namespace Avalonia.Controls.Notifications
/// Use <see cref="TimeSpan.Zero"/> for notifications that will remain open.</param> /// Use <see cref="TimeSpan.Zero"/> for notifications that will remain open.</param>
/// <param name="onClick">An Action to call when the notification is clicked.</param> /// <param name="onClick">An Action to call when the notification is clicked.</param>
/// <param name="onClose">An Action to call when the notification is closed.</param> /// <param name="onClose">An Action to call when the notification is closed.</param>
public Notification(string title, public Notification(string? title,
string message, string? message,
NotificationType type = NotificationType.Information, NotificationType type = NotificationType.Information,
TimeSpan? expiration = null, TimeSpan? expiration = null,
Action onClick = null, Action? onClick = null,
Action onClose = null) Action? onClose = null)
{ {
Title = title; Title = title;
Message = message; Message = message;
@ -37,10 +37,10 @@ namespace Avalonia.Controls.Notifications
} }
/// <inheritdoc/> /// <inheritdoc/>
public string Title { get; private set; } public string? Title { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public string Message { get; private set; } public string? Message { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public NotificationType Type { get; private set; } public NotificationType Type { get; private set; }
@ -49,9 +49,9 @@ namespace Avalonia.Controls.Notifications
public TimeSpan Expiration { get; private set; } public TimeSpan Expiration { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public Action OnClick { get; private set; } public Action? OnClick { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public Action OnClose { get; private set; } public Action? OnClose { get; private set; }
} }
} }

15
src/Avalonia.Controls/Notifications/NotificationCard.cs

@ -37,8 +37,11 @@ namespace Avalonia.Controls.Notifications
RaiseEvent(new RoutedEventArgs(NotificationClosedEvent)); RaiseEvent(new RoutedEventArgs(NotificationClosedEvent));
}); });
// Disabling nullable checking because of https://github.com/dotnet/reactive/issues/1525
#pragma warning disable CS8620
this.GetObservable(ContentProperty) this.GetObservable(ContentProperty)
.OfType<Notification>() .OfType<Notification>()
#pragma warning restore CS8620
.Subscribe(x => .Subscribe(x =>
{ {
switch (x.Type) switch (x.Type)
@ -102,7 +105,7 @@ namespace Avalonia.Controls.Notifications
/// <summary> /// <summary>
/// Raised when the <see cref="NotificationCard"/> has closed. /// Raised when the <see cref="NotificationCard"/> has closed.
/// </summary> /// </summary>
public event EventHandler<RoutedEventArgs> NotificationClosed public event EventHandler<RoutedEventArgs>? NotificationClosed
{ {
add { AddHandler(NotificationClosedEvent, value); } add { AddHandler(NotificationClosedEvent, value); }
remove { RemoveHandler(NotificationClosedEvent, value); } remove { RemoveHandler(NotificationClosedEvent, value); }
@ -110,13 +113,13 @@ namespace Avalonia.Controls.Notifications
public static bool GetCloseOnClick(Button obj) public static bool GetCloseOnClick(Button obj)
{ {
Contract.Requires<ArgumentNullException>(obj != null); _ = obj ?? throw new ArgumentNullException(nameof(obj));
return (bool)obj.GetValue(CloseOnClickProperty); return (bool)obj.GetValue(CloseOnClickProperty);
} }
public static void SetCloseOnClick(Button obj, bool value) public static void SetCloseOnClick(Button obj, bool value)
{ {
Contract.Requires<ArgumentNullException>(obj != null); _ = obj ?? throw new ArgumentNullException(nameof(obj));
obj.SetValue(CloseOnClickProperty, value); obj.SetValue(CloseOnClickProperty, value);
} }
@ -129,7 +132,7 @@ namespace Avalonia.Controls.Notifications
private static void OnCloseOnClickPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) private static void OnCloseOnClickPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{ {
var button = (Button)d; var button = (Button)d;
var value = (bool)e.NewValue; var value = (bool)e.NewValue!;
if (value) if (value)
{ {
button.Click += Button_Click; button.Click += Button_Click;
@ -143,10 +146,10 @@ namespace Avalonia.Controls.Notifications
/// <summary> /// <summary>
/// Called when a button inside the Notification is clicked. /// Called when a button inside the Notification is clicked.
/// </summary> /// </summary>
private static void Button_Click(object sender, RoutedEventArgs e) private static void Button_Click(object? sender, RoutedEventArgs e)
{ {
var btn = sender as ILogical; var btn = sender as ILogical;
var notification = btn.GetLogicalAncestors().OfType<NotificationCard>().FirstOrDefault(); var notification = btn?.GetLogicalAncestors().OfType<NotificationCard>().FirstOrDefault();
notification?.Close(); notification?.Close();
} }

8
src/Avalonia.Controls/Notifications/WindowNotificationManager.cs

@ -17,7 +17,7 @@ namespace Avalonia.Controls.Notifications
[PseudoClasses(":topleft", ":topright", ":bottomleft", ":bottomright")] [PseudoClasses(":topleft", ":topright", ":bottomleft", ":bottomright")]
public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager, ICustomSimpleHitTest public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager, ICustomSimpleHitTest
{ {
private IList _items; private IList? _items;
/// <summary> /// <summary>
/// Defines the <see cref="Position"/> property. /// Defines the <see cref="Position"/> property.
@ -107,7 +107,7 @@ namespace Avalonia.Controls.Notifications
{ {
notification.OnClose?.Invoke(); notification.OnClose?.Invoke();
_items.Remove(sender); _items?.Remove(sender);
}; };
} }
@ -121,9 +121,9 @@ namespace Avalonia.Controls.Notifications
(sender as NotificationCard)?.Close(); (sender as NotificationCard)?.Close();
}; };
_items.Add(notificationControl); _items?.Add(notificationControl);
if (_items.OfType<NotificationCard>().Count(i => !i.IsClosing) > MaxItems) if (_items?.OfType<NotificationCard>().Count(i => !i.IsClosing) > MaxItems)
{ {
_items.OfType<NotificationCard>().First(i => !i.IsClosing).Close(); _items.OfType<NotificationCard>().First(i => !i.IsClosing).Close();
} }

94
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -46,15 +46,15 @@ namespace Avalonia.Controls
/// Defines the <see cref="CultureInfo"/> property. /// Defines the <see cref="CultureInfo"/> property.
/// </summary> /// </summary>
[Obsolete] [Obsolete]
public static readonly DirectProperty<NumericUpDown, CultureInfo> CultureInfoProperty = public static readonly DirectProperty<NumericUpDown, CultureInfo?> CultureInfoProperty =
AvaloniaProperty.RegisterDirect<NumericUpDown, CultureInfo>(nameof(CultureInfo), o => o.CultureInfo, AvaloniaProperty.RegisterDirect<NumericUpDown, CultureInfo?>(nameof(CultureInfo), o => o.CultureInfo,
(o, v) => o.CultureInfo = v, CultureInfo.CurrentCulture); (o, v) => o.CultureInfo = v, CultureInfo.CurrentCulture);
/// <summary> /// <summary>
/// Defines the <see cref="NumberFormat"/> property. /// Defines the <see cref="NumberFormat"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<NumericUpDown, NumberFormatInfo> NumberFormatProperty = public static readonly DirectProperty<NumericUpDown, NumberFormatInfo?> NumberFormatProperty =
AvaloniaProperty.RegisterDirect<NumericUpDown, NumberFormatInfo>(nameof(NumberFormat), o => o.NumberFormat, AvaloniaProperty.RegisterDirect<NumericUpDown, NumberFormatInfo?>(nameof(NumberFormat), o => o.NumberFormat,
(o, v) => o.NumberFormat = v, NumberFormatInfo.CurrentInfo); (o, v) => o.NumberFormat = v, NumberFormatInfo.CurrentInfo);
/// <summary> /// <summary>
@ -97,8 +97,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Text"/> property. /// Defines the <see cref="Text"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<NumericUpDown, string> TextProperty = public static readonly DirectProperty<NumericUpDown, string?> TextProperty =
AvaloniaProperty.RegisterDirect<NumericUpDown, string>(nameof(Text), o => o.Text, (o, v) => o.Text = v, AvaloniaProperty.RegisterDirect<NumericUpDown, string?>(nameof(Text), o => o.Text, (o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
/// <summary> /// <summary>
@ -111,8 +111,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Watermark"/> property. /// Defines the <see cref="Watermark"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<string> WatermarkProperty = public static readonly StyledProperty<string?> WatermarkProperty =
AvaloniaProperty.Register<NumericUpDown, string>(nameof(Watermark)); AvaloniaProperty.Register<NumericUpDown, string?>(nameof(Watermark));
/// <summary> /// <summary>
/// Defines the <see cref="HorizontalContentAlignment"/> property. /// Defines the <see cref="HorizontalContentAlignment"/> property.
@ -126,27 +126,27 @@ namespace Avalonia.Controls
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty = public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
ContentControl.VerticalContentAlignmentProperty.AddOwner<NumericUpDown>(); ContentControl.VerticalContentAlignmentProperty.AddOwner<NumericUpDown>();
private IDisposable _textBoxTextChangedSubscription; private IDisposable? _textBoxTextChangedSubscription;
private decimal _value; private decimal _value;
private string _text; private string? _text;
private bool _internalValueSet; private bool _internalValueSet;
private bool _clipValueToMinMax; private bool _clipValueToMinMax;
private bool _isSyncingTextAndValueProperties; private bool _isSyncingTextAndValueProperties;
private bool _isTextChangedFromUI; private bool _isTextChangedFromUI;
private CultureInfo _cultureInfo; private CultureInfo? _cultureInfo;
private NumberStyles _parsingNumberStyle = NumberStyles.Any; private NumberStyles _parsingNumberStyle = NumberStyles.Any;
private NumberFormatInfo _numberFormat; private NumberFormatInfo? _numberFormat;
/// <summary> /// <summary>
/// Gets the Spinner template part. /// Gets the Spinner template part.
/// </summary> /// </summary>
private Spinner Spinner { get; set; } private Spinner? Spinner { get; set; }
/// <summary> /// <summary>
/// Gets the TextBox template part. /// Gets the TextBox template part.
/// </summary> /// </summary>
private TextBox TextBox { get; set; } private TextBox? TextBox { get; set; }
/// <summary> /// <summary>
/// Gets or sets the ability to perform increment/decrement operations via the keyboard, button spinners, or mouse wheel. /// Gets or sets the ability to perform increment/decrement operations via the keyboard, button spinners, or mouse wheel.
@ -188,7 +188,7 @@ namespace Avalonia.Controls
/// Gets or sets the current CultureInfo. /// Gets or sets the current CultureInfo.
/// </summary> /// </summary>
[Obsolete("CultureInfo is obsolete, please use NumberFormat instead.")] [Obsolete("CultureInfo is obsolete, please use NumberFormat instead.")]
public CultureInfo CultureInfo public CultureInfo? CultureInfo
{ {
get { return _cultureInfo; } get { return _cultureInfo; }
set set
@ -202,7 +202,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the current NumberFormatInfo /// Gets or sets the current NumberFormatInfo
/// </summary> /// </summary>
public NumberFormatInfo NumberFormat public NumberFormatInfo? NumberFormat
{ {
get { return _numberFormat; } get { return _numberFormat; }
set { SetAndRaise(NumberFormatProperty, ref _numberFormat, value); } set { SetAndRaise(NumberFormatProperty, ref _numberFormat, value); }
@ -265,7 +265,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the formatted string representation of the value. /// Gets or sets the formatted string representation of the value.
/// </summary> /// </summary>
public string Text public string? Text
{ {
get { return _text; } get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); } set { SetAndRaise(TextProperty, ref _text, value); }
@ -287,7 +287,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the object to use as a watermark if the <see cref="Value"/> is null. /// Gets or sets the object to use as a watermark if the <see cref="Value"/> is null.
/// </summary> /// </summary>
public string Watermark public string? Watermark
{ {
get { return GetValue(WatermarkProperty); } get { return GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); } set { SetValue(WatermarkProperty, value); }
@ -414,7 +414,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="oldValue">The old value.</param> /// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param> /// <param name="newValue">The new value.</param>
protected virtual void OnCultureInfoChanged(CultureInfo oldValue, CultureInfo newValue) protected virtual void OnCultureInfoChanged(CultureInfo? oldValue, CultureInfo? newValue)
{ {
if (IsInitialized) if (IsInitialized)
{ {
@ -427,7 +427,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="oldValue">The old value.</param> /// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param> /// <param name="newValue">The new value.</param>
protected virtual void OnNumberFormatChanged(NumberFormatInfo oldValue, NumberFormatInfo newValue) protected virtual void OnNumberFormatChanged(NumberFormatInfo? oldValue, NumberFormatInfo? newValue)
{ {
if (IsInitialized) if (IsInitialized)
{ {
@ -440,7 +440,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="oldValue">The old value.</param> /// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param> /// <param name="newValue">The new value.</param>
protected virtual void OnFormatStringChanged(string oldValue, string newValue) protected virtual void OnFormatStringChanged(string? oldValue, string? newValue)
{ {
if (IsInitialized) if (IsInitialized)
{ {
@ -510,7 +510,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="oldValue">The old value.</param> /// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param> /// <param name="newValue">The new value.</param>
protected virtual void OnTextChanged(string oldValue, string newValue) protected virtual void OnTextChanged(string? oldValue, string? newValue)
{ {
if (IsInitialized) if (IsInitialized)
{ {
@ -706,8 +706,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (CultureInfo)e.OldValue; var oldValue = (CultureInfo?)e.OldValue;
var newValue = (CultureInfo)e.NewValue; var newValue = (CultureInfo?)e.NewValue;
upDown.OnCultureInfoChanged(oldValue, newValue); upDown.OnCultureInfoChanged(oldValue, newValue);
} }
} }
@ -720,8 +720,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (NumberFormatInfo)e.OldValue; var oldValue = (NumberFormatInfo?)e.OldValue;
var newValue = (NumberFormatInfo)e.NewValue; var newValue = (NumberFormatInfo?)e.NewValue;
upDown.OnNumberFormatChanged(oldValue, newValue); upDown.OnNumberFormatChanged(oldValue, newValue);
} }
} }
@ -734,8 +734,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (decimal)e.OldValue; var oldValue = (decimal)e.OldValue!;
var newValue = (decimal)e.NewValue; var newValue = (decimal)e.NewValue!;
upDown.OnIncrementChanged(oldValue, newValue); upDown.OnIncrementChanged(oldValue, newValue);
} }
} }
@ -748,8 +748,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (string)e.OldValue; var oldValue = (string?)e.OldValue;
var newValue = (string)e.NewValue; var newValue = (string?)e.NewValue;
upDown.OnFormatStringChanged(oldValue, newValue); upDown.OnFormatStringChanged(oldValue, newValue);
} }
} }
@ -762,8 +762,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (bool)e.OldValue; var oldValue = (bool)e.OldValue!;
var newValue = (bool)e.NewValue; var newValue = (bool)e.NewValue!;
upDown.OnIsReadOnlyChanged(oldValue, newValue); upDown.OnIsReadOnlyChanged(oldValue, newValue);
} }
} }
@ -776,8 +776,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (decimal)e.OldValue; var oldValue = (decimal)e.OldValue!;
var newValue = (decimal)e.NewValue; var newValue = (decimal)e.NewValue!;
upDown.OnMaximumChanged(oldValue, newValue); upDown.OnMaximumChanged(oldValue, newValue);
} }
} }
@ -790,8 +790,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (decimal)e.OldValue; var oldValue = (decimal)e.OldValue!;
var newValue = (decimal)e.NewValue; var newValue = (decimal)e.NewValue!;
upDown.OnMinimumChanged(oldValue, newValue); upDown.OnMinimumChanged(oldValue, newValue);
} }
} }
@ -804,8 +804,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (string)e.OldValue; var oldValue = (string?)e.OldValue;
var newValue = (string)e.NewValue; var newValue = (string?)e.NewValue;
upDown.OnTextChanged(oldValue, newValue); upDown.OnTextChanged(oldValue, newValue);
} }
} }
@ -818,8 +818,8 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (decimal)e.OldValue; var oldValue = (decimal)e.OldValue!;
var newValue = (decimal)e.NewValue; var newValue = (decimal)e.NewValue!;
upDown.OnValueChanged(oldValue, newValue); upDown.OnValueChanged(oldValue, newValue);
} }
} }
@ -883,7 +883,7 @@ namespace Avalonia.Controls
} }
} }
private void OnSpinnerSpin(object sender, SpinEventArgs e) private void OnSpinnerSpin(object? sender, SpinEventArgs e)
{ {
if (AllowSpin && !IsReadOnly) if (AllowSpin && !IsReadOnly)
{ {
@ -914,9 +914,9 @@ namespace Avalonia.Controls
} }
} }
public event EventHandler<SpinEventArgs> Spinned; public event EventHandler<SpinEventArgs>? Spinned;
private void TextBoxOnPointerPressed(object sender, PointerPressedEventArgs e) private void TextBoxOnPointerPressed(object? sender, PointerPressedEventArgs e)
{ {
if (e.Pointer.Captured != Spinner) if (e.Pointer.Captured != Spinner)
{ {
@ -933,7 +933,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Raised when the <see cref="Value"/> changes. /// Raised when the <see cref="Value"/> changes.
/// </summary> /// </summary>
public event EventHandler<NumericUpDownValueChangedEventArgs> ValueChanged public event EventHandler<NumericUpDownValueChangedEventArgs>? ValueChanged
{ {
add { AddHandler(ValueChangedEvent, value); } add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); } remove { RemoveHandler(ValueChangedEvent, value); }
@ -949,7 +949,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="updateValueFromText">If value should be updated from text.</param> /// <param name="updateValueFromText">If value should be updated from text.</param>
/// <param name="text">The text.</param> /// <param name="text">The text.</param>
private bool SyncTextAndValueProperties(bool updateValueFromText, string text) private bool SyncTextAndValueProperties(bool updateValueFromText, string? text)
{ {
return SyncTextAndValueProperties(updateValueFromText, text, false); return SyncTextAndValueProperties(updateValueFromText, text, false);
} }
@ -960,7 +960,7 @@ namespace Avalonia.Controls
/// <param name="updateValueFromText">If value should be updated from text.</param> /// <param name="updateValueFromText">If value should be updated from text.</param>
/// <param name="text">The text.</param> /// <param name="text">The text.</param>
/// <param name="forceTextUpdate">Force text update.</param> /// <param name="forceTextUpdate">Force text update.</param>
private bool SyncTextAndValueProperties(bool updateValueFromText, string text, bool forceTextUpdate) private bool SyncTextAndValueProperties(bool updateValueFromText, string? text, bool forceTextUpdate)
{ {
if (_isSyncingTextAndValueProperties) if (_isSyncingTextAndValueProperties)
return true; return true;
@ -1092,7 +1092,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="text">Text to parse.</param> /// <param name="text">Text to parse.</param>
/// <param name="cultureInfo">The culture info.</param> /// <param name="cultureInfo">The culture info.</param>
private static decimal ParsePercent(string text, IFormatProvider cultureInfo) private static decimal ParsePercent(string text, IFormatProvider? cultureInfo)
{ {
var info = NumberFormatInfo.GetInstance(cultureInfo); var info = NumberFormatInfo.GetInstance(cultureInfo);
text = text.Replace(info.PercentSymbol, null); text = text.Replace(info.PercentSymbol, null);

24
src/Avalonia.Controls/Panel.cs

@ -21,7 +21,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Background"/> property. /// Defines the <see cref="Background"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IBrush> BackgroundProperty = public static readonly StyledProperty<IBrush?> BackgroundProperty =
Border.BackgroundProperty.AddOwner<Panel>(); Border.BackgroundProperty.AddOwner<Panel>();
/// <summary> /// <summary>
@ -32,7 +32,7 @@ namespace Avalonia.Controls
AffectsRender<Panel>(BackgroundProperty); AffectsRender<Panel>(BackgroundProperty);
} }
private EventHandler<ChildIndexChangedEventArgs> _childIndexChanged; private EventHandler<ChildIndexChangedEventArgs>? _childIndexChanged;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Panel"/> class. /// Initializes a new instance of the <see cref="Panel"/> class.
@ -51,13 +51,13 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or Sets Panel background brush. /// Gets or Sets Panel background brush.
/// </summary> /// </summary>
public IBrush Background public IBrush? Background
{ {
get { return GetValue(BackgroundProperty); } get { return GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); } set { SetValue(BackgroundProperty, value); }
} }
event EventHandler<ChildIndexChangedEventArgs> IChildIndexProvider.ChildIndexChanged event EventHandler<ChildIndexChangedEventArgs>? IChildIndexProvider.ChildIndexChanged
{ {
add => _childIndexChanged += value; add => _childIndexChanged += value;
remove => _childIndexChanged -= value; remove => _childIndexChanged -= value;
@ -110,34 +110,34 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
protected virtual void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) protected virtual void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
List<Control> controls; List<Control> controls;
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
controls = e.NewItems.OfType<Control>().ToList(); controls = e.NewItems!.OfType<Control>().ToList();
LogicalChildren.InsertRange(e.NewStartingIndex, controls); LogicalChildren.InsertRange(e.NewStartingIndex, controls);
VisualChildren.InsertRange(e.NewStartingIndex, e.NewItems.OfType<Visual>()); VisualChildren.InsertRange(e.NewStartingIndex, e.NewItems!.OfType<Visual>());
break; break;
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
LogicalChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex); LogicalChildren.MoveRange(e.OldStartingIndex, e.OldItems!.Count, e.NewStartingIndex);
VisualChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex); VisualChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex);
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
controls = e.OldItems.OfType<Control>().ToList(); controls = e.OldItems!.OfType<Control>().ToList();
LogicalChildren.RemoveAll(controls); LogicalChildren.RemoveAll(controls);
VisualChildren.RemoveAll(e.OldItems.OfType<Visual>()); VisualChildren.RemoveAll(e.OldItems!.OfType<Visual>());
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
for (var i = 0; i < e.OldItems.Count; ++i) for (var i = 0; i < e.OldItems!.Count; ++i)
{ {
var index = i + e.OldStartingIndex; var index = i + e.OldStartingIndex;
var child = (IControl)e.NewItems[i]; var child = (IControl)e.NewItems![i]!;
LogicalChildren[index] = child; LogicalChildren[index] = child;
VisualChildren[index] = child; VisualChildren[index] = child;
} }

37
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -4,12 +4,11 @@ using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.VisualTree; using Avalonia.VisualTree;
#nullable enable
namespace Avalonia.Controls.Platform namespace Avalonia.Controls.Platform
{ {
/// <summary> /// <summary>
@ -68,8 +67,8 @@ namespace Avalonia.Controls.Platform
window.Deactivated += WindowDeactivated; window.Deactivated += WindowDeactivated;
} }
if (_root is TopLevel tl) if (_root is TopLevel tl && tl.PlatformImpl is ITopLevelImpl pimpl)
tl.PlatformImpl.LostFocus += TopLevelLostPlatformFocus; pimpl.LostFocus += TopLevelLostPlatformFocus;
_inputManagerSubscription = InputManager?.Process.Subscribe(RawInput); _inputManagerSubscription = InputManager?.Process.Subscribe(RawInput);
} }
@ -118,7 +117,7 @@ namespace Avalonia.Controls.Platform
protected static TimeSpan MenuShowDelay { get; } = TimeSpan.FromMilliseconds(400); protected static TimeSpan MenuShowDelay { get; } = TimeSpan.FromMilliseconds(400);
protected internal virtual void GotFocus(object sender, GotFocusEventArgs e) protected internal virtual void GotFocus(object? sender, GotFocusEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
@ -128,7 +127,7 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void LostFocus(object sender, RoutedEventArgs e) protected internal virtual void LostFocus(object? sender, RoutedEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
@ -138,7 +137,7 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void KeyDown(object sender, KeyEventArgs e) protected internal virtual void KeyDown(object? sender, KeyEventArgs e)
{ {
KeyDown(GetMenuItem(e.Source as IControl), e); KeyDown(GetMenuItem(e.Source as IControl), e);
} }
@ -267,7 +266,7 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void AccessKeyPressed(object sender, RoutedEventArgs e) protected internal virtual void AccessKeyPressed(object? sender, RoutedEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
@ -288,7 +287,7 @@ namespace Avalonia.Controls.Platform
e.Handled = true; e.Handled = true;
} }
protected internal virtual void PointerEnter(object sender, PointerEventArgs e) protected internal virtual void PointerEnter(object? sender, PointerEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
@ -333,7 +332,7 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void PointerLeave(object sender, PointerEventArgs e) protected internal virtual void PointerLeave(object? sender, PointerEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
@ -368,12 +367,12 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void PointerPressed(object sender, PointerPressedEventArgs e) protected internal virtual void PointerPressed(object? sender, PointerPressedEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
var visual = (IVisual)sender;
if (e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed && item?.HasSubMenu == true) if (sender is IVisual visual &&
e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed && item?.HasSubMenu == true)
{ {
if (item.IsSubMenuOpen) if (item.IsSubMenuOpen)
{ {
@ -399,7 +398,7 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void PointerReleased(object sender, PointerReleasedEventArgs e) protected internal virtual void PointerReleased(object? sender, PointerReleasedEventArgs e)
{ {
var item = GetMenuItem(e.Source as IControl); var item = GetMenuItem(e.Source as IControl);
@ -410,7 +409,7 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void MenuOpened(object sender, RoutedEventArgs e) protected internal virtual void MenuOpened(object? sender, RoutedEventArgs e)
{ {
if (e.Source == Menu) if (e.Source == Menu)
{ {
@ -428,20 +427,18 @@ namespace Avalonia.Controls.Platform
} }
} }
protected internal virtual void RootPointerPressed(object sender, PointerPressedEventArgs e) protected internal virtual void RootPointerPressed(object? sender, PointerPressedEventArgs e)
{ {
if (Menu?.IsOpen == true) if (Menu?.IsOpen == true)
{ {
var control = e.Source as ILogical; if (e.Source is ILogical control && !Menu.IsLogicalAncestorOf(control))
if (!Menu.IsLogicalAncestorOf(control))
{ {
Menu.Close(); Menu.Close();
} }
} }
} }
protected internal virtual void WindowDeactivated(object sender, EventArgs e) protected internal virtual void WindowDeactivated(object? sender, EventArgs e)
{ {
Menu?.Close(); Menu?.Close();
} }

4
src/Avalonia.Controls/Platform/ExportWindowingSubsystemAttribute.cs

@ -6,7 +6,7 @@ namespace Avalonia.Platform
public class ExportWindowingSubsystemAttribute : Attribute public class ExportWindowingSubsystemAttribute : Attribute
{ {
public ExportWindowingSubsystemAttribute(OperatingSystemType requiredRuntimePlatform, int priority, string name, Type initializationType, public ExportWindowingSubsystemAttribute(OperatingSystemType requiredRuntimePlatform, int priority, string name, Type initializationType,
string initializationMethod, Type environmentChecker = null) string initializationMethod, Type? environmentChecker = null)
{ {
Name = name; Name = name;
InitializationType = initializationType; InitializationType = initializationType;
@ -17,7 +17,7 @@ namespace Avalonia.Platform
} }
public string InitializationMethod { get; private set; } public string InitializationMethod { get; private set; }
public Type EnvironmentChecker { get; } public Type? EnvironmentChecker { get; }
public Type InitializationType { get; private set; } public Type InitializationType { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public int Priority { get; private set; } public int Priority { get; private set; }

6
src/Avalonia.Controls/Platform/INativeControlHostImpl.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree; using Avalonia.VisualTree;
@ -19,7 +20,8 @@ namespace Avalonia.Controls.Platform
public interface INativeControlHostControlTopLevelAttachment : IDisposable public interface INativeControlHostControlTopLevelAttachment : IDisposable
{ {
INativeControlHostImpl AttachedTo { get; set; } INativeControlHostImpl? AttachedTo { get; set; }
bool IsCompatibleWith(INativeControlHostImpl host); bool IsCompatibleWith(INativeControlHostImpl host);
void HideWithSize(Size size); void HideWithSize(Size size);
void ShowInBounds(Rect rect); void ShowInBounds(Rect rect);
@ -27,6 +29,6 @@ namespace Avalonia.Controls.Platform
public interface ITopLevelImplWithNativeControlHost public interface ITopLevelImplWithNativeControlHost
{ {
INativeControlHostImpl NativeControlHost { get; } INativeControlHostImpl? NativeControlHost { get; }
} }
} }

2
src/Avalonia.Controls/Platform/ISystemDialogImpl.cs

@ -1,7 +1,5 @@
using System.Threading.Tasks; using System.Threading.Tasks;
#nullable enable
namespace Avalonia.Controls.Platform namespace Avalonia.Controls.Platform
{ {
/// <summary> /// <summary>

18
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -82,27 +82,27 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Gets or sets a method called when the toplevel receives input. /// Gets or sets a method called when the toplevel receives input.
/// </summary> /// </summary>
Action<RawInputEventArgs> Input { get; set; } Action<RawInputEventArgs>? Input { get; set; }
/// <summary> /// <summary>
/// Gets or sets a method called when the toplevel requires painting. /// Gets or sets a method called when the toplevel requires painting.
/// </summary> /// </summary>
Action<Rect> Paint { get; set; } Action<Rect>? Paint { get; set; }
/// <summary> /// <summary>
/// Gets or sets a method called when the toplevel is resized. /// Gets or sets a method called when the toplevel is resized.
/// </summary> /// </summary>
Action<Size, PlatformResizeReason> Resized { get; set; } Action<Size, PlatformResizeReason>? Resized { get; set; }
/// <summary> /// <summary>
/// Gets or sets a method called when the toplevel's scaling changes. /// Gets or sets a method called when the toplevel's scaling changes.
/// </summary> /// </summary>
Action<double> ScalingChanged { get; set; } Action<double>? ScalingChanged { get; set; }
/// <summary> /// <summary>
/// Gets or sets a method called when the toplevel's TransparencyLevel changes. /// Gets or sets a method called when the toplevel's TransparencyLevel changes.
/// </summary> /// </summary>
Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; } Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
/// <summary> /// <summary>
/// Creates a new renderer for the toplevel. /// Creates a new renderer for the toplevel.
@ -138,17 +138,17 @@ namespace Avalonia.Platform
/// Sets the cursor associated with the toplevel. /// Sets the cursor associated with the toplevel.
/// </summary> /// </summary>
/// <param name="cursor">The cursor. Use null for default cursor</param> /// <param name="cursor">The cursor. Use null for default cursor</param>
void SetCursor(ICursorImpl cursor); void SetCursor(ICursorImpl? cursor);
/// <summary> /// <summary>
/// Gets or sets a method called when the underlying implementation is destroyed. /// Gets or sets a method called when the underlying implementation is destroyed.
/// </summary> /// </summary>
Action Closed { get; set; } Action? Closed { get; set; }
/// <summary> /// <summary>
/// Gets or sets a method called when the input focus is lost. /// Gets or sets a method called when the input focus is lost.
/// </summary> /// </summary>
Action LostFocus { get; set; } Action? LostFocus { get; set; }
/// <summary> /// <summary>
/// Gets a mouse device associated with toplevel /// Gets a mouse device associated with toplevel
@ -156,7 +156,7 @@ namespace Avalonia.Platform
[CanBeNull] [CanBeNull]
IMouseDevice MouseDevice { get; } IMouseDevice MouseDevice { get; }
IPopupImpl CreatePopup(); IPopupImpl? CreatePopup();
/// <summary> /// <summary>
/// Sets the <see cref="WindowTransparencyLevel"/> hint of the TopLevel. /// Sets the <see cref="WindowTransparencyLevel"/> hint of the TopLevel.

2
src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs

@ -6,6 +6,6 @@ namespace Avalonia.Controls.Platform
{ {
public interface ITopLevelImplWithTextInputMethod : ITopLevelImpl public interface ITopLevelImplWithTextInputMethod : ITopLevelImpl
{ {
public ITextInputMethodImpl TextInputMethod { get; } public ITextInputMethodImpl? TextInputMethod { get; }
} }
} }

4
src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs

@ -1,8 +1,6 @@
using System; using System;
using Avalonia.Platform; using Avalonia.Platform;
#nullable enable
namespace Avalonia.Controls.Platform namespace Avalonia.Controls.Platform
{ {
public interface INativeMenuExporter public interface INativeMenuExporter
@ -24,6 +22,6 @@ namespace Avalonia.Controls.Platform
public interface ITopLevelImplWithNativeMenuExporter : ITopLevelImpl public interface ITopLevelImplWithNativeMenuExporter : ITopLevelImpl
{ {
ITopLevelNativeMenuExporter NativeMenuExporter { get; } ITopLevelNativeMenuExporter? NativeMenuExporter { get; }
} }
} }

2
src/Avalonia.Controls/Platform/ITrayIconImpl.cs

@ -1,8 +1,6 @@
using System; using System;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
#nullable enable
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
public interface ITrayIconImpl : IDisposable public interface ITrayIconImpl : IDisposable

6
src/Avalonia.Controls/Platform/IWindowBaseImpl.cs

@ -29,7 +29,7 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Gets or sets a method called when the window's position changes. /// Gets or sets a method called when the window's position changes.
/// </summary> /// </summary>
Action<PixelPoint> PositionChanged { get; set; } Action<PixelPoint>? PositionChanged { get; set; }
/// <summary> /// <summary>
/// Activates the window. /// Activates the window.
@ -39,12 +39,12 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Gets or sets a method called when the window is deactivated (loses focus). /// Gets or sets a method called when the window is deactivated (loses focus).
/// </summary> /// </summary>
Action Deactivated { get; set; } Action? Deactivated { get; set; }
/// <summary> /// <summary>
/// Gets or sets a method called when the window is activated (receives focus). /// Gets or sets a method called when the window is activated (receives focus).
/// </summary> /// </summary>
Action Activated { get; set; } Action? Activated { get; set; }
/// <summary> /// <summary>
/// Gets the platform window handle. /// Gets the platform window handle.

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

Loading…
Cancel
Save