Browse Source

Merge branch 'master' into robloo-SplitButton

pull/7422/head
Max Katz 4 years ago
committed by GitHub
parent
commit
509a856ea0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      Avalonia.sln
  2. 1
      build/CoreLibraries.props
  3. 2
      build/SharedVersion.props
  4. 4
      samples/ControlCatalog.Android/Assets/AboutAssets.txt
  5. 220
      samples/ControlCatalog/Pages/PointersPage.cs
  6. 37
      samples/ControlCatalog/Pages/ScreenPage.cs
  7. 22
      samples/ControlCatalog/Pages/ViewboxPage.xaml
  8. 19
      samples/ControlCatalog/Pages/ViewboxPage.xaml.cs
  9. 3
      samples/RenderDemo/MainWindow.xaml
  10. 54
      samples/RenderDemo/Pages/ClippingPage.xaml
  11. 17
      samples/RenderDemo/Pages/ClippingPage.xaml.cs
  12. 13
      samples/RenderDemo/Pages/CustomSkiaPage.cs
  13. 7
      samples/RenderDemo/Pages/FormattedTextPage.axaml
  14. 60
      samples/RenderDemo/Pages/FormattedTextPage.axaml.cs
  15. 7
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  16. 5
      src/Android/Avalonia.Android/AndroidPlatform.cs
  17. 2
      src/Android/Avalonia.Android/AppBuilder.cs
  18. 4
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  19. 18
      src/Android/Avalonia.Android/RuntimeInfo.cs
  20. 1
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  21. 5
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  22. 7
      src/Avalonia.Base/Threading/Dispatcher.cs
  23. 15
      src/Avalonia.Base/Threading/JobRunner.cs
  24. 2
      src/Avalonia.Base/Utilities/ImmutableReadOnlyListStructEnumerator.cs
  25. 9
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  26. 6
      src/Avalonia.Controls/ApiCompatBaseline.txt
  27. 35
      src/Avalonia.Controls/AppBuilderBase.cs
  28. 5
      src/Avalonia.Controls/Application.cs
  29. 26
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  30. 6
      src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
  31. 2
      src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs
  32. 309
      src/Avalonia.Controls/AutoCompleteBox.cs
  33. 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  34. 12
      src/Avalonia.Controls/Border.cs
  35. 225
      src/Avalonia.Controls/Button.cs
  36. 14
      src/Avalonia.Controls/ButtonSpinner.cs
  37. 76
      src/Avalonia.Controls/Calendar/Calendar.cs
  38. 6
      src/Avalonia.Controls/Calendar/CalendarButton.cs
  39. 87
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  40. 2
      src/Avalonia.Controls/Calendar/CalendarDateRange.cs
  41. 6
      src/Avalonia.Controls/Calendar/CalendarDayButton.cs
  42. 100
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  43. 2
      src/Avalonia.Controls/Calendar/DateTimeHelper.cs
  44. 4
      src/Avalonia.Controls/Calendar/SelectedDatesCollection.cs
  45. 2
      src/Avalonia.Controls/Canvas.cs
  46. 2
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  47. 4
      src/Avalonia.Controls/Chrome/TitleBar.cs
  48. 40
      src/Avalonia.Controls/ComboBox.cs
  49. 14
      src/Avalonia.Controls/ContentControl.cs
  50. 14
      src/Avalonia.Controls/ContextMenu.cs
  51. 2
      src/Avalonia.Controls/ContextRequestedEventArgs.cs
  52. 23
      src/Avalonia.Controls/Control.cs
  53. 35
      src/Avalonia.Controls/ControlExtensions.cs
  54. 3
      src/Avalonia.Controls/Converters/CornerRadiusFilterConverter.cs
  55. 4
      src/Avalonia.Controls/Converters/MarginMultiplierConverter.cs
  56. 2
      src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
  57. 4
      src/Avalonia.Controls/Converters/PlatformKeyGestureConverter.cs
  58. 29
      src/Avalonia.Controls/DataValidationErrors.cs
  59. 60
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  60. 103
      src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
  61. 28
      src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs
  62. 6
      src/Avalonia.Controls/DateTimePickers/PickerPresenterBase.cs
  63. 56
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  64. 75
      src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs
  65. 10
      src/Avalonia.Controls/Decorator.cs
  66. 40
      src/Avalonia.Controls/DefinitionBase.cs
  67. 6
      src/Avalonia.Controls/DefinitionList.cs
  68. 2
      src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs
  69. 4
      src/Avalonia.Controls/Diagnostics/ToolTipDiagnostics.cs
  70. 20
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  71. 3
      src/Avalonia.Controls/Expander.cs
  72. 7
      src/Avalonia.Controls/ExperimentalAcrylicBorder.cs
  73. 2
      src/Avalonia.Controls/Flyouts/Flyout.cs
  74. 20
      src/Avalonia.Controls/Flyouts/FlyoutBase.cs
  75. 8
      src/Avalonia.Controls/Flyouts/MenuFlyout.cs
  76. 13
      src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs
  77. 12
      src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
  78. 2
      src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs
  79. 26
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  80. 11
      src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
  81. 2
      src/Avalonia.Controls/Generators/MenuItemContainerGenerator.cs
  82. 12
      src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
  83. 8
      src/Avalonia.Controls/Generators/TreeContainerIndex.cs
  84. 23
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  85. 165
      src/Avalonia.Controls/Grid.cs
  86. 2
      src/Avalonia.Controls/GridLength.cs
  87. 62
      src/Avalonia.Controls/GridSplitter.cs
  88. 40
      src/Avalonia.Controls/HotkeyManager.cs
  89. 6
      src/Avalonia.Controls/IContentControl.cs
  90. 2
      src/Avalonia.Controls/IControl.cs
  91. 2
      src/Avalonia.Controls/IHeadered.cs
  92. 2
      src/Avalonia.Controls/IMenuElement.cs
  93. 4
      src/Avalonia.Controls/IMenuItem.cs
  94. 4
      src/Avalonia.Controls/IScrollAnchorProvider.cs
  95. 2
      src/Avalonia.Controls/IVirtualizingPanel.cs
  96. 56
      src/Avalonia.Controls/ItemsControl.cs
  97. 8
      src/Avalonia.Controls/ItemsSourceView.cs
  98. 8
      src/Avalonia.Controls/Label.cs
  99. 14
      src/Avalonia.Controls/LayoutTransformControl.cs
  100. 12
      src/Avalonia.Controls/ListBox.cs

41
Avalonia.sln

@ -60,20 +60,17 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BindingDemo", "samples\BindingDemo\BindingDemo.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-CC41-4F14-A8C8-267F579BF91E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}"
@ -235,15 +232,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "sampl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", "src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj", "{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 5
src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|iPhone = Ad-Hoc|iPhone
@ -2169,6 +2160,30 @@ Global
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2187,11 +2202,9 @@ Global
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
{6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}

1
build/CoreLibraries.props

@ -17,5 +17,6 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj" />
</ItemGroup>
</Project>

2
build/SharedVersion.props

@ -3,7 +3,7 @@
<PropertyGroup>
<Product>Avalonia</Product>
<Version>0.10.999</Version>
<Copyright>Copyright 2021 &#169; The AvaloniaUI Project</Copyright>
<Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright>
<PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

4
samples/ControlCatalog.Android/Assets/AboutAssets.txt

@ -1,7 +1,7 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with you package and will be accessible using Android's
These files will be deployed with your package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
@ -16,4 +16,4 @@ public class ReadAsset : Activity
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

220
samples/ControlCatalog/Pages/PointersPage.cs

@ -1,15 +1,37 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace ControlCatalog.Pages
namespace ControlCatalog.Pages;
public class PointersPage : Decorator
{
public class PointersPage : Control
public PointersPage()
{
Child = new TabControl
{
Items = new[]
{
new TabItem() { Header = "Contacts", Content = new PointerContactsTab() },
new TabItem() { Header = "IntermediatePoints", Content = new PointerIntermediatePointsTab() }
}
};
}
class PointerContactsTab : Control
{
class PointerInfo
{
@ -45,7 +67,7 @@ namespace ControlCatalog.Pages
private Dictionary<IPointer, PointerInfo> _pointers = new Dictionary<IPointer, PointerInfo>();
public PointersPage()
public PointerContactsTab()
{
ClipToBounds = true;
}
@ -104,4 +126,196 @@ namespace ControlCatalog.Pages
}
}
}
public class PointerIntermediatePointsTab : Decorator
{
public PointerIntermediatePointsTab()
{
this[TextBlock.ForegroundProperty] = Brushes.Black;
var slider = new Slider
{
Margin = new Thickness(5),
Minimum = 0,
Maximum = 500
};
var status = new TextBlock()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
};
Child = new Grid
{
Children =
{
new PointerCanvas(slider, status),
new Border
{
Background = Brushes.LightYellow,
Child = new StackPanel
{
Children =
{
new StackPanel
{
Orientation = Orientation.Horizontal,
Children =
{
new TextBlock { Text = "Thread sleep:" },
new TextBlock()
{
[!TextBlock.TextProperty] =slider.GetObservable(Slider.ValueProperty)
.Select(x=>x.ToString()).ToBinding()
}
}
},
slider
}
},
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
Width = 300,
Height = 60
},
status
}
};
}
class PointerCanvas : Control
{
private readonly Slider _slider;
private readonly TextBlock _status;
private int _events;
private Stopwatch _stopwatch = Stopwatch.StartNew();
private Dictionary<int, PointerPoints> _pointers = new();
class PointerPoints
{
struct CanvasPoint
{
public IBrush Brush;
public Point Point;
public double Radius;
}
readonly CanvasPoint[] _points = new CanvasPoint[1000];
int _index;
public void Render(DrawingContext context)
{
CanvasPoint? prev = null;
for (var c = 0; c < _points.Length; c++)
{
var i = (c + _index) % _points.Length;
var pt = _points[i];
if (prev.HasValue && prev.Value.Brush != null && pt.Brush != null)
context.DrawLine(new Pen(Brushes.Black), prev.Value.Point, pt.Point);
prev = pt;
if (pt.Brush != null)
context.DrawEllipse(pt.Brush, null, pt.Point, pt.Radius, pt.Radius);
}
}
void AddPoint(Point pt, IBrush brush, double radius)
{
_points[_index] = new CanvasPoint { Point = pt, Brush = brush, Radius = radius };
_index = (_index + 1) % _points.Length;
}
public void HandleEvent(PointerEventArgs e, Visual v)
{
e.Handled = true;
if (e.RoutedEvent == PointerPressedEvent)
AddPoint(e.GetPosition(v), Brushes.Green, 10);
else if (e.RoutedEvent == PointerReleasedEvent)
AddPoint(e.GetPosition(v), Brushes.Red, 10);
else
{
var pts = e.GetIntermediatePoints(v);
for (var c = 0; c < pts.Count; c++)
{
var pt = pts[c];
AddPoint(pt.Position, c == pts.Count - 1 ? Brushes.Blue : Brushes.Black,
c == pts.Count - 1 ? 5 : 2);
}
}
}
}
public PointerCanvas(Slider slider, TextBlock status)
{
_slider = slider;
_status = status;
DispatcherTimer.Run(() =>
{
if (_stopwatch.Elapsed.TotalSeconds > 1)
{
_status.Text = "Events per second: " + (_events / _stopwatch.Elapsed.TotalSeconds);
_stopwatch.Restart();
_events = 0;
}
return this.GetVisualRoot() != null;
}, TimeSpan.FromMilliseconds(10));
}
void HandleEvent(PointerEventArgs e)
{
_events++;
Thread.Sleep((int)_slider.Value);
InvalidateVisual();
if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)
{
_pointers.Remove(e.Pointer.Id);
return;
}
if (!_pointers.TryGetValue(e.Pointer.Id, out var pt))
_pointers[e.Pointer.Id] = pt = new PointerPoints();
pt.HandleEvent(e, this);
}
public override void Render(DrawingContext context)
{
context.FillRectangle(Brushes.White, Bounds);
foreach(var pt in _pointers.Values)
pt.Render(context);
base.Render(context);
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.ClickCount == 2)
{
_pointers.Clear();
InvalidateVisual();
return;
}
HandleEvent(e);
base.OnPointerPressed(e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
HandleEvent(e);
base.OnPointerMoved(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
HandleEvent(e);
base.OnPointerReleased(e);
}
}
}
}

37
samples/ControlCatalog/Pages/ScreenPage.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
@ -49,25 +50,33 @@ namespace ControlCatalog.Pages
context.DrawRectangle(p, boundsRect);
context.DrawRectangle(p, workingAreaRect);
var text = new FormattedText() { Typeface = new Typeface("Arial"), FontSize = 18 };
text.Text = $"Bounds: {screen.Bounds.TopLeft} {screen.Bounds.Width}:{screen.Bounds.Height}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text);
text.Text = $"WorkArea: {screen.WorkingArea.TopLeft} {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
var formattedText = CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height));
text.Text = $"Scaling: {screen.PixelDensity * 100}%";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
text.Text = $"Primary: {screen.Primary}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}";
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text);
formattedText =
CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20));
formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"Primary: {screen.Primary}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText =
CreateFormattedText(
$"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 80));
}
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10f, w.Bounds.Width / 10, w.Bounds.Height / 10));
}
private FormattedText CreateFormattedText(string textToFormat)
{
return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
Typeface.Default, 12, Brushes.Green);
}
}
}

22
samples/ControlCatalog/Pages/ViewboxPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="clr-namespace:System.Collections;assembly=netstandard"
x:Class="ControlCatalog.Pages.ViewboxPage">
<Grid RowDefinitions="Auto,*,*">
@ -12,8 +13,8 @@
<Border HorizontalAlignment="Center" Grid.Column="0" BorderThickness="1" BorderBrush="Orange" Width="200" Height="200">
<Border VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0" BorderThickness="1" BorderBrush="CornflowerBlue" Width="{Binding #WidthSlider.Value}" Height="{Binding #HeightSlider.Value}" >
<Viewbox
Stretch="{Binding #StretchSelector.SelectedItem}"
StretchDirection="{Binding #StretchDirectionSelector.SelectedItem}">
Stretch="{Binding #StretchSelector.SelectedItem, FallbackValue={x:Static Stretch.Uniform}}"
StretchDirection="{Binding #StretchDirectionSelector.SelectedItem, FallbackValue={x:Static StretchDirection.Both}}">
<Ellipse Width="50" Height="50" Fill="CornflowerBlue" />
</Viewbox>
</Border>
@ -25,9 +26,22 @@
<TextBlock Text="Height" />
<Slider Minimum="10" Maximum="200" Value="100" x:Name="HeightSlider" TickFrequency="25" TickPlacement="TopLeft" />
<TextBlock Text="Stretch" />
<ComboBox x:Name="StretchSelector" HorizontalAlignment="Stretch" Margin="0,0,0,2" />
<ComboBox x:Name="StretchSelector" HorizontalAlignment="Stretch" SelectedIndex="0" Margin="0,0,0,2">
<collections:ArrayList>
<Stretch>Uniform</Stretch>
<Stretch>UniformToFill</Stretch>
<Stretch>Fill</Stretch>
<Stretch>None</Stretch>
</collections:ArrayList>
</ComboBox>
<TextBlock Text="Stretch Direction" />
<ComboBox x:Name="StretchDirectionSelector" HorizontalAlignment="Stretch" />
<ComboBox x:Name="StretchDirectionSelector" SelectedIndex="0" HorizontalAlignment="Stretch">
<collections:ArrayList>
<StretchDirection>Both</StretchDirection>
<StretchDirection>DownOnly</StretchDirection>
<StretchDirection>UpOnly</StretchDirection>
</collections:ArrayList>
</ComboBox>
</StackPanel>
</Grid>

19
samples/ControlCatalog/Pages/ViewboxPage.xaml.cs

@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace ControlCatalog.Pages
{
@ -9,24 +8,6 @@ namespace ControlCatalog.Pages
public ViewboxPage()
{
InitializeComponent();
var stretchSelector = this.FindControl<ComboBox>("StretchSelector");
stretchSelector.Items = new[]
{
Stretch.Uniform, Stretch.UniformToFill, Stretch.Fill, Stretch.None
};
stretchSelector.SelectedIndex = 0;
var stretchDirectionSelector = this.FindControl<ComboBox>("StretchDirectionSelector");
stretchDirectionSelector.Items = new[]
{
StretchDirection.Both, StretchDirection.DownOnly, StretchDirection.UpOnly
};
stretchDirectionSelector.SelectedIndex = 0;
}
private void InitializeComponent()

3
samples/RenderDemo/MainWindow.xaml

@ -57,6 +57,9 @@
<TabItem Header="GlyphRun">
<pages:GlyphRunPage />
</TabItem>
<TabItem Header="FormattedText">
<pages:FormattedTextPage />
</TabItem>
<TabItem Header="LineBounds">
<pages:LineBoundsPage />
</TabItem>

54
samples/RenderDemo/Pages/ClippingPage.xaml

@ -19,30 +19,36 @@
</Style>
</Styles>
</Grid.Styles>
<Border Name="clipped"
Background="Yellow"
Width="100"
Height="100"
Clip="M 58.625 0.07421875
C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703
C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594
C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312
C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875
C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422
C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125
C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172
C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438
C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953
C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078
C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594
C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859
C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766
C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359
C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531
C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609
C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344
C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812
C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z ">
<Border Name="clipped"
Background="Yellow"
Width="100"
Height="100"
Classes.clip="{Binding #useMask.IsChecked}">
<Border.Styles>
<Style Selector="Border.clip">
<Setter Property="Clip"
Value="M 58.625 0.07421875
C 50.305778 0.26687364 42.411858 7.0346526 41.806641 15.595703
C 42.446442 22.063923 39.707425 13.710754 36.982422 12.683594
C 29.348395 6.1821635 16.419398 8.4359222 11.480469 17.195312
C 6.0935256 25.476803 9.8118851 37.71125 18.8125 41.6875
C 9.1554771 40.62945 -0.070876925 49.146842 0.21679688 58.857422
C 0.21545578 60.872512 0.56758794 62.88911 1.2617188 64.78125
C 4.3821886 74.16708 16.298268 78.921772 25.03125 74.326172
C 28.266843 72.062552 26.298191 74.214838 25.414062 76.398438
C 21.407348 85.589198 27.295992 97.294293 37.097656 99.501953
C 46.864883 102.3541 57.82177 94.726518 58.539062 84.580078
C 58.142158 79.498998 59.307538 83.392694 61.207031 85.433594
C 67.532324 93.056874 80.440232 93.192029 86.882812 85.630859
C 93.836392 78.456939 92.396838 65.538666 84.115234 60.009766
C 79.783641 57.904836 83.569793 58.802369 86.375 58.193359
C 96.383335 56.457569 102.87506 44.824101 99.083984 35.394531
C 95.963498 26.008711 84.047451 21.254079 75.314453 25.849609
C 72.078834 28.113269 74.047517 25.960974 74.931641 23.777344
C 78.93827 14.586564 73.049722 2.8815081 63.248047 0.67382812
C 61.721916 0.22817968 60.165597 0.038541919 58.625 0.07421875 z " />
</Style>
</Border.Styles>
<Border Name="clipChild" Background="Red" Margin="4">
<!-- Setting opacity puts the TextBox on a new layer -->
<TextBox Text="Avalonia" Opacity="0.9" VerticalAlignment="Center"/>

17
samples/RenderDemo/Pages/ClippingPage.xaml.cs

@ -1,35 +1,18 @@
using System;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace RenderDemo.Pages
{
public class ClippingPage : UserControl
{
private Geometry _clip;
public ClippingPage()
{
InitializeComponent();
WireUpCheckbox();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void WireUpCheckbox()
{
var useMask = this.FindControl<CheckBox>("useMask");
var clipped = this.FindControl<Border>("clipped");
_clip = clipped.Clip;
useMask.Click += (s, e) => clipped.Clip = clipped.Clip == null ? _clip : null;
}
}
}

13
samples/RenderDemo/Pages/CustomSkiaPage.cs

@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
@ -41,7 +42,10 @@ namespace RenderDemo.Pages
{
var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas;
if (canvas == null)
context.DrawText(Brushes.Black, new Point(), _noSkia.PlatformImpl);
using (var c = new DrawingContext(context, false))
{
c.DrawText(_noSkia, new Point());
}
else
{
canvas.Save();
@ -108,10 +112,9 @@ namespace RenderDemo.Pages
public override void Render(DrawingContext context)
{
var noSkia = new FormattedText()
{
Text = "Current rendering API is not Skia"
};
var noSkia = new FormattedText("Current rendering API is not Skia", CultureInfo.CurrentCulture,
FlowDirection.LeftToRight, Typeface.Default, 12, Brushes.Black);
context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), noSkia));
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
}

7
samples/RenderDemo/Pages/FormattedTextPage.axaml

@ -0,0 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="RenderDemo.Pages.FormattedTextPage">
</UserControl>

60
samples/RenderDemo/Pages/FormattedTextPage.axaml.cs

@ -0,0 +1,60 @@
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace RenderDemo.Pages
{
public class FormattedTextPage : UserControl
{
public FormattedTextPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public override void Render(DrawingContext context)
{
const string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor";
// Create the initial formatted text string.
var formattedText = new FormattedText(
testString,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
32,
Brushes.Black) { MaxTextWidth = 300, MaxTextHeight = 240 };
// Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
// Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
// The font size is calculated in terms of points -- not as device-independent pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);
// Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
formattedText.SetFontWeight(FontWeight.Bold, 6, 11);
var gradient = new LinearGradientBrush
{
GradientStops =
new GradientStops { new GradientStop(Colors.Orange, 0), new GradientStop(Colors.Teal, 1) },
StartPoint = new RelativePoint(0,0, RelativeUnit.Relative),
EndPoint = new RelativePoint(0,1, RelativeUnit.Relative)
};
// Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
formattedText.SetForegroundBrush(gradient, 6, 11);
// Use an Italic font style beginning at the 28th character and continuing for 28 characters.
formattedText.SetFontStyle(FontStyle.Italic, 28, 28);
context.DrawText(formattedText, new Point(10, 0));
}
}
}

7
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -13,6 +13,7 @@ namespace RenderDemo.Pages
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
private float _fontSize = 20;
private int _direction = 10;
@ -38,7 +39,7 @@ namespace RenderDemo.Pages
private void UpdateGlyphRun()
{
var c = (uint)_rand.Next(65, 90);
var c = (char)_rand.Next(65, 90);
if (_fontSize + _direction > 200)
{
@ -54,6 +55,8 @@ namespace RenderDemo.Pages
_glyphIndices[0] = _glyphTypeface.GetGlyph(c);
_characters[0] = c;
var scale = (double)_fontSize / _glyphTypeface.DesignEmHeight;
var drawingGroup = new DrawingGroup();
@ -61,7 +64,7 @@ namespace RenderDemo.Pages
var glyphRunDrawing = new GlyphRunDrawing
{
Foreground = Brushes.Black,
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices),
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _characters, _glyphIndices)
};
drawingGroup.Children.Add(glyphRunDrawing);

5
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -10,7 +10,7 @@ using Avalonia.Input.Platform;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
using Avalonia.Skia;
namespace Avalonia
@ -59,8 +59,7 @@ namespace Avalonia.Android
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IAssetLoader>().ToConstant(new AssetLoader(appType.Assembly));
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
SkiaPlatform.Initialize();

2
src/Android/Avalonia.Android/AppBuilder.cs

@ -1,5 +1,5 @@
using Avalonia.Controls;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
namespace Avalonia
{

4
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -5,9 +5,11 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj">
<SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
</ProjectReference>
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
<Import Project="..\..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\AndroidWorkarounds.props" />
</Project>

18
src/Android/Avalonia.Android/RuntimeInfo.cs

@ -1,18 +0,0 @@
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform
{
public RuntimePlatformInfo GetRuntimeInfo() => new RuntimePlatformInfo
{
IsCoreClr = false,
IsDesktop = false,
IsMobile = true,
IsDotNetFramework = false,
IsMono = true,
IsUnix = true,
OperatingSystem = OperatingSystemType.Android
};
}
}

1
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@ -146,6 +146,7 @@ namespace Avalonia.Collections
{
if (_inner.TryGetValue(key, out var value))
{
_inner.Remove(key);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));

5
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@ -1,5 +1,4 @@
using System;
using System.Reflection;
namespace Avalonia.Platform
{
@ -23,6 +22,7 @@ namespace Avalonia.Platform
public OperatingSystemType OperatingSystem { get; set; }
public bool IsDesktop { get; set; }
public bool IsMobile { get; set; }
public bool IsBrowser { get; set; }
public bool IsCoreClr { get; set; }
public bool IsMono { get; set; }
public bool IsDotNetFramework { get; set; }
@ -36,6 +36,7 @@ namespace Avalonia.Platform
Linux,
OSX,
Android,
iOS
iOS,
Browser
}
}

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

@ -74,6 +74,13 @@ namespace Avalonia.Threading
/// </summary>
/// <param name="minimumPriority"></param>
public void RunJobs(DispatcherPriority minimumPriority) => _jobRunner.RunJobs(minimumPriority);
/// <summary>
/// Use this method to check if there are more prioritized tasks
/// </summary>
/// <param name="minimumPriority"></param>
public bool HasJobsWithPriority(DispatcherPriority minimumPriority) =>
_jobRunner.HasJobsWithPriority(minimumPriority);
/// <inheritdoc/>
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)

15
src/Avalonia.Base/Threading/JobRunner.cs

@ -121,6 +121,21 @@ namespace Avalonia.Threading
return null;
}
public bool HasJobsWithPriority(DispatcherPriority minimumPriority)
{
for (int c = (int)minimumPriority; c < (int)DispatcherPriority.MaxValue; c++)
{
var q = _queues[c];
lock (q)
{
if (q.Count > 0)
return true;
}
}
return false;
}
private interface IJob
{
/// <summary>

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

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Avalonia.Utilities
{
public struct ImmutableReadOnlyListStructEnumerator<T> : IEnumerator, IEnumerator<T>
public struct ImmutableReadOnlyListStructEnumerator<T> : IEnumerator<T>
{
private readonly IReadOnlyList<T> _readOnlyList;
private int _pos;

9
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -2215,7 +2215,14 @@ namespace Avalonia.Controls
/// <param name="e">PointerWheelEventArgs</param>
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
e.Handled = e.Handled || UpdateScroll(e.Delta * DATAGRID_mouseWheelDelta);
if(UpdateScroll(e.Delta * DATAGRID_mouseWheelDelta))
{
e.Handled = true;
}
else
{
e.Handled = e.Handled || !ScrollViewer.GetIsScrollChainingEnabled(this);
}
}
internal bool UpdateScroll(Vector delta)

6
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -43,6 +43,10 @@ MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.Off
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Notifications.NotificationCard.CloseOnClickProperty' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.Platform.ITopLevelNativeMenuExporter.SetNativeMenu(Avalonia.Controls.NativeMenu)' is present in the contract but not in the implementation.
MembersMustExist : Member 'protected Avalonia.Media.FormattedText Avalonia.Controls.Presenters.TextPresenter.CreateFormattedText()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.FormattedText Avalonia.Controls.Presenters.TextPresenter.FormattedText.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Int32 Avalonia.Controls.Presenters.TextPresenter.GetCaretIndex(Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.Controls.Presenters.TextPresenter.InvalidateFormattedText()' does not exist in the implementation but it does exist in the contract.
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Primitives.PopupRoot' does not implement interface 'Avalonia.Utilities.IWeakSubscriber<Avalonia.Controls.ResourcesChangedEventArgs>' in the implementation but it does in the contract.
EnumValuesMustMatch : Enum value 'Avalonia.Platform.ExtendClientAreaChromeHints Avalonia.Platform.ExtendClientAreaChromeHints.Default' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Nullable<Avalonia.Size> Avalonia.Platform.ITopLevelImpl.FrameSize' is present in the implementation but not in the contract.
@ -63,4 +67,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platfor
MembersMustExist : Member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size, Avalonia.Platform.PlatformResizeReason)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.ITrayIconImpl Avalonia.Platform.IWindowingPlatform.CreateTrayIcon()' is present in the implementation but not in the contract.
Total Issues: 64
Total Issues: 68

35
src/Avalonia.Controls/AppBuilderBase.cs

@ -14,9 +14,9 @@ namespace Avalonia.Controls
public abstract class AppBuilderBase<TAppBuilder> where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
{
private static bool s_setupWasAlreadyCalled;
private Action _optionsInitializers;
private Func<Application> _appFactory;
private IApplicationLifetime _lifetime;
private Action? _optionsInitializers;
private Func<Application>? _appFactory;
private IApplicationLifetime? _lifetime;
/// <summary>
/// Gets or sets the <see cref="IRuntimePlatform"/> instance.
@ -31,32 +31,32 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the <see cref="Application"/> instance being initialized.
/// </summary>
public Application Instance { get; private set; }
public Application? Instance { get; private set; }
/// <summary>
/// Gets the type of the Instance (even if it's not created yet)
/// </summary>
public Type ApplicationType { get; private set; }
public Type? ApplicationType { get; private set; }
/// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary>
public Action WindowingSubsystemInitializer { get; private set; }
public Action? WindowingSubsystemInitializer { get; private set; }
/// <summary>
/// Gets the name of the currently selected windowing subsystem.
/// </summary>
public string WindowingSubsystemName { get; private set; }
public string? WindowingSubsystemName { get; private set; }
/// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem.
/// </summary>
public Action RenderingSubsystemInitializer { get; private set; }
public Action? RenderingSubsystemInitializer { get; private set; }
/// <summary>
/// Gets the name of the currently selected rendering subsystem.
/// </summary>
public string RenderingSubsystemName { get; private set; }
public string? RenderingSubsystemName { get; private set; }
/// <summary>
/// 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>
/// <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")]
public void Start<TMainWindow>(Func<object> dataContextProvider = null)
public void Start<TMainWindow>(Func<object>? dataContextProvider = null)
where TMainWindow : Window, new()
{
AfterSetup(builder =>
@ -134,7 +134,7 @@ namespace Avalonia.Controls
var window = new TMainWindow();
if (dataContextProvider != null)
window.DataContext = dataContextProvider();
((IClassicDesktopStyleApplicationLifetime)builder.Instance.ApplicationLifetime)
((IClassicDesktopStyleApplicationLifetime)builder.Instance!.ApplicationLifetime!)
.MainWindow = window;
});
@ -155,7 +155,7 @@ namespace Avalonia.Controls
public void Start(AppMainDelegate main, string[] args)
{
Setup();
main(Instance, args);
main(Instance!, args);
}
/// <summary>
@ -226,8 +226,8 @@ namespace Avalonia.Controls
var platformClassName = assemblyName.Replace("Avalonia.", string.Empty) + "Platform";
var platformClassFullName = assemblyName + "." + platformClassName;
var platformClass = assembly.GetType(platformClassFullName);
var init = platformClass.GetRuntimeMethod("Initialize", Type.EmptyTypes);
init.Invoke(null, null);
var init = platformClass!.GetRuntimeMethod("Initialize", Type.EmptyTypes);
init!.Invoke(null, null);
};
public TAppBuilder UseAvaloniaModules() => AfterSetup(builder => SetupAvaloniaModules());
@ -251,7 +251,7 @@ namespace Avalonia.Controls
where constructor.GetParameters().Length == 0 && !constructor.IsStatic
select constructor).Single() into constructor
select (Action)(() => constructor.Invoke(Array.Empty<object>()));
Delegate.Combine(moduleInitializers.ToArray()).DynamicInvoke();
Delegate.Combine(moduleInitializers.ToArray())!.DynamicInvoke();
}
/// <summary>
@ -292,6 +292,11 @@ namespace Avalonia.Controls
throw new InvalidOperationException("No rendering system configured.");
}
if (_appFactory == null)
{
throw new InvalidOperationException("No Application factory configured.");
}
if (s_setupWasAlreadyCalled && CheckSetup)
{
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.Styling;
using Avalonia.Threading;
#nullable enable
namespace Avalonia
{
@ -177,13 +176,13 @@ namespace Avalonia
/// </summary>
public IApplicationLifetime? ApplicationLifetime { get; set; }
event Action<IReadOnlyList<IStyle>> IGlobalStyles.GlobalStylesAdded
event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesAdded
{
add => _stylesAdded += value;
remove => _stylesAdded -= value;
}
event Action<IReadOnlyList<IStyle>> IGlobalStyles.GlobalStylesRemoved
event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesRemoved
{
add => _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
{
private int _exitCode;
private CancellationTokenSource _cts;
private CancellationTokenSource? _cts;
private bool _isShuttingDown;
private HashSet<Window> _windows = new HashSet<Window>();
private static ClassicDesktopStyleApplicationLifetime _activeLifetime;
private static ClassicDesktopStyleApplicationLifetime? _activeLifetime;
static ClassicDesktopStyleApplicationLifetime()
{
Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened);
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?.HandleWindowClosed((Window)sender);
_activeLifetime?._windows.Remove((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()
@ -46,24 +46,24 @@ namespace Avalonia.Controls.ApplicationLifetimes
}
/// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs>? Startup;
/// <inheritdoc/>
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
public event EventHandler<ShutdownRequestedEventArgs>? ShutdownRequested;
/// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
public event EventHandler<ControlledApplicationLifetimeExitEventArgs>? Exit;
/// <summary>
/// Gets the arguments passed to the AppBuilder Start method.
/// </summary>
public string[] Args { get; set; }
public string[]? Args { get; set; }
/// <inheritdoc/>
public ShutdownMode ShutdownMode { get; set; }
/// <inheritdoc/>
public Window MainWindow { get; set; }
public Window? MainWindow { get; set; }
public IReadOnlyList<Window> Windows => _windows.ToList();
@ -183,7 +183,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
return true;
}
private void OnShutdownRequested(object sender, ShutdownRequestedEventArgs e) => DoShutdown(e);
private void OnShutdownRequested(object? sender, ShutdownRequestedEventArgs e) => DoShutdown(e);
}
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)"/>
/// method.
/// </summary>
string[] Args { get; }
string[]? Args { get; }
/// <summary>
/// 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>
/// The main window.
/// </value>
Window MainWindow { get; set; }
Window? MainWindow { get; set; }
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
/// each window to cancel the shutdown of the application. Windows cannot however prevent OS shutdown.
/// </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
{
Control MainView { get; set; }
Control? MainView { get; set; }
}
}

309
src/Avalonia.Controls/AutoCompleteBox.cs

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

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

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

12
src/Avalonia.Controls/Border.cs

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

225
src/Avalonia.Controls/Button.cs

@ -42,30 +42,30 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Command"/> property.
/// </summary>
public static readonly DirectProperty<Button, ICommand> CommandProperty =
AvaloniaProperty.RegisterDirect<Button, ICommand>(nameof(Command),
public static readonly DirectProperty<Button, ICommand?> CommandProperty =
AvaloniaProperty.RegisterDirect<Button, ICommand?>(nameof(Command),
button => button.Command, (button, command) => button.Command = command, enableDataValidation: true);
/// <summary>
/// Defines the <see cref="HotKey"/> property.
/// </summary>
public static readonly StyledProperty<KeyGesture> HotKeyProperty =
public static readonly StyledProperty<KeyGesture?> HotKeyProperty =
HotKeyManager.HotKeyProperty.AddOwner<Button>();
/// <summary>
/// Defines the <see cref="CommandParameter"/> property.
/// </summary>
public static readonly StyledProperty<object> CommandParameterProperty =
AvaloniaProperty.Register<Button, object>(nameof(CommandParameter));
public static readonly StyledProperty<object?> CommandParameterProperty =
AvaloniaProperty.Register<Button, object?>(nameof(CommandParameter));
/// <summary>
/// Defines the <see cref="IsDefaultProperty"/> property.
/// Defines the <see cref="IsDefault"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsDefaultProperty =
AvaloniaProperty.Register<Button, bool>(nameof(IsDefault));
/// <summary>
/// Defines the <see cref="IsCancelProperty"/> property.
/// Defines the <see cref="IsCancel"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsCancelProperty =
AvaloniaProperty.Register<Button, bool>(nameof(IsCancel));
@ -76,6 +76,9 @@ namespace Avalonia.Controls
public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
RoutedEvent.Register<Button, RoutedEventArgs>(nameof(Click), RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="IsPressed"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsPressedProperty =
AvaloniaProperty.Register<Button, bool>(nameof(IsPressed));
@ -85,9 +88,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<FlyoutBase> FlyoutProperty =
AvaloniaProperty.Register<Button, FlyoutBase>(nameof(Flyout));
private ICommand _command;
private ICommand? _command;
private bool _commandCanExecute = true;
private KeyGesture _hotkey;
private KeyGesture? _hotkey;
/// <summary>
/// Initializes static members of the <see cref="Button"/> class.
@ -95,13 +98,12 @@ namespace Avalonia.Controls
static Button()
{
FocusableProperty.OverrideDefaultValue(typeof(Button), true);
CommandProperty.Changed.Subscribe(CommandChanged);
CommandParameterProperty.Changed.Subscribe(CommandParameterChanged);
IsDefaultProperty.Changed.Subscribe(IsDefaultChanged);
IsCancelProperty.Changed.Subscribe(IsCancelChanged);
AccessKeyHandler.AccessKeyPressedEvent.AddClassHandler<Button>((lbl, args) => lbl.OnAccessKey(args));
}
/// <summary>
/// Initializes a new instance of the <see cref="Button"/> class.
/// </summary>
public Button()
{
UpdatePseudoClasses(IsPressed);
@ -110,10 +112,10 @@ namespace Avalonia.Controls
/// <summary>
/// Raised when the user clicks the button.
/// </summary>
public event EventHandler<RoutedEventArgs> Click
public event EventHandler<RoutedEventArgs>? Click
{
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
add => AddHandler(ClickEvent, value);
remove => RemoveHandler(ClickEvent, value);
}
/// <summary>
@ -121,35 +123,35 @@ namespace Avalonia.Controls
/// </summary>
public ClickMode ClickMode
{
get { return GetValue(ClickModeProperty); }
set { SetValue(ClickModeProperty, value); }
get => GetValue(ClickModeProperty);
set => SetValue(ClickModeProperty, value);
}
/// <summary>
/// Gets or sets an <see cref="ICommand"/> to be invoked when the button is clicked.
/// </summary>
public ICommand Command
public ICommand? Command
{
get { return _command; }
set { SetAndRaise(CommandProperty, ref _command, value); }
get => _command;
set => SetAndRaise(CommandProperty, ref _command, value);
}
/// <summary>
/// Gets or sets an <see cref="KeyGesture"/> associated with this control
/// </summary>
public KeyGesture HotKey
public KeyGesture? HotKey
{
get { return GetValue(HotKeyProperty); }
set { SetValue(HotKeyProperty, value); }
get => GetValue(HotKeyProperty);
set => SetValue(HotKeyProperty, value);
}
/// <summary>
/// Gets or sets a parameter to be passed to the <see cref="Command"/>.
/// </summary>
public object CommandParameter
public object? CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
/// <summary>
@ -158,8 +160,8 @@ namespace Avalonia.Controls
/// </summary>
public bool IsDefault
{
get { return GetValue(IsDefaultProperty); }
set { SetValue(IsDefaultProperty, value); }
get => GetValue(IsDefaultProperty);
set => SetValue(IsDefaultProperty, value);
}
/// <summary>
@ -168,18 +170,21 @@ namespace Avalonia.Controls
/// </summary>
public bool IsCancel
{
get { return GetValue(IsCancelProperty); }
set { SetValue(IsCancelProperty, value); }
get => GetValue(IsCancelProperty);
set => SetValue(IsCancelProperty, value);
}
/// <summary>
/// Gets or sets a value indicating whether the button is currently pressed.
/// </summary>
public bool IsPressed
{
get { return GetValue(IsPressedProperty); }
private set { SetValue(IsPressedProperty, value); }
get => GetValue(IsPressedProperty);
private set => SetValue(IsPressedProperty, value);
}
/// <summary>
/// Gets or sets the Flyout that should be shown with this button
/// Gets or sets the Flyout that should be shown with this button.
/// </summary>
public FlyoutBase Flyout
{
@ -187,7 +192,8 @@ namespace Avalonia.Controls
set => SetValue(FlyoutProperty, value);
}
protected override bool IsEnabledCore => base.IsEnabledCore && _commandCanExecute;
/// <inheritdoc/>
protected override bool IsEnabledCore => base.IsEnabledCore && _commandCanExecute;
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
@ -224,6 +230,7 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc/>
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
if (_hotkey != null) // Control attached again, set Hotkey to create a hotkey manager for this control
@ -240,6 +247,7 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc/>
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
// This will cause the hotkey manager to dispose the observer and the reference to this control
@ -358,12 +366,14 @@ namespace Avalonia.Controls
}
}
}
/// <inheritdoc/>
protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
{
IsPressed = false;
}
/// <inheritdoc/>
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
@ -371,119 +381,93 @@ namespace Avalonia.Controls
IsPressed = false;
}
/// <inheritdoc/>
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == IsPressedProperty)
{
UpdatePseudoClasses(change.NewValue.GetValueOrDefault<bool>());
}
else if (change.Property == FlyoutProperty)
if (change.Property == CommandProperty)
{
// If flyout is changed while one is already open, make sure we
// close the old one first
if (change.OldValue.GetValueOrDefault() is FlyoutBase oldFlyout &&
oldFlyout.IsOpen)
if (((ILogical)this).IsAttachedToLogicalTree)
{
oldFlyout.Hide();
if (change.OldValue.GetValueOrDefault() is ICommand oldCommand)
{
oldCommand.CanExecuteChanged -= CanExecuteChanged;
}
if (change.NewValue.GetValueOrDefault() is ICommand newCommand)
{
newCommand.CanExecuteChanged += CanExecuteChanged;
}
}
}
}
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
{
base.UpdateDataValidation(property, value);
if (property == CommandProperty)
CanExecuteChanged(this, EventArgs.Empty);
}
else if (change.Property == CommandParameterProperty)
{
if (value.Type == BindingValueType.BindingError)
CanExecuteChanged(this, EventArgs.Empty);
}
else if (change.Property == IsCancelProperty)
{
var isCancel = change.NewValue.GetValueOrDefault<bool>();
if (VisualRoot is IInputElement inputRoot)
{
if (_commandCanExecute)
if (isCancel)
{
_commandCanExecute = false;
UpdateIsEffectivelyEnabled();
ListenForCancel(inputRoot);
}
else
{
StopListeningForCancel(inputRoot);
}
}
}
}
/// <summary>
/// Called when the <see cref="Command"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private static void CommandChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.Sender is Button button)
else if (change.Property == IsDefaultProperty)
{
if (((ILogical)button).IsAttachedToLogicalTree)
var isDefault = change.NewValue.GetValueOrDefault<bool>();
if (VisualRoot is IInputElement inputRoot)
{
if (e.OldValue is ICommand oldCommand)
if (isDefault)
{
oldCommand.CanExecuteChanged -= button.CanExecuteChanged;
ListenForDefault(inputRoot);
}
if (e.NewValue is ICommand newCommand)
else
{
newCommand.CanExecuteChanged += button.CanExecuteChanged;
StopListeningForDefault(inputRoot);
}
}
button.CanExecuteChanged(button, EventArgs.Empty);
}
}
/// <summary>
/// Called when the <see cref="CommandParameter"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private static void CommandParameterChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.Sender is Button button)
else if (change.Property == IsPressedProperty)
{
button.CanExecuteChanged(button, EventArgs.Empty);
UpdatePseudoClasses(change.NewValue.GetValueOrDefault<bool>());
}
}
/// <summary>
/// Called when the <see cref="IsDefault"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private static void IsDefaultChanged(AvaloniaPropertyChangedEventArgs e)
{
var button = e.Sender as Button;
var isDefault = (bool)e.NewValue;
if (button?.VisualRoot is IInputElement inputRoot)
else if (change.Property == FlyoutProperty)
{
if (isDefault)
{
button.ListenForDefault(inputRoot);
}
else
// If flyout is changed while one is already open, make sure we
// close the old one first
if (change.OldValue.GetValueOrDefault() is FlyoutBase oldFlyout &&
oldFlyout.IsOpen)
{
button.StopListeningForDefault(inputRoot);
oldFlyout.Hide();
}
}
}
/// <summary>
/// Called when the <see cref="IsCancel"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private static void IsCancelChanged(AvaloniaPropertyChangedEventArgs e)
/// <inheritdoc/>
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
{
var button = e.Sender as Button;
var isCancel = (bool)e.NewValue;
if (button?.VisualRoot is IInputElement inputRoot)
base.UpdateDataValidation(property, value);
if (property == CommandProperty)
{
if (isCancel)
{
button.ListenForCancel(inputRoot);
}
else
if (value.Type == BindingValueType.BindingError)
{
button.StopListeningForCancel(inputRoot);
if (_commandCanExecute)
{
_commandCanExecute = false;
UpdateIsEffectivelyEnabled();
}
}
}
}
@ -493,7 +477,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="sender">The event sender.</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);
@ -545,7 +529,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="sender">The event sender.</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)
{
@ -558,7 +542,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="sender">The event sender.</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)
{
@ -566,6 +550,9 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Updates the visual state of the control by applying latest PseudoClasses.
/// </summary>
private void UpdatePseudoClasses(bool isPressed)
{
PseudoClasses.Set(":pressed", isPressed);

14
src/Avalonia.Controls/ButtonSpinner.cs

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

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

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

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

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

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

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

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

@ -40,7 +40,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Gets or sets the Calendar associated with this button.
/// </summary>
internal Calendar Owner { get; set; }
internal Calendar? Owner { get; set; }
internal int Index { get; set; }
/// <summary>
@ -177,7 +177,7 @@ namespace Avalonia.Controls.Primitives
/// stylus touches the tablet PC) while the mouse pointer is over a
/// UIElement.
/// </summary>
public event EventHandler<PointerPressedEventArgs> CalendarDayButtonMouseDown;
public event EventHandler<PointerPressedEventArgs>? CalendarDayButtonMouseDown;
/// <summary>
/// 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
/// capture).
/// </summary>
public event EventHandler<PointerReleasedEventArgs> CalendarDayButtonMouseUp;
public event EventHandler<PointerReleasedEventArgs>? CalendarDayButtonMouseUp;
/// <summary>
/// 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_ElementYearView = "YearView";
private Button _headerButton;
private Button _nextButton;
private Button _previousButton;
private ITemplate<IControl> _dayTitleTemplate;
private Button? _headerButton;
private Button? _nextButton;
private Button? _previousButton;
private ITemplate<IControl>? _dayTitleTemplate;
private DateTime _currentMonth;
private bool _isMouseLeftButtonDown = false;
@ -45,11 +45,11 @@ namespace Avalonia.Controls.Primitives
private System.Globalization.Calendar _calendar = new System.Globalization.GregorianCalendar();
private PointerPressedEventArgs _downEventArg;
private PointerPressedEventArgs _downEventArgYearView;
private PointerPressedEventArgs? _downEventArg;
private PointerPressedEventArgs? _downEventArgYearView;
internal Calendar Owner { get; set; }
internal CalendarDayButton CurrentButton { get; set; }
internal Calendar? Owner { get; set; }
internal CalendarDayButton? CurrentButton { get; set; }
public static readonly StyledProperty<IBrush> HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner<CalendarItem>();
public IBrush HeaderBackground
@ -57,13 +57,13 @@ namespace Avalonia.Controls.Primitives
get { return GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); }
}
public static readonly DirectProperty<CalendarItem, ITemplate<IControl>> DayTitleTemplateProperty =
AvaloniaProperty.RegisterDirect<CalendarItem, ITemplate<IControl>>(
public static readonly DirectProperty<CalendarItem, ITemplate<IControl>?> DayTitleTemplateProperty =
AvaloniaProperty.RegisterDirect<CalendarItem, ITemplate<IControl>?>(
nameof(DayTitleTemplate),
o => o.DayTitleTemplate,
(o,v) => o.DayTitleTemplate = v,
defaultBindingMode: BindingMode.OneTime);
public ITemplate<IControl> DayTitleTemplate
public ITemplate<IControl>? DayTitleTemplate
{
get { return _dayTitleTemplate; }
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,
/// and decade mode.
/// </summary>
internal Button HeaderButton
internal Button? HeaderButton
{
get { return _headerButton; }
private set
@ -94,7 +94,7 @@ namespace Avalonia.Controls.Primitives
/// Gets the button that displays the next page of the calendar when it
/// is clicked.
/// </summary>
internal Button NextButton
internal Button? NextButton
{
get { return _nextButton; }
private set
@ -125,7 +125,7 @@ namespace Avalonia.Controls.Primitives
/// Gets the button that displays the previous page of the calendar when
/// it is clicked.
/// </summary>
internal Button PreviousButton
internal Button? PreviousButton
{
get { return _previousButton; }
private set
@ -156,11 +156,11 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Gets the Grid that hosts the content when in month mode.
/// </summary>
internal Grid MonthView { get; set; }
internal Grid? MonthView { get; set; }
/// <summary>
/// Gets the Grid that hosts the content when in year or decade mode.
/// </summary>
internal Grid YearView { get; set; }
internal Grid? YearView { get; set; }
private void PopulateGrids()
{
@ -294,7 +294,7 @@ namespace Avalonia.Controls.Primitives
{
for (int childIndex = 0; childIndex < Calendar.ColumnsPerMonth; childIndex++)
{
var daytitle = MonthView.Children[childIndex];
var daytitle = MonthView!.Children[childIndex];
if (daytitle != null)
{
if (Owner != null)
@ -495,8 +495,7 @@ namespace Avalonia.Controls.Primitives
for (int childIndex = Calendar.ColumnsPerMonth; childIndex < count; childIndex++)
{
CalendarDayButton childButton = MonthView.Children[childIndex] as CalendarDayButton;
Contract.Requires<ArgumentNullException>(childButton != null);
CalendarDayButton childButton = (CalendarDayButton)MonthView!.Children[childIndex];
childButton.Index = childIndex;
SetButtonState(childButton, dateToAdd);
@ -532,8 +531,7 @@ namespace Avalonia.Controls.Primitives
childIndex++;
for (int i = childIndex; i < count; i++)
{
childButton = MonthView.Children[i] as CalendarDayButton;
Contract.Requires<ArgumentNullException>(childButton != null);
childButton = (CalendarDayButton)MonthView.Children[i];
// button needs a content to occupy the necessary space
// for the content presenter
childButton.Content = i.ToString(DateTimeHelper.GetCurrentDateFormat());
@ -626,10 +624,9 @@ namespace Avalonia.Controls.Primitives
private void SetMonthButtonsForYearMode()
{
int count = 0;
foreach (object child in YearView.Children)
foreach (object child in YearView!.Children)
{
CalendarButton childButton = child as CalendarButton;
Contract.Requires<ArgumentNullException>(childButton != null);
CalendarButton childButton = (CalendarButton)child;
// There should be no time component. Time is 12:00 AM
DateTime day = new DateTime(_currentMonth.Year, count + 1, 1);
childButton.DataContext = day;
@ -703,7 +700,7 @@ namespace Avalonia.Controls.Primitives
{
if (Owner != null && calendarButton != null && calendarButton.DataContext != null)
{
Owner.FocusCalendarButton.IsCalendarButtonFocused = false;
Owner.FocusCalendarButton!.IsCalendarButtonFocused = false;
Owner.FocusCalendarButton = calendarButton;
calendarButton.IsCalendarButtonFocused = Owner.HasFocusInternal;
@ -722,10 +719,9 @@ namespace Avalonia.Controls.Primitives
{
int year;
int count = -1;
foreach (object child in YearView.Children)
foreach (object child in YearView!.Children)
{
CalendarButton childButton = child as CalendarButton;
Contract.Requires<ArgumentNullException>(childButton != null);
CalendarButton childButton = (CalendarButton)child;
year = decade + count;
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)
{
@ -805,7 +801,7 @@ namespace Avalonia.Controls.Primitives
{
Owner.Focus();
}
Button b = (Button)sender;
Button b = (Button)sender!;
DateTime d;
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)
{
@ -842,14 +838,14 @@ namespace Avalonia.Controls.Primitives
Owner.Focus();
}
Button b = (Button)sender;
Button b = (Button)sender!;
if (b.IsEnabled)
{
Owner.OnPreviousClick();
}
}
}
internal void NextButton_Click(object sender, RoutedEventArgs e)
internal void NextButton_Click(object? sender, RoutedEventArgs e)
{
if (Owner != null)
{
@ -857,7 +853,7 @@ namespace Avalonia.Controls.Primitives
{
Owner.Focus();
}
Button b = (Button)sender;
Button b = (Button)sender!;
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)
{
@ -878,7 +874,7 @@ namespace Avalonia.Controls.Primitives
{
case CalendarSelectionMode.SingleDate:
{
DateTime selectedDate = (DateTime)b.DataContext;
DateTime selectedDate = (DateTime)b.DataContext!;
Owner.CalendarDatePickerDisplayDateFlag = true;
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)
{
@ -917,15 +913,14 @@ namespace Avalonia.Controls.Primitives
bool ctrl, shift;
CalendarExtensions.GetMetaKeyState(e.KeyModifiers, out ctrl, out shift);
CalendarDayButton b = sender as CalendarDayButton;
CalendarDayButton b = (CalendarDayButton)sender!;
if (b != null)
{
_isControlPressed = ctrl;
if (b.IsEnabled && !b.IsBlackout)
{
DateTime selectedDate = (DateTime)b.DataContext;
Contract.Requires<ArgumentNullException>(selectedDate != null);
DateTime selectedDate = (DateTime)b.DataContext!;
_isMouseLeftButtonDown = true;
// null check is added for unit tests
if (e != null)
@ -1027,7 +1022,7 @@ namespace Avalonia.Controls.Primitives
if (Owner != null)
{
Owner.HoverEndIndex = b.Index;
Owner.HoverEnd = (DateTime)b.DataContext;
Owner.HoverEnd = (DateTime)b.DataContext!;
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)
{
CalendarDayButton b = sender as CalendarDayButton;
CalendarDayButton? b = sender as CalendarDayButton;
if (b != null && !b.IsBlackout)
{
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 (_isControlPressed && Owner.SelectionMode == CalendarSelectionMode.MultipleRange)
{
CalendarDayButton b = sender as CalendarDayButton;
Contract.Requires<ArgumentNullException>(b != null);
CalendarDayButton b = (CalendarDayButton)sender!;
if (b.IsSelected)
{
@ -1118,10 +1112,9 @@ namespace Avalonia.Controls.Primitives
_isControlPressed = false;
}
private void Month_CalendarButtonMouseDown(object sender, PointerPressedEventArgs e)
private void Month_CalendarButtonMouseDown(object? sender, PointerPressedEventArgs e)
{
CalendarButton b = sender as CalendarButton;
Contract.Requires<ArgumentNullException>(b != null);
CalendarButton b = (CalendarButton)sender!;
_isMouseLeftButtonDownYearView = true;
@ -1133,13 +1126,13 @@ namespace Avalonia.Controls.Primitives
UpdateYearViewSelection(b);
}
internal void Month_CalendarButtonMouseUp(object sender, PointerReleasedEventArgs e)
internal void Month_CalendarButtonMouseUp(object? sender, PointerReleasedEventArgs e)
{
_isMouseLeftButtonDownYearView = false;
if (Owner != null)
{
DateTime newmonth = (DateTime)((CalendarButton)sender).DataContext;
DateTime newmonth = (DateTime)((CalendarButton)sender!).DataContext!;
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)
{
CalendarButton b = sender as CalendarButton;
Contract.Requires<ArgumentNullException>(b != null);
CalendarButton b = (CalendarButton)sender!;
UpdateYearViewSelection(b);
}
}

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

@ -5,6 +5,7 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace Avalonia.Controls
@ -73,6 +74,7 @@ namespace Avalonia.Controls
return newD;
}
[return: NotNullIfNotNull("d")]
public static DateTime? DiscardTime(DateTime? d)
{
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)
{
_owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(null, removedItems, addedItems));
_owner.OnSelectedDatesCollectionChanged(new SelectionChangedEventArgs(SelectingItemsControl.SelectionChangedEvent, removedItems, addedItems));
}
/// <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.UpdateMonths();
_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="wrap">Whether to wrap around when the first or last item is reached.</param>
/// <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
return null;

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

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

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

@ -3,8 +3,6 @@ using System.Reactive.Disposables;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
#nullable enable
namespace Avalonia.Controls.Chrome
{
/// <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>
/// Defines the <see cref="SelectionBoxItem"/> property.
/// </summary>
public static readonly DirectProperty<ComboBox, object> SelectionBoxItemProperty =
AvaloniaProperty.RegisterDirect<ComboBox, object>(nameof(SelectionBoxItem), o => o.SelectionBoxItem);
public static readonly DirectProperty<ComboBox, object?> SelectionBoxItemProperty =
AvaloniaProperty.RegisterDirect<ComboBox, object?>(nameof(SelectionBoxItem), o => o.SelectionBoxItem);
/// <summary>
/// Defines the <see cref="VirtualizationMode"/> property.
@ -58,14 +58,14 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="PlaceholderText"/> property.
/// </summary>
public static readonly StyledProperty<string> PlaceholderTextProperty =
AvaloniaProperty.Register<ComboBox, string>(nameof(PlaceholderText));
public static readonly StyledProperty<string?> PlaceholderTextProperty =
AvaloniaProperty.Register<ComboBox, string?>(nameof(PlaceholderText));
/// <summary>
/// Defines the <see cref="PlaceholderForeground"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> PlaceholderForegroundProperty =
AvaloniaProperty.Register<ComboBox, IBrush>(nameof(PlaceholderForeground));
public static readonly StyledProperty<IBrush?> PlaceholderForegroundProperty =
AvaloniaProperty.Register<ComboBox, IBrush?>(nameof(PlaceholderForeground));
/// <summary>
/// Defines the <see cref="HorizontalContentAlignment"/> property.
@ -80,8 +80,8 @@ namespace Avalonia.Controls
ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>();
private bool _isDropDownOpen;
private Popup _popup;
private object _selectionBoxItem;
private Popup? _popup;
private object? _selectionBoxItem;
private readonly CompositeDisposable _subscriptionsOnOpen = new CompositeDisposable();
/// <summary>
@ -117,7 +117,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the item to display as the control's content.
/// </summary>
protected object SelectionBoxItem
protected object? SelectionBoxItem
{
get { return _selectionBoxItem; }
set { SetAndRaise(SelectionBoxItemProperty, ref _selectionBoxItem, value); }
@ -126,7 +126,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the PlaceHolder text.
/// </summary>
public string PlaceholderText
public string? PlaceholderText
{
get { return GetValue(PlaceholderTextProperty); }
set { SetValue(PlaceholderTextProperty, value); }
@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the Brush that renders the placeholder text.
/// </summary>
public IBrush PlaceholderForeground
public IBrush? PlaceholderForeground
{
get { return GetValue(PlaceholderForegroundProperty); }
set { SetValue(PlaceholderForegroundProperty, value); }
@ -262,9 +262,9 @@ namespace Avalonia.Controls
/// <inheritdoc/>
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))
{
@ -304,7 +304,7 @@ namespace Avalonia.Controls
}
}
private void PopupClosed(object sender, EventArgs e)
private void PopupClosed(object? sender, EventArgs e)
{
_subscriptionsOnOpen.Clear();
@ -314,7 +314,7 @@ namespace Avalonia.Controls
}
}
private void PopupOpened(object sender, EventArgs e)
private void PopupOpened(object? sender, EventArgs e)
{
TryFocusSelectedItem();
@ -326,7 +326,7 @@ namespace Avalonia.Controls
toplevel.AddDisposableHandler(PointerWheelChangedEvent, (s, ev) =>
{
//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;
}
@ -360,12 +360,12 @@ namespace Avalonia.Controls
var selectedIndex = SelectedIndex;
if (IsDropDownOpen && selectedIndex != -1)
{
var container = ItemContainerGenerator.ContainerFromIndex(selectedIndex);
var container = ItemContainerGenerator!.ContainerFromIndex(selectedIndex);
if (container == null && SelectedIndex != -1)
{
ScrollIntoView(Selection.SelectedIndex);
container = ItemContainerGenerator.ContainerFromIndex(selectedIndex);
container = ItemContainerGenerator!.ContainerFromIndex(selectedIndex);
}
if (container != null && CanFocus(container))
@ -377,7 +377,7 @@ namespace Avalonia.Controls
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;
@ -415,7 +415,7 @@ namespace Avalonia.Controls
private void SelectFocusedItem()
{
foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator.Containers)
foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator!.Containers)
{
if (dropdownItem.ContainerControl.IsFocused)
{

14
src/Avalonia.Controls/ContentControl.cs

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

14
src/Avalonia.Controls/ContextMenu.cs

@ -14,8 +14,6 @@ using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Styling;
#nullable enable
namespace Avalonia.Controls
{
/// <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;
Focus();
@ -376,12 +374,12 @@ namespace Avalonia.Controls
_popupHostChangedHandler?.Invoke(_popup!.Host);
}
private void PopupClosing(object sender, CancelEventArgs e)
private void PopupClosing(object? sender, CancelEventArgs e)
{
e.Cancel = CancelClosing();
}
private void PopupClosed(object sender, EventArgs e)
private void PopupClosed(object? sender, EventArgs e)
{
foreach (var i in LogicalChildren)
{
@ -411,7 +409,7 @@ namespace Avalonia.Controls
_popupHostChangedHandler?.Invoke(null);
}
private void PopupKeyUp(object sender, KeyEventArgs e)
private void PopupKeyUp(object? sender, KeyEventArgs e)
{
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
&& 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
&& control.ContextMenu is ContextMenu contextMenu)

2
src/Avalonia.Controls/ContextRequestedEventArgs.cs

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

23
src/Avalonia.Controls/Control.cs

@ -1,16 +1,16 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Rendering;
using Avalonia.Styling;
using Avalonia.VisualTree;
#nullable enable
namespace Avalonia.Controls
{
/// <summary>
@ -60,7 +60,13 @@ namespace Avalonia.Controls
public static readonly RoutedEvent<ContextRequestedEventArgs> ContextRequestedEvent =
RoutedEvent.Register<Control, ContextRequestedEventArgs>(nameof(ContextRequested),
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="FlowDirection"/> property.
/// </summary>
public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty =
AvaloniaProperty.RegisterAttached<Control, Control, FlowDirection>(nameof(FlowDirection), inherits: true);
private DataTemplates? _dataTemplates;
private IControl? _focusAdorner;
@ -108,11 +114,20 @@ namespace Avalonia.Controls
get => GetValue(TagProperty);
set => SetValue(TagProperty, value);
}
/// <summary>
/// Gets or sets the text flow direction.
/// </summary>
public FlowDirection FlowDirection
{
get => GetValue(FlowDirectionProperty);
set => SetValue(FlowDirectionProperty, value);
}
/// <summary>
/// Occurs when the user has completed a context input gesture, such as a right-click.
/// </summary>
public event EventHandler<ContextRequestedEventArgs> ContextRequested
public event EventHandler<ContextRequestedEventArgs>? ContextRequested
{
add => AddHandler(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>
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));
}
@ -29,7 +29,7 @@ namespace Avalonia.Controls
/// <param name="rect">The area of the control to being into view.</param>
public static void BringIntoView(this IControl control, Rect rect)
{
Contract.Requires<ArgumentNullException>(control != null);
_ = control ?? throw new ArgumentNullException(nameof(control));
if (control.IsEffectivelyVisible)
{
@ -51,10 +51,10 @@ namespace Avalonia.Controls
/// <param name="control">The control to look in.</param>
/// <param name="name">The name of the control to find.</param>
/// <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);
Contract.Requires<ArgumentNullException>(name != null);
_ = control ?? throw new ArgumentNullException(nameof(control));
_ = name ?? throw new ArgumentNullException(nameof(name));
var nameScope = control.FindNameScope();
@ -66,6 +66,29 @@ namespace Avalonia.Controls
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>
/// Sets a pseudoclass depending on an observable trigger.
/// </summary>
@ -75,7 +98,7 @@ namespace Avalonia.Controls
/// <returns>A disposable used to cancel the subscription.</returns>
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));
}

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

@ -1,5 +1,4 @@
#nullable enable
using System;
using System;
using System.Globalization;
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 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)
{
@ -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();
}

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

@ -11,7 +11,7 @@ namespace Avalonia.Controls.Converters
{
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 ||
values == null ||

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

@ -13,7 +13,7 @@ namespace Avalonia.Controls.Converters
/// </summary>
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)
{
@ -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();
}

29
src/Avalonia.Controls/DataValidationErrors.cs

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

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

@ -93,15 +93,15 @@ namespace Avalonia.Controls
defaultBindingMode: BindingMode.TwoWay);
// Template Items
private Button _flyoutButton;
private TextBlock _dayText;
private TextBlock _monthText;
private TextBlock _yearText;
private Grid _container;
private Rectangle _spacer1;
private Rectangle _spacer2;
private Popup _popup;
private DatePickerPresenter _presenter;
private Button? _flyoutButton;
private TextBlock? _dayText;
private TextBlock? _monthText;
private TextBlock? _yearText;
private Grid? _container;
private Rectangle? _spacer1;
private Rectangle? _spacer2;
private Popup? _popup;
private DatePickerPresenter? _presenter;
private bool _areControlsAvailable;
@ -256,7 +256,7 @@ namespace Avalonia.Controls
/// <summary>
/// Raised when the <see cref="SelectedDate"/> changes
/// </summary>
public event EventHandler<DatePickerSelectedValueChangedEventArgs> SelectedDateChanged;
public event EventHandler<DatePickerSelectedValueChangedEventArgs>? SelectedDateChanged;
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();
}
private void OnConfirmed(object sender, EventArgs e)
private void OnConfirmed(object? sender, EventArgs e)
{
_popup.Close();
SelectedDate = _presenter.Date;
_popup!.Close();
SelectedDate = _presenter!.Date;
}
private void SetGrid()
@ -325,7 +325,7 @@ namespace Avalonia.Controls
return;
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),
(_yearText, YearVisible ? fmt.IndexOf("y", StringComparison.OrdinalIgnoreCase) : -1),
@ -366,11 +366,11 @@ namespace Avalonia.Controls
var isSpacer1Visible = columnIndex > 1;
var isSpacer2Visible = columnIndex > 2;
// ternary conditional operator is used to make sure grid cells will be validated
Grid.SetColumn(_spacer1, isSpacer1Visible ? 1 : 0);
Grid.SetColumn(_spacer2, isSpacer2Visible ? 3 : 0);
Grid.SetColumn(_spacer1!, isSpacer1Visible ? 1 : 0);
Grid.SetColumn(_spacer2!, isSpacer2Visible ? 3 : 0);
_spacer1.IsVisible = isSpacer1Visible;
_spacer2.IsVisible = isSpacer2Visible;
_spacer1!.IsVisible = isSpacer1Visible;
_spacer2!.IsVisible = isSpacer2Visible;
}
private void SetSelectedDateText()
@ -382,37 +382,37 @@ namespace Avalonia.Controls
{
PseudoClasses.Set(":hasnodate", false);
var selDate = SelectedDate.Value;
_monthText.Text = selDate.ToString(MonthFormat);
_yearText.Text = selDate.ToString(YearFormat);
_dayText.Text = selDate.ToString(DayFormat);
_monthText!.Text = selDate.ToString(MonthFormat);
_yearText!.Text = selDate.ToString(YearFormat);
_dayText!.Text = selDate.ToString(DayFormat);
}
else
{
PseudoClasses.Set(":hasnodate", true);
_monthText.Text = "month";
_yearText.Text = "year";
_dayText.Text = "day";
_monthText!.Text = "month";
_yearText!.Text = "year";
_dayText!.Text = "day";
}
}
private void OnFlyoutButtonClicked(object sender, RoutedEventArgs e)
private void OnFlyoutButtonClicked(object? sender, RoutedEventArgs e)
{
if (_presenter == null)
throw new InvalidOperationException("No DatePickerPresenter found");
_presenter.Date = SelectedDate ?? DateTimeOffset.Now;
_popup.IsOpen = true;
_popup!.IsOpen = true;
var deltaY = _presenter.GetOffsetForPopup();
// 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.PopupPositionerConstraintAdjustment.SlideY);
}
protected virtual void OnSelectedDateChanged(object sender, DatePickerSelectedValueChangedEventArgs e)
protected virtual void OnSelectedDateChanged(object? sender, DatePickerSelectedValueChangedEventArgs 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);
// Template Items
private Grid _pickerContainer;
private Button _acceptButton;
private Button _dismissButton;
private Rectangle _spacer1;
private Rectangle _spacer2;
private Panel _monthHost;
private Panel _yearHost;
private Panel _dayHost;
private DateTimePickerPanel _monthSelector;
private DateTimePickerPanel _yearSelector;
private DateTimePickerPanel _daySelector;
private Button _monthUpButton;
private Button _dayUpButton;
private Button _yearUpButton;
private Button _monthDownButton;
private Button _dayDownButton;
private Button _yearDownButton;
private Grid? _pickerContainer;
private Button? _acceptButton;
private Button? _dismissButton;
private Rectangle? _spacer1;
private Rectangle? _spacer2;
private Panel? _monthHost;
private Panel? _yearHost;
private Panel? _dayHost;
private DateTimePickerPanel? _monthSelector;
private DateTimePickerPanel? _yearSelector;
private DateTimePickerPanel? _daySelector;
private Button? _monthUpButton;
private Button? _dayUpButton;
private Button? _yearUpButton;
private Button? _monthDownButton;
private Button? _dayDownButton;
private Button? _yearDownButton;
private DateTimeOffset _date;
private string _dayFormat = "%d";
@ -308,9 +308,12 @@ namespace Avalonia.Controls
e.Handled = true;
break;
case Key.Tab:
var nextFocus = KeyboardNavigationHandler.GetNext(FocusManager.Instance.Current, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
e.Handled = true;
if (FocusManager.Instance?.Current is IInputElement focus)
{
var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
e.Handled = true;
}
break;
case Key.Enter:
Date = _syncDate;
@ -332,13 +335,13 @@ namespace Avalonia.Controls
_suppressUpdateSelection = true;
_monthSelector.MaximumValue = 12;
_monthSelector!.MaximumValue = 12;
_monthSelector.MinimumValue = 1;
_monthSelector.ItemFormat = MonthFormat;
_daySelector.ItemFormat = DayFormat;
_daySelector!.ItemFormat = DayFormat;
_yearSelector.MaximumValue = MaxYear.Year;
_yearSelector!.MaximumValue = MaxYear.Year;
_yearSelector.MinimumValue = MinYear.Year;
_yearSelector.ItemFormat = YearFormat;
@ -375,7 +378,7 @@ namespace Avalonia.Controls
private void SetGrid()
{
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),
(_yearHost, YearVisible ? fmt.IndexOf("y", StringComparison.OrdinalIgnoreCase) : -1),
@ -383,7 +386,7 @@ namespace Avalonia.Controls
};
columns.Sort((x, y) => x.Item2 - y.Item2);
_pickerContainer.ColumnDefinitions.Clear();
_pickerContainer!.ColumnDefinitions.Clear();
var columnIndex = 0;
@ -416,18 +419,18 @@ namespace Avalonia.Controls
var isSpacer1Visible = columnIndex > 1;
var isSpacer2Visible = columnIndex > 2;
// ternary conditional operator is used to make sure grid cells will be validated
Grid.SetColumn(_spacer1, isSpacer1Visible ? 1 : 0);
Grid.SetColumn(_spacer2, isSpacer2Visible ? 3 : 0);
Grid.SetColumn(_spacer1!, isSpacer1Visible ? 1 : 0);
Grid.SetColumn(_spacer2!, isSpacer2Visible ? 3 : 0);
_spacer1.IsVisible = isSpacer1Visible;
_spacer2.IsVisible = isSpacer2Visible;
_spacer1!.IsVisible = isSpacer1Visible;
_spacer2!.IsVisible = isSpacer2Visible;
}
private void SetInitialFocus()
{
int monthCol = MonthVisible ? Grid.GetColumn(_monthHost) : int.MaxValue;
int dayCol = DayVisible ? Grid.GetColumn(_dayHost) : int.MaxValue;
int yearCol = YearVisible ? Grid.GetColumn(_yearHost) : int.MaxValue;
int monthCol = MonthVisible ? Grid.GetColumn(_monthHost!) : int.MaxValue;
int dayCol = DayVisible ? Grid.GetColumn(_dayHost!) : int.MaxValue;
int yearCol = YearVisible ? Grid.GetColumn(_yearHost!) : int.MaxValue;
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();
}
private void OnAcceptButtonClicked(object sender, RoutedEventArgs e)
private void OnAcceptButtonClicked(object? sender, RoutedEventArgs e)
{
Date = _syncDate;
OnConfirmed();
}
private void OnSelectorButtonClick(object sender, RoutedEventArgs e)
private void OnSelectorButtonClick(object? sender, RoutedEventArgs e)
{
if (sender == _monthUpButton)
_monthSelector.ScrollUp();
_monthSelector!.ScrollUp();
else if (sender == _monthDownButton)
_monthSelector.ScrollDown();
_monthSelector!.ScrollDown();
else if (sender == _yearUpButton)
_yearSelector.ScrollUp();
_yearSelector!.ScrollUp();
else if (sender == _yearDownButton)
_yearSelector.ScrollDown();
_yearSelector!.ScrollDown();
else if (sender == _dayUpButton)
_daySelector.ScrollUp();
_daySelector!.ScrollUp();
else if (sender == _dayDownButton)
_daySelector.ScrollDown();
_daySelector!.ScrollDown();
}
private void OnYearChanged(object sender, EventArgs e)
private void OnYearChanged(object? sender, EventArgs e)
{
if (_suppressUpdateSelection)
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,
_syncDate.Day > maxDays ? maxDays : _syncDate.Day, 0, 0, 0, _syncDate.Offset);
@ -487,7 +490,7 @@ namespace Avalonia.Controls
_suppressUpdateSelection = true;
_daySelector.FormatDate = newDate.Date;
_daySelector!.FormatDate = newDate.Date;
if (_daySelector.MaximumValue != maxDays)
_daySelector.MaximumValue = maxDays;
@ -497,19 +500,19 @@ namespace Avalonia.Controls
_suppressUpdateSelection = false;
}
private void OnDayChanged(object sender, EventArgs e)
private void OnDayChanged(object? sender, EventArgs e)
{
if (_suppressUpdateSelection)
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)
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,
_syncDate.Day > maxDays ? maxDays : _syncDate.Day, 0, 0, 0, _syncDate.Offset);
@ -521,7 +524,7 @@ namespace Avalonia.Controls
_suppressUpdateSelection = true;
_daySelector.FormatDate = newDate.Date;
_daySelector!.FormatDate = newDate.Date;
_syncDate = newDate;
if (_daySelector.MaximumValue != maxDays)
@ -535,7 +538,7 @@ namespace Avalonia.Controls
internal double GetOffsetForPopup()
{
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 bool _hasInit;
private bool _suppressUpdateOffset;
private ListBoxItem _pressedItem;
private ListBoxItem? _pressedItem;
public DateTimePickerPanel()
{
@ -271,9 +271,9 @@ namespace Avalonia.Controls.Primitives
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)
{
@ -523,40 +523,44 @@ namespace Avalonia.Controls.Primitives
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;
}
}
private void OnItemPointerUp(object sender, PointerReleasedEventArgs e)
private void OnItemPointerUp(object? sender, PointerReleasedEventArgs e)
{
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;
e.Handled = true;
}
}
//Helper to get ListBoxItem from pointerevent source
private ListBoxItem GetItemFromSource(IVisual src)
private ListBoxItem? GetItemFromSource(IVisual src)
{
var item = src;
while (item != null && !(item is ListBoxItem))
{
item = item.VisualParent;
}
return (ListBoxItem)item;
return (ListBoxItem?)item;
}
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)
{

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

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

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

@ -49,18 +49,18 @@ namespace Avalonia.Controls
defaultBindingMode: BindingMode.TwoWay);
// Template Items
private TimePickerPresenter _presenter;
private Button _flyoutButton;
private Border _firstPickerHost;
private Border _secondPickerHost;
private Border _thirdPickerHost;
private TextBlock _hourText;
private TextBlock _minuteText;
private TextBlock _periodText;
private Rectangle _firstSplitter;
private Rectangle _secondSplitter;
private Grid _contentGrid;
private Popup _popup;
private TimePickerPresenter? _presenter;
private Button? _flyoutButton;
private Border? _firstPickerHost;
private Border? _secondPickerHost;
private Border? _thirdPickerHost;
private TextBlock? _hourText;
private TextBlock? _minuteText;
private TextBlock? _periodText;
private Rectangle? _firstSplitter;
private Rectangle? _secondSplitter;
private Grid? _contentGrid;
private Popup? _popup;
private TimeSpan? _selectedTime;
private int _minuteIncrement = 1;
@ -142,7 +142,7 @@ namespace Avalonia.Controls
/// <summary>
/// Raised when the <see cref="SelectedTime"/> property changes
/// </summary>
public event EventHandler<TimePickerSelectedValueChangedEventArgs> SelectedTimeChanged;
public event EventHandler<TimePickerSelectedValueChangedEventArgs>? SelectedTimeChanged;
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
@ -200,15 +200,15 @@ namespace Avalonia.Controls
var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *";
_contentGrid.ColumnDefinitions = new ColumnDefinitions(columnsD);
_thirdPickerHost.IsVisible = !use24HourClock;
_secondSplitter.IsVisible = !use24HourClock;
_thirdPickerHost!.IsVisible = !use24HourClock;
_secondSplitter!.IsVisible = !use24HourClock;
Grid.SetColumn(_firstPickerHost, 0);
Grid.SetColumn(_secondPickerHost, 2);
Grid.SetColumn(_firstPickerHost!, 0);
Grid.SetColumn(_secondPickerHost!, 2);
Grid.SetColumn(_thirdPickerHost, use24HourClock ? 0 : 4);
Grid.SetColumn(_firstSplitter, 1);
Grid.SetColumn(_firstSplitter!, 1);
Grid.SetColumn(_secondSplitter, use24HourClock ? 0 : 3);
}
@ -220,7 +220,7 @@ namespace Avalonia.Controls
var time = SelectedTime;
if (time.HasValue)
{
var newTime = SelectedTime.Value;
var newTime = SelectedTime!.Value;
if (ClockIdentifier == "12HourClock")
{
@ -252,30 +252,30 @@ namespace Avalonia.Controls
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();
// 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.PopupPositionerConstraintAdjustment.SlideY);
}
private void OnDismissPicker(object sender, EventArgs e)
private void OnDismissPicker(object? sender, EventArgs e)
{
_popup.Close();
_popup!.Close();
Focus();
}
private void OnConfirmed(object sender, EventArgs e)
private void OnConfirmed(object? sender, EventArgs e)
{
_popup.Close();
SelectedTime = _presenter.Time;
_popup!.Close();
SelectedTime = _presenter!.Time;
}
}
}

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

@ -40,20 +40,20 @@ namespace Avalonia.Controls
}
// TemplateItems
private Grid _pickerContainer;
private Button _acceptButton;
private Button _dismissButton;
private Rectangle _spacer2;
private Panel _periodHost;
private DateTimePickerPanel _hourSelector;
private DateTimePickerPanel _minuteSelector;
private DateTimePickerPanel _periodSelector;
private Button _hourUpButton;
private Button _minuteUpButton;
private Button _periodUpButton;
private Button _hourDownButton;
private Button _minuteDownButton;
private Button _periodDownButton;
private Grid? _pickerContainer;
private Button? _acceptButton;
private Button? _dismissButton;
private Rectangle? _spacer2;
private Panel? _periodHost;
private DateTimePickerPanel? _hourSelector;
private DateTimePickerPanel? _minuteSelector;
private DateTimePickerPanel? _periodSelector;
private Button? _hourUpButton;
private Button? _minuteUpButton;
private Button? _periodUpButton;
private Button? _hourDownButton;
private Button? _minuteDownButton;
private Button? _periodDownButton;
// Backing Fields
private TimeSpan _time;
@ -156,9 +156,12 @@ namespace Avalonia.Controls
e.Handled = true;
break;
case Key.Tab:
var nextFocus = KeyboardNavigationHandler.GetNext(FocusManager.Instance.Current, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
e.Handled = true;
if (FocusManager.Instance?.Current is IInputElement focus)
{
var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
e.Handled = true;
}
break;
case Key.Enter:
OnConfirmed();
@ -170,9 +173,9 @@ namespace Avalonia.Controls
protected override void OnConfirmed()
{
var hr = _hourSelector.SelectedValue;
var min = _minuteSelector.SelectedValue;
var per = _periodSelector.SelectedValue;
var hr = _hourSelector!.SelectedValue;
var min = _minuteSelector!.SelectedValue;
var per = _periodSelector!.SelectedValue;
if (ClockIdentifier == "12HourClock")
{
@ -190,20 +193,20 @@ namespace Avalonia.Controls
return;
bool clock12 = ClockIdentifier == "12HourClock";
_hourSelector.MaximumValue = clock12 ? 12 : 23;
_hourSelector!.MaximumValue = clock12 ? 12 : 23;
_hourSelector.MinimumValue = clock12 ? 1 : 0;
_hourSelector.ItemFormat = "%h";
var hr = Time.Hours;
_hourSelector.SelectedValue = !clock12 ? hr :
hr > 12 ? hr - 12 : hr == 0 ? 12 : hr;
_minuteSelector.MaximumValue = 59;
_minuteSelector!.MaximumValue = 59;
_minuteSelector.MinimumValue = 0;
_minuteSelector.Increment = MinuteIncrement;
_minuteSelector.SelectedValue = Time.Minutes;
_minuteSelector.ItemFormat = "mm";
_periodSelector.MaximumValue = 1;
_periodSelector!.MaximumValue = 1;
_periodSelector.MinimumValue = 0;
_periodSelector.SelectedValue = hr >= 12 ? 1 : 0;
@ -216,45 +219,45 @@ namespace Avalonia.Controls
bool use24HourClock = ClockIdentifier == "24HourClock";
var columnsD = use24HourClock ? "*, Auto, *" : "*, Auto, *, Auto, *";
_pickerContainer.ColumnDefinitions = new ColumnDefinitions(columnsD);
_pickerContainer!.ColumnDefinitions = new ColumnDefinitions(columnsD);
_spacer2.IsVisible = !use24HourClock;
_periodHost.IsVisible = !use24HourClock;
_spacer2!.IsVisible = !use24HourClock;
_periodHost!.IsVisible = !use24HourClock;
Grid.SetColumn(_spacer2, use24HourClock ? 0 : 3);
Grid.SetColumn(_periodHost, use24HourClock ? 0 : 4);
}
private void OnDismissButtonClicked(object sender, RoutedEventArgs e)
private void OnDismissButtonClicked(object? sender, RoutedEventArgs e)
{
OnDismiss();
}
private void OnAcceptButtonClicked(object sender, RoutedEventArgs e)
private void OnAcceptButtonClicked(object? sender, RoutedEventArgs e)
{
OnConfirmed();
}
private void OnSelectorButtonClick(object sender, RoutedEventArgs e)
private void OnSelectorButtonClick(object? sender, RoutedEventArgs e)
{
if (sender == _hourUpButton)
_hourSelector.ScrollUp();
_hourSelector!.ScrollUp();
else if (sender == _hourDownButton)
_hourSelector.ScrollDown();
_hourSelector!.ScrollDown();
else if (sender == _minuteUpButton)
_minuteSelector.ScrollUp();
_minuteSelector!.ScrollUp();
else if (sender == _minuteDownButton)
_minuteSelector.ScrollDown();
_minuteSelector!.ScrollDown();
else if (sender == _periodUpButton)
_periodSelector.ScrollUp();
_periodSelector!.ScrollUp();
else if (sender == _periodDownButton)
_periodSelector.ScrollDown();
_periodSelector!.ScrollDown();
}
internal double GetOffsetForPopup()
{
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>
/// Defines the <see cref="Child"/> property.
/// </summary>
public static readonly StyledProperty<IControl> ChildProperty =
AvaloniaProperty.Register<Decorator, IControl>(nameof(Child));
public static readonly StyledProperty<IControl?> ChildProperty =
AvaloniaProperty.Register<Decorator, IControl?>(nameof(Child));
/// <summary>
/// Defines the <see cref="Padding"/> property.
@ -33,7 +33,7 @@ namespace Avalonia.Controls
/// Gets or sets the decorated control.
/// </summary>
[Content]
public IControl Child
public IControl? Child
{
get { return GetValue(ChildProperty); }
set { SetValue(ChildProperty, value); }
@ -66,8 +66,8 @@ namespace Avalonia.Controls
/// <param name="e">The event args.</param>
private void ChildChanged(AvaloniaPropertyChangedEventArgs e)
{
var oldChild = (Control)e.OldValue;
var newChild = (Control)e.NewValue;
var oldChild = (Control?)e.OldValue;
var newChild = (Control?)e.NewValue;
if (oldChild != null)
{

40
src/Avalonia.Controls/DefinitionBase.cs

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

6
src/Avalonia.Controls/DefinitionList.cs

@ -2,8 +2,6 @@ using System.Collections;
using System.Collections.Specialized;
using Avalonia.Collections;
#nullable enable
namespace Avalonia.Controls
{
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;
@ -62,7 +60,7 @@ namespace Avalonia.Controls
for (var i = 0; i < count; i++)
{
var definition = (DefinitionBase) items[i];
var definition = (DefinitionBase) items[i]!;
if (wasRemoved)
{

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

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

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

@ -1,6 +1,4 @@
#nullable enable
namespace Avalonia.Controls.Diagnostics
namespace Avalonia.Controls.Diagnostics
{
/// <summary>
/// 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 Size _clientSize;
public IInputRoot InputRoot { get; private set; }
public IInputRoot? InputRoot { get; private set; }
public bool IsDisposed { get; private set; }
public virtual void Dispose()
@ -47,12 +47,12 @@ namespace Avalonia.Controls.Embedding.Offscreen
}
}
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size, PlatformResizeReason> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public Action<RawInputEventArgs>? Input { get; set; }
public Action<Rect>? Paint { get; set; }
public Action<Size, PlatformResizeReason>? Resized { get; set; }
public Action<double>? ScalingChanged { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
/// <inheritdoc/>
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 void SetCursor(ICursorImpl cursor)
public virtual void SetCursor(ICursorImpl? cursor)
{
}
public Action Closed { get; set; }
public Action LostFocus { get; set; }
public Action? Closed { get; set; }
public Action? LostFocus { get; set; }
public abstract IMouseDevice MouseDevice { get; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { }
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 Avalonia.Animation;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
#nullable enable
namespace Avalonia.Controls
{
/// <summary>

7
src/Avalonia.Controls/ExperimentalAcrylicBorder.cs

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

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

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

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

@ -8,8 +8,6 @@ using Avalonia.Input.Raw;
using Avalonia.Layout;
using Avalonia.Logging;
#nullable enable
namespace Avalonia.Controls.Primitives
{
public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider
@ -267,7 +265,7 @@ namespace Avalonia.Controls.Primitives
return true;
}
private void PlacementTarget_DetachedFromVisualTree(object sender, VisualTreeAttachmentEventArgs e)
private void PlacementTarget_DetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
{
_ = HideCore(false);
}
@ -335,7 +333,7 @@ namespace Avalonia.Controls.Primitives
protected virtual void OnOpened()
{
Opened?.Invoke(this, null);
Opened?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnClosing(CancelEventArgs args)
@ -345,7 +343,7 @@ namespace Avalonia.Controls.Primitives
protected virtual void OnClosed()
{
Closed?.Invoke(this, null);
Closed?.Invoke(this, EventArgs.Empty);
}
/// <summary>
@ -368,14 +366,14 @@ namespace Avalonia.Controls.Primitives
return popup;
}
private void OnPopupOpened(object sender, EventArgs e)
private void OnPopupOpened(object? sender, EventArgs e)
{
IsOpen = true;
_popupHostChangedHandler?.Invoke(Popup!.Host);
}
private void OnPopupClosing(object sender, CancelEventArgs e)
private void OnPopupClosing(object? sender, CancelEventArgs e)
{
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);
@ -391,7 +389,7 @@ namespace Avalonia.Controls.Primitives
}
// 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
&& 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
&& sender is Control control
&& control.ContextFlyout is FlyoutBase flyout)
{
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.Metadata;
#nullable enable
namespace Avalonia.Controls
{
public class MenuFlyout : FlyoutBase
@ -18,7 +16,7 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Items"/> property
/// </summary>
public static readonly DirectProperty<MenuFlyout, IEnumerable> ItemsProperty =
public static readonly DirectProperty<MenuFlyout, IEnumerable?> ItemsProperty =
ItemsControl.ItemsProperty.AddOwner<MenuFlyout>(x => x.Items,
(x, v) => x.Items = v);
@ -35,7 +33,7 @@ namespace Avalonia.Controls
/// Gets or sets the items of the MenuFlyout
/// </summary>
[Content]
public IEnumerable Items
public IEnumerable? Items
{
get => _items;
set => SetAndRaise(ItemsProperty, ref _items, value);
@ -51,7 +49,7 @@ namespace Avalonia.Controls
}
private Classes? _classes;
private IEnumerable _items;
private IEnumerable? _items;
private IDataTemplate? _itemTemplate;
protected override Control CreatePresenter()

13
src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs

@ -43,5 +43,18 @@ namespace Avalonia.Controls
{
return new MenuItemContainerGenerator(this);
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
foreach (var i in LogicalChildren)
{
if (i is MenuItem menuItem)
{
menuItem.IsSubMenuOpen = false;
}
}
}
}
}

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

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

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

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

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

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

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

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

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

@ -21,12 +21,12 @@ namespace Avalonia.Controls.Generators
/// <summary>
/// Signaled whenever new containers are materialized.
/// </summary>
public event EventHandler<ItemContainerEventArgs> Materialized;
public event EventHandler<ItemContainerEventArgs>? Materialized;
/// <summary>
/// Event raised whenever containers are dematerialized.
/// </summary>
public event EventHandler<ItemContainerEventArgs> Dematerialized;
public event EventHandler<ItemContainerEventArgs>? Dematerialized;
/// <summary>
/// Gets the currently materialized containers.
@ -92,7 +92,7 @@ namespace Avalonia.Controls.Generators
/// </summary>
/// <param name="item">The item.</param>
/// <returns>The container, or null of not found.</returns>
public IControl ContainerFromItem(object item)
public IControl? ContainerFromItem(object item)
{
if (item != null)
{
@ -108,7 +108,7 @@ namespace Avalonia.Controls.Generators
/// </summary>
/// <param name="container">The container.</param>
/// <returns>The item, or null of not found.</returns>
public object ItemFromContainer(IControl container)
public object? ItemFromContainer(IControl? container)
{
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
where T : class, IControl, new()
{
private TreeView _treeView;
private TreeView? _treeView;
/// <summary>
/// Initializes a new instance of the <see cref="TreeItemContainerGenerator{T}"/> class.
@ -32,20 +32,15 @@ namespace Avalonia.Controls.Generators
AvaloniaProperty isExpandedProperty)
: base(owner, contentProperty, contentTemplateProperty)
{
Contract.Requires<ArgumentNullException>(owner != null);
Contract.Requires<ArgumentNullException>(contentProperty != null);
Contract.Requires<ArgumentNullException>(itemsProperty != null);
Contract.Requires<ArgumentNullException>(isExpandedProperty != null);
ItemsProperty = itemsProperty;
IsExpandedProperty = isExpandedProperty;
ItemsProperty = itemsProperty ?? throw new ArgumentNullException(nameof(itemsProperty));
IsExpandedProperty = isExpandedProperty ?? throw new ArgumentNullException(nameof(isExpandedProperty));
UpdateIndex();
}
/// <summary>
/// Gets the container index for the tree.
/// </summary>
public TreeContainerIndex Index { get; private set; }
public TreeContainerIndex? Index { get; private set; }
/// <summary>
/// Gets the item container's Items property.
@ -58,7 +53,7 @@ namespace Avalonia.Controls.Generators
protected AvaloniaProperty IsExpandedProperty { get; }
/// <inheritdoc/>
protected override IControl CreateContainer(object item)
protected override IControl? CreateContainer(object? item)
{
var container = item as T;
@ -141,12 +136,12 @@ namespace Avalonia.Controls.Generators
{
private readonly IDataTemplate _inner;
public WrapperTreeDataTemplate(IDataTemplate inner) => _inner = inner;
public IControl Build(object param) => _inner.Build(param);
public bool Match(object data) => _inner.Match(data);
public InstancedBinding ItemsSelector(object item) => null;
public IControl? Build(object? param) => _inner.Build(param);
public bool Match(object? data) => _inner.Match(data);
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 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.Specialized;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Avalonia.Layout;
using Avalonia.Media;
@ -48,7 +49,7 @@ namespace Avalonia.Controls
/// <param name="value">Column property value.</param>
public static void SetColumn(Control element, int value)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ColumnProperty, value);
}
@ -59,7 +60,7 @@ namespace Avalonia.Controls
/// <returns>Column property value.</returns>
public static int GetColumn(Control element)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ColumnProperty);
}
@ -70,7 +71,7 @@ namespace Avalonia.Controls
/// <param name="value">Row property value.</param>
public static void SetRow(Control element, int value)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(RowProperty, value);
}
@ -81,7 +82,7 @@ namespace Avalonia.Controls
/// <returns>Row property value.</returns>
public static int GetRow(Control element)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(RowProperty);
}
@ -92,7 +93,7 @@ namespace Avalonia.Controls
/// <param name="value">ColumnSpan property value.</param>
public static void SetColumnSpan(Control element, int value)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(ColumnSpanProperty, value);
}
@ -103,7 +104,7 @@ namespace Avalonia.Controls
/// <returns>ColumnSpan property value.</returns>
public static int GetColumnSpan(Control element)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(ColumnSpanProperty);
}
@ -114,7 +115,7 @@ namespace Avalonia.Controls
/// <param name="value">RowSpan property value.</param>
public static void SetRowSpan(Control element, int value)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(RowSpanProperty, value);
}
@ -125,7 +126,7 @@ namespace Avalonia.Controls
/// <returns>RowSpan property value.</returns>
public static int GetRowSpan(Control element)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(RowSpanProperty);
}
@ -136,7 +137,7 @@ namespace Avalonia.Controls
/// <param name="value">IsSharedSizeScope property value.</param>
public static void SetIsSharedSizeScope(Control element, bool value)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
element.SetValue(IsSharedSizeScopeProperty, value);
}
@ -147,7 +148,7 @@ namespace Avalonia.Controls
/// <returns>IsSharedSizeScope property value.</returns>
public static bool GetIsSharedSizeScope(Control element)
{
Contract.Requires<ArgumentNullException>(element != null);
_ = element ?? throw new ArgumentNullException(nameof(element));
return element.GetValue(IsSharedSizeScopeProperty);
}
@ -573,7 +574,7 @@ namespace Avalonia.Controls
/// <summary>
/// <see cref="Panel.ChildrenChanged"/>
/// </summary>
protected override void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
protected override void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
CellsStructureDirty = true;
base.ChildrenChanged(sender, e);
@ -598,7 +599,7 @@ namespace Avalonia.Controls
{
double value = 0.0;
Contract.Requires<NullReferenceException>(_data != null);
Debug.Assert(_data != null);
// actual value calculations require structure to be up-to-date
if (!ColumnDefinitionsDirty)
@ -620,7 +621,7 @@ namespace Avalonia.Controls
{
double value = 0.0;
Contract.Requires<NullReferenceException>(_data != null);
Debug.Assert(_data != null);
// actual value calculations require structure to be up-to-date
if (!RowDefinitionsDirty)
@ -994,7 +995,7 @@ namespace Avalonia.Controls
}
var children = this.Children;
Hashtable spanStore = null;
Hashtable? spanStore = null;
bool ignoreDesiredSizeV = forceInfinityV;
int i = cellsHead;
@ -1048,7 +1049,7 @@ namespace Avalonia.Controls
foreach (DictionaryEntry e in spanStore)
{
SpanKey key = (SpanKey)e.Key;
double requestedSize = (double)e.Value;
double requestedSize = (double)e.Value!;
EnsureMinSizeInDefinitionRange(
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="value">Value to store. If an entry already exists the biggest value is stored.</param>
private static void RegisterSpan(
ref Hashtable store,
ref Hashtable? store,
int start,
int count,
bool u,
@ -1081,7 +1082,7 @@ namespace Avalonia.Controls
}
SpanKey key = new SpanKey(start, count, u);
object o = store[key];
object? o = store[key];
if (o == null
|| value > (double)o)
@ -1605,12 +1606,12 @@ namespace Avalonia.Controls
while (minCount > 0 && tempDefinitions[minCount - 1].MeasureSize < 0.0)
{
--minCount;
tempDefinitions[minCount] = null;
tempDefinitions[minCount] = null!;
}
while (maxCount > 0 && tempDefinitions[defCount + maxCount - 1].MeasureSize < 0.0)
{
--maxCount;
tempDefinitions[defCount + maxCount] = null;
tempDefinitions[defCount + maxCount] = null!;
}
}
@ -2321,7 +2322,7 @@ namespace Avalonia.Controls
/// by adding / removing GridLinesRenderer visual.
/// Returns a reference to GridLinesRenderer visual or null.
/// </summary>
private GridLinesRenderer EnsureGridLinesRenderer()
private GridLinesRenderer? EnsureGridLinesRenderer()
{
//
// synchronize the state
@ -2369,16 +2370,16 @@ namespace Avalonia.Controls
grid.InvalidateVisual();
}
grid.SetFlags((bool)e.NewValue, Flags.ShowGridLinesPropertyValue);
grid.SetFlags((bool)e.NewValue!, Flags.ShowGridLinesPropertyValue);
}
private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
Visual child = d as Visual;
Visual? child = d as Visual;
if (child != null)
{
Grid grid = child.GetVisualParent<Grid>();
Grid? grid = child.GetVisualParent<Grid>();
if (grid != null
&& grid.ExtData != null
&& 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
/// the relative sort order.
/// </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;
@ -2426,7 +2427,7 @@ namespace Avalonia.Controls
/// </summary>
private IReadOnlyList<DefinitionBase> DefinitionsU
{
get { return (ExtData.DefinitionsU); }
get { return (ExtData.DefinitionsU!); }
}
/// <summary>
@ -2434,7 +2435,7 @@ namespace Avalonia.Controls
/// </summary>
private IReadOnlyList<DefinitionBase> DefinitionsV
{
get { return (ExtData.DefinitionsV); }
get { return (ExtData.DefinitionsV!); }
}
/// <summary>
@ -2450,7 +2451,7 @@ namespace Avalonia.Controls
if (extData.TempDefinitions == null
|| extData.TempDefinitions.Length < requiredLength)
{
WeakReference tempDefinitionsWeakRef = (WeakReference)Thread.GetData(s_tempDefinitionsDataSlot);
WeakReference? tempDefinitionsWeakRef = (WeakReference?)Thread.GetData(s_tempDefinitionsDataSlot);
if (tempDefinitionsWeakRef == null)
{
extData.TempDefinitions = new DefinitionBase[requiredLength];
@ -2458,7 +2459,7 @@ namespace Avalonia.Controls
}
else
{
extData.TempDefinitions = (DefinitionBase[])tempDefinitionsWeakRef.Target;
extData.TempDefinitions = (DefinitionBase[]?)tempDefinitionsWeakRef.Target;
if (extData.TempDefinitions == null
|| extData.TempDefinitions.Length < requiredLength)
{
@ -2515,7 +2516,7 @@ namespace Avalonia.Controls
/// </summary>
private CellCache[] PrivateCells
{
get { return (ExtData.CellCachesCollection); }
get { return (ExtData.CellCachesCollection!); }
}
/// <summary>
@ -2586,7 +2587,7 @@ namespace Avalonia.Controls
/// </summary>
private ExtendedData ExtData
{
get { return (_data); }
get { return (_data!); }
}
/// <summary>
@ -2608,17 +2609,17 @@ namespace Avalonia.Controls
}
// Extended data instantiated on demand, for non-trivial case handling only
private ExtendedData _data;
private ExtendedData? _data;
// Grid validity / property caches dirtiness flags
private Flags _flags;
private GridLinesRenderer _gridLinesRenderer;
private GridLinesRenderer? _gridLinesRenderer;
// Keeps track of definition indices.
int[] _definitionIndices;
int[]? _definitionIndices;
// Stores unrounded values and rounding errors during layout rounding.
double[] _roundingErrors;
double[]? _roundingErrors;
// 5 is an arbitrary constant chosen to end the measure loop
private const int c_layoutLoopMaxCount = 5;
@ -2635,16 +2636,16 @@ namespace Avalonia.Controls
/// </summary>
private class ExtendedData
{
internal ColumnDefinitions ColumnDefinitions; // collection of column 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> DefinitionsV; // collection of row definitions used during calc
internal CellCache[] CellCachesCollection; // backing store for logical children
internal ColumnDefinitions? ColumnDefinitions; // collection of column 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>? DefinitionsV; // collection of row definitions used during calc
internal CellCache[]? CellCachesCollection; // backing store for logical children
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 CellGroup3; // index of the first cell in third cell group
internal int CellGroup4; // index of the first cell in forth cell group
internal DefinitionBase[] TempDefinitions; // temporary array used during layout for various purposes
internal DefinitionBase[]? TempDefinitions; // temporary array used during layout for various purposes
// TempDefinitions.Length == Max(definitionsU.Length, definitionsV.Length)
}
@ -2831,9 +2832,9 @@ namespace Avalonia.Controls
/// <summary>
/// <see cref="object.Equals(object)"/>
/// </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
&& sk._start == _start
&& sk._count == _count
@ -2866,10 +2867,10 @@ namespace Avalonia.Controls
/// </summary>
private class SpanPreferredDistributionOrderComparer : IComparer
{
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
DefinitionBase definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase;
DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase? definitionY = y as DefinitionBase;
int result;
@ -2908,10 +2909,10 @@ namespace Avalonia.Controls
/// </summary>
private class SpanMaxDistributionOrderComparer : IComparer
{
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
DefinitionBase definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase;
DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase? definitionY = y as DefinitionBase;
int result;
@ -2954,17 +2955,16 @@ namespace Avalonia.Controls
internal StarDistributionOrderIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{
Contract.Requires<NullReferenceException>(definitions != null);
this.definitions = definitions;
this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
}
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
int? indexX = x as int?;
int? indexY = y as int?;
DefinitionBase definitionX = null;
DefinitionBase definitionY = null;
DefinitionBase? definitionX = null;
DefinitionBase? definitionY = null;
if (indexX != null)
{
@ -2995,17 +2995,16 @@ namespace Avalonia.Controls
internal DistributionOrderIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{
Contract.Requires<NullReferenceException>(definitions != null);
this.definitions = definitions;
this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
}
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
int? indexX = x as int?;
int? indexY = y as int?;
DefinitionBase definitionX = null;
DefinitionBase definitionY = null;
DefinitionBase? definitionX = null;
DefinitionBase? definitionY = null;
if (indexX != null)
{
@ -3038,11 +3037,10 @@ namespace Avalonia.Controls
internal RoundingErrorIndexComparer(double[] errors)
{
Contract.Requires<NullReferenceException>(errors != null);
this.errors = errors;
this.errors = errors ?? throw new ArgumentNullException(nameof(errors));
}
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
int? indexX = x as int?;
int? indexY = y as int?;
@ -3067,10 +3065,10 @@ namespace Avalonia.Controls
/// </summary>
private class MinRatioComparer : IComparer
{
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
DefinitionBase definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase;
DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase? definitionY = y as DefinitionBase;
int result;
@ -3090,10 +3088,10 @@ namespace Avalonia.Controls
/// </summary>
private class MaxRatioComparer : IComparer
{
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
DefinitionBase definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase;
DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase? definitionY = y as DefinitionBase;
int result;
@ -3112,10 +3110,10 @@ namespace Avalonia.Controls
/// </summary>
private class StarWeightComparer : IComparer
{
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
DefinitionBase definitionX = x as DefinitionBase;
DefinitionBase definitionY = y as DefinitionBase;
DefinitionBase? definitionX = x as DefinitionBase;
DefinitionBase? definitionY = y as DefinitionBase;
int result;
@ -3137,17 +3135,16 @@ namespace Avalonia.Controls
internal MinRatioIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{
Contract.Requires<NullReferenceException>(definitions != null);
this.definitions = definitions;
this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
}
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
int? indexX = x as int?;
int? indexY = y as int?;
DefinitionBase definitionX = null;
DefinitionBase definitionY = null;
DefinitionBase? definitionX = null;
DefinitionBase? definitionY = null;
if (indexX != null)
{
@ -3178,17 +3175,16 @@ namespace Avalonia.Controls
internal MaxRatioIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{
Contract.Requires<NullReferenceException>(definitions != null);
this.definitions = definitions;
this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
}
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
int? indexX = x as int?;
int? indexY = y as int?;
DefinitionBase definitionX = null;
DefinitionBase definitionY = null;
DefinitionBase? definitionX = null;
DefinitionBase? definitionY = null;
if (indexX != null)
{
@ -3219,17 +3215,16 @@ namespace Avalonia.Controls
internal StarWeightIndexComparer(IReadOnlyList<DefinitionBase> definitions)
{
Contract.Requires<NullReferenceException>(definitions != null);
this.definitions = definitions;
this.definitions = definitions ?? throw new ArgumentNullException(nameof(definitions));
}
public int Compare(object x, object y)
public int Compare(object? x, object? y)
{
int? indexX = x as int?;
int? indexY = y as int?;
DefinitionBase definitionX = null;
DefinitionBase definitionY = null;
DefinitionBase? definitionX = null;
DefinitionBase? definitionY = null;
if (indexX != null)
{

2
src/Avalonia.Controls/GridLength.cs

@ -135,7 +135,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="o">The object with which to test equality.</param>
/// <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)
{

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

40
src/Avalonia.Controls/HotkeyManager.cs

@ -7,29 +7,29 @@ namespace Avalonia.Controls
{
public class HotKeyManager
{
public static readonly AttachedProperty<KeyGesture> HotKeyProperty
= AvaloniaProperty.RegisterAttached<Control, KeyGesture>("HotKey", typeof(HotKeyManager));
public static readonly AttachedProperty<KeyGesture?> HotKeyProperty
= AvaloniaProperty.RegisterAttached<Control, KeyGesture?>("HotKey", typeof(HotKeyManager));
class HotkeyCommandWrapper : ICommand
{
public HotkeyCommandWrapper(ICommandSource control)
public HotkeyCommandWrapper(ICommandSource? 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) =>
CommandSource.Command?.CanExecute(CommandSource.CommandParameter) == true
public bool CanExecute(object? parameter) =>
CommandSource?.Command?.CanExecute(CommandSource.CommandParameter) == true
&& CommandSource.IsEffectivelyEnabled;
public void Execute(object parameter) =>
GetCommand()?.Execute(CommandSource.CommandParameter);
public void Execute(object? parameter) =>
GetCommand()?.Execute(CommandSource?.CommandParameter);
#pragma warning disable 67 // Event not used
public event EventHandler CanExecuteChanged;
public event EventHandler? CanExecuteChanged;
#pragma warning restore 67
}
@ -37,12 +37,12 @@ namespace Avalonia.Controls
class Manager
{
private readonly IControl _control;
private TopLevel _root;
private IDisposable _parentSub;
private IDisposable _hotkeySub;
private KeyGesture _hotkey;
private TopLevel? _root;
private IDisposable? _parentSub;
private IDisposable? _hotkeySub;
private KeyGesture? _hotkey;
private readonly HotkeyCommandWrapper _wrapper;
private KeyBinding _binding;
private KeyBinding? _binding;
public Manager(IControl control)
{
@ -56,14 +56,14 @@ namespace Avalonia.Controls
_parentSub = AncestorFinder.Create<TopLevel>(_control).Subscribe(OnParentChanged);
}
private void OnParentChanged(TopLevel control)
private void OnParentChanged(TopLevel? control)
{
Unregister();
_root = control;
Register();
}
private void OnHotkeyChanged(KeyGesture hotkey)
private void OnHotkeyChanged(KeyGesture? hotkey)
{
if (hotkey == null)
//Subscription will be recreated by static property watcher
@ -95,8 +95,8 @@ namespace Avalonia.Controls
void Stop()
{
Unregister();
_parentSub.Dispose();
_hotkeySub.Dispose();
_parentSub?.Dispose();
_hotkeySub?.Dispose();
}
}
@ -118,6 +118,6 @@ namespace Avalonia.Controls
});
}
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>
/// Gets or sets the content to display.
/// </summary>
object Content { get; set; }
object? Content { get; set; }
/// <summary>
/// Gets or sets the data template used to display the content of the control.
/// </summary>
IDataTemplate ContentTemplate { get; set; }
IDataTemplate? ContentTemplate { get; set; }
/// <summary>
/// Gets or sets the horizontal alignment of the content within the control.
@ -29,4 +29,4 @@ namespace Avalonia.Controls
/// </summary>
VerticalAlignment VerticalContentAlignment { get; set; }
}
}
}

2
src/Avalonia.Controls/IControl.cs

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

2
src/Avalonia.Controls/IHeadered.cs

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

2
src/Avalonia.Controls/IMenuElement.cs

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

4
src/Avalonia.Controls/IMenuItem.cs

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

4
src/Avalonia.Controls/IScrollAnchorProvider.cs

@ -1,6 +1,4 @@
#nullable enable
namespace Avalonia.Controls
namespace Avalonia.Controls
{
/// <summary>
/// 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
/// not act as a virtualizing controller.
/// </remarks>
IVirtualizingController Controller { get; set; }
IVirtualizingController? Controller { get; set; }
/// <summary>
/// Gets a value indicating whether the panel is full.

56
src/Avalonia.Controls/ItemsControl.cs

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

8
src/Avalonia.Controls/ItemsSourceView.cs

@ -7,12 +7,9 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Controls.Utils;
#nullable enable
namespace Avalonia.Controls
{
/// <summary>
@ -196,7 +193,7 @@ namespace Avalonia.Controls
_collectionChanged?.Invoke(this, args);
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
OnItemsSourceChanged(e);
}
@ -239,8 +236,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="index">The index.</param>
/// <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();
IEnumerator IEnumerable.GetEnumerator() => Inner.GetEnumerator();

8
src/Avalonia.Controls/Label.cs

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

14
src/Avalonia.Controls/LayoutTransformControl.cs

@ -14,8 +14,8 @@ namespace Avalonia.Controls
/// </summary>
public class LayoutTransformControl : Decorator
{
public static readonly StyledProperty<ITransform> LayoutTransformProperty =
AvaloniaProperty.Register<LayoutTransformControl, ITransform>(nameof(LayoutTransform));
public static readonly StyledProperty<ITransform?> LayoutTransformProperty =
AvaloniaProperty.Register<LayoutTransformControl, ITransform?>(nameof(LayoutTransform));
public static readonly StyledProperty<bool> UseRenderTransformProperty =
AvaloniaProperty.Register<LayoutTransformControl, bool>(nameof(UseRenderTransform));
@ -37,7 +37,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets a graphics transformation that should apply to this element when layout is performed.
/// </summary>
public ITransform LayoutTransform
public ITransform? LayoutTransform
{
get { return GetValue(LayoutTransformProperty); }
set { SetValue(LayoutTransformProperty, value); }
@ -52,7 +52,7 @@ namespace Avalonia.Controls
set { SetValue(UseRenderTransformProperty, value); }
}
public IControl TransformRoot => Child;
public IControl? TransformRoot => Child;
/// <summary>
/// Provides the behavior for the "Arrange" pass of layout.
@ -146,7 +146,7 @@ namespace Avalonia.Controls
return transformedDesiredSize;
}
IDisposable _renderTransformChangedEvent;
IDisposable? _renderTransformChangedEvent;
private void OnUseRenderTransformPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
@ -158,7 +158,7 @@ namespace Avalonia.Controls
// workaround.
var target = e.Sender as LayoutTransformControl;
var shouldUseRenderTransform = (bool)e.NewValue;
var shouldUseRenderTransform = (bool)e.NewValue!;
if (target != null)
{
if (shouldUseRenderTransform)
@ -217,7 +217,7 @@ namespace Avalonia.Controls
/// Transformation matrix corresponding to _matrixTransform.
/// </summary>
private Matrix _transformation;
private IDisposable _transformChangedEvent = null;
private IDisposable? _transformChangedEvent = null;
/// <summary>
/// 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>
/// Defines the <see cref="Scroll"/> property.
/// </summary>
public static readonly DirectProperty<ListBox, IScrollable> ScrollProperty =
AvaloniaProperty.RegisterDirect<ListBox, IScrollable>(nameof(Scroll), o => o.Scroll);
public static readonly DirectProperty<ListBox, IScrollable?> ScrollProperty =
AvaloniaProperty.RegisterDirect<ListBox, IScrollable?>(nameof(Scroll), o => o.Scroll);
/// <summary>
/// Defines the <see cref="SelectedItems"/> property.
/// </summary>
public static readonly new DirectProperty<SelectingItemsControl, IList> SelectedItemsProperty =
public static readonly new DirectProperty<SelectingItemsControl, IList?> SelectedItemsProperty =
SelectingItemsControl.SelectedItemsProperty;
/// <summary>
@ -50,7 +50,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty<ItemVirtualizationMode> VirtualizationModeProperty =
ItemsPresenter.VirtualizationModeProperty.AddOwner<ListBox>();
private IScrollable _scroll;
private IScrollable? _scroll;
/// <summary>
/// Initializes static members of the <see cref="ItemsControl"/> class.
@ -64,14 +64,14 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the scroll information for the <see cref="ListBox"/>.
/// </summary>
public IScrollable Scroll
public IScrollable? Scroll
{
get { return _scroll; }
private set { SetAndRaise(ScrollProperty, ref _scroll, value); }
}
/// <inheritdoc/>
public new IList SelectedItems
public new IList? SelectedItems
{
get => base.SelectedItems;
set => base.SelectedItems = value;

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

Loading…
Cancel
Save