From 55faeb2dc64e424143d36bd038f4332aa61bbd65 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Wed, 3 Mar 2021 15:36:45 -0800 Subject: [PATCH 01/13] Enable Nullable on Unit Tests --- .../MaxLengthReachedBehavior_Tests.cs | 4 +- .../UserStoppedTypingBehavior_Tests.cs | 4 +- .../Converters/DoubleToIntConverter_Tests.cs | 4 +- .../Converters/EnumToBoolConverter_Tests.cs | 48 +++++++++---------- .../ItemSelectedEventArgsConverter_Tests.cs | 6 ++- .../ItemTappedEventArgsConverter_Tests.cs | 2 + .../ListIsNotNullOrEmptyConverter_Tests.cs | 15 +++--- .../ListIsNullOrEmptyConverter_Tests.cs | 13 ++--- .../Converters/ListToStringConverter_Tests.cs | 21 ++++---- .../EnableInitOnlyProperties.cs | 4 ++ .../LocalizationResourceManagerTests.cs | 2 +- .../LocalizedStringTests.cs | 4 +- .../WeakEventManager_ActionT_Tests.cs | 22 ++------- .../WeakEventManager_EventHandlerT_Tests.cs | 32 ++++++------- .../Mocks/MockPlatformServices.cs | 4 +- .../Mocks/MockResourceManager.cs | 2 +- .../Namespace_Tests.cs | 47 +++++++++++------- .../AsyncCommandTests/AsyncCommand_Tests.cs | 27 ++++++----- .../AsyncCommandTests/IAsyncCommand_Tests.cs | 4 +- .../ICommand_AsyncCommand_Tests.cs | 14 +++--- .../AsyncValueCommand_Tests.cs | 18 +++---- .../ICommand_AsyncValueCommand_Tests.cs | 14 +++--- .../CommandFactory_AsyncCommand_Tests.cs | 14 +++--- .../CommandFactory_AsyncValueCommand_Tests.cs | 14 +++--- .../CommandFactory_Command_Tests.cs | 7 ++- .../ObjectModel/ObservableObject_Tests.cs | 19 +++----- .../ObservableRangeCollection_Tests.cs | 18 ++++--- .../ObjectModel/Person.cs | 10 ++-- .../Views/MediaSource_Tests.cs | 10 ++-- .../Xamarin.CommunityToolkit.UnitTests.csproj | 4 +- 30 files changed, 200 insertions(+), 207 deletions(-) mode change 100755 => 100644 src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/EnumToBoolConverter_Tests.cs create mode 100644 src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/EnableInitOnlyProperties.cs diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs index 0760c3011..721f4427c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs @@ -144,8 +144,8 @@ public void ShouldNotDismissKeyboardWhenOptionSetToFalse() Entry CreateEntry(int? maxLength = 2, bool shouldDismissKeyboardAutomatically = false, - ICommand command = null, - EventHandler eventHandler = null) + ICommand? command = null, + EventHandler? eventHandler = null) { var behavior = new MaxLengthReachedBehavior { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs index b69fdc3eb..b8ddc0563 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs @@ -160,8 +160,8 @@ public async Task ShouldExecuteCommandImmediatelyWhenMinimumLengthThreholdHasNot public Entry CreateEntryWithBehavior(int timeThreshold = defaultTimeThreshold, int lengthThreshold = defaultLengthThreshold, bool shouldDismissKeyboardAutomatically = false, - ICommand command = null, - object commandParameter = null) + ICommand? command = null, + object? commandParameter = null) { var entry = new Entry { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DoubleToIntConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DoubleToIntConverter_Tests.cs index abd7560e3..4462a3cea 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DoubleToIntConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DoubleToIntConverter_Tests.cs @@ -12,7 +12,7 @@ public class DoubleToIntConverter_Tests [InlineData(2.55, 3)] [InlineData(2.555, 3)] [InlineData(2.555, 652, 255)] - public void DoubleToIntConverter(double value, int expectedResult, object ratio = null) + public void DoubleToIntConverter(double value, int expectedResult, object? ratio = null) { var doubleToIntConverter = new DoubleToIntConverter(); @@ -23,7 +23,7 @@ public void DoubleToIntConverter(double value, int expectedResult, object ratio [Theory] [InlineData(2, 2)] - public void DoubleToIntConverterBack(int value, double expectedResult, object ratio = null) + public void DoubleToIntConverterBack(int value, double expectedResult, object? ratio = null) { var doubleToIntConverter = new DoubleToIntConverter(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/EnumToBoolConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/EnumToBoolConverter_Tests.cs old mode 100755 new mode 100644 index b61063c29..75493eca2 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/EnumToBoolConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/EnumToBoolConverter_Tests.cs @@ -80,68 +80,68 @@ public void EnumToBoolConvert_ParameterNotSameEnum_ReturnsFalse(object parameter Assert.Equal(expectedResult, result); } - public static IEnumerable ConvertTestData() + public static IEnumerable ConvertTestData() { // Simple enum - yield return new object[] + yield return new object?[] { null, TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Five, true }; - yield return new object[] + yield return new object?[] { null, TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six, false }; - yield return new object[] + yield return new object?[] { - new object[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six, true + new object?[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six, true }; - yield return new object[] + yield return new object?[] { - new object[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.Six, null, true + new object?[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.Six, null, true }; - yield return new object[] + yield return new object?[] { - new object[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.One, TestEnumForEnumToBoolConverter.Five, false + new object?[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.One, TestEnumForEnumToBoolConverter.Five, false }; - yield return new object[] + yield return new object?[] { - new object[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.Two, null, false + new object?[] { TestEnumForEnumToBoolConverter.Five, TestEnumForEnumToBoolConverter.Six }, TestEnumForEnumToBoolConverter.Two, null, false }; // Flagged enum - yield return new object[] + yield return new object?[] { - new object[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.One, null, true + new object?[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.One, null, true }; - yield return new object[] + yield return new object?[] { - new object[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.Two, null, true + new object?[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.Two, null, true }; - yield return new object[] + yield return new object?[] { - new object[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.Three, null, true + new object?[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.Three, null, true }; - yield return new object[] + yield return new object?[] { - new object[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.Four, null, false + new object?[] { (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), TestFlaggedEnumForEnumToBoolConverter.Two }, TestFlaggedEnumForEnumToBoolConverter.Four, null, false }; - yield return new object[] + yield return new object?[] { null, TestFlaggedEnumForEnumToBoolConverter.One, (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), true }; - yield return new object[] + yield return new object?[] { null, TestFlaggedEnumForEnumToBoolConverter.Three, (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), true }; - yield return new object[] + yield return new object?[] { null, TestFlaggedEnumForEnumToBoolConverter.Two, (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), false }; - yield return new object[] + yield return new object?[] { null, (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), true }; - yield return new object[] + yield return new object?[] { null, (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Two | TestFlaggedEnumForEnumToBoolConverter.Three), (TestFlaggedEnumForEnumToBoolConverter.One | TestFlaggedEnumForEnumToBoolConverter.Three), false }; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemSelectedEventArgsConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemSelectedEventArgsConverter_Tests.cs index c2e5d9cde..2c34f9750 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemSelectedEventArgsConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemSelectedEventArgsConverter_Tests.cs @@ -9,14 +9,16 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters { public class ItemSelectedEventArgsConverter_Tests { - static object expectedValue = 100; + static readonly object expectedValue = 100; public static IEnumerable GetData() => new List { // We know it's deprecated, still good to test it #pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. new object[] { new SelectedItemChangedEventArgs(expectedValue), expectedValue }, - new object[] { null, null }, + new object?[] { null, null }, +#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types. #pragma warning restore CS0618 // Type or member is obsolete }; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemTappedEventArgsConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemTappedEventArgsConverter_Tests.cs index 2d825deff..8530f1d7e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemTappedEventArgsConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ItemTappedEventArgsConverter_Tests.cs @@ -15,8 +15,10 @@ public class ItemTappedEventArgsConverter_Tests { // We know it's deprecated, still good to test it #pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. new object[] { new ItemTappedEventArgs(null, expectedValue), expectedValue }, new object[] { new ItemTappedEventArgs(null, null), null }, +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. #pragma warning restore CS0618 // Type or member is obsolete }; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNotNullOrEmptyConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNotNullOrEmptyConverter_Tests.cs index 0046c4b58..382e4a215 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNotNullOrEmptyConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNotNullOrEmptyConverter_Tests.cs @@ -9,16 +9,13 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters { public class ListIsNotNullOrEmptyConverter_Tests { - public static IEnumerable GetData() + public static IEnumerable GetData() => new List { - return new List - { - new object[] { new List(), false}, - new object[] { new List() { "TestValue"}, true}, - new object[] { null, false}, - new object[] { Enumerable.Range(1, 3), true}, - }; - } + new object[] { new List(), false}, + new object[] { new List() { "TestValue"}, true}, + new object?[] { null, false}, + new object[] { Enumerable.Range(1, 3), true}, + }; [Theory] [MemberData(nameof(GetData))] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNullOrEmptyConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNullOrEmptyConverter_Tests.cs index d34243e70..9d30e45ad 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNullOrEmptyConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListIsNullOrEmptyConverter_Tests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -9,16 +9,13 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters { public class ListIsNullOrEmptyConverter_Tests { - public static IEnumerable GetData() - { - return new List + public static IEnumerable GetData() => new List { new object[] { new List(), true}, - new object[] { new List() { "TestValue"}, false}, - new object[] { null, true}, - new object[] { Enumerable.Range(1, 3), false}, + new object[] { new List() { "TestValue" }, false}, + new object?[] { null, true }, + new object[] { Enumerable.Range(1, 3), false }, }; - } [Theory] [MemberData(nameof(GetData))] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListToStringConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListToStringConverter_Tests.cs index dcd12e13a..6580d9f35 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListToStringConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ListToStringConverter_Tests.cs @@ -7,17 +7,16 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters { public class ListToStringConverter_Tests { - public static IEnumerable GetData() - => new List - { - new object[] { new string[] { "A", "B", "C" }, "+_+", "A+_+B+_+C" }, - new object[] { new string[] { "A", string.Empty, "C" }, ",", "A,C" }, - new object[] { new string[] { "A", null, "C" }, ",", "A,C" }, - new object[] { new string[] { "A" }, ":-:", "A" }, - new object[] { new string[] { }, ",", string.Empty }, - new object[] { null, ",", string.Empty }, - new object[] { new string[] { "A", "B", "C" }, null, "ABC" }, - }; + public static IEnumerable GetData() => new List + { + new object[] { new string[] { "A", "B", "C" }, "+_+", "A+_+B+_+C" }, + new object[] { new string[] { "A", string.Empty, "C" }, ",", "A,C" }, + new object?[] { new string?[] { "A", null, "C" }, ",", "A,C" }, + new object[] { new string[] { "A" }, ":-:", "A" }, + new object[] { new string[] { }, ",", string.Empty }, + new object?[] { null, ",", string.Empty }, + new object?[] { new string[] { "A", "B", "C" }, null, "ABC" }, + }; [Theory] [MemberData(nameof(GetData))] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/EnableInitOnlyProperties.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/EnableInitOnlyProperties.cs new file mode 100644 index 000000000..f3a7fee73 --- /dev/null +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/EnableInitOnlyProperties.cs @@ -0,0 +1,4 @@ +namespace System.Runtime.CompilerServices +{ + public record IsExternalInit; +} diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizationResourceManagerTests/LocalizationResourceManagerTests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizationResourceManagerTests/LocalizationResourceManagerTests.cs index 6a669f5fd..950c5330d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizationResourceManagerTests/LocalizationResourceManagerTests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizationResourceManagerTests/LocalizationResourceManagerTests.cs @@ -48,7 +48,7 @@ public void LocalizationResourceManager_PropertyChanged_Triggered() // Arrange var culture2 = new CultureInfo("en"); localizationManager.CurrentCulture = culture2; - CultureInfo changedCulture = null; + CultureInfo? changedCulture = null; localizationManager.PropertyChanged += (s, e) => changedCulture = localizationManager.CurrentCulture; // Act, Assert diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizedStringTests/LocalizedStringTests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizedStringTests/LocalizedStringTests.cs index df6043244..ee903096f 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizedStringTests/LocalizedStringTests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/LocalizedStringTests/LocalizedStringTests.cs @@ -20,7 +20,7 @@ public LocalizedStringTests() readonly CultureInfo initialCulture = CultureInfo.InvariantCulture; readonly ResourceManager resourceManager; - LocalizedString localizedString; + LocalizedString? localizedString; [Fact] public void LocalizedStringTests_Localized_ValidImplementation() @@ -30,7 +30,7 @@ public void LocalizedStringTests_Localized_ValidImplementation() var culture2 = new CultureInfo("en"); localizedString = new LocalizedString(localizationManager, () => localizationManager[testString]); - string responceOnCultureChanged = null; + string? responceOnCultureChanged = null; localizedString.PropertyChanged += (sender, args) => responceOnCultureChanged = localizedString.Localized; // Act diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs index ddc61c429..d03445aaa 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs @@ -135,14 +135,12 @@ void HandleDelegateTest(string message) public void WeakEventManagerActionT_AddEventHandler_NullHandler() { // Arrange - Action nullAction = null; + Action? nullAction = null; // Act // Assert -#pragma warning disable CS8604 //Possible null reference argument for parameter Assert.Throws(() => actionEventManager.AddEventHandler(nullAction, nameof(ActionEvent))); -#pragma warning restore CS8604 //Possible null reference argument for parameter } @@ -154,23 +152,19 @@ public void WeakEventManagerActionT_AddEventHandler_NullEventName() // Act // Assert -#pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type Assert.Throws(() => actionEventManager.AddEventHandler(s => { var temp = s; }, null)); -#pragma warning restore CS8625 } [Fact] public void WeakEventManagerActionT_AddEventHandler_EmptyEventName() { // Arrange - Action nullAction = null; + Action? nullAction = null; // Act // Assert -#pragma warning disable CS8604 //Possible null reference argument for parameter Assert.Throws(() => actionEventManager.AddEventHandler(nullAction, string.Empty)); -#pragma warning restore CS8604 //Possible null reference argument for parameter } [Fact] @@ -181,23 +175,19 @@ public void WeakEventManagerActionT_AddEventHandler_WhitespaceEventName() // Act // Assert -#pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type Assert.Throws(() => actionEventManager.AddEventHandler(s => { var temp = s; }, " ")); -#pragma warning restore CS8625 } [Fact] public void WeakEventManagerActionT_RemoveEventHandler_NullHandler() { // Arrange - Action nullAction = null; + Action? nullAction = null; // Act // Assert -#pragma warning disable CS8604 //Possible null reference argument for parameter Assert.Throws(() => actionEventManager.RemoveEventHandler(nullAction)); -#pragma warning restore CS8604 } [Fact] @@ -208,9 +198,7 @@ public void WeakEventManagerActionT_RemoveEventHandler_NullEventName() // Act // Assert -#pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type Assert.Throws(() => actionEventManager.RemoveEventHandler(s => { var temp = s; }, null)); -#pragma warning restore CS8625 } [Fact] @@ -221,9 +209,7 @@ public void WeakEventManagerActionT_RemoveEventHandler_EmptyEventName() // Act // Assert -#pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type Assert.Throws(() => actionEventManager.RemoveEventHandler(s => { var temp = s; }, string.Empty)); -#pragma warning restore CS8625 } [Fact] @@ -234,9 +220,7 @@ public void WeakEventManagerActionT_RemoveEventHandler_WhiteSpaceEventName() // Act // Assert -#pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type Assert.Throws(() => actionEventManager.RemoveEventHandler(s => { var temp = s; }, " ")); -#pragma warning restore CS8625 } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs index 8d5190f7f..0247f9962 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs @@ -17,7 +17,7 @@ public void WeakEventManagerTEventArgs_HandleEvent_ValidImplementation() const string stringEventArg = "Test"; var didEventFire = false; - void HandleTestEvent(object sender, string? e) + void HandleTestEvent(object? sender, string? e) { if (sender == null || e == null) throw new ArgumentNullException(nameof(sender)); @@ -49,7 +49,7 @@ public void WeakEventManageTEventArgs_HandleEvent_NullSender() var didEventFire = false; - void HandleTestEvent(object sender, string e) + void HandleTestEvent(object? sender, string e) { Assert.Null(sender); @@ -74,7 +74,7 @@ public void WeakEventManagerTEventArgs_HandleEvent_NullEventArgs() TestStringEvent += HandleTestEvent; var didEventFire = false; - void HandleTestEvent(object sender, string e) + void HandleTestEvent(object? sender, string e) { if (sender == null) throw new ArgumentNullException(nameof(sender)); @@ -105,7 +105,7 @@ public void WeakEventManagerTEventArgs_HandleEvent_InvalidHandleEvent() var didEventFire = false; - void HandleTestEvent(object sender, string e) => didEventFire = true; + void HandleTestEvent(object? sender, string e) => didEventFire = true; // Act TestStringWeakEventManager.RaiseEvent(this, "Test", nameof(TestEvent)); @@ -119,13 +119,13 @@ public void WeakEventManagerTEventArgs_HandleEvent_InvalidHandleEvent() public void WeakEventManager_NullEventManager() { // Arrange - WeakEventManager unassignedEventManager = null; + WeakEventManager? unassignedEventManager = null; // Act // Assert #pragma warning disable CS8602 //Dereference of a possible null reference - Assert.Throws(() => unassignedEventManager.RaiseEvent(null, null, nameof(TestEvent))); + Assert.Throws(() => unassignedEventManager.RaiseEvent(null, string.Empty, nameof(TestEvent))); #pragma warning restore CS8602 } @@ -137,7 +137,7 @@ public void WeakEventManagerTEventArgs_UnassignedEventManager() var didEventFire = false; TestStringEvent += HandleTestEvent; - void HandleTestEvent(object sender, string e) => didEventFire = true; + void HandleTestEvent(object? sender, string e) => didEventFire = true; // Act #pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type @@ -157,7 +157,7 @@ public void WeakEventManagerTEventArgs_UnassignedEvent() TestStringEvent += HandleTestEvent; TestStringEvent -= HandleTestEvent; - void HandleTestEvent(object sender, string e) => didEventFire = true; + void HandleTestEvent(object? sender, string e) => didEventFire = true; // Act TestStringWeakEventManager.RaiseEvent(this, "Test", nameof(TestStringEvent)); @@ -174,9 +174,9 @@ public void WeakEventManagerT_AddEventHandler_NullHandler() // Act // Assert -#pragma warning disable CS8625 //Cannot convert null literal to non-nullable reference type +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. Assert.Throws(() => TestStringWeakEventManager.AddEventHandler((EventHandler)null)); -#pragma warning restore CS8625 +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } [Fact] @@ -187,9 +187,7 @@ public void WeakEventManagerT_AddEventHandler_NullEventName() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => TestStringWeakEventManager.AddEventHandler(s => { var temp = s; }, null)); -#pragma warning restore CS8625 } [Fact] @@ -222,9 +220,9 @@ public void WeakEventManagerT_RemoveEventHandler_NullHandler() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. Assert.Throws(() => TestStringWeakEventManager.RemoveEventHandler((EventHandler)null)); -#pragma warning restore CS8625 +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } [Fact] @@ -235,9 +233,7 @@ public void WeakEventManagerT_RemoveEventHandler_NullEventName() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => TestStringWeakEventManager.AddEventHandler(s => { var temp = s; }, null)); -#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference } [Fact] @@ -269,12 +265,12 @@ public void WeakEventManagerT_HandleEvent_InvalidHandleEvent() TestStringEvent += HandleTestStringEvent; var didEventFire = false; - void HandleTestStringEvent(object sender, string e) => didEventFire = true; + void HandleTestStringEvent(object? sender, string e) => didEventFire = true; // Act // Assert - Assert.Throws(() => TestStringWeakEventManager.RaiseEvent("", nameof(TestStringEvent))); + Assert.Throws(() => TestStringWeakEventManager.RaiseEvent(string.Empty, nameof(TestStringEvent))); Assert.False(didEventFire); TestStringEvent -= HandleTestStringEvent; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockPlatformServices.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockPlatformServices.cs index 18d3fcc03..d0a5aa648 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockPlatformServices.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockPlatformServices.cs @@ -31,7 +31,7 @@ public bool IsInvokeRequired public OSAppTheme RequestedTheme => OSAppTheme.Unspecified; - public string RuntimePlatform { get; set; } + public string RuntimePlatform { get; set; } = string.Empty; public void BeginInvokeOnMainThread(Action action) => action(); @@ -49,7 +49,7 @@ public Task GetStreamAsync(Uri uri, CancellationToken cancellationToken) public Assembly[] GetAssemblies() => new Assembly[0]; - public IIsolatedStorageFile GetUserStoreForApplication() + public IIsolatedStorageFile? GetUserStoreForApplication() => null; Assembly[] IPlatformServices.GetAssemblies() diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockResourceManager.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockResourceManager.cs index c57aa3b39..3c0289d2a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockResourceManager.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Mocks/MockResourceManager.cs @@ -5,6 +5,6 @@ namespace Xamarin.CommunityToolkit.UnitTests.Mocks { class MockResourceManager : ResourceManager { - public override string GetString(string name, CultureInfo culture) => culture.EnglishName; + public override string GetString(string name, CultureInfo? culture) => culture?.EnglishName ?? string.Empty; } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Namespace_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Namespace_Tests.cs index 3f710be90..9bcf4bd50 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Namespace_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Namespace_Tests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Reflection; using Xamarin.CommunityToolkit.Behaviors.Internals; using Xamarin.CommunityToolkit.Converters; @@ -15,62 +16,72 @@ public class Namespace_Tests [Fact] public void MakeSureConvertersAreInTheRightNamespace() { - var allTheTypes = Assembly.GetAssembly(typeof(InvertedBoolConverter)).GetTypes(); + var allTheTypes = Assembly.GetAssembly(typeof(InvertedBoolConverter))?.GetTypes(); + if (allTheTypes is null) + throw new NullReferenceException(); foreach (var type in allTheTypes.Where(t => t.Name.EndsWith("Converter") && t.GetInterface(nameof(IValueConverter)) != null)) { - Assert.True(type.Namespace.Equals("Xamarin.CommunityToolkit.Converters"), - $"{type.FullName} not in Xamarin.CommunityToolkit.Converters namespace"); + Assert.True(type?.Namespace?.Equals("Xamarin.CommunityToolkit.Converters"), + $"{type?.FullName} not in Xamarin.CommunityToolkit.Converters namespace"); } } [Fact] public void MakeSureEffectsAreInTheRightNamespace() { - var allTheTypes = Assembly.GetAssembly(typeof(SafeAreaEffect)).GetTypes(); + var allTheTypes = Assembly.GetAssembly(typeof(SafeAreaEffect))?.GetTypes(); + if (allTheTypes is null) + throw new NullReferenceException(); foreach (var type in allTheTypes.Where(t => t.Name.EndsWith("Effect") && t.IsClass && t.IsSealed && t.IsAbstract)) { - Assert.True(type.Namespace.Equals("Xamarin.CommunityToolkit.Effects"), - $"{type.FullName} not in Xamarin.CommunityToolkit.Effects namespace"); + Assert.True(type?.Namespace?.Equals("Xamarin.CommunityToolkit.Effects"), + $"{type?.FullName} not in Xamarin.CommunityToolkit.Effects namespace"); } } [Fact] public void MakeSureMarkupExtensionsAreInTheRightNamespace() { - var allTheTypes = Assembly.GetAssembly(typeof(TranslateExtension)).GetTypes(); + var allTheTypes = Assembly.GetAssembly(typeof(TranslateExtension))?.GetTypes(); + if (allTheTypes is null) + throw new NullReferenceException(); foreach (var type in allTheTypes.Where(t => t.Name.EndsWith("Extension") && t.GetInterface("IMarkupExtension") != null)) { - Assert.True(type.Namespace.Equals("Xamarin.CommunityToolkit.Extensions") || - type.Namespace.Equals("Xamarin.CommunityToolkit.Extensions.Internals"), - $"{type.FullName} not in nameof(Xamarin.CommunityToolkit.Extensions namespace"); + Assert.True(type?.Namespace?.Equals("Xamarin.CommunityToolkit.Extensions") is true || + type?.Namespace?.Equals("Xamarin.CommunityToolkit.Extensions.Internals") is true, + $"{type?.FullName} not in nameof(Xamarin.CommunityToolkit.Extensions namespace"); } } [Fact] public void MakeSureBehaviorsAreInTheRightNamespace() { - var allTheTypes = Assembly.GetAssembly(typeof(BaseBehavior<>)).GetTypes(); + var allTheTypes = Assembly.GetAssembly(typeof(BaseBehavior<>))?.GetTypes(); + if (allTheTypes is null) + throw new NullReferenceException(); foreach (var type in allTheTypes.Where(t => t.Name.EndsWith("Behavior") && t.IsSubclassOf(typeof(BaseBehavior<>)))) { - Assert.True(type.Namespace.Equals("Xamarin.CommunityToolkit.Behaviors"), - $"{type.FullName} not in Xamarin.CommunityToolkit.Behaviors namespace"); + Assert.True(type?.Namespace?.Equals("Xamarin.CommunityToolkit.Behaviors"), + $"{type?.FullName} not in Xamarin.CommunityToolkit.Behaviors namespace"); } } [Fact] public void MakeSureViewsAreInTheRightNamespace() { - var allTheTypes = Assembly.GetAssembly(typeof(AvatarView)).GetTypes(); + var allTheTypes = Assembly.GetAssembly(typeof(AvatarView))?.GetTypes(); + if (allTheTypes is null) + throw new NullReferenceException(); foreach (var type in allTheTypes.Where(t => t.IsSubclassOf(typeof(View)))) { - Assert.True(type.Namespace.Equals("Xamarin.CommunityToolkit.UI.Views") || - type.Namespace.Equals("Xamarin.CommunityToolkit.UI.Views.Internals"), - $"{type.FullName} not in Xamarin.CommunityToolkit.UI.Views namespace"); + Assert.True(type?.Namespace?.Equals("Xamarin.CommunityToolkit.UI.Views") is true || + type?.Namespace?.Equals("Xamarin.CommunityToolkit.UI.Views.Internals") is true, + $"{type?.FullName} not in Xamarin.CommunityToolkit.UI.Views namespace"); } } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs index 63cbe4e0c..53ddb4f9d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs @@ -152,7 +152,7 @@ public void AsyncCommand_NoParameter_CanExecuteFalse_NoParameter_Test() public void AsyncCommand_NoParameter_NoCanExecute_Test() { // Arrange - Func canExecute = null; + Func? canExecute = null; var command = new AsyncCommand(NoParameterTask, canExecute); // Act @@ -189,7 +189,7 @@ public void AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_MainThreadExe Assert.True(didCanExecuteChangeFire); Assert.True(command.CanExecute(null)); - void handleCanExecuteChanged(object sender, EventArgs e) => didCanExecuteChangeFire = true; + void handleCanExecuteChanged(object? sender, EventArgs e) => didCanExecuteChangeFire = true; } [Fact] @@ -222,7 +222,7 @@ public void AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_MainThreadExe Assert.True(didCanExecuteChangeFire); Assert.True(command.CanExecute(null)); - void handleCanExecuteChanged(object sender, EventArgs e) => didCanExecuteChangeFire = true; + void handleCanExecuteChanged(object? sender, EventArgs e) => didCanExecuteChangeFire = true; }); [Fact] @@ -258,14 +258,14 @@ public async Task AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_Backgro Assert.True(command.CanExecute(null)); }); - void handleCanExecuteChanged(object sender, EventArgs e) => didCanExecuteChangeFire = true; + void handleCanExecuteChanged(object? sender, EventArgs e) => didCanExecuteChangeFire = true; } [Fact] public async Task AsyncCommand_RaiseCanExecuteChanged_BackgroundThreadCreation_MainThreadExecution_Test() { // Arrange - AsyncCommand command = null; + AsyncCommand? command = null; var didCanExecuteChangeFire = false; var canCommandExecute = false; @@ -289,20 +289,23 @@ public async Task AsyncCommand_RaiseCanExecuteChanged_BackgroundThreadCreation_M }).ConfigureAwait(true); // Act + if (command is null) + throw new NullReferenceException(); + command.RaiseCanExecuteChanged(); // Assert Assert.True(didCanExecuteChangeFire); Assert.True(command.CanExecute(null)); - void handleCanExecuteChanged(object sender, EventArgs e) => didCanExecuteChangeFire = true; + void handleCanExecuteChanged(object? sender, EventArgs e) => didCanExecuteChangeFire = true; } [Fact] public async Task AsyncCommand_ChangeCanExecute_Test() { // Arrange - var canExecuteChangedTCS = new TaskCompletionSource(); + var canExecuteChangedTCS = new TaskCompletionSource(); var canCommandExecute = false; var didCanExecuteChangeFire = false; @@ -322,16 +325,14 @@ public async Task AsyncCommand_ChangeCanExecute_Test() Assert.False(didCanExecuteChangeFire); // Act -#pragma warning disable CS0618 // Type or member is obsolete command.ChangeCanExecute(); await canExecuteChangedTCS.Task; -#pragma warning restore CS0618 // Type or member is obsolete // Assert Assert.True(didCanExecuteChangeFire); Assert.True(command.CanExecute(null)); - void handleCanExecuteChanged(object sender, EventArgs e) + void handleCanExecuteChanged(object? sender, EventArgs e) { didCanExecuteChangeFire = true; canExecuteChangedTCS.SetResult(null); @@ -363,14 +364,14 @@ public async Task AsyncCommand_CanExecuteChanged_AllowsMultipleExecutions_Test() Assert.True(command.CanExecute(null)); Assert.Equal(0, canExecuteChangedCount); - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; } [Fact] public async Task AsyncCommand_CanExecuteChanged_DoesNotAllowMultipleExecutions_Test() { // Arrange - var canExecuteChangedGreaterThan1TCS = new TaskCompletionSource(); + var canExecuteChangedGreaterThan1TCS = new TaskCompletionSource(); var canExecuteChangedCount = 0; @@ -394,7 +395,7 @@ public async Task AsyncCommand_CanExecuteChanged_DoesNotAllowMultipleExecutions_ Assert.True(command.CanExecute(null)); Assert.Equal(2, canExecuteChangedCount); - void handleCanExecuteChanged(object sender, EventArgs e) + void handleCanExecuteChanged(object? sender, EventArgs e) { if (++canExecuteChangedCount > 1) canExecuteChangedGreaterThan1TCS.SetResult(null); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/IAsyncCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/IAsyncCommand_Tests.cs index 8c7bdc80a..c4d700278 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/IAsyncCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/IAsyncCommand_Tests.cs @@ -201,7 +201,7 @@ public async Task IAsyncCommand_CanExecuteChanged_AllowsMultipleExecutions_Test( Assert.True(command.CanExecute(null)); Assert.Equal(0, canExecuteChangedCount); - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; } [Fact] @@ -229,7 +229,7 @@ public async Task IAsyncCommand_CanExecuteChanged_DoesNotAllowMultipleExecutions Assert.True(command.CanExecute(null)); Assert.Equal(2, canExecuteChangedCount); - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/ICommand_AsyncCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/ICommand_AsyncCommand_Tests.cs index 691eff1fa..1e8ba3806 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/ICommand_AsyncCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/ICommand_AsyncCommand_Tests.cs @@ -43,7 +43,7 @@ public async Task ICommand_Execute_StringParameter_Test(string parameter) public void ICommand_ExecuteAsync_InvalidValueTypeParameter_Test() { // Arrange - InvalidCommandParameterException actualInvalidCommandParameterException = null; + InvalidCommandParameterException? actualInvalidCommandParameterException = null; var expectedInvalidCommandParameterException = new InvalidCommandParameterException(typeof(string), typeof(int)); ICommand command = new AsyncCommand(StringParameterTask); @@ -61,7 +61,7 @@ public void ICommand_ExecuteAsync_InvalidValueTypeParameter_Test() public void ICommand_ExecuteAsync_InvalidReferenceTypeParameter_Test() { // Arrange - InvalidCommandParameterException actualInvalidCommandParameterException = null; + InvalidCommandParameterException? actualInvalidCommandParameterException = null; var expectedInvalidCommandParameterException = new InvalidCommandParameterException(typeof(int), typeof(string)); ICommand command = new AsyncCommand(IntParameterTask); @@ -78,7 +78,7 @@ public void ICommand_ExecuteAsync_InvalidReferenceTypeParameter_Test() public void ICommand_ExecuteAsync_ValueTypeParameter_Test() { // Arrange - InvalidCommandParameterException actualInvalidCommandParameterException = null; + InvalidCommandParameterException? actualInvalidCommandParameterException = null; var expectedInvalidCommandParameterException = new InvalidCommandParameterException(typeof(int)); ICommand command = new AsyncCommand(IntParameterTask); @@ -197,7 +197,7 @@ public async Task ICommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_ ICommand command = new AsyncCommand(IntParameterTask); - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(Delay); @@ -239,7 +239,7 @@ public async Task ICommand_Parameter_CanExecuteChanged_DoesNotAllowMultipleExecu Assert.True(command.CanExecute(null)); Assert.Equal(2, canExecuteChangedCount); - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; } [Fact] @@ -251,7 +251,7 @@ public async Task ICommand_NoParameter_CanExecuteChanged_AllowsMultipleExecution ICommand command = new AsyncCommand(() => IntParameterTask(Delay)); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(null); @@ -277,7 +277,7 @@ public async Task ICommand_NoParameter_CanExecuteChanged_DoesNotAllowMultipleExe ICommand command = new AsyncCommand(() => IntParameterTask(Delay), allowsMultipleExecutions: false); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(null); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs index 152aed39e..1e83d0c7b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs @@ -175,7 +175,7 @@ public void AsyncValueCommandNoParameter_CanExecuteFalseNoParameter_Test() public void AsyncValueCommandNoParameter_NoCanExecute_Test() { // Arrange - Func canExecute = null; + Func? canExecute = null; var command = new AsyncValueCommand(NoParameterTask, canExecute); // Act @@ -188,7 +188,7 @@ public void AsyncValueCommandNoParameter_NoCanExecute_Test() public async Task AsyncValueCommand_RaiseCanExecuteChanged_Test() { // Arrange - var handleCanExecuteChangedTCS = new TaskCompletionSource(); + var handleCanExecuteChangedTCS = new TaskCompletionSource(); var canCommandExecute = false; var didCanExecuteChangeFire = false; @@ -215,7 +215,7 @@ public async Task AsyncValueCommand_RaiseCanExecuteChanged_Test() Assert.True(didCanExecuteChangeFire); Assert.True(command.CanExecute(null)); - void handleCanExecuteChanged(object sender, EventArgs e) + void handleCanExecuteChanged(object? sender, EventArgs e) { didCanExecuteChangeFire = true; handleCanExecuteChangedTCS.SetResult(null); @@ -226,7 +226,7 @@ void handleCanExecuteChanged(object sender, EventArgs e) public async Task AsyncValueCommand_ChangeCanExecute_Test() { // Arrange - var handleCanExecuteChangedTCS = new TaskCompletionSource(); + var handleCanExecuteChangedTCS = new TaskCompletionSource(); var canCommandExecute = false; var didCanExecuteChangeFire = false; @@ -255,7 +255,7 @@ public async Task AsyncValueCommand_ChangeCanExecute_Test() Assert.True(didCanExecuteChangeFire); Assert.True(command.CanExecute(null)); - void handleCanExecuteChanged(object sender, EventArgs e) + void handleCanExecuteChanged(object? sender, EventArgs e) { didCanExecuteChangeFire = true; handleCanExecuteChangedTCS.SetResult(null); @@ -271,7 +271,7 @@ public async Task AsyncValueCommand_Parameter_CanExecuteChanged_AllowsMultipleEx var command = new AsyncValueCommand(IntParameterTask); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; Assert.True(command.AllowsMultipleExecutions); @@ -299,7 +299,7 @@ public async Task AsyncValueCommand_Parameter_CanExecuteChanged_DoesNotAllowMult var command = new AsyncValueCommand(IntParameterTask, allowsMultipleExecutions: false); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; Assert.False(command.AllowsMultipleExecutions); @@ -327,7 +327,7 @@ public async Task AsyncValueCommand_NoParameter_CanExecuteChanged_AllowsMultiple var command = new AsyncValueCommand(() => IntParameterTask(Delay)); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; Assert.True(command.AllowsMultipleExecutions); @@ -355,7 +355,7 @@ public async Task AsyncValueCommand_NoParameter_CanExecuteChanged_DoesNotAllowMu var command = new AsyncValueCommand(() => IntParameterTask(Delay), allowsMultipleExecutions: false); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; Assert.False(command.AllowsMultipleExecutions); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/ICommand_AsyncValueCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/ICommand_AsyncValueCommand_Tests.cs index fc7265ffa..587ae2290 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/ICommand_AsyncValueCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/ICommand_AsyncValueCommand_Tests.cs @@ -43,7 +43,7 @@ public async Task ICommand_Execute_StringParameter_Test(string parameter) public async Task ICommand_Execute_InvalidValueTypeParameter_Test() { // Arrange - InvalidCommandParameterException actualInvalidCommandParameterException = null; + InvalidCommandParameterException? actualInvalidCommandParameterException = null; var expectedInvalidCommandParameterException = new InvalidCommandParameterException(typeof(string), typeof(int)); ICommand command = new AsyncValueCommand(StringParameterTask); @@ -69,7 +69,7 @@ public async Task ICommand_Execute_InvalidValueTypeParameter_Test() public async Task ICommand_Execute_InvalidReferenceTypeParameter_Test() { // Arrange - InvalidCommandParameterException actualInvalidCommandParameterException = null; + InvalidCommandParameterException? actualInvalidCommandParameterException = null; var expectedInvalidCommandParameterException = new InvalidCommandParameterException(typeof(int), typeof(string)); ICommand command = new AsyncValueCommand(IntParameterTask); @@ -95,7 +95,7 @@ public async Task ICommand_Execute_InvalidReferenceTypeParameter_Test() public async Task ICommand_Execute_ValueTypeParameter_Test() { // Arrange - InvalidCommandParameterException actualInvalidCommandParameterException = null; + InvalidCommandParameterException? actualInvalidCommandParameterException = null; var expectedInvalidCommandParameterException = new InvalidCommandParameterException(typeof(int)); ICommand command = new AsyncValueCommand(IntParameterTask); @@ -224,7 +224,7 @@ public async Task ICommand_Parameter_CanExecuteChanged_AllowsMultipleExecutions_ ICommand command = new AsyncValueCommand(IntParameterTask); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(Delay); @@ -249,7 +249,7 @@ public async Task ICommand_Parameter_CanExecuteChanged_DoesNotAllowMultipleExecu ICommand command = new AsyncValueCommand(IntParameterTask, allowsMultipleExecutions: false); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(Delay); @@ -275,7 +275,7 @@ public async Task ICommand_NoParameter_CanExecuteChanged_AllowsMultipleExecution ICommand command = new AsyncValueCommand(() => IntParameterTask(Delay)); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(null); @@ -301,7 +301,7 @@ public async Task ICommand_NoParameter_CanExecuteChanged_DoesNotAllowMultipleExe ICommand command = new AsyncValueCommand(() => IntParameterTask(Delay), allowsMultipleExecutions: false); command.CanExecuteChanged += handleCanExecuteChanged; - void handleCanExecuteChanged(object sender, EventArgs e) => canExecuteChangedCount++; + void handleCanExecuteChanged(object? sender, EventArgs e) => canExecuteChangedCount++; // Act command.Execute(null); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs index 6b5618c3c..2f4f65408 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs @@ -13,7 +13,7 @@ public class CommandFactoryAsyncCommandTests : BaseCommandTests public void AsyncCommand_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -61,7 +61,7 @@ public async Task AsyncCommand_ObjectCanExecuteParameter() public void AsyncCommand_FuncBool_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -73,7 +73,7 @@ public void AsyncCommand_FuncBool_NullExecuteParameter() public async Task AsyncCommand_FuncBool_NullCanExecuteParameter() { // Arrange - Func canExecute = null; + Func? canExecute = null; var command = CommandFactory.Create(NoParameterTask, canExecute); // Act @@ -112,7 +112,7 @@ public async Task AsyncCommand_FuncBool_ValidExecuteParameter_ValidCanExecutePar public void AsyncCommandT_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -162,7 +162,7 @@ public async Task AsyncCommandT_ObjectCanExecuteParameter() public void AsyncCommandT_FuncBool_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -174,7 +174,7 @@ public void AsyncCommandT_FuncBool_NullExecuteParameter() public async Task AsyncCommandT_FuncBool_NullCanExecuteParameter() { // Arrange - Func canExecute = null; + Func? canExecute = null; var command = CommandFactory.Create(IntParameterTask, canExecute); // Act @@ -213,7 +213,7 @@ public async Task AsyncCommandT_FuncBool_ValidExecuteParameter_ValidCanExecutePa public void AsyncCommandTExecuteTCanExecute_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs index 2655be1e4..387663ec4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs @@ -14,7 +14,7 @@ public class CommandFactoryAsyncValueCommandTests : BaseAsyncValueCommandTests public void AsyncValueCommand_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -62,7 +62,7 @@ public async Task AsyncValueCommand_ObjectCanExecuteParameter() public void AsyncValueCommand_FuncBool_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -74,7 +74,7 @@ public void AsyncValueCommand_FuncBool_NullExecuteParameter() public async Task AsyncValueCommand_FuncBool_NullCanExecuteParameter() { // Arrange - Func canExecute = null; + Func? canExecute = null; var command = CommandFactory.Create(NoParameterTask, canExecute); // Act @@ -113,7 +113,7 @@ public async Task AsyncValueCommand_FuncBool_ValidExecuteParameter_ValidCanExecu public void AsyncValueCommandT_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -163,7 +163,7 @@ public async Task AsyncValueCommandT_ObjectCanExecuteParameter() public void AsyncValueCommandT_FuncBool_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act @@ -175,7 +175,7 @@ public void AsyncValueCommandT_FuncBool_NullExecuteParameter() public async Task AsyncValueCommandT_FuncBool_NullCanExecuteParameter() { // Arrange - Func canExecute = null; + Func? canExecute = null; var command = CommandFactory.Create(IntParameterTask, canExecute); // Act @@ -214,7 +214,7 @@ public async Task AsyncValueCommandT_FuncBool_ValidExecuteParameter_ValidCanExec public void AsyncValueCommandTExecuteTCanExecute_NullExecuteParameter() { // Arrange - Func execute = null; + Func? execute = null; // Act diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs index b6e4f48d4..635b6fada 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs @@ -1,6 +1,5 @@ using System; using System.Windows.Input; -using Xamarin.CommunityToolkit.Exceptions; using Xamarin.CommunityToolkit.ObjectModel; using Xunit; @@ -12,7 +11,7 @@ public class CommandFactoryCommandTests : BaseCommandTests public void Action_NullExecuteParameter() { // Arrange - Action execute = null; + Action? execute = null; // Act @@ -71,7 +70,7 @@ public void Action_ValidCanExecuteParameter() public void ActionObject_NullExecuteParameter() { // Arrange - Action execute = null; + Action? execute = null; // Act @@ -132,7 +131,7 @@ public void ActionObject_ValidCanExecuteParameter() public void ActionInt_NullExecuteParameter() { // Arrange - Action execute = null; + Action? execute = null; // Act diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableObject_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableObject_Tests.cs index 009506d37..060fbf7e5 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableObject_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableObject_Tests.cs @@ -7,21 +7,16 @@ namespace Xamarin.CommunityToolkit.UnitTests.ObjectModel { public sealed class ObservableObject_Tests { - Person person; - - public ObservableObject_Tests() + readonly Person person = new Person { - person = new Person - { - FirstName = "James", - LastName = "Montemagno" - }; - } + FirstName = "James", + LastName = "Montemagno" + }; [Fact] public void OnPropertyChanged() { - PropertyChangedEventArgs updated = null; + PropertyChangedEventArgs? updated = null; person.PropertyChanged += (sender, args) => { updated = args; @@ -30,13 +25,13 @@ public void OnPropertyChanged() person.FirstName = "Motz"; Assert.NotNull(updated); - Assert.Equal(nameof(person.FirstName), updated.PropertyName); + Assert.Equal(nameof(person.FirstName), updated?.PropertyName); } [Fact] public void OnDidntChange() { - PropertyChangedEventArgs updated = null; + PropertyChangedEventArgs? updated = null; person.PropertyChanged += (sender, args) => { updated = args; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableRangeCollection_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableRangeCollection_Tests.cs index beba839f1..13222b067 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableRangeCollection_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ObservableRangeCollection_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Linq; using Xamarin.CommunityToolkit.ObjectModel; using Xunit; using Xunit.Sdk; @@ -121,7 +122,7 @@ public void RemoveRangeRemoveFact() throw new XunitException("Expected and actual OldItems don't match."); for (var i = 0; i < expected.Length; i++) { - if (expected[i] != (int)e.OldItems[i]) + if (expected[i] != (int?)e.OldItems[i]) throw new XunitException("Expected and actual OldItems don't match."); } }; @@ -176,12 +177,6 @@ public void RemoveRange_should_NOT_mutate_collection_when_source_data_is_not_pre Assert.Equal(6, collection.Count); } - class CollectionWrapper - { - public readonly ObservableRangeCollection Collection = new ObservableRangeCollection(); - public ObservableRangeCollection NullCollection; - } - [Fact] public void AddCollection() { @@ -200,6 +195,7 @@ public void AddToNullCollection() { var toAdd = new[] { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3 }; +#pragma warning disable CS8670 // Object or collection initializer implicitly dereferences possibly null member. Assert.Throws(() => { var wrapper = new CollectionWrapper() @@ -207,6 +203,14 @@ public void AddToNullCollection() NullCollection = { toAdd } }; }); +#pragma warning restore CS8670 // Object or collection initializer implicitly dereferences possibly null member. + } + + class CollectionWrapper + { + public ObservableRangeCollection Collection { get; } = new ObservableRangeCollection(); + + public ObservableRangeCollection? NullCollection { get; init; } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/Person.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/Person.cs index 25c7b0dff..25993c9cc 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/Person.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/Person.cs @@ -5,14 +5,14 @@ namespace Xamarin.CommunityToolkit.UnitTests.ObjectModel { class Person : ObservableObject { - string firstName; - string lastName; + string firstName = string.Empty; + string lastName = string.Empty; - public Action Changed { get; set; } + public Action? Changed { get; set; } - public Action Changing { get; set; } + public Action? Changing { get; set; } - public Func Validate { get; set; } + public Func? Validate { get; set; } public string FirstName { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs index 013c75f9b..1fc571a25 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs @@ -32,7 +32,7 @@ public void TestHelpers() public void TestImplicitFileConversion() { var mediaElement = new UI.Views.MediaElement { Source = "File.mp4" }; - Assert.True(mediaElement.Source != null); + Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); Assert.Equal("File.mp4", ((Core.FileMediaSource)mediaElement.Source).File); } @@ -40,7 +40,7 @@ public void TestImplicitFileConversion() [Fact] public void TestImplicitStringConversionWhenNull() { - string s = null; + string? s = null; var sut = (Core.MediaSource)s; Assert.IsType(sut); Assert.Null(((Core.FileMediaSource)sut).File); @@ -50,7 +50,7 @@ public void TestImplicitStringConversionWhenNull() public void TestImplicitUriConversion() { var mediaElement = new UI.Views.MediaElement { Source = new Uri("http://xamarin.com/media.mp4") }; - Assert.True(mediaElement.Source != null); + Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)mediaElement.Source).Uri.AbsoluteUri); } @@ -59,7 +59,7 @@ public void TestImplicitUriConversion() public void TestImplicitStringUriConversion() { var mediaElement = new UI.Views.MediaElement { Source = "http://xamarin.com/media.mp4" }; - Assert.True(mediaElement.Source != null); + Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)mediaElement.Source).Uri.AbsoluteUri); } @@ -67,7 +67,7 @@ public void TestImplicitStringUriConversion() [Fact] public void TestImplicitUriConversionWhenNull() { - Uri u = null; + Uri? u = null; var sut = (Core.MediaSource)u; Assert.Null(sut); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj index 506115a4f..bf7e510f4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj @@ -2,7 +2,9 @@ netcoreapp2.1;netcoreapp3.1;net461 - + enable + nullable + latest false From 192313f8fc982694195c69495bbcedf36668df18 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Wed, 3 Mar 2021 19:54:21 -0800 Subject: [PATCH 02/13] Enable Nullable on Xamarin.CommunityToolkit.Markup --- .../BindableObjectExtensions.cs | 82 ++++++++-------- .../BindableObjectMultiBindExtensions.cs | 74 +++++++-------- .../ElementExtensions.cs | 4 +- .../ElementGesturesExtensions.cs | 18 ++-- .../FuncConverter.cs | 28 +++--- .../FuncMultiConverter.cs | 94 ++++++++++--------- .../RelativeLayout.cs | 8 +- .../Xamarin.CommunityToolkit.Markup/Style.cs | 2 +- .../Xamarin.CommunityToolkit.Markup.csproj | 3 + 9 files changed, 161 insertions(+), 152 deletions(-) diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectExtensions.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectExtensions.cs index 73bbcbb1f..1b4e10e42 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectExtensions.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectExtensions.cs @@ -13,12 +13,12 @@ public static class BindableObjectExtensions BindableProperty targetProperty, string path = bindingContextPath, BindingMode mode = BindingMode.Default, - IValueConverter converter = null, - object converterParameter = null, - string stringFormat = null, - object source = null, - object targetNullValue = null, - object fallbackValue = null) where TBindable : BindableObject + IValueConverter? converter = null, + object? converterParameter = null, + string? stringFormat = null, + object? source = null, + object? targetNullValue = null, + object? fallbackValue = null) where TBindable : BindableObject { bindable.SetBinding( targetProperty, @@ -36,12 +36,12 @@ public static class BindableObjectExtensions BindableProperty targetProperty, string path = bindingContextPath, BindingMode mode = BindingMode.Default, - Func convert = null, - Func convertBack = null, - string stringFormat = null, - object source = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + Func? convert = null, + Func? convertBack = null, + string? stringFormat = null, + object? source = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject { var converter = new FuncConverter(convert, convertBack); bindable.SetBinding( @@ -60,13 +60,13 @@ public static class BindableObjectExtensions BindableProperty targetProperty, string path = bindingContextPath, BindingMode mode = BindingMode.Default, - Func convert = null, - Func convertBack = null, - TParam converterParameter = default, - string stringFormat = null, - object source = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + Func? convert = null, + Func? convertBack = null, + TParam? converterParameter = default, + string? stringFormat = null, + object? source = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject { var converter = new FuncConverter(convert, convertBack); bindable.SetBinding( @@ -84,12 +84,12 @@ public static class BindableObjectExtensions this TBindable bindable, string path = bindingContextPath, BindingMode mode = BindingMode.Default, - IValueConverter converter = null, - object converterParameter = null, - string stringFormat = null, - object source = null, - object targetNullValue = null, - object fallbackValue = null) where TBindable : BindableObject + IValueConverter? converter = null, + object? converterParameter = null, + string? stringFormat = null, + object? source = null, + object? targetNullValue = null, + object? fallbackValue = null) where TBindable : BindableObject { bindable.Bind( DefaultBindableProperties.GetFor(bindable), @@ -102,12 +102,12 @@ public static class BindableObjectExtensions this TBindable bindable, string path = bindingContextPath, BindingMode mode = BindingMode.Default, - Func convert = null, - Func convertBack = null, - string stringFormat = null, - object source = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + Func? convert = null, + Func? convertBack = null, + string? stringFormat = null, + object? source = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject { var converter = new FuncConverter(convert, convertBack); bindable.Bind( @@ -121,13 +121,13 @@ public static class BindableObjectExtensions this TBindable bindable, string path = bindingContextPath, BindingMode mode = BindingMode.Default, - Func convert = null, - Func convertBack = null, - TParam converterParameter = default, - string stringFormat = null, - object source = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + Func? convert = null, + Func? convertBack = null, + TParam? converterParameter = default, + string? stringFormat = null, + object? source = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject { var converter = new FuncConverter(convert, convertBack); bindable.Bind( @@ -141,9 +141,9 @@ public static class BindableObjectExtensions public static TBindable BindCommand( this TBindable bindable, string path = bindingContextPath, - object source = null, - string parameterPath = bindingContextPath, - object parameterSource = null) where TBindable : BindableObject + object? source = null, + string? parameterPath = bindingContextPath, + object? parameterSource = null) where TBindable : BindableObject { (var commandProperty, var parameterProperty) = DefaultBindableProperties.GetForCommand(bindable); diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectMultiBindExtensions.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectMultiBindExtensions.cs index 6eeec55b2..fc3bcf9d7 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectMultiBindExtensions.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/BindableObjectMultiBindExtensions.cs @@ -12,12 +12,12 @@ public static class BindableObjectMultiBindExtensions BindableProperty targetProperty, BindingBase binding1, BindingBase binding2, - Func, TDest> convert = null, - Func> convertBack = null, + Func, TDest>? convert = null, + Func>? convertBack = null, BindingMode mode = BindingMode.Default, - string stringFormat = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + string? stringFormat = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject => bindable.Bind( targetProperty, new List { binding1, binding2 }, @@ -34,13 +34,13 @@ public static class BindableObjectMultiBindExtensions BindableProperty targetProperty, BindingBase binding1, BindingBase binding2, - Func, TParam, TDest> convert = null, - Func> convertBack = null, - TParam converterParameter = default, + Func, TParam?, TDest>? convert = null, + Func>? convertBack = null, + TParam? converterParameter = default, BindingMode mode = BindingMode.Default, - string stringFormat = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + string? stringFormat = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject => bindable.Bind( targetProperty, new List { binding1, binding2 }, @@ -58,12 +58,12 @@ public static class BindableObjectMultiBindExtensions BindingBase binding1, BindingBase binding2, BindingBase binding3, - Func, TDest> convert = null, - Func> convertBack = null, + Func, TDest>? convert = null, + Func>? convertBack = null, BindingMode mode = BindingMode.Default, - string stringFormat = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + string? stringFormat = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject => bindable.Bind( targetProperty, new List { binding1, binding2, binding3 }, @@ -81,13 +81,13 @@ public static class BindableObjectMultiBindExtensions BindingBase binding1, BindingBase binding2, BindingBase binding3, - Func, TParam, TDest> convert = null, - Func> convertBack = null, - TParam converterParameter = default, + Func, TParam?, TDest>? convert = null, + Func>? convertBack = null, + TParam? converterParameter = default, BindingMode mode = BindingMode.Default, - string stringFormat = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + string? stringFormat = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject => bindable.Bind( targetProperty, new List { binding1, binding2, binding3 }, @@ -106,12 +106,12 @@ public static class BindableObjectMultiBindExtensions BindingBase binding2, BindingBase binding3, BindingBase binding4, - Func, TDest> convert = null, - Func> convertBack = null, + Func, TDest>? convert = null, + Func>? convertBack = null, BindingMode mode = BindingMode.Default, - string stringFormat = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + string? stringFormat = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject => bindable.Bind( targetProperty, new List { binding1, binding2, binding3, binding4 }, @@ -130,13 +130,13 @@ public static class BindableObjectMultiBindExtensions BindingBase binding2, BindingBase binding3, BindingBase binding4, - Func, TParam, TDest> convert = null, - Func> convertBack = null, - TParam converterParameter = default, + Func, TParam?, TDest>? convert = null, + Func>? convertBack = null, + TParam? converterParameter = default, BindingMode mode = BindingMode.Default, - string stringFormat = null, - TDest targetNullValue = default, - TDest fallbackValue = default) where TBindable : BindableObject + string? stringFormat = null, + TDest? targetNullValue = default, + TDest? fallbackValue = default) where TBindable : BindableObject => bindable.Bind( targetProperty, new List { binding1, binding2, binding3, binding4 }, @@ -153,11 +153,11 @@ public static class BindableObjectMultiBindExtensions BindableProperty targetProperty, IList bindings, IMultiValueConverter converter, - object converterParameter = default, + object? converterParameter = default, BindingMode mode = BindingMode.Default, - string stringFormat = null, - object targetNullValue = null, - object fallbackValue = null) where TBindable : BindableObject + string? stringFormat = null, + object? targetNullValue = null, + object? fallbackValue = null) where TBindable : BindableObject { bindable.SetBinding(targetProperty, new MultiBinding { diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/ElementExtensions.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/ElementExtensions.cs index 05bf63c77..1c0652eb8 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/ElementExtensions.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/ElementExtensions.cs @@ -41,7 +41,7 @@ public static class ElementExtensions public static TElement Effects(this TElement element, params Effect[] effects) where TElement : Element { - for (int i = 0; i < effects.Length; i++) + for (var i = 0; i < effects.Length; i++) element.Effects.Add(effects[i]); return element; } @@ -59,7 +59,7 @@ public static class ElementExtensions public static TFontElement Font( this TFontElement fontElement, - string family = null, + string? family = null, double? size = null, bool? bold = null, bool? italic = null) where TFontElement : Element, IFontElement diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/ElementGesturesExtensions.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/ElementGesturesExtensions.cs index 2aea06ddb..e8d581169 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/ElementGesturesExtensions.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/ElementGesturesExtensions.cs @@ -13,9 +13,9 @@ public static class ElementGesturesExtensions public static TGestureElement BindClickGesture( this TGestureElement gestureElement, string commandPath = bindingContextPath, - object commandSource = null, - string parameterPath = null, - object parameterSource = null) where TGestureElement : Element, IGestureRecognizers + object? commandSource = null, + string? parameterPath = null, + object? parameterSource = null) where TGestureElement : Element, IGestureRecognizers => ClickGesture(gestureElement, g => g.BindCommand(commandPath, commandSource, parameterPath, parameterSource)); /// Add a , @@ -24,9 +24,9 @@ public static class ElementGesturesExtensions public static TGestureElement BindSwipeGesture( this TGestureElement gestureElement, string commandPath = bindingContextPath, - object commandSource = null, - string parameterPath = null, - object parameterSource = null) where TGestureElement : Element, IGestureRecognizers + object? commandSource = null, + string? parameterPath = null, + object? parameterSource = null) where TGestureElement : Element, IGestureRecognizers => SwipeGesture(gestureElement, g => g.BindCommand(commandPath, commandSource, parameterPath, parameterSource)); /// Add a , @@ -35,9 +35,9 @@ public static class ElementGesturesExtensions public static TGestureElement BindTapGesture( this TGestureElement gestureElement, string commandPath = bindingContextPath, - object commandSource = null, - string parameterPath = null, - object parameterSource = null) where TGestureElement : Element, IGestureRecognizers + object? commandSource = null, + string? parameterPath = null, + object? parameterSource = null) where TGestureElement : Element, IGestureRecognizers => TapGesture(gestureElement, g => g.BindCommand(commandPath, commandSource, parameterPath, parameterSource)); /// Add a , diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs index ca14bacbc..d435ea093 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs @@ -6,25 +6,25 @@ namespace Xamarin.CommunityToolkit.Markup { public class FuncConverter : IValueConverter { - readonly Func convert; - readonly Func convertBack; + readonly Func? convert; + readonly Func? convertBack; - readonly Func convertWithParam; - readonly Func convertBackWithParam; + readonly Func? convertWithParam; + readonly Func? convertBackWithParam; - readonly Func convertWithParamAndCulture; - readonly Func convertBackWithParamAndCulture; + readonly Func? convertWithParamAndCulture; + readonly Func? convertBackWithParamAndCulture; - public FuncConverter(Func convertWithParamAndCulture = null, Func convertBackWithParamAndCulture = null) + public FuncConverter(Func? convertWithParamAndCulture = null, Func? convertBackWithParamAndCulture = null) { this.convertWithParamAndCulture = convertWithParamAndCulture; this.convertBackWithParamAndCulture = convertBackWithParamAndCulture; } - public FuncConverter(Func convertWithParam = null, Func convertBackWithParam = null) + public FuncConverter(Func? convertWithParam = null, Func? convertBackWithParam = null) { this.convertWithParam = convertWithParam; this.convertBackWithParam = convertBackWithParam; } - public FuncConverter(Func convert = null, Func convertBack = null) + public FuncConverter(Func? convert = null, Func? convertBack = null) { this.convert = convert; this.convertBack = convertBack; } - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (convert != null) { @@ -50,7 +50,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn return default(TDest); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (convertBack != null) { @@ -79,19 +79,19 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu public class FuncConverter : FuncConverter { - public FuncConverter(Func convert = null, Func convertBack = null) + public FuncConverter(Func? convert = null, Func? convertBack = null) : base(convert, convertBack) { } } public class FuncConverter : FuncConverter { - public FuncConverter(Func convert = null, Func convertBack = null) + public FuncConverter(Func? convert = null, Func? convertBack = null) : base(convert, convertBack) { } } public class FuncConverter : FuncConverter { - public FuncConverter(Func convert = null, Func convertBack = null) + public FuncConverter(Func? convert = null, Func? convertBack = null) : base(convert, convertBack) { } } diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/FuncMultiConverter.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/FuncMultiConverter.cs index d7030c57e..398e36056 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/FuncMultiConverter.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/FuncMultiConverter.cs @@ -6,25 +6,25 @@ namespace Xamarin.CommunityToolkit.Markup { public class FuncMultiConverter : IMultiValueConverter { - readonly Func convert; - readonly Func convertBack; + readonly Func? convert; + readonly Func? convertBack; - readonly Func convertWithParam; - readonly Func convertBackWithParam; + readonly Func? convertWithParam; + readonly Func? convertBackWithParam; - readonly Func convertWithParamAndCulture; - readonly Func convertBackWithParamAndCulture; + readonly Func? convertWithParamAndCulture; + readonly Func? convertBackWithParamAndCulture; - public FuncMultiConverter(Func convertWithParamAndCulture = null, Func convertBackWithParamAndCulture = null) + public FuncMultiConverter(Func? convertWithParamAndCulture = null, Func? convertBackWithParamAndCulture = null) { this.convertWithParamAndCulture = convertWithParamAndCulture; this.convertBackWithParamAndCulture = convertBackWithParamAndCulture; } - public FuncMultiConverter(Func convertWithParam = null, Func convertBackWithParam = null) + public FuncMultiConverter(Func? convertWithParam = null, Func? convertBackWithParam = null) { this.convertWithParam = convertWithParam; this.convertBackWithParam = convertBackWithParam; } - public FuncMultiConverter(Func convert = null, Func convertBack = null) + public FuncMultiConverter(Func? convert = null, Func? convertBack = null) { this.convert = convert; this.convertBack = convertBack; } - public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object[] values, Type targetType, object? parameter, CultureInfo culture) { if (convert != null) return convert(values); @@ -47,7 +47,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur return BindableProperty.UnsetValue; } - public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + public object?[]? ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture) { if (convertBack != null) { @@ -76,85 +76,91 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, public class FuncMultiConverter : FuncMultiConverter { - static T To(object value) => value != null ? (T)value : default; + static T? To(object? value) => value != null ? (T)value : default; - static object[] ToObjects(ValueTuple values) => new object[] { values.Item1, values.Item2 }; + static object?[] ToObjects(ValueTuple values) => new object?[] { values.Item1, values.Item2 }; public FuncMultiConverter( - Func, TDest> convert = null, - Func> convertBack = null) + Func, TDest>? convert = null, + Func>? convertBack = null) : base( convert == null ? default(Func) : (object[] values) => convert((To(values[0]), To(values[1]))), - convertBack == null ? default(Func) : (TDest value) => ToObjects(convertBack(value))) { } + convertBack == null ? default(Func) : (TDest? value) => ToObjects(convertBack(value))) + { } } public class FuncMultiConverter : FuncMultiConverter { - static T To(object value) => value != null ? (T)value : default; + static T? To(object? value) => value != null ? (T)value : default; - static object[] ToObjects(ValueTuple values) => new object[] { values.Item1, values.Item2, values.Item3 }; + static object?[] ToObjects(ValueTuple values) => new object?[] { values.Item1, values.Item2, values.Item3 }; public FuncMultiConverter( - Func, TDest> convert = null, - Func> convertBack = null) + Func, TDest>? convert = null, + Func>? convertBack = null) : base( convert == null ? default(Func) : (object[] values) => convert((To(values[0]), To(values[1]), To(values[2]))), - convertBack == null ? default(Func) : (TDest value) => ToObjects(convertBack(value))) { } + convertBack == null ? default(Func) : (TDest? value) => ToObjects(convertBack(value))) + { } } public class FuncMultiConverter : FuncMultiConverter { - static T To(object value) => value != null ? (T)value : default; + static T? To(object? value) => value != null ? (T)value : default; - static object[] ToObjects(ValueTuple values) => new object[] { values.Item1, values.Item2, values.Item3, values.Item4 }; + static object?[] ToObjects(ValueTuple values) => new object?[] { values.Item1, values.Item2, values.Item3, values.Item4 }; public FuncMultiConverter( - Func, TDest> convert = null, - Func> convertBack = null) + Func, TDest>? convert = null, + Func>? convertBack = null) : base( convert == null ? default(Func) : (object[] values) => convert((To(values[0]), To(values[1]), To(values[2]), To(values[3]))), - convertBack == null ? default(Func) : (TDest value) => ToObjects(convertBack(value))) { } + convertBack == null ? default(Func) : (TDest? value) => ToObjects(convertBack(value))) + { } } public class FuncMultiConverterWithParam : FuncMultiConverter { - static T To(object value) => value != null ? (T)value : default; + static T? To(object? value) => value != null ? (T)value : default; - static object[] ToObjects(ValueTuple values) => new object[] { values.Item1, values.Item2 }; + static object?[] ToObjects(ValueTuple values) => new object?[] { values.Item1, values.Item2 }; public FuncMultiConverterWithParam( - Func, TParam, TDest> convert = null, - Func> convertBack = null) + Func, TParam?, TDest>? convert = null, + Func>? convertBack = null) : base( - convert == null ? default(Func) : (object[] values, TParam param) => convert((To(values[0]), To(values[1])), param), - convertBack == null ? default(Func) : (TDest value, TParam param) => ToObjects(convertBack(value, param))) { } + convert == null ? default(Func) : (object[] values, TParam? param) => convert((To(values[0]), To(values[1])), param), + convertBack == null ? default(Func) : (TDest? value, TParam? param) => ToObjects(convertBack(value, param))) + { } } public class FuncMultiConverterWithParam : FuncMultiConverter { - static T To(object value) => value != null ? (T)value : default; + static T? To(object value) => value != null ? (T)value : default; - static object[] ToObjects(ValueTuple values) => new object[] { values.Item1, values.Item2, values.Item3 }; + static object?[] ToObjects(ValueTuple values) => new object?[] { values.Item1, values.Item2, values.Item3 }; public FuncMultiConverterWithParam( - Func, TParam, TDest> convert = null, - Func> convertBack = null) + Func, TParam?, TDest>? convert = null, + Func>? convertBack = null) : base( - convert == null ? default(Func) : (object[] values, TParam param) => convert((To(values[0]), To(values[1]), To(values[2])), param), - convertBack == null ? default(Func) : (TDest value, TParam param) => ToObjects(convertBack(value, param))) { } + convert == null ? default(Func) : (object[] values, TParam? param) => convert((To(values[0]), To(values[1]), To(values[2])), param), + convertBack == null ? default(Func) : (TDest? value, TParam? param) => ToObjects(convertBack(value, param))) + { } } public class FuncMultiConverterWithParam : FuncMultiConverter { - static T To(object value) => value != null ? (T)value : default; + static T? To(object? value) => value != null ? (T)value : default; - static object[] ToObjects(ValueTuple values) => new object[] { values.Item1, values.Item2, values.Item3, values.Item4 }; + static object?[] ToObjects(ValueTuple values) => new object?[] { values.Item1, values.Item2, values.Item3, values.Item4 }; public FuncMultiConverterWithParam( - Func, TParam, TDest> convert = null, - Func> convertBack = null) + Func, TParam?, TDest>? convert = null, + Func>? convertBack = null) : base( - convert == null ? default(Func) : (object[] values, TParam param) => convert((To(values[0]), To(values[1]), To(values[2]), To(values[3])), param), - convertBack == null ? default(Func) : (TDest value, TParam param) => ToObjects(convertBack(value, param))) { } + convert == null ? default(Func) : (object[] values, TParam? param) => convert((To(values[0]), To(values[1]), To(values[2]), To(values[3])), param), + convertBack == null ? default(Func) : (TDest? value, TParam? param) => ToObjects(convertBack(value, param))) + { } } } \ No newline at end of file diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/RelativeLayout.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/RelativeLayout.cs index a5a3789a7..83f618f17 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/RelativeLayout.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/RelativeLayout.cs @@ -42,14 +42,14 @@ public class BoundsConstrainedView : ConstrainedView readonly Bounds bounds; public BoundsConstrainedView(View view, Bounds bounds) - : base(view) { this.bounds = bounds; } + : base(view) => this.bounds = bounds; public override void AddTo(RelativeLayout layout) => layout.Children.Add(view, bounds); } public class ExpressionsConstrainedView : ConstrainedView { - Expression x, y, width, height; + Expression? x, y, width, height; public ExpressionsConstrainedView(View view) : base(view) { } @@ -67,7 +67,7 @@ public ExpressionsConstrainedView(View view) public class ConstraintsConstrainedView : ConstrainedView { - Constraint x, y, width, height; + Constraint? x, y, width, height; public ConstraintsConstrainedView(View view) : base(view) { } @@ -103,7 +103,7 @@ public abstract class ConstrainedView { protected readonly View view; - protected ConstrainedView(View view) { this.view = view; } + protected ConstrainedView(View view) => this.view = view; public abstract void AddTo(RelativeLayout layout); } diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/Style.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/Style.cs index e640f7ed3..66b7722f5 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/Style.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/Style.cs @@ -4,7 +4,7 @@ namespace Xamarin.CommunityToolkit.Markup { public class Style where T : BindableObject { - public static implicit operator Style(Style style) => style?.FormsStyle; + public static implicit operator Style?(Style? style) => style?.FormsStyle; public Style FormsStyle { get; } diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj b/src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj index 93991dd56..60d2281de 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj @@ -32,6 +32,9 @@ true xamarin,xamarin.forms,toolkit,kit,communitytoolkit,xamarincommunitytoolkit,markup,csharpformarkup,csharp,csharpmarkup Debug;Release + enable + nullable + latest From 5befb6fc023f86f4eeaf037ee379b78b6057e16d Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:36:19 -0800 Subject: [PATCH 03/13] Enable Nullable on Xamarin.CommunityToolkit.Sample --- samples/XCT.Sample/Helpers/RelayCommand.cs | 84 ++++--- samples/XCT.Sample/Helpers/XLog.cs | 26 +-- .../BoolToObjectConverterPage.xaml.cs | 14 +- .../DoubleToIntConverterPage.xaml.cs | 14 +- .../EnumToBoolConverterPage.xaml.cs | 13 +- .../Converters/EqualConverterPage.xaml.cs | 14 +- .../IndexToArrayItemConverterPage.xaml.cs | 14 +- .../Converters/IntToBoolConverterPage.xaml.cs | 14 +- .../InvertedBoolConverterPage.xaml.cs | 7 +- .../IsNotNullOrEmptyConverterPage.xaml.cs | 14 +- .../ListToStringConverterPage.xaml.cs | 14 +- .../Converters/NotEqualConverterPage.xaml.cs | 14 +- .../Converters/TextCaseConverterPage.xaml.cs | 7 +- .../Pages/Effects/ShadowEffectPage.xaml.cs | 8 +- .../Pages/Markup/SearchPage.logic.cs | 6 +- .../TestCases/MediaElementSourcePage.xaml.cs | 14 +- .../TouchEffectCollectionViewPage.xaml.cs | 17 +- .../Pages/Views/SnackBarPage.xaml.cs | 1 + .../XCT.Sample/ViewModels/AboutViewModel.cs | 6 +- .../ViewModels/Base/BaseGalleryViewModel.cs | 4 +- .../MaxLengthReachedBehaviorViewModel.cs | 2 +- .../ProgressBarAnimationBehaviorViewModel.cs | 34 ++- .../UserStoppedTypingBehaviorViewModel.cs | 6 +- .../ByteArrayToImageSourceViewModel.cs | 4 +- .../EnumToBoolConverterViewModel.cs | 42 ++-- .../IndexToArrayItemConverterViewModel.cs | 4 +- .../IsNullOrEmptyConverterViewModel.cs | 14 +- .../ItemTappedEventArgsViewModel.cs | 15 +- .../VariableMultiValueConverterViewModel.cs | 3 +- .../Effects/EffectsGalleryViewModel.cs | 11 +- .../ViewModels/Markup/SearchViewModel.cs | 13 +- .../XCT.Sample/ViewModels/SettingViewModel.cs | 37 ++-- .../ViewModels/Views/ExpanderViewModel.cs | 2 +- .../ViewModels/Views/PopupControlViewModel.cs | 5 +- .../ViewModels/Views/StateLayoutViewModel.cs | 2 +- .../Views/TabItemsSourceViewModel.cs | 205 +++++++++--------- .../Views/Tabs/LazyTestViewModel.cs | 2 +- .../Views/Tabs/NormalTestViewModel.cs | 2 +- .../Xamarin.CommunityToolkit.Sample.csproj | 4 + 39 files changed, 304 insertions(+), 408 deletions(-) diff --git a/samples/XCT.Sample/Helpers/RelayCommand.cs b/samples/XCT.Sample/Helpers/RelayCommand.cs index 453460545..ed556ddf8 100644 --- a/samples/XCT.Sample/Helpers/RelayCommand.cs +++ b/samples/XCT.Sample/Helpers/RelayCommand.cs @@ -7,25 +7,21 @@ namespace Xamarin.CommunityToolkit.Sample { public class RelayCommand : ICommand { - readonly Action execute; - readonly Func asyncExecute; + readonly Action? execute; + readonly Func? asyncExecute; + readonly Func? canExecute; - Func canExecute; int executingCount; - public RelayCommand(Action execute, Func canExecute = null) + public RelayCommand(Action execute, Func? canExecute = null) { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - this.execute = execute; + this.execute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } - protected RelayCommand(Func execute, Func canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity + protected RelayCommand(Func execute, Func? canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - asyncExecute = execute; + asyncExecute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } @@ -34,7 +30,7 @@ public RelayCommand(Action execute, Func canExecute = null) /// /// Ignored; this is the paremeterless command class /// - public bool CanExecute(object parameter = null) + public bool CanExecute(object? parameter = null) { try { @@ -47,15 +43,12 @@ public bool CanExecute(object parameter = null) } } - public event EventHandler CanExecuteChanged; + public event EventHandler? CanExecuteChanged; - public void RaiseCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } + public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); // Asynchronous command handling based on http://stackoverflow.com/a/31595509/6043538 - public async void Execute(object parameter = null) + public async void Execute(object? parameter = null) { var couldExecuteBeforeExecute = CanExecute(); if (!couldExecuteBeforeExecute) @@ -70,8 +63,10 @@ public async void Execute(object parameter = null) { if (execute != null) execute(); - else + else if (asyncExecute != null) await asyncExecute(); + else + throw new Exception("Execute is null"); } catch (Exception ex) { @@ -89,31 +84,30 @@ public async void Execute(object parameter = null) public class RelayCommandAsync : RelayCommand { - public RelayCommandAsync(Func execute, Func canExecute = null) - : base(execute, canExecute) { } // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + public RelayCommandAsync(Func execute, Func? canExecute = null) + : base(execute, canExecute) + { + // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + } } public class RelayCommand : ICommand { - readonly Action execute; - readonly Func asyncExecute; + readonly Action? execute; + readonly Func? asyncExecute; + readonly Func? canExecute; - Func canExecute; int executingCount; - public RelayCommand(Action execute, Func canExecute = null) + public RelayCommand(Action execute, Func? canExecute = null) { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - this.execute = execute; + this.execute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } - protected RelayCommand(Func execute, Func canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity + protected RelayCommand(Func execute, Func? canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - asyncExecute = execute; + asyncExecute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } @@ -122,11 +116,11 @@ public RelayCommand(Action execute, Func canExecut /// /// /// - public bool CanExecute(object parameter = null) + public bool CanExecute(object? parameter = null) { try { - return canExecute != null ? canExecute((TParameter)parameter) : executingCount == 0; + return canExecute != null ? canExecute((TParameter?)parameter) : executingCount == 0; } catch (Exception ex) { @@ -135,12 +129,9 @@ public bool CanExecute(object parameter = null) } } - public event EventHandler CanExecuteChanged; + public event EventHandler? CanExecuteChanged; - public void RaiseCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } + public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); // Asynchronous command handling based on http://stackoverflow.com/a/31595509/6043538 public async void Execute(object parameterAsObject) @@ -159,13 +150,11 @@ public async void Execute(object parameterAsObject) var parameter = (TParameter)parameterAsObject; if (execute != null) - { execute(parameter); - } + else if (asyncExecute != null) + await asyncExecute.Invoke(parameter); else - { - await asyncExecute(parameter); - } + throw new Exception("Execute is null"); } catch (Exception ex) { @@ -183,7 +172,10 @@ public async void Execute(object parameterAsObject) public class RelayCommandAsync : RelayCommand { - public RelayCommandAsync(Func execute, Func canExecute = null) - : base(execute, canExecute) { } // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + public RelayCommandAsync(Func execute, Func? canExecute = null) + : base(execute, canExecute) + { + // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + } } } \ No newline at end of file diff --git a/samples/XCT.Sample/Helpers/XLog.cs b/samples/XCT.Sample/Helpers/XLog.cs index 88dd1c65c..79e77b027 100644 --- a/samples/XCT.Sample/Helpers/XLog.cs +++ b/samples/XCT.Sample/Helpers/XLog.cs @@ -13,7 +13,7 @@ namespace Xamarin.CommunityToolkit.Sample /// public static class XLog { - static string rootFolderPattern = null; + static string? rootFolderPattern = null; #if WINDOWS_UWP static LoggingChannel loggingChannel; #endif @@ -22,7 +22,7 @@ public static class XLog /// Call this before logging starts. /// /// Should match the top folder name(s) within the source control repository, e.g. @"\MobileRealtimePush\MobileRealtimePush\". Any folders before the first match of this pattern are omitted from the logged source file paths - public static void Init(string rootFolderPattern = null) + public static void Init(string? rootFolderPattern = null) { XLog.rootFolderPattern = rootFolderPattern; #if WINDOWS_UWP @@ -46,10 +46,10 @@ public static void Init(string rootFolderPattern = null) /// supplied by compiler, no need to specify in code unless you want to pass a deeper call context [Conditional("DEBUG")] public static void Debug( - object data = null, - string tag = null, - [CallerMemberName] string memberName = null, - [CallerFilePath] string sourceFilePath = null, + object? data = null, + string? tag = null, + [CallerMemberName] string? memberName = null, + [CallerFilePath] string? sourceFilePath = null, [CallerLineNumber] int sourceLineNumber = -1) { var message = FormatLogString(data, tag, memberName, sourceFilePath, sourceLineNumber); @@ -75,10 +75,10 @@ public static void Init(string rootFolderPattern = null) /// supplied by compiler, no need to specify in code unless you want to pass a deeper call context [Conditional("TRACE")] public static void Trace( - object data = null, - string tag = null, - [CallerMemberName] string memberName = null, - [CallerFilePath] string sourceFilePath = null, + object? data = null, + string? tag = null, + [CallerMemberName] string? memberName = null, + [CallerFilePath] string? sourceFilePath = null, [CallerLineNumber] int sourceLineNumber = -1) { var message = FormatLogString(data, tag, memberName, sourceFilePath, sourceLineNumber); @@ -90,9 +90,9 @@ public static void Init(string rootFolderPattern = null) #endif } - public static string TruncateAt(this string s, int maxLength, string truncatedSuffix = "...") => s?.Length <= maxLength ? s : s.Substring(0, maxLength) + truncatedSuffix; + public static string TruncateAt(this string? s, int maxLength, string truncatedSuffix = "...") => s?.Length <= maxLength ? s : s?.Substring(0, maxLength) + truncatedSuffix; - static string FormatLogString(object data = null, string tag = null, string memberName = null, string sourceFilePath = null, int sourceLineNumber = -1) + static string FormatLogString(object? data, string? tag, string? memberName, string? sourceFilePath, int sourceLineNumber) { var line = new StringBuilder(); @@ -121,7 +121,7 @@ static string FormatLogString(object data = null, string tag = null, string memb line.Append(dataString); } - if (!string.IsNullOrEmpty(sourceFilePath)) + if (sourceFilePath != null && !string.IsNullOrEmpty(sourceFilePath)) { if (!string.IsNullOrEmpty(rootFolderPattern)) { diff --git a/samples/XCT.Sample/Pages/Converters/BoolToObjectConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/BoolToObjectConverterPage.xaml.cs index f2ecfdbe0..eca12a485 100644 --- a/samples/XCT.Sample/Pages/Converters/BoolToObjectConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/BoolToObjectConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class BoolToObjectConverterPage + public partial class BoolToObjectConverterPage { - public BoolToObjectConverterPage() - { - InitializeComponent(); - } + public BoolToObjectConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/DoubleToIntConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/DoubleToIntConverterPage.xaml.cs index 01aa699eb..fd29fb21d 100644 --- a/samples/XCT.Sample/Pages/Converters/DoubleToIntConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/DoubleToIntConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class DoubleToIntConverterPage + public partial class DoubleToIntConverterPage { - public DoubleToIntConverterPage() - { - InitializeComponent(); - } + public DoubleToIntConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/EnumToBoolConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/EnumToBoolConverterPage.xaml.cs index 65eb2fa3d..bad3953b4 100644 --- a/samples/XCT.Sample/Pages/Converters/EnumToBoolConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/EnumToBoolConverterPage.xaml.cs @@ -1,10 +1,7 @@ -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class EnumToBoolConverterPage - { - public EnumToBoolConverterPage() - { - InitializeComponent(); - } - } + public partial class EnumToBoolConverterPage + { + public EnumToBoolConverterPage() => InitializeComponent(); + } } \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Converters/EqualConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/EqualConverterPage.xaml.cs index 3753f43fd..231772eea 100644 --- a/samples/XCT.Sample/Pages/Converters/EqualConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/EqualConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class EqualConverterPage + public partial class EqualConverterPage { - public EqualConverterPage() - { - InitializeComponent(); - } + public EqualConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/IndexToArrayItemConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/IndexToArrayItemConverterPage.xaml.cs index 875cb4d9c..ba36595f5 100644 --- a/samples/XCT.Sample/Pages/Converters/IndexToArrayItemConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/IndexToArrayItemConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class IndexToArrayItemConverterPage + public partial class IndexToArrayItemConverterPage { - public IndexToArrayItemConverterPage() - { - InitializeComponent(); - } + public IndexToArrayItemConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/IntToBoolConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/IntToBoolConverterPage.xaml.cs index 298700e29..669fe5f66 100644 --- a/samples/XCT.Sample/Pages/Converters/IntToBoolConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/IntToBoolConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class IntToBoolConverterPage + public partial class IntToBoolConverterPage { - public IntToBoolConverterPage() - { - InitializeComponent(); - } + public IntToBoolConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/InvertedBoolConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/InvertedBoolConverterPage.xaml.cs index 0f5c5935a..9c338ea2e 100644 --- a/samples/XCT.Sample/Pages/Converters/InvertedBoolConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/InvertedBoolConverterPage.xaml.cs @@ -1,10 +1,7 @@ namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class InvertedBoolConverterPage + public partial class InvertedBoolConverterPage { - public InvertedBoolConverterPage() - { - InitializeComponent(); - } + public InvertedBoolConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/IsNotNullOrEmptyConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/IsNotNullOrEmptyConverterPage.xaml.cs index 2387d5c39..b3a0d5c36 100644 --- a/samples/XCT.Sample/Pages/Converters/IsNotNullOrEmptyConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/IsNotNullOrEmptyConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class IsNotNullOrEmptyConverterPage + public partial class IsNotNullOrEmptyConverterPage { - public IsNotNullOrEmptyConverterPage() - { - InitializeComponent(); - } + public IsNotNullOrEmptyConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/ListToStringConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/ListToStringConverterPage.xaml.cs index 775386057..4280638e0 100644 --- a/samples/XCT.Sample/Pages/Converters/ListToStringConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/ListToStringConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class ListToStringConverterPage + public partial class ListToStringConverterPage { - public ListToStringConverterPage() - { - InitializeComponent(); - } + public ListToStringConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/NotEqualConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/NotEqualConverterPage.xaml.cs index a2d56d681..e1d362d38 100644 --- a/samples/XCT.Sample/Pages/Converters/NotEqualConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/NotEqualConverterPage.xaml.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace Xamarin.CommunityToolkit.Sample.Pages.Converters +namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class NotEqualConverterPage + public partial class NotEqualConverterPage { - public NotEqualConverterPage() - { - InitializeComponent(); - } + public NotEqualConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Converters/TextCaseConverterPage.xaml.cs b/samples/XCT.Sample/Pages/Converters/TextCaseConverterPage.xaml.cs index 079919177..8018c6196 100644 --- a/samples/XCT.Sample/Pages/Converters/TextCaseConverterPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Converters/TextCaseConverterPage.xaml.cs @@ -1,10 +1,7 @@ namespace Xamarin.CommunityToolkit.Sample.Pages.Converters { - public partial class TextCaseConverterPage + public partial class TextCaseConverterPage { - public TextCaseConverterPage() - { - InitializeComponent(); - } + public TextCaseConverterPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Effects/ShadowEffectPage.xaml.cs b/samples/XCT.Sample/Pages/Effects/ShadowEffectPage.xaml.cs index c3f683297..d8e62916b 100644 --- a/samples/XCT.Sample/Pages/Effects/ShadowEffectPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Effects/ShadowEffectPage.xaml.cs @@ -1,11 +1,7 @@ - -namespace Xamarin.CommunityToolkit.Sample.Pages.Effects +namespace Xamarin.CommunityToolkit.Sample.Pages.Effects { public partial class ShadowEffectPage { - public ShadowEffectPage() - { - InitializeComponent(); - } + public ShadowEffectPage() => InitializeComponent(); } } diff --git a/samples/XCT.Sample/Pages/Markup/SearchPage.logic.cs b/samples/XCT.Sample/Pages/Markup/SearchPage.logic.cs index 1960071c3..d7ea4e911 100644 --- a/samples/XCT.Sample/Pages/Markup/SearchPage.logic.cs +++ b/samples/XCT.Sample/Pages/Markup/SearchPage.logic.cs @@ -9,21 +9,21 @@ namespace Xamarin.CommunityToolkit.Sample public partial class SearchPage : BasePage { readonly SearchViewModel vm; - View header; + View? header; public SearchPage() { On().SetUseSafeArea(true); BackgroundColor = Color.Black; - BindingContext = new SearchViewModel(); + BindingContext = vm = new SearchViewModel(); Build(); } void Search_FocusChanged(object sender, FocusEventArgs e) { ViewExtensions.CancelAnimations(header); - header.TranslateTo(e.IsFocused ? -56 : 0, 0, 250, Easing.CubicOut); + header?.TranslateTo(e.IsFocused ? -56 : 0, 0, 250, Easing.CubicOut); } } } \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs b/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs index 39d015c1c..35799ea00 100644 --- a/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs +++ b/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs @@ -1,23 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xamarin.CommunityToolkit.Core; +using Xamarin.CommunityToolkit.Core; using Xamarin.Forms; -using Xamarin.Forms.Xaml; namespace Xamarin.CommunityToolkit.Sample.Pages.TestCases { public partial class MediaElementSourcePage { - public MediaElementSourcePage() - { - InitializeComponent(); - } + public MediaElementSourcePage() => InitializeComponent(); } - class MediaElementViewModel : BindableObject { public string VideoAsString { get; set; } = "https://tipcalculator.appwithkiss.com/video/Hint_1_2_EN_12.mov"; diff --git a/samples/XCT.Sample/Pages/TestCases/TouchEffectCollectionViewPage.xaml.cs b/samples/XCT.Sample/Pages/TestCases/TouchEffectCollectionViewPage.xaml.cs index ada32eb11..78b5f8c86 100644 --- a/samples/XCT.Sample/Pages/TestCases/TouchEffectCollectionViewPage.xaml.cs +++ b/samples/XCT.Sample/Pages/TestCases/TouchEffectCollectionViewPage.xaml.cs @@ -1,19 +1,16 @@ - -using System.Windows.Input; -using Xamarin.Forms; +using System.Windows.Input; +using Xamarin.CommunityToolkit.ObjectModel; namespace Xamarin.CommunityToolkit.Sample.Pages.TestCases { public partial class TouchEffectCollectionViewPage { - ICommand longPressCommand; - public TouchEffectCollectionViewPage() - => InitializeComponent(); - - public ICommand LongPressCommand => longPressCommand ??= new Command(() => { - this.DisplayAlert("Long Press", null, "OK"); - }); + InitializeComponent(); + LongPressCommand = new AsyncCommand(() => DisplayAlert("Long Press", null, "OK")); + } + + public ICommand LongPressCommand { get; } } } diff --git a/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs b/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs index 7a6247a4a..a0c74f101 100644 --- a/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs +++ b/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs @@ -40,6 +40,7 @@ async void DisplaySnackBarWithPadding(object sender, EventArgs args) await this.DisplaySnackBarAsync(options); } + async void DisplayToastClicked(object sender, EventArgs args) { await this.DisplayToastAsync(GenerateLongText(5)); diff --git a/samples/XCT.Sample/ViewModels/AboutViewModel.cs b/samples/XCT.Sample/ViewModels/AboutViewModel.cs index e7d242b4c..b7133e5e9 100644 --- a/samples/XCT.Sample/ViewModels/AboutViewModel.cs +++ b/samples/XCT.Sample/ViewModels/AboutViewModel.cs @@ -12,9 +12,9 @@ public class AboutViewModel : BaseViewModel { readonly GitHubClient gitHubClient = new GitHubClient(new ProductHeaderValue("XamarinCommunityToolkitSample")); - RepositoryContributor[] contributors = new RepositoryContributor[0]; + RepositoryContributor[] contributors = Array.Empty(); - RepositoryContributor selectedContributor; + RepositoryContributor? selectedContributor; string emptyViewText = "Loading data..."; @@ -37,7 +37,7 @@ public RepositoryContributor[] Contributors set => SetProperty(ref contributors, value); } - public RepositoryContributor SelectedContributor + public RepositoryContributor? SelectedContributor { get => selectedContributor; set => SetProperty(ref selectedContributor, value); diff --git a/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs index 249ebdc5c..e04cb7f92 100644 --- a/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs @@ -20,9 +20,9 @@ public BaseGalleryViewModel() public ICommand FilterCommand { get; } - public string FilterValue { private get; set; } + public string FilterValue { private get; set; } = string.Empty; - public IEnumerable FilteredItems { get; private set; } + public IEnumerable FilteredItems { get; private set; } = Array.Empty(); protected abstract IEnumerable CreateItems(); diff --git a/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs index 299e48459..af0555810 100644 --- a/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs @@ -6,7 +6,7 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors { public class MaxLengthReachedBehaviorViewModel : BaseViewModel { - string commandExecutions; + string commandExecutions = string.Empty; public string CommandExecutions { diff --git a/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs index 5e2d5680d..4e950d778 100644 --- a/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs @@ -1,37 +1,31 @@ -using System; -using System.Threading.Tasks; -using System.Windows.Input; -using Xamarin.CommunityToolkit.ObjectModel; +using System.Windows.Input; +using Xamarin.Forms; namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors { public class ProgressBarAnimationBehaviorViewModel : BaseViewModel { double progress; - ICommand setTo0Command; - ICommand setTo50Command; - ICommand setTo100Command; - public double Progress + public ProgressBarAnimationBehaviorViewModel() { - get => progress; - set - { - progress = value; - OnPropertyChanged(); - } + SetTo0Command = new Command(() => SetProgress(0)); + SetTo50Command = new Command(() => SetProgress(0.5)); + SetTo100Command = new Command(() => SetProgress(1)); } - public ICommand SetTo0Command => setTo0Command ??= new AsyncCommand(() => SetProgress(0)); + public ICommand SetTo0Command { get; } - public ICommand SetTo50Command => setTo50Command ??= new AsyncCommand(() => SetProgress(0.5)); + public ICommand SetTo50Command { get; } - public ICommand SetTo100Command => setTo100Command ??= new AsyncCommand(() => SetProgress(1)); + public ICommand SetTo100Command { get; } - async Task SetProgress(double - progress) + public double Progress { - Progress = progress; + get => progress; + set => SetProperty(ref progress, value); } + + void SetProgress(double progress) => Progress = progress; } } \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Behaviors/UserStoppedTypingBehaviorViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/UserStoppedTypingBehaviorViewModel.cs index 816bc670c..8ce3761d1 100644 --- a/samples/XCT.Sample/ViewModels/Behaviors/UserStoppedTypingBehaviorViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Behaviors/UserStoppedTypingBehaviorViewModel.cs @@ -6,9 +6,7 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors { public class UserStoppedTypingBehaviorViewModel : BaseViewModel { - #region Properties - - string performedSearches; + string performedSearches = string.Empty; public string PerformedSearches { @@ -18,8 +16,6 @@ public string PerformedSearches public ICommand SearchCommand { get; } - #endregion Properties - public UserStoppedTypingBehaviorViewModel() => SearchCommand = CommandFactory.Create(PerformSearch); diff --git a/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs index a7e7ef2bb..44385785e 100644 --- a/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs @@ -11,9 +11,9 @@ public class ByteArrayToImageSourceViewModel : BaseViewModel { readonly GitHubClient gitHubClient = new GitHubClient(new ProductHeaderValue("XamarinCommunityToolkitSample")); - byte[] avatar; + byte[]? avatar; - public byte[] Avatar + public byte[]? Avatar { get => avatar; set => SetProperty(ref avatar, value); diff --git a/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs index 3f2a86794..872968358 100644 --- a/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs @@ -1,25 +1,25 @@ -namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters +namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters { - public class EnumToBoolConverterViewModel : BaseViewModel - { - private IssueState selectedState = IssueState.None; + public class EnumToBoolConverterViewModel : BaseViewModel + { + private IssueState selectedState = IssueState.None; - public IssueState SelectedState - { - get => selectedState; - set => SetProperty(ref selectedState, value); - } - } + public IssueState SelectedState + { + get => selectedState; + set => SetProperty(ref selectedState, value); + } + } - public enum IssueState - { - None = 0, - New = 1, - Open = 2, - Waiting = 3, - Developing = 4, - WantFix = 5, - Rejected = 6, - Resolved = 7 - } + public enum IssueState + { + None = 0, + New = 1, + Open = 2, + Waiting = 3, + Developing = 4, + WantFix = 5, + Rejected = 6, + Resolved = 7 + } } \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Converters/IndexToArrayItemConverterViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/IndexToArrayItemConverterViewModel.cs index 115b7eecb..bca6995d3 100644 --- a/samples/XCT.Sample/ViewModels/Converters/IndexToArrayItemConverterViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/IndexToArrayItemConverterViewModel.cs @@ -1,9 +1,9 @@ -using System; -namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters +namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters { public class IndexToArrayItemConverterViewModel : BaseViewModel { int index; + public int Index { get => index; diff --git a/samples/XCT.Sample/ViewModels/Converters/IsNullOrEmptyConverterViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/IsNullOrEmptyConverterViewModel.cs index c2efb0616..03aa7b628 100644 --- a/samples/XCT.Sample/ViewModels/Converters/IsNullOrEmptyConverterViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/IsNullOrEmptyConverterViewModel.cs @@ -7,7 +7,11 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters { public class IsNullOrEmptyConverterViewModel : BaseViewModel { - public ObservableCollection DummyItemSource { get; set; } = new ObservableCollection + string? selectedItem; + + public IsNullOrEmptyConverterViewModel() => ClearSelectionCommand = new Command(() => SelectedItem = null); + + public ObservableCollection DummyItemSource { get; } = new ObservableCollection { "Dummy Item 0", "Dummy Item 1", @@ -17,16 +21,12 @@ public class IsNullOrEmptyConverterViewModel : BaseViewModel "Dummy Item 5", }; - string selectedItem; + public ICommand ClearSelectionCommand { get; } - public string SelectedItem + public string? SelectedItem { get => selectedItem; set => SetProperty(ref selectedItem, value); } - - ICommand clearSelectionCommand; - - public ICommand ClearSelectionCommand => clearSelectionCommand ??= new Command(() => SelectedItem = null); } } diff --git a/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs index 8aa56632b..42500cfd7 100644 --- a/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs @@ -7,13 +7,12 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters { public class ItemTappedEventArgsViewModel { - public IEnumerable Items { get; } = - new List() - { - new Person() { Id = 1, Name = "Person 1" }, - new Person() { Id = 2, Name = "Person 2" }, - new Person() { Id = 3, Name = "Person 3" } - }; + public IEnumerable Items { get; } = new List() + { + new Person() { Id = 1, Name = "Person 1" }, + new Person() { Id = 2, Name = "Person 2" }, + new Person() { Id = 3, Name = "Person 3" } + }; public ICommand ItemTappedCommand { get; } = CommandFactory.Create(person => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person.Name, "Cancel")); @@ -23,6 +22,6 @@ public class Person { public int Id { get; set; } - public string Name { get; set; } + public string Name { get; set; } = string.Empty; } } \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Converters/VariableMultiValueConverterViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/VariableMultiValueConverterViewModel.cs index 6606443d2..5b1feabf6 100644 --- a/samples/XCT.Sample/ViewModels/Converters/VariableMultiValueConverterViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/VariableMultiValueConverterViewModel.cs @@ -1,5 +1,4 @@ -using System; -namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters +namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters { public class VariableMultiValueConverterViewModel : BaseViewModel { diff --git a/samples/XCT.Sample/ViewModels/Effects/EffectsGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Effects/EffectsGalleryViewModel.cs index 9fadd562a..38a70cdb3 100644 --- a/samples/XCT.Sample/ViewModels/Effects/EffectsGalleryViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Effects/EffectsGalleryViewModel.cs @@ -32,20 +32,17 @@ public class EffectsGalleryViewModel : BaseGalleryViewModel new SectionModel( typeof(TouchEffectPage), nameof(TouchEffect), - "The TouchEffect is an effect that allows changing the view's appearance depending on the touch state (normal, pressed, hovered). Also, it allows to handle long presses." - ), + "The TouchEffect is an effect that allows changing the view's appearance depending on the touch state (normal, pressed, hovered). Also, it allows to handle long presses."), new SectionModel( typeof(LifeCycleEffectPage), nameof(LifecycleEffect), - "The LifeCycle is an effect that allows you to know when a control or layout is loaded or/and unloaded in the screen and perform actions based on that." - ), - + "The LifeCycle is an effect that allows you to know when a control or layout is loaded or/and unloaded in the screen and perform actions based on that."), + new SectionModel( typeof(ShadowEffectPage), nameof(ShadowEffect), - "The ShadowEffect allows all views to display shadow."), - + "The ShadowEffect allows all views to display shadow.") }; } } \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Markup/SearchViewModel.cs b/samples/XCT.Sample/ViewModels/Markup/SearchViewModel.cs index 132006d9a..481dba3d4 100644 --- a/samples/XCT.Sample/ViewModels/Markup/SearchViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Markup/SearchViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Xamarin.Essentials; @@ -67,7 +68,9 @@ public SearchViewModel() public ICommand OpenHelpCommand { get; } - void Back() { } + void Back() + { + } void Like(Tweet tweet) => tweet.IsLikedByMe = !tweet.IsLikedByMe; @@ -77,18 +80,18 @@ public SearchViewModel() public class Tweet : BaseViewModel { - public string AuthorImage { get; set; } + public string AuthorImage { get; set; } = string.Empty; - public string Header { get; set; } + public string Header { get; set; } = string.Empty; - public List Body { get; set; } + public List Body { get; set; } = Enumerable.Empty().ToList(); public bool IsLikedByMe { get; set; } } public class TextFragment { - public string Text { get; set; } + public string Text { get; set; } = string.Empty; public bool IsMatch { get; set; } } diff --git a/samples/XCT.Sample/ViewModels/SettingViewModel.cs b/samples/XCT.Sample/ViewModels/SettingViewModel.cs index 5324b25cd..ba9646adf 100644 --- a/samples/XCT.Sample/ViewModels/SettingViewModel.cs +++ b/samples/XCT.Sample/ViewModels/SettingViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Windows.Input; @@ -12,26 +13,10 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels { public class SettingViewModel : BaseViewModel { - IList supportedLanguages; - - public IList SupportedLanguages - { - get => supportedLanguages; - private set => SetProperty(ref supportedLanguages, value); - } + IList supportedLanguages = Array.Empty(); Language selectedLanguage; - public Language SelectedLanguage - { - get => selectedLanguage; - set => SetProperty(ref selectedLanguage, value); - } - - public LocalizedString AppVersion { get; } = new LocalizedString(() => string.Format(AppResources.Version, AppInfo.VersionString)); - - public ICommand ChangeLanguageCommand { get; } - public SettingViewModel() { LoadLanguages(); @@ -43,6 +28,22 @@ public SettingViewModel() }); } + public LocalizedString AppVersion { get; } = new LocalizedString(() => string.Format(AppResources.Version, AppInfo.VersionString)); + + public ICommand ChangeLanguageCommand { get; } + + public Language SelectedLanguage + { + get => selectedLanguage; + set => SetProperty(ref selectedLanguage, value); + } + + public IList SupportedLanguages + { + get => supportedLanguages; + private set => SetProperty(ref supportedLanguages, value); + } + void LoadLanguages() { SupportedLanguages = new List() diff --git a/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs b/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs index 108859756..9281f689f 100644 --- a/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs @@ -46,7 +46,7 @@ public ExpanderViewModel() public sealed class Item : BaseViewModel { - string name; + string name = string.Empty; bool isExpanded; bool isEnabled = true; diff --git a/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs b/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs index 2e6fd0d7d..85e924594 100644 --- a/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs @@ -13,7 +13,8 @@ public class PopupGalleryViewModel { INavigation Navigation => App.Current.MainPage.Navigation; - public IEnumerable Examples { get; } = new List { + public IEnumerable Examples { get; } = new[] + { new SectionModel(typeof(SimplePopup), "Simple Popup", Color.Red, "Displays a basic popup centered on the screen"), new SectionModel(typeof(PopupPositionPage), "Custom Positioning Popup", Color.Red, "Displays a basic popup anywhere on the screen using VerticalOptions and HorizontalOptions"), new SectionModel(typeof(ButtonPopup), "Popup With 1 Button", Color.Red, "Displays a basic popup with a confirm button"), @@ -37,7 +38,7 @@ async void OnDisplayPopup(Type popupType) if (view is Popup popup) { var result = await Navigation.ShowPopupAsync(popup); - await App.Current.MainPage.DisplayAlert("Popup Result", result, "OKAY"); + await Application.Current.MainPage.DisplayAlert("Popup Result", result, "OKAY"); } else if (view is BasePopup basePopup) { diff --git a/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs b/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs index d1d63e27c..f856df57d 100644 --- a/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs @@ -7,7 +7,7 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views { public class StateLayoutViewModel : BaseViewModel { - string customState; + string customState = string.Empty; LayoutState currentState; LayoutState mainState; diff --git a/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs b/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs index 451391518..4d890f101 100644 --- a/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs @@ -7,11 +7,16 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views { public class Monkey { - public string Index { get; set; } - public string Name { get; set; } - public string Location { get; set; } - public string Details { get; set; } - public string Image { get; set; } + public string Index { get; set; } = string.Empty; + + public string Name { get; set; } = string.Empty; + + public string Location { get; set; } = string.Empty; + + public string Details { get; set; } = string.Empty; + + public string Image { get; set; } = string.Empty; + public Color Color { get; set; } } @@ -25,112 +30,106 @@ public TabItemsSourceViewModel() UpdateDataCommand = CommandFactory.Create(UpdateData); } - public ObservableCollection Monkeys { get; set; } + public ObservableCollection Monkeys { get; } = LoadMonkeys(); public ICommand ClearDataCommand { get; } public ICommand UpdateDataCommand { get; } - void LoadMonkeys() + static ObservableCollection LoadMonkeys() => new ObservableCollection { - Monkeys = new ObservableCollection + new Monkey { - new Monkey - { - Index = "0", - Name = "Baboon", - Location = "Africa & Asia", - Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg", - Color = Color.LightSalmon - }, - - new Monkey - { - Index = "1", - Name = "Capuchin Monkey", - Location = "Central & South America", - Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg", - Color = Color.LightBlue - }, - - new Monkey - { - Index = "2", - Name = "Blue Monkey", - Location = "Central and East Africa", - Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg", - Color = Color.LightSlateGray - }, - - new Monkey - { - Index = "3", - Name = "Squirrel Monkey", - Location = "Central & South America", - Details = "The squirrel monkeys are the New World monkeys of the genus Saimiri. They are the only genus in the subfamily Saimirinae. The name of the genus Saimiri is of Tupi origin, and was also used as an English name by early researchers.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Saimiri_sciureus-1_Luc_Viatour.jpg/220px-Saimiri_sciureus-1_Luc_Viatour.jpg", - Color = Color.Chocolate - }, - - new Monkey - { - Index = "4", - Name = "Golden Lion Tamarin", - Location = "Brazil", - Details = "The golden lion tamarin also known as the golden marmoset, is a small New World monkey of the family Callitrichidae.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Golden_lion_tamarin_portrait3.jpg/220px-Golden_lion_tamarin_portrait3.jpg", - Color = Color.Violet - }, - - new Monkey - { - Index = "5", - Name = "Howler Monkey", - Location = "South America", - Details = "Howler monkeys are among the largest of the New World monkeys. Fifteen species are currently recognised. Previously classified in the family Cebidae, they are now placed in the family Atelidae.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Alouatta_guariba.jpg/200px-Alouatta_guariba.jpg", - Color = Color.Aqua - }, - - new Monkey - { - Index = "6", - Name = "Japanese Macaque", - Location = "Japan", - Details = "The Japanese macaque, is a terrestrial Old World monkey species native to Japan. They are also sometimes known as the snow monkey because they live in areas where snow covers the ground for months each", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Macaca_fuscata_fuscata1.jpg/220px-Macaca_fuscata_fuscata1.jpg", - Color = Color.OrangeRed - }, - - new Monkey - { - Index = "7", - Name = "Mandrill", - Location = "Southern Cameroon, Gabon, Equatorial Guinea, and Congo", - Details = "The mandrill is a primate of the Old World monkey family, closely related to the baboons and even more closely to the drill. It is found in southern Cameroon, Gabon, Equatorial Guinea, and Congo.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Mandrill_at_san_francisco_zoo.jpg/220px-Mandrill_at_san_francisco_zoo.jpg", - Color = Color.MediumPurple - }, - - new Monkey - { - Index = "8", - Name = "Proboscis Monkey", - Location = "Borneo", - Details = "The proboscis monkey or long-nosed monkey, known as the bekantan in Malay, is a reddish-brown arboreal Old World monkey that is endemic to the south-east Asian island of Borneo.", - Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Proboscis_Monkey_in_Borneo.jpg/250px-Proboscis_Monkey_in_Borneo.jpg", - Color = Color.Pink - } - }; - } + Index = "0", + Name = "Baboon", + Location = "Africa & Asia", + Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg", + Color = Color.LightSalmon + }, + + new Monkey + { + Index = "1", + Name = "Capuchin Monkey", + Location = "Central & South America", + Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg", + Color = Color.LightBlue + }, + + new Monkey + { + Index = "2", + Name = "Blue Monkey", + Location = "Central and East Africa", + Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg", + Color = Color.LightSlateGray + }, + + new Monkey + { + Index = "3", + Name = "Squirrel Monkey", + Location = "Central & South America", + Details = "The squirrel monkeys are the New World monkeys of the genus Saimiri. They are the only genus in the subfamily Saimirinae. The name of the genus Saimiri is of Tupi origin, and was also used as an English name by early researchers.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Saimiri_sciureus-1_Luc_Viatour.jpg/220px-Saimiri_sciureus-1_Luc_Viatour.jpg", + Color = Color.Chocolate + }, + + new Monkey + { + Index = "4", + Name = "Golden Lion Tamarin", + Location = "Brazil", + Details = "The golden lion tamarin also known as the golden marmoset, is a small New World monkey of the family Callitrichidae.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Golden_lion_tamarin_portrait3.jpg/220px-Golden_lion_tamarin_portrait3.jpg", + Color = Color.Violet + }, + + new Monkey + { + Index = "5", + Name = "Howler Monkey", + Location = "South America", + Details = "Howler monkeys are among the largest of the New World monkeys. Fifteen species are currently recognised. Previously classified in the family Cebidae, they are now placed in the family Atelidae.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Alouatta_guariba.jpg/200px-Alouatta_guariba.jpg", + Color = Color.Aqua + }, - void ClearData() - { - Monkeys.Clear(); - } + new Monkey + { + Index = "6", + Name = "Japanese Macaque", + Location = "Japan", + Details = "The Japanese macaque, is a terrestrial Old World monkey species native to Japan. They are also sometimes known as the snow monkey because they live in areas where snow covers the ground for months each", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Macaca_fuscata_fuscata1.jpg/220px-Macaca_fuscata_fuscata1.jpg", + Color = Color.OrangeRed + }, + + new Monkey + { + Index = "7", + Name = "Mandrill", + Location = "Southern Cameroon, Gabon, Equatorial Guinea, and Congo", + Details = "The mandrill is a primate of the Old World monkey family, closely related to the baboons and even more closely to the drill. It is found in southern Cameroon, Gabon, Equatorial Guinea, and Congo.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Mandrill_at_san_francisco_zoo.jpg/220px-Mandrill_at_san_francisco_zoo.jpg", + Color = Color.MediumPurple + }, + + new Monkey + { + Index = "8", + Name = "Proboscis Monkey", + Location = "Borneo", + Details = "The proboscis monkey or long-nosed monkey, known as the bekantan in Malay, is a reddish-brown arboreal Old World monkey that is endemic to the south-east Asian island of Borneo.", + Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Proboscis_Monkey_in_Borneo.jpg/250px-Proboscis_Monkey_in_Borneo.jpg", + Color = Color.Pink + } + }; + + void ClearData() => Monkeys.Clear(); void UpdateData() { diff --git a/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs index bb1934888..e3f6c5828 100644 --- a/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs @@ -6,7 +6,7 @@ sealed class LazyTestViewModel : ObservableObject { public static LazyTestViewModel Current { get; } = new LazyTestViewModel(); - string title; + string title = string.Empty; public string Title { diff --git a/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs index ff764bcf8..81c51d12d 100644 --- a/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs @@ -6,7 +6,7 @@ sealed class NormalTestViewModel : ObservableObject { public static NormalTestViewModel Current { get; } = new NormalTestViewModel(); - string loadedViews; + string loadedViews = string.Empty; public string LoadedViews { diff --git a/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj b/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj index 6c19fb7d5..dc869bed2 100644 --- a/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj +++ b/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj @@ -3,6 +3,9 @@ netstandard2.0 true + enable + nullable + latest @@ -11,6 +14,7 @@ + From 2533b698505b3b213c38005f37620acd78f92bbb Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:42:32 -0800 Subject: [PATCH 04/13] Enable Nullable on Android, GTK, iOS and Tizen Samples --- samples/XCT.Sample.Android/SplashActivity.cs | 2 +- .../Xamarin.CommunityToolkit.Sample.Android.csproj | 3 +++ .../Xamarin.CommunityToolkit.Sample.GTK.csproj | 3 +++ .../Xamarin.CommunityToolkit.Sample.Tizen.csproj | 3 +++ .../XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs | 7 +++++-- .../Xamarin.CommunityToolkit.Sample.iOS.csproj | 3 +++ 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/samples/XCT.Sample.Android/SplashActivity.cs b/samples/XCT.Sample.Android/SplashActivity.cs index c9d8f69df..2883e4e55 100644 --- a/samples/XCT.Sample.Android/SplashActivity.cs +++ b/samples/XCT.Sample.Android/SplashActivity.cs @@ -9,7 +9,7 @@ namespace Xamarin.CommunityToolkit.Sample.Droid [Activity(Label = "XamarinCommunityToolkitSample", Icon = "@mipmap/icon", Theme = "@style/SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] public class SplashActivity : AppCompatActivity { - protected override void OnCreate(Bundle savedInstanceState) + protected override void OnCreate(Bundle? savedInstanceState) { base.OnCreate(savedInstanceState); var intent = new Intent(this, typeof(MainActivity)); diff --git a/samples/XCT.Sample.Android/Xamarin.CommunityToolkit.Sample.Android.csproj b/samples/XCT.Sample.Android/Xamarin.CommunityToolkit.Sample.Android.csproj index 2a3c8b3ea..46778f3cc 100644 --- a/samples/XCT.Sample.Android/Xamarin.CommunityToolkit.Sample.Android.csproj +++ b/samples/XCT.Sample.Android/Xamarin.CommunityToolkit.Sample.Android.csproj @@ -22,6 +22,9 @@ Xamarin.Android.Net.AndroidClientHandler + enable + nullable + latest true diff --git a/samples/XCT.Sample.GTK/Xamarin.CommunityToolkit.Sample.GTK.csproj b/samples/XCT.Sample.GTK/Xamarin.CommunityToolkit.Sample.GTK.csproj index a46ed016e..aed0d4dc2 100644 --- a/samples/XCT.Sample.GTK/Xamarin.CommunityToolkit.Sample.GTK.csproj +++ b/samples/XCT.Sample.GTK/Xamarin.CommunityToolkit.Sample.GTK.csproj @@ -13,6 +13,9 @@ 512 true + enable + nullable + latest true diff --git a/samples/XCT.Sample.Tizen/Xamarin.CommunityToolkit.Sample.Tizen.csproj b/samples/XCT.Sample.Tizen/Xamarin.CommunityToolkit.Sample.Tizen.csproj index c08a698d6..7205fdacd 100644 --- a/samples/XCT.Sample.Tizen/Xamarin.CommunityToolkit.Sample.Tizen.csproj +++ b/samples/XCT.Sample.Tizen/Xamarin.CommunityToolkit.Sample.Tizen.csproj @@ -3,6 +3,9 @@ Exe tizen40 + enable + nullable + latest diff --git a/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs b/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs index f1231d834..af6c3fc37 100644 --- a/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs +++ b/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs @@ -25,8 +25,11 @@ public override void ViewWillAppear(bool animated) // Newest iOS version fix - trycatch isn't optimal try { - NavigationBar.ScrollEdgeAppearance.ShadowImage = new UIKit.UIImage(); - NavigationBar.ScrollEdgeAppearance.ShadowColor = null; + if (NavigationBar.ScrollEdgeAppearance != null) + { + NavigationBar.ScrollEdgeAppearance.ShadowImage = new UIKit.UIImage(); + NavigationBar.ScrollEdgeAppearance.ShadowColor = null; + } } catch (Exception) { diff --git a/samples/XCT.Sample.iOS/Xamarin.CommunityToolkit.Sample.iOS.csproj b/samples/XCT.Sample.iOS/Xamarin.CommunityToolkit.Sample.iOS.csproj index 6462f5970..15021eca2 100644 --- a/samples/XCT.Sample.iOS/Xamarin.CommunityToolkit.Sample.iOS.csproj +++ b/samples/XCT.Sample.iOS/Xamarin.CommunityToolkit.Sample.iOS.csproj @@ -15,6 +15,9 @@ true NSUrlSessionHandler automatic + enable + nullable + latest true From bc00611f61d88aef6785ee08ac81d4b4ca3c36ae Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:54:14 -0800 Subject: [PATCH 05/13] Enable Nullable for UWP & WPF Sample Projects --- .../XCT.Sample.UWP/Xamarin.CommunityToolkit.Sample.UWP.csproj | 3 +++ .../XCT.Sample.WPF/Xamarin.CommunityToolkit.Sample.WPF.csproj | 3 +++ 2 files changed, 6 insertions(+) diff --git a/samples/XCT.Sample.UWP/Xamarin.CommunityToolkit.Sample.UWP.csproj b/samples/XCT.Sample.UWP/Xamarin.CommunityToolkit.Sample.UWP.csproj index 517b29fcc..111a1ee5f 100644 --- a/samples/XCT.Sample.UWP/Xamarin.CommunityToolkit.Sample.UWP.csproj +++ b/samples/XCT.Sample.UWP/Xamarin.CommunityToolkit.Sample.UWP.csproj @@ -18,6 +18,9 @@ 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} false + enable + nullable + latest true diff --git a/samples/XCT.Sample.WPF/Xamarin.CommunityToolkit.Sample.WPF.csproj b/samples/XCT.Sample.WPF/Xamarin.CommunityToolkit.Sample.WPF.csproj index a76a51019..4860d5d06 100644 --- a/samples/XCT.Sample.WPF/Xamarin.CommunityToolkit.Sample.WPF.csproj +++ b/samples/XCT.Sample.WPF/Xamarin.CommunityToolkit.Sample.WPF.csproj @@ -16,6 +16,9 @@ true + enable + nullable + latest AnyCPU From bac3aefaa09fe3dbcce600542ca7f5c31ba61c5c Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 01:41:04 -0800 Subject: [PATCH 06/13] Add Nullability --- .../XCT.Sample/ViewModels/AboutViewModel.cs | 2 +- .../ViewModels/Base/BaseGalleryViewModel.cs | 2 +- .../XCT.Sample/ViewModels/SettingViewModel.cs | 2 +- .../Animations/AnimationBehavior.shared.cs | 7 +- .../AnimationTypes/AnimationBase.shared.cs | 2 +- .../AnimationTypes/FadeAnimation.shared.cs | 9 +- .../FlipHorizontalAnimation.shared.cs | 9 +- .../FlipVerticalAnimation.shared.cs | 9 +- .../AnimationTypes/RotateAnimation.shared.cs | 9 +- .../AnimationTypes/ScaleAnimation.shared.cs | 9 +- .../AnimationTypes/ShakeAnimation.shared.cs | 15 +- .../Behaviors/BaseBehavior.shared.cs | 10 +- .../EventToCommandBehavior.shared.cs | 6 +- .../ImpliedOrderGridBehavior.shared.cs | 18 +- .../Behaviors/MaskedBehavior.shared.cs | 19 +- .../MaxLengthReachedBehavior.shared.cs | 2 +- .../ProgressBarAnimationBehavior.shared.cs | 7 +- .../UserStoppedTypingBehavior.shared.cs | 10 +- .../CharactersValidationBehavior.shared.cs | 6 +- .../EmailValidationBehavior.shared.cs | 2 +- .../MultiValidationBehavior.shared.cs | 13 +- .../NumericValidationBehavior.shared.cs | 11 +- ...RequiredStringValidationBehavior.shared.cs | 2 +- .../TextValidationBehavior.shared.cs | 6 +- .../UriValidationBehavior.shared.cs | 2 +- .../Validators/ValidationBehavior.shared.cs | 14 +- .../BoolToObjectConverter.shared.cs | 6 +- .../ByteArrayToImageSourceConverter.shared.cs | 4 +- .../Converters/EnumToBoolConverter.shared.cs | 4 +- .../ItemSelectedEventArgsConverter.shared.cs | 2 +- .../ItemTappedEventArgsConverter.shared.cs | 2 +- .../ListToStringConverter.shared.cs | 6 +- .../MultiConverterParameter.shared.cs | 4 +- .../Converters/TextCaseConverter.shared.cs | 46 +++-- .../VariableMultiValueConverter.shared.cs | 4 +- .../Core/FileMediaSource.shared.cs | 2 +- .../Core/MediaSource.shared.cs | 2 +- .../Core/StreamMediaSource.shared.cs | 14 +- .../LifeCycle/LifeCycleEffectRouter.ios.cs | 6 +- .../RemoveBorder/RemoveBorderEffect.ios.cs | 2 +- .../SafeArea/SafeAreaEffectRouter.ios.cs | 8 +- .../SelectAllText/SelectAllTextEffect.ios.cs | 13 +- .../Effects/Touch/GestureManager.shared.cs | 24 +-- .../Effects/Touch/PlatformTouchEffect.ios.cs | 19 +- .../Effects/Touch/TouchEffect.shared.cs | 29 ++- .../Effects/VisualFeedback/TouchEvents.ios.cs | 8 +- .../VisualFeedbackEffectRouter.android.cs | 72 +++++--- .../VisualFeedbackEffectRouter.ios.cs | 55 +++--- .../ImageResourceExtension.shared.cs | 6 +- .../NavigableElementExtensions.shared.cs | 2 +- .../NavigationExtensions.android.cs | 2 +- .../Navigation/NavigationExtensions.ios.cs | 2 +- .../Navigation/NavigationExtensions.shared.cs | 2 +- .../Extensions/TranslateExtension.shared.cs | 4 +- .../VisualElementExtension.shared.cs | 13 +- .../DelegateWeakEventManager.shared.cs | 4 +- .../LocalizationResourceManager.shared.cs | 8 +- .../Helpers/LocalizedString.shared.cs | 8 +- .../Helpers/Subscription.shared.cs | 4 +- .../Helpers/WeakEventManager.shared.cs | 2 +- .../Helpers/WeakEventManagerService.shared.cs | 14 +- .../ObjectModel/AsyncCommand.shared.cs | 22 +-- .../ObjectModel/AsyncValueCommand.shared.cs | 22 +-- .../CommandFactory.IAsyncCommand.shared.cs | 36 ++-- ...ommandFactory.IAsyncValueCommand.shared.cs | 22 +-- .../Internals/BaseAsyncCommand.shared.cs | 24 +-- .../Internals/BaseAsyncValueCommand.shared.cs | 24 +-- .../Internals/BaseCommand.android.cs | 10 +- .../Internals/BaseCommand.shared.cs | 6 +- .../ObjectModel/ObservableObject.shared.cs | 4 +- .../Views/AvatarView/AvatarView.shared.cs | 31 ++-- .../IImageSourceValidator.shared.cs | 2 +- ...tor.android.ios.macos.uwp.wpf.gtk.tizen.cs | 4 +- .../AvatarView/ImageSourceValidator.shared.cs | 2 +- .../Views/BadgeView/BadgeView.shared.cs | 6 +- .../Views/BaseTemplatedView.shared.cs | 15 +- .../Android/AutoFitTextureView.android.cs | 6 +- .../Android/CameraCaptureListener.android.cs | 2 +- .../CameraCaptureStateListener.android.cs | 4 +- .../Android/CameraViewRenderer.android.cs | 2 +- .../Android/ImageAvailableListener.android.cs | 16 +- .../Android/MotionEventHelper.android.cs | 2 +- .../Views/CameraView/CameraView.shared.cs | 8 +- .../MediaCapturedEventArgs.shared.cs | 22 ++- .../CameraView/iOS/CameraViewRenderer.ios.cs | 31 ++-- .../CameraView/iOS/FormsCameraView.ios.cs | 69 +++++--- .../Views/Expander/Expander.shared.cs | 27 +-- ...Handler.android.ios.macos.tizen.uwp.wpf.cs | 2 +- .../GravatarImageSourceHandler.ios.macos.cs | 9 +- .../iOS/GravatarImageSourceHandler.ios.cs | 4 +- .../Android/FormsVideoView.android.cs | 35 ++-- .../Android/MediaElementRenderer.android.cs | 42 ++--- .../Views/MediaElement/MediaElement.shared.cs | 18 +- .../MediaElement/UriTypeConverter.shared.cs | 4 +- .../iOS/MediaElementRenderer.ios.cs | 38 ++-- .../Popup/Android/PopupRenderer.android.cs | 166 ++++++++---------- .../Views/Popup/BasePopup.shared.cs | 4 +- .../Popup/PopupDismissedEventArgs.shared.cs | 4 +- .../Views/Popup/PopupOfT.shared.cs | 10 +- .../Views/Popup/iOS/PopupRenderer.ios.cs | 62 +++++-- .../Views/RangeSlider/RangeSlider.shared.cs | 22 +-- .../Views/Shield.shared.cs | 4 +- .../Views/SideMenuView/SideMenuView.shared.cs | 24 ++- .../SideMenuView/SideMenuViewRenderer.ios.cs | 8 +- .../Helpers/NativeSnackButton.ios.macos.cs | 10 +- .../Snackbar/Helpers/iOS/IOSSnackBar.ios.cs | 17 +- .../ActionMessageSnackBarView.ios.cs | 5 +- .../iOS/SnackbarViews/BaseSnackBarView.ios.cs | 15 +- .../SnackbarViews/MessageSnackBarView.ios.cs | 4 +- .../Snackbar/Options/MessageOptions.shared.cs | 2 +- .../Options/SnackBarActionOptions.shared.cs | 6 +- .../Views/Snackbar/SnackBar.ios.macos.cs | 4 +- .../StateLayoutController.shared.cs | 20 +-- .../Views/TabView/TabBadgeView.shared.cs | 68 ++++--- .../Views/TabView/TabView.shared.cs | 22 +-- .../Views/TabView/TabViewItem.shared.cs | 8 +- .../Xamarin.CommunityToolkit.csproj | 3 + 117 files changed, 901 insertions(+), 764 deletions(-) mode change 100755 => 100644 src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs diff --git a/samples/XCT.Sample/ViewModels/AboutViewModel.cs b/samples/XCT.Sample/ViewModels/AboutViewModel.cs index b7133e5e9..db6479da4 100644 --- a/samples/XCT.Sample/ViewModels/AboutViewModel.cs +++ b/samples/XCT.Sample/ViewModels/AboutViewModel.cs @@ -12,7 +12,7 @@ public class AboutViewModel : BaseViewModel { readonly GitHubClient gitHubClient = new GitHubClient(new ProductHeaderValue("XamarinCommunityToolkitSample")); - RepositoryContributor[] contributors = Array.Empty(); + RepositoryContributor[] contributors = Enumerable.Empty().ToArray(); RepositoryContributor? selectedContributor; diff --git a/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs index e04cb7f92..55e001563 100644 --- a/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs @@ -22,7 +22,7 @@ public BaseGalleryViewModel() public string FilterValue { private get; set; } = string.Empty; - public IEnumerable FilteredItems { get; private set; } = Array.Empty(); + public IEnumerable FilteredItems { get; private set; } = Enumerable.Empty(); protected abstract IEnumerable CreateItems(); diff --git a/samples/XCT.Sample/ViewModels/SettingViewModel.cs b/samples/XCT.Sample/ViewModels/SettingViewModel.cs index ba9646adf..c211f1cf9 100644 --- a/samples/XCT.Sample/ViewModels/SettingViewModel.cs +++ b/samples/XCT.Sample/ViewModels/SettingViewModel.cs @@ -13,7 +13,7 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels { public class SettingViewModel : BaseViewModel { - IList supportedLanguages = Array.Empty(); + IList supportedLanguages = Enumerable.Empty().ToList(); Language selectedLanguage; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationBehavior.shared.cs index f8e147b4e..9e66e00a9 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationBehavior.shared.cs @@ -14,7 +14,7 @@ public AnimationBase AnimationType } bool isAnimating; - TapGestureRecognizer tapGestureRecognizer; + TapGestureRecognizer? tapGestureRecognizer; protected override void OnAttachedTo(VisualElement bindable) { @@ -37,14 +37,15 @@ protected override void OnDetachingFrom(VisualElement bindable) base.OnDetachingFrom(bindable); } - protected override async void OnTriggerHandled(object sender = null, object eventArgs = null) + protected override async void OnTriggerHandled(object? sender = null, object? eventArgs = null) { if (isAnimating) return; isAnimating = true; - await AnimationType?.Animate((View)sender); + if (AnimationType != null) + await AnimationType.Animate((View?)sender); if (Command?.CanExecute(CommandParameter) ?? false) Command.Execute(CommandParameter); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/AnimationBase.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/AnimationBase.shared.cs index bfb14cdf9..9d31b42ac 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/AnimationBase.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/AnimationBase.shared.cs @@ -31,7 +31,7 @@ static object GetDefaultDurationProperty(BindableObject bindable) protected abstract uint DefaultDuration { get; set; } - public abstract Task Animate(TView view); + public abstract Task Animate(TView? view); } public abstract class AnimationBase : AnimationBase diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FadeAnimation.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FadeAnimation.shared.cs index 6abf1af9c..683e40c07 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FadeAnimation.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FadeAnimation.shared.cs @@ -16,10 +16,13 @@ public double Fade protected override uint DefaultDuration { get; set; } = 300; - public override async Task Animate(View view) + public override async Task Animate(View? view) { - await view.FadeTo(Fade, Duration, Easing); - await view.FadeTo(1, Duration, Easing); + if (view != null) + { + await view.FadeTo(Fade, Duration, Easing); + await view.FadeTo(1, Duration, Easing); + } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipHorizontalAnimation.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipHorizontalAnimation.shared.cs index 295dc86ce..aeb62ebe7 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipHorizontalAnimation.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipHorizontalAnimation.shared.cs @@ -9,10 +9,13 @@ public class FlipHorizontalAnimation : RotateAnimation protected override uint DefaultDuration { get; set; } = 300; - public override async Task Animate(View view) + public override async Task Animate(View? view) { - await view.RotateYTo(Rotation, Duration, Easing); - await view.RotateYTo(0, Duration, Easing); + if (view != null) + { + await view.RotateYTo(Rotation, Duration, Easing); + await view.RotateYTo(0, Duration, Easing); + } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipVerticalAnimation.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipVerticalAnimation.shared.cs index 9737157f8..2912b2ea2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipVerticalAnimation.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/FlipVerticalAnimation.shared.cs @@ -7,10 +7,13 @@ public class FlipVerticalAnimation : RotateAnimation { protected override double DefaultRotation { get; set; } = 90; - public override async Task Animate(View view) + public override async Task Animate(View? view) { - await view.RotateXTo(Rotation, Duration, Easing); - await view.RotateXTo(0, Duration, Easing); + if (view != null) + { + await view.RotateXTo(Rotation, Duration, Easing); + await view.RotateXTo(0, Duration, Easing); + } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/RotateAnimation.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/RotateAnimation.shared.cs index 3b9e6ee7f..c0f6d77c2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/RotateAnimation.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/RotateAnimation.shared.cs @@ -21,10 +21,13 @@ static object GetDefaulRotationProperty(BindableObject bindable) protected virtual double DefaultRotation { get; set; } = 180.0; - public override async Task Animate(View view) + public override async Task Animate(View? view) { - await view.RotateTo(Rotation, Duration, Easing); - view.Rotation = 0; + if (view != null) + { + await view.RotateTo(Rotation, Duration, Easing); + view.Rotation = 0; + } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ScaleAnimation.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ScaleAnimation.shared.cs index e189609c0..b7c346b91 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ScaleAnimation.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ScaleAnimation.shared.cs @@ -16,10 +16,13 @@ public double Scale protected override uint DefaultDuration { get; set; } = 170; - public override async Task Animate(View view) + public override async Task Animate(View? view) { - await view.ScaleTo(Scale, Duration, Easing); - await view.ScaleTo(1, Duration, Easing); + if (view != null) + { + await view.ScaleTo(Scale, Duration, Easing); + await view.ScaleTo(1, Duration, Easing); + } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ShakeAnimation.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ShakeAnimation.shared.cs index 16616c146..5c78e92d1 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ShakeAnimation.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Animations/AnimationTypes/ShakeAnimation.shared.cs @@ -16,15 +16,18 @@ public double StartFactor protected override uint DefaultDuration { get; set; } = 50; - public override async Task Animate(View view) + public override async Task Animate(View? view) { - for (var i = StartFactor; i > 0; i = i - 5) + if (view != null) { - await view.TranslateTo(-i, 0, Duration, Easing); - await view.TranslateTo(i, 0, Duration, Easing); - } + for (var i = StartFactor; i > 0; i -= 5) + { + await view.TranslateTo(-i, 0, Duration, Easing); + await view.TranslateTo(i, 0, Duration, Easing); + } - view.TranslationX = 0; + view.TranslationX = 0; + } } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/BaseBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/BaseBehavior.shared.cs index c331fb17a..c44cca494 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/BaseBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/BaseBehavior.shared.cs @@ -11,15 +11,15 @@ namespace Xamarin.CommunityToolkit.Behaviors.Internals /// The that the behavior can be applied to public abstract class BaseBehavior : Behavior where TView : VisualElement { - static readonly MethodInfo getContextMethod + static readonly MethodInfo? getContextMethod = typeof(BindableObject).GetRuntimeMethods()?.FirstOrDefault(m => m.Name == "GetContext"); - static readonly FieldInfo bindingField + static readonly FieldInfo? bindingField = getContextMethod?.ReturnType.GetRuntimeField("Binding"); - BindingBase defaultBindingContextBinding; + BindingBase? defaultBindingContextBinding; - protected TView View { get; private set; } + protected TView? View { get; private set; } protected virtual void OnViewPropertyChanged(object sender, PropertyChangedEventArgs e) { @@ -56,7 +56,7 @@ protected override void OnDetachingFrom(TView bindable) View = null; } - protected bool IsBound(BindableProperty property, BindingBase defaultBinding = null) + protected bool IsBound(BindableProperty property, BindingBase? defaultBinding = null) { var context = getContextMethod?.Invoke(this, new object[] { property }); return context != null diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/EventToCommandBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/EventToCommandBehavior.shared.cs index 0505d0c38..2ec6de04a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/EventToCommandBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/EventToCommandBehavior.shared.cs @@ -38,9 +38,9 @@ public class EventToCommandBehavior : BaseBehavior readonly MethodInfo eventHandlerMethodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod(nameof(OnTriggerHandled)); - Delegate eventHandler; + Delegate? eventHandler; - EventInfo eventInfo; + EventInfo? eventInfo; /// /// The name of the event that should be associated with . This is bindable property. @@ -122,7 +122,7 @@ void UnregisterEvent() } [Preserve(Conditional = true)] - protected virtual void OnTriggerHandled(object sender = null, object eventArgs = null) + protected virtual void OnTriggerHandled(object? sender = null, object? eventArgs = null) { var parameter = CommandParameter ?? EventArgsConverter?.Convert(eventArgs, typeof(object), null, null) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ImpliedOrderGridBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ImpliedOrderGridBehavior.shared.cs index ec40e4082..4fa0a65e4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ImpliedOrderGridBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ImpliedOrderGridBehavior.shared.cs @@ -11,7 +11,6 @@ namespace Xamarin.CommunityToolkit.Behaviors /// public class ImpliedOrderGridBehavior : BaseBehavior { - bool[][] usedMatrix; int rowCount; int columnCount; @@ -46,6 +45,9 @@ void LogWarning(string warning) bool[][] InitMatrix() { + if (View == null) + throw new NullReferenceException($"{nameof(View)} cannot be null"); + rowCount = View.RowDefinitions.Count; if (rowCount == 0) rowCount = 1; @@ -58,12 +60,12 @@ bool[][] InitMatrix() return newMatrix; } - void FindNextCell(out int rowIndex, out int columnIndex) + void FindNextCell(out int rowIndex, out int columnIndex, out bool[][] matrix) { - usedMatrix ??= InitMatrix(); + matrix = InitMatrix(); // Find the first available row - var row = usedMatrix.FirstOrDefault(r => r.Any(c => !c)); + var row = matrix.FirstOrDefault(r => r.Any(c => !c)); // If no row is found, set cell to origin and log if (row == null) @@ -73,13 +75,13 @@ void FindNextCell(out int rowIndex, out int columnIndex) columnIndex = Math.Max(columnCount - 1, 0); return; } - rowIndex = usedMatrix.IndexOf(row); + rowIndex = matrix.IndexOf(row); // Find the first available column columnIndex = row.IndexOf(row.FirstOrDefault(c => !c)); } - void UpdateUsedCells(int row, int column, int rowSpan, int columnSpan) + void UpdateUsedCells(int row, int column, int rowSpan, int columnSpan, bool[][] usedMatrix) { var rowEnd = row + rowSpan; var columnEnd = column + columnSpan; @@ -112,7 +114,7 @@ void ProcessElement(BindableObject view) var columnSpan = Grid.GetColumnSpan(view); var rowSpan = Grid.GetRowSpan(view); - FindNextCell(out var row, out var column); + FindNextCell(out var row, out var column, out var usedMatrix); // Check to see if the user manually assigned a row or column if (view.IsSet(Grid.ColumnProperty)) @@ -120,7 +122,7 @@ void ProcessElement(BindableObject view) if (view.IsSet(Grid.RowProperty)) row = Grid.GetRow(view); - UpdateUsedCells(row, column, rowSpan, columnSpan); + UpdateUsedCells(row, column, rowSpan, columnSpan, usedMatrix); // Set attributes view.SetValue(Grid.ColumnProperty, column); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaskedBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaskedBehavior.shared.cs index 9addd051c..d790f4b38 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaskedBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaskedBehavior.shared.cs @@ -23,7 +23,7 @@ public class MaskedBehavior : BaseBehavior public static readonly BindableProperty UnMaskedCharacterProperty = BindableProperty.Create(nameof(UnMaskedCharacter), typeof(char), typeof(MaskedBehavior), 'X', propertyChanged: OnUnMaskedCharacterPropertyChanged); - IDictionary positions; + IDictionary? positions; bool applyingMask; @@ -65,7 +65,7 @@ void OnTextPropertyChanged() return; applyingMask = true; - ApplyMask(View.Text); + ApplyMask(View?.Text); applyingMask = false; } @@ -95,16 +95,21 @@ void OnMaskChanged() return; } - var originalText = RemoveMask(View?.Text); + var originalText = RemoveMask_NullableString(View?.Text); SetPositions(); ApplyMask(originalText); } - string RemoveMask(string text) + string? RemoveMask_NullableString(string? text) { - if (string.IsNullOrEmpty(text)) + if (text == null || string.IsNullOrEmpty(text)) return text; + return RemoveMask(text); + } + + string RemoveMask(string text) + { var maskChars = positions .Select(c => c.Value) .Distinct() @@ -113,9 +118,9 @@ string RemoveMask(string text) return string.Join(string.Empty, text.Split(maskChars)); } - void ApplyMask(string text) + void ApplyMask(string? text) { - if (!string.IsNullOrWhiteSpace(text) && positions != null) + if (text != null && !string.IsNullOrWhiteSpace(text) && positions != null) { if (text.Length > Mask.Length) text = text.Remove(text.Length - 1); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs index 11a993787..8dc352dd2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs @@ -62,7 +62,7 @@ protected override void OnViewPropertyChanged(object sender, PropertyChangedEven void OnTextPropertyChanged() { - if (!(View.Text?.Length >= View.MaxLength)) + if (View == null || !(View.Text.Length >= View.MaxLength)) return; if (ShouldDismissKeyboardAutomatically) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ProgressBarAnimationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ProgressBarAnimationBehavior.shared.cs index 838b1cdb0..043aeef26 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ProgressBarAnimationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/ProgressBarAnimationBehavior.shared.cs @@ -21,7 +21,10 @@ public double AnimateProgress static void OnAnimateProgressPropertyChanged(BindableObject bindable, object oldValue, object newValue) => ((ProgressBarAnimationBehavior)bindable).Animate(); - void Animate() - => View.ProgressTo(AnimateProgress, 500, Easing.Linear); + async void Animate() + { + if (View != null) + await View.ProgressTo(AnimateProgress, 500, Easing.Linear); + } } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs index a3aab0be5..6a82b6f77 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs @@ -42,7 +42,7 @@ public class UserStoppedTypingBehavior : BaseBehavior public static readonly BindableProperty ShouldDismissKeyboardAutomaticallyProperty = BindableProperty.Create(nameof(ShouldDismissKeyboardAutomatically), typeof(bool), typeof(UserStoppedTypingBehavior), false); - CancellationTokenSource tokenSource; + CancellationTokenSource? tokenSource; /// /// Command that is triggered when the is reached. When is set, it's only triggered when both conditions are met. This is a bindable property. @@ -105,17 +105,17 @@ void OnTextPropertyChanged() } tokenSource = new CancellationTokenSource(); - _ = Task.Delay(StoppedTypingTimeThreshold, tokenSource.Token) + Task.Delay(StoppedTypingTimeThreshold, tokenSource.Token) .ContinueWith(task => { if (task.Status == TaskStatus.Canceled || - View.Text.Length < MinimumLengthThreshold) + View?.Text.Length < MinimumLengthThreshold) return; - if (ShouldDismissKeyboardAutomatically) + if (View != null && ShouldDismissKeyboardAutomatically) Device.BeginInvokeOnMainThread(View.Unfocus); - if (Command?.CanExecute(CommandParameter ?? View.Text) ?? false) + if (View != null && Command?.CanExecute(CommandParameter ?? View.Text) is true) Command.Execute(CommandParameter ?? View.Text); }); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/CharactersValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/CharactersValidationBehavior.shared.cs index 03e4198d9..73b16f6cf 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/CharactersValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/CharactersValidationBehavior.shared.cs @@ -12,7 +12,7 @@ namespace Xamarin.CommunityToolkit.Behaviors /// public class CharactersValidationBehavior : TextValidationBehavior { - List> characterPredicates; + List> characterPredicates = Enumerable.Empty>().ToList(); /// /// Backing BindableProperty for the property. @@ -65,7 +65,7 @@ public int MaximumCharacterCount set => SetValue(MaximumCharacterCountProperty, value); } - protected override async ValueTask ValidateAsync(object value, CancellationToken token) + protected override async ValueTask ValidateAsync(object? value, CancellationToken token) => await base.ValidateAsync(value, token).ConfigureAwait(false) && Validate(value?.ToString()); @@ -102,7 +102,7 @@ static IEnumerable> GetCharacterPredicates(CharacterType charact void OnCharacterTypePropertyChanged() => characterPredicates = GetCharacterPredicates(CharacterType).ToList(); - bool Validate(string value) + bool Validate(string? value) { var count = value?.ToCharArray().Count(character => characterPredicates.Any(predicate => predicate.Invoke(character))) ?? 0; return count >= MinimumCharacterCount diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/EmailValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/EmailValidationBehavior.shared.cs index 9e30523b2..a2f090ea2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/EmailValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/EmailValidationBehavior.shared.cs @@ -21,7 +21,7 @@ protected override string DefaultRegexPattern protected override RegexOptions DefaultRegexOptions => RegexOptions.IgnoreCase; - protected override object Decorate(object value) + protected override object? Decorate(object? value) { var stringValue = base.Decorate(value)?.ToString(); #if NETSTANDARD1_0 diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/MultiValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/MultiValidationBehavior.shared.cs index f59b999ee..b0bc83291 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/MultiValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/MultiValidationBehavior.shared.cs @@ -24,8 +24,7 @@ public class MultiValidationBehavior : ValidationBehavior public static readonly BindableProperty ErrorProperty = BindableProperty.CreateAttached(nameof(GetError), typeof(object), typeof(MultiValidationBehavior), null); - readonly ObservableCollection children - = new ObservableCollection(); + readonly ObservableCollection children = new ObservableCollection(); /// /// Constructor for this behavior. @@ -36,7 +35,7 @@ public MultiValidationBehavior() /// /// Holds the errors from all of the nested invalid validators in . This is a bindable property. /// - public List Errors + public List? Errors { get => (List)GetValue(ErrorsProperty); set => SetValue(ErrorsProperty, value); @@ -45,16 +44,14 @@ public List Errors /// /// All child behaviors that are part of this . This is a bindable property. /// - public IList Children - => children; + public IList Children => children; /// /// Method to extract the error from the attached property for a child behavior in . /// /// The that we extract the attached Error property /// Object containing error information - public static object GetError(BindableObject bindable) - => bindable.GetValue(ErrorProperty); + public static object GetError(BindableObject bindable) => bindable.GetValue(ErrorProperty); /// /// Method to set the error on the attached property for a child behavior in . @@ -64,7 +61,7 @@ public static object GetError(BindableObject bindable) public static void SetError(BindableObject bindable, object value) => bindable.SetValue(ErrorProperty, value); - protected override async ValueTask ValidateAsync(object value, CancellationToken token) + protected override async ValueTask ValidateAsync(object? value, CancellationToken token) { await Task.WhenAll(children.Select(c => { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/NumericValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/NumericValidationBehavior.shared.cs index da1c1978b..922d8c8b9 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/NumericValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/NumericValidationBehavior.shared.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using Xamarin.CommunityToolkit.Behaviors.Internals; @@ -71,12 +72,14 @@ public int MaximumDecimalPlaces set => SetValue(MaximumDecimalPlacesProperty, value); } - protected override object Decorate(object value) + protected override object? Decorate(object? value) => base.Decorate(value)?.ToString()?.Trim(); - protected override ValueTask ValidateAsync(object value, CancellationToken token) + protected override ValueTask ValidateAsync(object? value, CancellationToken token) { - var valueString = value as string; + if (value is not string valueString) + throw new ArgumentException($"Expected type string for parameter {nameof(value)}"); + if (!(double.TryParse(valueString, out var numeric) && numeric >= MinimumValue && numeric <= MaximumValue)) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/RequiredStringValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/RequiredStringValidationBehavior.shared.cs index 8c5cd7f69..b40f27eb2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/RequiredStringValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/RequiredStringValidationBehavior.shared.cs @@ -25,7 +25,7 @@ public string RequiredString set => SetValue(RequiredStringProperty, value); } - protected override ValueTask ValidateAsync(object value, CancellationToken token) + protected override ValueTask ValidateAsync(object? value, CancellationToken token) => new ValueTask(value?.ToString() == RequiredString); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/TextValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/TextValidationBehavior.shared.cs index 41fcbb2ee..bd1bdb3bf 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/TextValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/TextValidationBehavior.shared.cs @@ -42,7 +42,7 @@ public class TextValidationBehavior : ValidationBehavior public static readonly BindableProperty RegexOptionsProperty = BindableProperty.Create(nameof(RegexOptions), typeof(RegexOptions), typeof(TextValidationBehavior), defaultValueCreator: GetDefaultRegexOptions, propertyChanged: OnRegexPropertyChanged); - Regex regex; + Regex? regex; /// /// The minimum length of the value that will be allowed. This is a bindable property. @@ -98,7 +98,7 @@ public RegexOptions RegexOptions protected virtual RegexOptions DefaultRegexOptions => RegexOptions.None; - protected override object Decorate(object value) + protected override object? Decorate(object? value) { var stringValue = base.Decorate(value)?.ToString(); var flags = DecorationFlags; @@ -121,7 +121,7 @@ protected override object Decorate(object value) return stringValue; } - protected override ValueTask ValidateAsync(object value, CancellationToken token) + protected override ValueTask ValidateAsync(object? value, CancellationToken token) { var text = value?.ToString(); return new ValueTask( diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/UriValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/UriValidationBehavior.shared.cs index 231b351a2..6af0ff965 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/UriValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/UriValidationBehavior.shared.cs @@ -25,7 +25,7 @@ public UriKind UriKind set => SetValue(UriKindProperty, value); } - protected override async ValueTask ValidateAsync(object value, CancellationToken token) + protected override async ValueTask ValidateAsync(object? value, CancellationToken token) => await base.ValidateAsync(value, token).ConfigureAwait(false) && Uri.IsWellFormedUriString(value?.ToString(), UriKind); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/ValidationBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/ValidationBehavior.shared.cs index c723fb288..29687c29c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/ValidationBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/Validators/ValidationBehavior.shared.cs @@ -73,9 +73,9 @@ public abstract class ValidationBehavior : BaseBehavior bool isAttaching; - BindingBase defaultValueBinding; + BindingBase? defaultValueBinding; - CancellationTokenSource validationTokenSource; + CancellationTokenSource? validationTokenSource; /// /// Indicates whether or not the current value is considered valid. This is a bindable property. @@ -134,7 +134,7 @@ public ValidationFlags Flags /// /// The value to validate. This is a bindable property. /// - public object Value + public object? Value { get => GetValue(ValueProperty); set => SetValue(ValueProperty, value); @@ -169,9 +169,9 @@ public ICommand ForceValidateCommand internal ValueTask ValidateNestedAsync(CancellationToken token) => UpdateStateAsync(true, token); - protected virtual object Decorate(object value) => value; + protected virtual object? Decorate(object? value) => value; - protected abstract ValueTask ValidateAsync(object value, CancellationToken token); + protected abstract ValueTask ValidateAsync(object? value, CancellationToken token); protected override void OnAttachedTo(VisualElement bindable) { @@ -202,7 +202,7 @@ protected override void OnViewPropertyChanged(object sender, PropertyChangedEven base.OnViewPropertyChanged(sender, e); if (e.PropertyName == VisualElement.IsFocusedProperty.PropertyName) { - currentStatus = View.IsFocused + currentStatus = View?.IsFocused is true ? ValidationFlags.ValidateOnFocusing : ValidationFlags.ValidateOnUnfocusing; _ = UpdateStateAsync(false); @@ -306,7 +306,7 @@ void UpdateStyle() View.Style = IsValid ? ValidStyle : InvalidStyle; } - void ResetValidationTokenSource(CancellationTokenSource newTokenSource) + void ResetValidationTokenSource(CancellationTokenSource? newTokenSource) { validationTokenSource?.Cancel(); validationTokenSource = newTokenSource; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs index 3cde18df6..108b55739 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs @@ -20,12 +20,12 @@ public class BoolToObjectConverter : ValueConverterExtension, IValueCon /// /// The object that corresponds to True value. /// - public TObject TrueObject { get; set; } + public TObject? TrueObject { get; set; } /// /// The object that corresponds to False value. /// - public TObject FalseObject { get; set; } + public TObject? FalseObject { get; set; } /// /// Converts to object. @@ -35,7 +35,7 @@ public class BoolToObjectConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// The object assigned to if value equals True, otherwise the value assigned to . - 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 bool result) return result ? TrueObject : FalseObject; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs index e07b6d7cf..74dbd2898 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs @@ -20,7 +20,7 @@ public class ByteArrayToImageSourceConverter : ValueConverterExtension, IValueCo /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An object of type . - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; @@ -39,7 +39,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An object of type . - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs old mode 100755 new mode 100644 index 7a9539671..ac7b8c28b --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs @@ -42,9 +42,9 @@ public object Convert(object value, Type targetType, object parameter, CultureIn ? CompareTwoEnums(enumValue, parameter as Enum) : TrueValues.Any(item => CompareTwoEnums(enumValue, item)); - static bool CompareTwoEnums(Enum valueToCheck, object referenceValue) + static bool CompareTwoEnums(Enum valueToCheck, object? referenceValue) { - if (!(referenceValue is Enum referenceEnumValue)) + if (referenceValue is not Enum referenceEnumValue) return false; var valueToCheckType = valueToCheck.GetType(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs index f1a48906b..7512d8566 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs @@ -18,7 +18,7 @@ public class ItemSelectedEventArgsConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A object from object of type . - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs index 83bd96497..09dc63970 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs @@ -18,7 +18,7 @@ public class ItemTappedEventArgsConverter : ValueConverterExtension, IValueConve /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A object from object of type . - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs index 85c7d3bad..d83c02047 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs @@ -15,7 +15,7 @@ public class ListToStringConverter : ValueConverterExtension, IValueConverter /// /// The separator that should be between each item in the collection /// - public string Separator { get; set; } + public string Separator { get; set; } = string.Empty; /// /// Concatenates the items of a collection, using the specified between each item. On each item ToString() will be called. @@ -30,10 +30,10 @@ public object Convert(object value, Type targetType, object parameter, CultureIn if (value == null) return string.Empty; - if (!(value is IEnumerable enumerable)) + if (value is not IEnumerable enumerable) throw new ArgumentException("Value cannot be casted to IEnumerable", nameof(value)); - if (!((parameter ?? Separator ?? string.Empty) is string separator)) + if ((parameter ?? Separator ?? string.Empty) is not string separator) throw new ArgumentException("Parameter cannot be casted to string", nameof(parameter)); var collection = enumerable diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverterParameter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverterParameter.shared.cs index 85950c23d..0ff557592 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverterParameter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverterParameter.shared.cs @@ -11,11 +11,11 @@ public class MultiConverterParameter : BindableObject /// /// The type of object of this parameter. /// - public Type ConverterType { get; set; } + public Type? ConverterType { get; set; } /// /// The value of this parameter. /// - public object Value { get; set; } + public object? Value { get; set; } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs index 8d8f9ce39..36210689d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs @@ -24,7 +24,7 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// The desired text case that the text should be converted to. Must match enum value. /// The culture to use in the converter. This is not implemented. /// The converted text representation with the desired casing. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture) => value == null || value is string || value is char ? Convert(value?.ToString(), parameter) : throw new ArgumentException("Value is neither a string nor a char", nameof(value)); @@ -40,30 +40,26 @@ public object Convert(object value, Type targetType, object parameter, CultureIn public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); - object Convert(string value, object parameter) - => GetParameter(parameter) switch - { - TextCaseType.Lower => value?.ToLowerInvariant(), - TextCaseType.Upper => value?.ToUpperInvariant(), - TextCaseType.FirstUpperRestLower => !string.IsNullOrWhiteSpace(value) - ? value.Substring(0, 1).ToUpperInvariant() + value.Substring(1).ToLowerInvariant() - : value, - _ => value - }; + object? Convert(string? value, object parameter) => GetParameter(parameter) switch + { + TextCaseType.Lower => value?.ToLowerInvariant(), + TextCaseType.Upper => value?.ToUpperInvariant(), + TextCaseType.FirstUpperRestLower => value != null && !string.IsNullOrWhiteSpace(value) + ? value.Substring(0, 1).ToUpperInvariant() + value.Substring(1).ToLowerInvariant() + : value, + _ => value + }; - TextCaseType GetParameter(object parameter) - => parameter == null - ? Type - : parameter switch - { - TextCaseType type => type, - string typeString => Enum.TryParse(typeString, out TextCaseType result) - ? result - : throw new ArgumentException("Cannot parse text case from the string", nameof(parameter)), - int typeInt => Enum.IsDefined(typeof(TextCaseType), typeInt) - ? (TextCaseType)typeInt - : throw new ArgumentException("Cannot convert integer to text case enum value", nameof(parameter)), - _ => TextCaseType.None, - }; + TextCaseType GetParameter(object parameter) => parameter == null ? Type : parameter switch + { + TextCaseType type => type, + string typeString => Enum.TryParse(typeString, out TextCaseType result) + ? result + : throw new ArgumentException("Cannot parse text case from the string", nameof(parameter)), + int typeInt => Enum.IsDefined(typeof(TextCaseType), typeInt) + ? (TextCaseType)typeInt + : throw new ArgumentException("Cannot convert integer to text case enum value", nameof(parameter)), + _ => TextCaseType.None, + }; } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs index ffc7afb09..409290caa 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs @@ -62,9 +62,9 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// All bindings that evaluate to true if is true. Or null if is not a value or is false. - public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + public object[]? ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { - if (!(value is bool boolValue) || targetTypes.Any(t => !t.IsAssignableFrom(typeof(bool)))) + if (value is not bool boolValue || targetTypes.Any(t => !t.IsAssignableFrom(typeof(bool)))) return null; return boolValue ? targetTypes.Select(t => ConditionType == MultiBindingCondition.All).OfType().ToArray() : null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs index 49edbc3a6..f8aeb5edf 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs @@ -19,7 +19,7 @@ public string File public static implicit operator FileMediaSource(string file) => (FileMediaSource)FromFile(file); - public static implicit operator string(FileMediaSource file) => file?.File; + public static implicit operator string?(FileMediaSource? file) => file?.File; static void OnFileMediaSourceChanged(BindableObject bindable, object oldValue, object newValue) => ((FileMediaSource)bindable).OnSourceChanged(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs index cba24f769..53b693e02 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs @@ -25,7 +25,7 @@ public abstract class MediaSource : Element : FromFile(source); [Preserve(Conditional = true)] - public static implicit operator MediaSource(Uri uri) => uri == null ? null : FromUri(uri); + public static implicit operator MediaSource?(Uri uri) => uri == null ? null : FromUri(uri); protected void OnSourceChanged() => weakEventManager.RaiseEvent(this, EventArgs.Empty, nameof(SourceChanged)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/StreamMediaSource.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/StreamMediaSource.shared.cs index 37e2d41b9..447fb2bb4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/StreamMediaSource.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/StreamMediaSource.shared.cs @@ -9,14 +9,14 @@ namespace Xamarin.CommunityToolkit.Core public class StreamMediaSource : MediaSource, IStreamImageSource { readonly object synchandle = new object(); - CancellationTokenSource cancellationTokenSource; + CancellationTokenSource? cancellationTokenSource; - TaskCompletionSource completionSource; + TaskCompletionSource? completionSource; public static readonly BindableProperty StreamProperty = BindableProperty.Create(nameof(Stream), typeof(Func>), typeof(StreamMediaSource)); - protected CancellationTokenSource CancellationTokenSource + protected CancellationTokenSource? CancellationTokenSource { get => cancellationTokenSource; private set @@ -47,12 +47,16 @@ protected override void OnPropertyChanged(string propertyName) base.OnPropertyChanged(propertyName); } - async Task IStreamImageSource.GetStreamAsync(CancellationToken userToken) + async Task IStreamImageSource.GetStreamAsync(CancellationToken userToken) { if (Stream == null) return null; OnLoadingStarted(); + + if (CancellationTokenSource == null) + throw new Exception($"{nameof(OnLoadingStarted)} not called"); + userToken.Register(CancellationTokenSource.Cancel); try { @@ -72,7 +76,7 @@ protected void OnLoadingCompleted(bool cancelled) if (!IsLoading || completionSource == null) return; - var tcs = Interlocked.Exchange(ref completionSource, null); + var tcs = Interlocked.Exchange?>(ref completionSource, null); if (tcs != null) tcs.SetResult(cancelled); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.ios.cs index 9964b30f4..79c441f6e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.ios.cs @@ -14,7 +14,7 @@ namespace Xamarin.CommunityToolkit.iOS.Effects /// public class LifeCycleEffectRouter : PlatformEffect { - LifecycleEffect lifeCycleEffect; + LifecycleEffect? lifeCycleEffect; protected override void OnAttached() { @@ -26,9 +26,9 @@ protected override void OnAttached() void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - if (e.PropertyName == "Renderer") + if (e.PropertyName == "Renderer" && lifeCycleEffect != null) { - var result = Platform.GetRenderer(Element as VisualElement); + var result = Platform.GetRenderer((VisualElement)Element); if (result != null) lifeCycleEffect.RaiseLoadedEvent(Element); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.ios.cs index 8499ae09e..00d257d2b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.ios.cs @@ -12,7 +12,7 @@ public class RemoveBorderEffect : PlatformEffect { UITextBorderStyle? oldBorderStyle; - UITextField TextField => Control as UITextField; + UITextField TextField => (UITextField)Control; protected override void OnAttached() { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SafeArea/SafeAreaEffectRouter.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SafeArea/SafeAreaEffectRouter.ios.cs index a32e9dd57..3c08bc081 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SafeArea/SafeAreaEffectRouter.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SafeArea/SafeAreaEffectRouter.ios.cs @@ -13,8 +13,7 @@ public class SafeAreaEffectRouter : PlatformEffect { Thickness initialMargin; - new View Element - => base.Element as View; + new View Element => (View)base.Element; bool IsEligibleToConsumeEffect => Element != null @@ -43,9 +42,6 @@ protected override void OnDetached() Element.Margin = initialMargin; } - double CalculateInsets(double insetsComponent, bool shouldUseInsetsComponent) - => shouldUseInsetsComponent - ? insetsComponent - : 0; + double CalculateInsets(double insetsComponent, bool shouldUseInsetsComponent) => shouldUseInsetsComponent ? insetsComponent : 0; } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.ios.cs index e78a6b9d1..cb8b6d3ab 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.ios.cs @@ -19,13 +19,12 @@ public class SelectAllTextEffect : PlatformEffect void ApplyEffect(bool apply) => ApplyToControl(Control, apply); - bool ApplyToControl(T controlType, bool apply) => - controlType switch - { - UITextField textField => ApplyToUITextField(textField, apply), - UITextView _ => ApplyToUITextView(apply), - _ => throw new NotSupportedException($"Control of type: {controlType.GetType().Name} is not supported by this effect.") - }; + bool ApplyToControl(T controlType, bool apply) => controlType switch + { + UITextField textField => ApplyToUITextField(textField, apply), + UITextView _ => ApplyToUITextView(apply), + _ => throw new NotSupportedException($"Control of type: {controlType?.GetType().Name} is not supported by this effect.") + }; #region - UITextField diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs index c384fe70d..0eec16061 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs @@ -15,11 +15,11 @@ sealed class GestureManager Color defaultBackgroundColor; - CancellationTokenSource longPressTokenSource; + CancellationTokenSource? longPressTokenSource; - CancellationTokenSource animationTokenSource; + CancellationTokenSource? animationTokenSource; - Func animationTaskFactory; + Func? animationTaskFactory; double? durationMultiplier; @@ -135,7 +135,7 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated) } var durationMultiplier = this.durationMultiplier; this.durationMultiplier = null; - await GetAnimationTask(sender, state, hoverState, durationMultiplier.GetValueOrDefault()).ConfigureAwait(false); + await GetAnimationTask(sender, state, hoverState, animationTokenSource.Token, durationMultiplier.GetValueOrDefault()).ConfigureAwait(false); return; } @@ -143,7 +143,7 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated) if (pulseCount == 0 || (state == TouchState.Normal && !isToggled.HasValue)) { - await GetAnimationTask(sender, state, hoverState).ConfigureAwait(false); + await GetAnimationTask(sender, state, hoverState, animationTokenSource.Token).ConfigureAwait(false); return; } do @@ -152,7 +152,7 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated) ? TouchState.Normal : TouchState.Pressed; - await GetAnimationTask(sender, rippleState, hoverState); + await GetAnimationTask(sender, rippleState, hoverState, animationTokenSource.Token); if (token.IsCancellationRequested) return; @@ -160,7 +160,7 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated) ? TouchState.Pressed : TouchState.Normal; - await GetAnimationTask(sender, rippleState, hoverState); + await GetAnimationTask(sender, rippleState, hoverState, animationTokenSource.Token); if (token.IsCancellationRequested) return; } @@ -199,7 +199,7 @@ internal void HandleLongPress(TouchEffect sender) }); } - internal void SetCustomAnimationTask(Func animationTaskFactory) + internal void SetCustomAnimationTask(Func? animationTaskFactory) => this.animationTaskFactory = animationTaskFactory; internal void Reset() @@ -225,10 +225,11 @@ internal void OnTapped(TouchEffect sender) void HandleCollectionViewSelection(TouchEffect sender) { - if (!sender.Element.TryFindParentElementWithParentOfType(out var element, out CollectionView collectionView)) + if (!sender.Element.TryFindParentElementWithParentOfType(out var result, out CollectionView? parent)) return; - var item = element.BindingContext ?? element; + var collectionView = parent ?? throw new NullReferenceException(); + var item = result?.BindingContext ?? result ?? throw new NullReferenceException(); switch (collectionView.SelectionMode) { @@ -566,12 +567,11 @@ Color GetBackgroundColor(Color color) ? color : defaultBackgroundColor; - Task GetAnimationTask(TouchEffect sender, TouchState touchState, HoverState hoverState, double? durationMultiplier = null) + Task GetAnimationTask(TouchEffect sender, TouchState touchState, HoverState hoverState, CancellationToken token, double? durationMultiplier = null) { if (sender.Element == null) return Task.FromResult(false); - var token = animationTokenSource.Token; var duration = sender.AnimationDuration; var easing = sender.AnimationEasing; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.ios.cs index 3d7b150dd..7cffec3fc 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.ios.cs @@ -14,11 +14,11 @@ namespace Xamarin.CommunityToolkit.iOS.Effects { public class PlatformTouchEffect : PlatformEffect { - UIGestureRecognizer touchGesture; + UIGestureRecognizer? touchGesture; - UIGestureRecognizer hoverGesture; + UIGestureRecognizer? hoverGesture; - TouchEffect effect; + TouchEffect? effect; UIView View => Container ?? Control; @@ -83,7 +83,7 @@ void OnHover() if (effect?.IsDisabled ?? true) return; - switch (hoverGesture.State) + switch (hoverGesture?.State) { case UIGestureRecognizerState.Began: case UIGestureRecognizerState.Changed: @@ -101,7 +101,7 @@ void PreventButtonHighlight(object sender, EventArgs args) sealed class TouchUITapGestureRecognizer : UIGestureRecognizer { - TouchEffect effect; + TouchEffect? effect; float? defaultRadius; float? defaultShadowRadius; float? defaultShadowOpacity; @@ -118,7 +118,7 @@ public TouchUITapGestureRecognizer(TouchEffect effect) public bool IsButton { get; set; } - UIView Renderer => effect?.Element.GetRenderer() as UIView; + UIView? Renderer => (UIView?)effect?.Element.GetRenderer(); public override void TouchesBegan(NSSet touches, UIEvent evt) { @@ -172,7 +172,7 @@ public override void TouchesMoved(NSSet touches, UIEvent evt) } } - var status = point != null && Renderer.Bounds.Contains(point.Value) + var status = point != null && Renderer?.Bounds.Contains(point.Value) is true ? TouchStatus.Started : TouchStatus.Canceled; @@ -187,8 +187,9 @@ protected override void Dispose(bool disposing) if (disposing) { effect = null; - Delegate = null; + Delegate.Dispose(); } + base.Dispose(disposing); } @@ -209,7 +210,7 @@ public void HandleTouch(TouchStatus status, TouchInteractionStatus? interactionS interactionStatus = null; } - effect.HandleTouch(status); + effect?.HandleTouch(status); if (interactionStatus.HasValue) effect?.HandleUserInteraction(interactionStatus.Value); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs index 9bc825783..50e58d1ab 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs @@ -462,10 +462,10 @@ public class TouchEffect : RoutingEffect readonly WeakEventManager weakEventManager = new WeakEventManager(); - VisualElement element; + VisualElement? element; public TouchEffect() - : base(EffectIds.TouchEffect) + : base(EffectIds.TouchEffect) { #region Required work-around to prevent linker from removing the platform-specific implementation #if __ANDROID__ @@ -500,13 +500,13 @@ public static void SetShouldMakeChildrenInputTransparent(BindableObject bindable => bindable.SetValue(ShouldMakeChildrenInputTransparentProperty, value); public static ICommand GetCommand(BindableObject bindable) - => bindable.GetValue(CommandProperty) as ICommand; + => (ICommand)bindable.GetValue(CommandProperty); public static void SetCommand(BindableObject bindable, ICommand value) => bindable.SetValue(CommandProperty, value); public static ICommand GetLongPressCommand(BindableObject bindable) - => bindable.GetValue(LongPressCommandProperty) as ICommand; + => (ICommand)bindable.GetValue(LongPressCommandProperty); public static void SetLongPressCommand(BindableObject bindable, ICommand value) => bindable.SetValue(LongPressCommandProperty, value); @@ -710,7 +710,7 @@ public static void SetAnimationDuration(BindableObject bindable, int value) => bindable.SetValue(AnimationDurationProperty, value); public static Easing GetAnimationEasing(BindableObject bindable) - => bindable.GetValue(AnimationEasingProperty) as Easing; + => (Easing)bindable.GetValue(AnimationEasingProperty); public static void SetAnimationEasing(BindableObject bindable, Easing value) => bindable.SetValue(AnimationEasingProperty, value); @@ -722,7 +722,7 @@ public static void SetPressedAnimationDuration(BindableObject bindable, int valu => bindable.SetValue(PressedAnimationDurationProperty, value); public static Easing GetPressedAnimationEasing(BindableObject bindable) - => bindable.GetValue(PressedAnimationEasingProperty) as Easing; + => (Easing)bindable.GetValue(PressedAnimationEasingProperty); public static void SetPressedAnimationEasing(BindableObject bindable, Easing value) => bindable.SetValue(PressedAnimationEasingProperty, value); @@ -734,7 +734,7 @@ public static void SetNormalAnimationDuration(BindableObject bindable, int value => bindable.SetValue(NormalAnimationDurationProperty, value); public static Easing GetNormalAnimationEasing(BindableObject bindable) - => bindable.GetValue(NormalAnimationEasingProperty) as Easing; + => (Easing)bindable.GetValue(NormalAnimationEasingProperty); public static void SetNormalAnimationEasing(BindableObject bindable, Easing value) => bindable.SetValue(NormalAnimationEasingProperty, value); @@ -746,7 +746,7 @@ public static void SetHoveredAnimationDuration(BindableObject bindable, int valu => bindable.SetValue(HoveredAnimationDurationProperty, value); public static Easing GetHoveredAnimationEasing(BindableObject bindable) - => bindable.GetValue(HoveredAnimationEasingProperty) as Easing; + => (Easing)bindable.GetValue(HoveredAnimationEasingProperty); public static void SetHoveredAnimationEasing(BindableObject bindable, Easing value) => bindable.SetValue(HoveredAnimationEasingProperty, value); @@ -843,7 +843,7 @@ public static void SetShouldSetImageOnAnimationEnd(BindableObject bindable, bool static void TryGenerateEffect(BindableObject bindable, object oldValue, object newValue) { - if (!(bindable is VisualElement view) || view.Effects.OfType().Any()) + if (bindable is not VisualElement view || view.Effects.OfType().Any()) return; view.Effects.Add(new TouchEffect { IsAutoGenerated = true }); @@ -1047,14 +1047,13 @@ internal new VisualElement Element } } - internal static TouchEffect GetFrom(BindableObject bindable) + internal static TouchEffect? GetFrom(BindableObject bindable) { var effects = (bindable as VisualElement)?.Effects?.OfType(); - return effects?.FirstOrDefault(x => !x.IsAutoGenerated) - ?? effects?.FirstOrDefault(); + return effects?.FirstOrDefault(x => !x.IsAutoGenerated) ?? effects?.FirstOrDefault(); } - internal static TouchEffect PickFrom(BindableObject bindable) + internal static TouchEffect? PickFrom(BindableObject bindable) { var effects = (bindable as VisualElement)?.Effects?.OfType(); return effects?.FirstOrDefault(x => !x.IsAutoGenerated && !x.IsUsed) @@ -1114,7 +1113,7 @@ internal void HandleLongPress() void SetChildrenInputTransparent(bool value) { - if (!(Element is Layout layout)) + if (Element is not Layout layout) return; layout.ChildAdded -= OnLayoutChildAdded; @@ -1131,7 +1130,7 @@ void SetChildrenInputTransparent(bool value) void OnLayoutChildAdded(object sender, ElementEventArgs e) { - if (!(e.Element is View view)) + if (e.Element is not View view) return; view.InputTransparent = ShouldMakeChildrenInputTransparent && diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/TouchEvents.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/TouchEvents.ios.cs index 0c85b3c21..7f4713499 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/TouchEvents.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/TouchEvents.ios.cs @@ -5,13 +5,13 @@ namespace Xamarin.CommunityToolkit.iOS.Effects [Foundation.Preserve(AllMembers = true)] class TouchEvents { - public event EventHandler TouchBegin; + public event EventHandler? TouchBegin; - public event EventHandler TouchMove; + public event EventHandler? TouchMove; - public event EventHandler TouchEnd; + public event EventHandler? TouchEnd; - public event EventHandler TouchCancel; + public event EventHandler? TouchCancel; public virtual void OnTouchBegin() => TouchBegin?.Invoke(this, EventArgs.Empty); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.android.cs index b77ee0b48..6566634e7 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.android.cs @@ -1,4 +1,5 @@ -using Android.Content.Res; +using System; +using Android.Content.Res; using Android.Graphics.Drawables; using Android.Runtime; using Android.Views; @@ -17,19 +18,19 @@ namespace Xamarin.CommunityToolkit.Android.Effects [Preserve(AllMembers = true)] public class VisualFeedbackEffectRouter : PlatformEffect { - AView view; - RippleDrawable ripple; - Drawable orgDrawable; - FrameLayout rippleOverlay; - FastRendererOnLayoutChangeListener fastListener; + AView? view; + RippleDrawable? ripple; + Drawable? orgDrawable; + FrameLayout? rippleOverlay; + FastRendererOnLayoutChangeListener? fastListener; - bool IsClickable => !(Element is Layout || Element is BoxView); + bool IsClickable => Element is not (Layout or BoxView); protected override void OnAttached() { view = Control ?? Container; - SetUpRipple(); + SetUpRipple(view); if (IsClickable) view.Touch += OnViewTouch; @@ -41,18 +42,32 @@ protected override void OnDetached() { if (!IsClickable) { - view.Touch -= OnOverlayTouch; - view.RemoveOnLayoutChangeListener(fastListener); + if (view != null) + { + view.Touch -= OnOverlayTouch; + view.RemoveOnLayoutChangeListener(fastListener); + } + + if (fastListener != null) + { + fastListener.Dispose(); + fastListener = null; + } - fastListener.Dispose(); - fastListener = null; - rippleOverlay.Dispose(); - rippleOverlay = null; + if (rippleOverlay != null) + { + rippleOverlay.Dispose(); + rippleOverlay = null; + } } else { - view.Touch -= OnViewTouch; - view.Background = orgDrawable; + if (view != null) + { + view.Touch -= OnViewTouch; + view.Background = orgDrawable; + } + orgDrawable = null; } @@ -82,13 +97,13 @@ void UpdateEffectColor() ripple?.SetColor(GetPressedColorSelector(nativeColor)); } - void SetUpRipple() + void SetUpRipple(in AView view) { ripple = CreateRipple(AColor.Transparent); if (!IsClickable) { - rippleOverlay = new FrameLayout(view.Context) + rippleOverlay = new FrameLayout(view.Context ?? throw new NullReferenceException()) { Clickable = true, LongClickable = true, @@ -107,10 +122,11 @@ void SetUpRipple() void SetUpOverlay() { - var parent = view.Parent as ViewGroup; + var parent = view?.Parent as ViewGroup; - parent.AddView(rippleOverlay); + parent?.AddView(rippleOverlay); + _ = rippleOverlay ?? throw new NullReferenceException(); rippleOverlay.BringToFront(); rippleOverlay.Touch += OnOverlayTouch; } @@ -132,7 +148,7 @@ RippleDrawable CreateRipple(AColor color) return new RippleDrawable(GetPressedColorSelector(color), null, mask); } - var back = view.Background; + var back = view?.Background; if (back == null) { @@ -156,16 +172,14 @@ RippleDrawable CreateRipple(AColor color) internal class FastRendererOnLayoutChangeListener : Java.Lang.Object, AView.IOnLayoutChangeListener { bool hasParent = false; - VisualFeedbackEffectRouter effect; + VisualFeedbackEffectRouter? effect; - public FastRendererOnLayoutChangeListener(VisualFeedbackEffectRouter effect) - { - this.effect = effect; - } + public FastRendererOnLayoutChangeListener(VisualFeedbackEffectRouter effect) => this.effect = effect; - public void OnLayoutChange(AView v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) + public void OnLayoutChange(AView? v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - effect.rippleOverlay.Layout(v.Left, v.Top, v.Right, v.Bottom); + if (v != null) + effect?.rippleOverlay?.Layout(v.Left, v.Top, v.Right, v.Bottom); if (hasParent) { @@ -173,7 +187,7 @@ public void OnLayoutChange(AView v, int left, int top, int right, int bottom, in } hasParent = true; - effect.SetUpOverlay(); + effect?.SetUpOverlay(); } protected override void Dispose(bool disposing) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.ios.cs index 910611543..1a254e14a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/VisualFeedback/VisualFeedbackEffectRouter.ios.cs @@ -12,10 +12,10 @@ namespace Xamarin.CommunityToolkit.iOS.Effects [Foundation.Preserve(AllMembers = true)] public class VisualFeedbackEffectRouter : PlatformEffect { - TouchEvents touchEvents; - TouchEventsGestureRecognizer touchRecognizer; - UIView view; - UIView layer; + TouchEvents? touchEvents; + TouchEventsGestureRecognizer? touchRecognizer; + UIView? view; + UIView? layer; float alpha; protected override void OnAttached() @@ -57,22 +57,29 @@ protected override void OnAttached() protected override void OnDetached() { - touchEvents.TouchBegin -= OnTouchBegin; - touchEvents.TouchEnd -= OnTouchEnd; - touchEvents.TouchCancel -= OnTouchEnd; + if (touchEvents != null) + { + touchEvents.TouchBegin -= OnTouchBegin; + touchEvents.TouchEnd -= OnTouchEnd; + touchEvents.TouchCancel -= OnTouchEnd; + } - view.RemoveGestureRecognizer(touchRecognizer); - touchRecognizer.Delegate?.Dispose(); - touchRecognizer.Delegate = null; - touchRecognizer.Dispose(); + if (view != null && touchRecognizer != null) + { + view.RemoveGestureRecognizer(touchRecognizer); + touchRecognizer.Delegate.Dispose(); + touchRecognizer.Dispose(); + } - touchEvents = null; - touchRecognizer = null; + if (layer != null) + { + layer.RemoveFromSuperview(); + layer.Dispose(); + } - layer.RemoveFromSuperview(); - layer.Dispose(); layer = null; - + touchRecognizer = null; + touchEvents = null; view = null; } @@ -90,30 +97,34 @@ void UpdateEffectColor() { var color = VisualFeedbackEffect.GetFeedbackColor(Element); alpha = color.A < 1.0f ? 1f : 0.1f; - layer.BackgroundColor = color.ToUIColor(); + + if (layer != null) + layer.BackgroundColor = color.ToUIColor(); } async void OnTouchBegin(object sender, EventArgs e) { - if (!(Element is VisualElement visualElement) || !visualElement.IsEnabled) + if (Element is not VisualElement visualElement || !visualElement.IsEnabled) return; - view.BecomeFirstResponder(); + view?.BecomeFirstResponder(); await UIView.AnimateAsync(0.5, () => { - layer.Alpha = alpha; + if (layer != null) + layer.Alpha = alpha; }); } async void OnTouchEnd(object sender, EventArgs e) { - if (!(Element is VisualElement visualElement) || !visualElement.IsEnabled) + if (Element is not VisualElement visualElement || !visualElement.IsEnabled) return; await UIView.AnimateAsync(0.5, () => { - layer.Alpha = 0; + if (layer != null) + layer.Alpha = 0; }); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/ImageResourceExtension.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/ImageResourceExtension.shared.cs index 66090e203..9510d43c7 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/ImageResourceExtension.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/ImageResourceExtension.shared.cs @@ -11,14 +11,14 @@ namespace Xamarin.CommunityToolkit.Extensions /// Provides ImageSource by Resource Id from the current app's assembly. /// [ContentProperty(nameof(Id))] - public class ImageResourceExtension : IMarkupExtension + public class ImageResourceExtension : IMarkupExtension { /// /// The Resource Id of the image. /// - public string Id { get; set; } + public string Id { get; set; } = string.Empty; - public ImageSource ProvideValue(IServiceProvider serviceProvider) + public ImageSource? ProvideValue(IServiceProvider serviceProvider) => Id == null ? null : ImageSource.FromResource(Id, Application.Current.GetType() diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/NavigableElement/NavigableElementExtensions.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/NavigableElement/NavigableElementExtensions.shared.cs index 78b262388..77cebc2d7 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/NavigableElement/NavigableElementExtensions.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/NavigableElement/NavigableElementExtensions.shared.cs @@ -36,7 +36,7 @@ public static class NavigableElementExtensions /// /// A task that will complete once the is dismissed. /// - public static Task ShowPopupAsync(this NavigableElement element, Popup popup) => + public static Task ShowPopupAsync(this NavigableElement element, Popup popup) => element.Navigation.ShowPopupAsync(popup); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.android.cs index 668c99914..164422241 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.android.cs @@ -9,7 +9,7 @@ public static partial class NavigationExtensions static void PlatformShowPopup(BasePopup popup) => Platform.CreateRendererWithContext(popup, ToolkitPlatform.Context); - static Task PlatformShowPopupAsync(Popup popup) + static Task PlatformShowPopupAsync(Popup popup) { PlatformShowPopup(popup); return popup.Result; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.ios.cs index 30620892f..4c7eaf4a8 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.ios.cs @@ -9,7 +9,7 @@ public static partial class NavigationExtensions static void PlatformShowPopup(BasePopup popup) => Platform.CreateRenderer(popup); - static Task PlatformShowPopupAsync(Popup popup) + static Task PlatformShowPopupAsync(Popup popup) { PlatformShowPopup(popup); return popup.Result; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.shared.cs index a25a717bf..532bcd1b2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.shared.cs @@ -36,7 +36,7 @@ public static partial class NavigationExtensions /// /// A task that will complete once the is dismissed. /// - public static Task ShowPopupAsync(this INavigation navigation, Popup popup) => + public static Task ShowPopupAsync(this INavigation navigation, Popup popup) => PlatformShowPopupAsync(popup); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/TranslateExtension.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/TranslateExtension.shared.cs index 07068996f..d1b93d4ee 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/TranslateExtension.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/TranslateExtension.shared.cs @@ -8,9 +8,9 @@ namespace Xamarin.CommunityToolkit.Extensions [ContentProperty(nameof(Text))] public class TranslateExtension : IMarkupExtension { - public string Text { get; set; } + public string Text { get; set; } = string.Empty; - public string StringFormat { get; set; } + public string StringFormat { get; set; } = string.Empty; object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) => ProvideValue(serviceProvider); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/VisualElement/VisualElementExtension.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/VisualElement/VisualElementExtension.shared.cs index 89a25faee..f4a561f5c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/VisualElement/VisualElementExtension.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/VisualElement/VisualElementExtension.shared.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Xamarin.Forms; @@ -9,7 +10,7 @@ namespace Xamarin.CommunityToolkit.Extensions /// public static partial class VisualElementExtension { - public static Task ColorTo(this VisualElement element, Color color, uint length = 250u, Easing easing = null) + public static Task ColorTo(this VisualElement element, Color color, uint length = 250u, Easing? easing = null) { _ = element ?? throw new ArgumentNullException(nameof(element)); @@ -38,7 +39,7 @@ public static void AbortAnimations(this VisualElement element, params string[] o element.AbortAnimation(name); } - internal static bool TryFindParentElementWithParentOfType(this VisualElement element, out VisualElement result, out T parent) where T : VisualElement + internal static bool TryFindParentElementWithParentOfType(this VisualElement element, out VisualElement? result, out T? parent) where T : VisualElement { _ = element ?? throw new ArgumentNullException(nameof(element)); @@ -46,9 +47,9 @@ public static void AbortAnimations(this VisualElement element, params string[] o parent = null; while (element?.Parent != null) { - if (!(element.Parent is T parentElement)) + if (element.Parent is not T parentElement) { - element = element.Parent as VisualElement; + element = (VisualElement)element.Parent; continue; } result = element; @@ -58,7 +59,7 @@ public static void AbortAnimations(this VisualElement element, params string[] o return false; } - internal static bool TryFindParentOfType(this VisualElement element, out T parent) where T : VisualElement - => TryFindParentElementWithParentOfType(element, out _, out parent); + internal static bool TryFindParentOfType(this VisualElement element, out T? parent) where T : VisualElement + => TryFindParentElementWithParentOfType(element, out _, out parent); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/DelegateWeakEventManager.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/DelegateWeakEventManager.shared.cs index 579ce86f8..35087b95b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/DelegateWeakEventManager.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/DelegateWeakEventManager.shared.cs @@ -18,7 +18,7 @@ public class DelegateWeakEventManager /// /// Handler /// Event name - public void AddEventHandler(Delegate handler, [CallerMemberName] string eventName = "") + public void AddEventHandler(Delegate? handler, [CallerMemberName] string eventName = "") { if (IsNullOrWhiteSpace(eventName)) throw new ArgumentNullException(nameof(eventName)); @@ -34,7 +34,7 @@ public void AddEventHandler(Delegate handler, [CallerMemberName] string eventNam /// /// Handler /// Event name - public void RemoveEventHandler(Delegate handler, [CallerMemberName] string eventName = "") + public void RemoveEventHandler(Delegate? handler, [CallerMemberName] string eventName = "") { if (IsNullOrWhiteSpace(eventName)) throw new ArgumentNullException(nameof(eventName)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizationResourceManager.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizationResourceManager.shared.cs index e38fe1001..d1f09dceb 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizationResourceManager.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizationResourceManager.shared.cs @@ -14,7 +14,7 @@ public class LocalizationResourceManager : ObservableObject public static LocalizationResourceManager Current => currentHolder.Value; - ResourceManager resourceManager; + ResourceManager? resourceManager; CultureInfo currentCulture = Thread.CurrentThread.CurrentUICulture; LocalizationResourceManager() @@ -30,10 +30,10 @@ public void Init(ResourceManager resource, CultureInfo initialCulture) CurrentCulture = initialCulture; } - public string GetValue(string text) => - resourceManager.GetString(text, CurrentCulture); + public string? GetValue(string text) => + resourceManager?.GetString(text, CurrentCulture); - public string this[string text] => + public string? this[string text] => GetValue(text); [Obsolete("Please, use " + nameof(CurrentCulture) + " to set culture")] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs index 98e8802ee..0fcfa473c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs @@ -7,14 +7,14 @@ namespace Xamarin.CommunityToolkit.Helpers #if !NETSTANDARD1_0 public class LocalizedString : ObservableObject { - readonly Func generator; + readonly Func? generator; - public LocalizedString(Func generator = null) + public LocalizedString(Func? generator = null) : this(LocalizationResourceManager.Current, generator) { } - public LocalizedString(LocalizationResourceManager localizationManager, Func generator = null) + public LocalizedString(LocalizationResourceManager localizationManager, Func? generator = null) { this.generator = generator; @@ -23,7 +23,7 @@ public LocalizedString(LocalizationResourceManager localizationManager, Func OnPropertyChanged(null); } - public string Localized => generator?.Invoke(); + public string? Localized => generator?.Invoke(); [Preserve(Conditional = true)] public static implicit operator LocalizedString(Func func) => new LocalizedString(func); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/Subscription.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/Subscription.shared.cs index 0d26a4cb3..ac55aa507 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/Subscription.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/Subscription.shared.cs @@ -6,11 +6,11 @@ namespace Xamarin.CommunityToolkit.Helpers { struct Subscription { - public WeakReference Subscriber { get; } + public WeakReference? Subscriber { get; } public MethodInfo Handler { get; } - public Subscription(WeakReference subscriber, MethodInfo handler) + public Subscription(WeakReference? subscriber, MethodInfo handler) { Subscriber = subscriber; Handler = handler ?? throw new ArgumentNullException(nameof(handler)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManager.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManager.shared.cs index 080a576a7..eb670f768 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManager.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManager.shared.cs @@ -121,7 +121,7 @@ public static class WeakEventManagerExtensions /// Sender /// Event arguments /// Event name - public static void RaiseEvent(this Forms.WeakEventManager weakEventManager, object sender, object eventArgs, string eventName) + public static void RaiseEvent(this Forms.WeakEventManager weakEventManager, object? sender, object eventArgs, string eventName) { _ = weakEventManager ?? throw new ArgumentNullException(nameof(weakEventManager)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs index 4c78694dd..8f51b7b1b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs @@ -10,7 +10,7 @@ namespace Xamarin.CommunityToolkit.Helpers { static class EventManagerService { - internal static void AddEventHandler(in string eventName, in object handlerTarget, in MethodInfo methodInfo, in Dictionary> eventHandlers) + internal static void AddEventHandler(in string eventName, in object? handlerTarget, in MethodInfo methodInfo, in Dictionary> eventHandlers) { var doesContainSubscriptions = eventHandlers.TryGetValue(eventName, out var targets); if (!doesContainSubscriptions || targets == null) @@ -25,7 +25,7 @@ internal static void AddEventHandler(in string eventName, in object handlerTarge targets.Add(new Subscription(new WeakReference(handlerTarget), methodInfo)); } - internal static void RemoveEventHandler(in string eventName, in object handlerTarget, in MemberInfo methodInfo, in Dictionary> eventHandlers) + internal static void RemoveEventHandler(in string eventName, in object? handlerTarget, in MemberInfo methodInfo, in Dictionary> eventHandlers) { var doesContainSubscriptions = eventHandlers.TryGetValue(eventName, out var subscriptions); if (!doesContainSubscriptions || subscriptions == null) @@ -46,7 +46,7 @@ internal static void RemoveEventHandler(in string eventName, in object handlerTa } } - internal static void HandleEvent(in string eventName, in object sender, in object eventArgs, in Dictionary> eventHandlers) + internal static void HandleEvent(in string eventName, in object? sender, in object? eventArgs, in Dictionary> eventHandlers) { AddRemoveEvents(eventName, eventHandlers, out var toRaise); @@ -72,7 +72,7 @@ internal static void HandleEvent(in string eventName, in object sender, in objec } } - internal static void HandleEvent(in string eventName, in object actionEventArgs, in Dictionary> eventHandlers) + internal static void HandleEvent(in string eventName, in object? actionEventArgs, in Dictionary> eventHandlers) { AddRemoveEvents(eventName, eventHandlers, out var toRaise); @@ -124,10 +124,10 @@ internal static void HandleEvent(in string eventName, in Dictionary> eventHandlers, out List<(object Instance, MethodInfo EventHandler)> toRaise) + static void AddRemoveEvents(in string eventName, in Dictionary> eventHandlers, out List<(object? Instance, MethodInfo EventHandler)> toRaise) { var toRemove = new List(); - toRaise = new List<(object, MethodInfo)>(); + toRaise = new List<(object?, MethodInfo)>(); var doesContainEventName = eventHandlers.TryGetValue(eventName, out var target); if (doesContainEventName && target != null) @@ -159,7 +159,7 @@ static void AddRemoveEvents(in string eventName, in Dictionary : BaseAsyncCommandIf an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncCommand( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : base(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -47,9 +47,9 @@ public class AsyncCommand : BaseAsyncCommand, IAsyncCommand /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncCommand( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : base(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -64,9 +64,9 @@ public class AsyncCommand : BaseAsyncCommand, IAsyncCommand /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncCommand( - Func execute, + Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : this(execute, ConvertCanExecute(canExecute), onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -94,8 +94,8 @@ public class AsyncCommand : BaseAsyncCommand, IAsyncCommand /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncCommand( Func execute, - Func canExecute = null, - Action onException = null, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : base(ConvertExecute(execute), canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -112,7 +112,7 @@ public class AsyncCommand : BaseAsyncCommand, IAsyncCommand public AsyncCommand( Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : this(execute, ConvertCanExecute(canExecute), onException, continueOnCapturedContext, allowsMultipleExecutions) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/AsyncValueCommand.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/AsyncValueCommand.shared.cs index 5961f7a0a..60d5b4e7b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/AsyncValueCommand.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/AsyncValueCommand.shared.cs @@ -15,9 +15,9 @@ public class AsyncValueCommand : BaseAsyncValueCommandIf an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncValueCommand( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : base(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -44,9 +44,9 @@ public class AsyncValueCommand : BaseAsyncValueCommand, IAsyncValu /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncValueCommand( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : base(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -61,9 +61,9 @@ public class AsyncValueCommand : BaseAsyncValueCommand, IAsyncValu /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncValueCommand( - Func execute, + Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : this(execute, ConvertCanExecute(canExecute), onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -91,8 +91,8 @@ public class AsyncValueCommand : BaseAsyncValueCommand, IAsyncVa /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread public AsyncValueCommand( Func execute, - Func canExecute = null, - Action onException = null, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : base(ConvertExecute(execute), canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions) @@ -109,7 +109,7 @@ public class AsyncValueCommand : BaseAsyncValueCommand, IAsyncVa public AsyncValueCommand( Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) : this(execute, ConvertCanExecute(canExecute), onException, continueOnCapturedContext, allowsMultipleExecutions) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncCommand.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncCommand.shared.cs index 40276897c..b06b43683 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncCommand.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncCommand.shared.cs @@ -18,8 +18,8 @@ public partial class CommandFactory /// IAsyncCommand public static IAsyncCommand Create( Func execute, - Func canExecute = null, - Action onException = null, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -35,7 +35,7 @@ public partial class CommandFactory public static IAsyncCommand Create( Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -49,9 +49,9 @@ public partial class CommandFactory /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// IAsyncCommand public static IAsyncCommand Create( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -65,9 +65,9 @@ public partial class CommandFactory /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// IAsyncCommand public static IAsyncCommand Create( - Func execute, + Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -81,9 +81,9 @@ public partial class CommandFactory /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// IAsyncCommand public static IAsyncCommand Create( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -97,7 +97,7 @@ public partial class CommandFactory /// IAsyncCommand public static IAsyncCommand Create(Func execute) { - Func canExecute = null; + Func? canExecute = null; return Create(execute, canExecute, null, false, true); } @@ -107,7 +107,7 @@ public static IAsyncCommand Create(Func execute) /// The Function executed when Execute or ExecuteAsync is called. This does not check canExecute before executing and will execute even if canExecute is false /// The Function that verifies whether or not AsyncCommand should execute. /// IAsyncCommand - public static IAsyncCommand Create(Func execute, Func canExecute) => + public static IAsyncCommand Create(Func execute, Func canExecute) => Create(execute, canExecute, null, false, true); /// @@ -124,9 +124,9 @@ public static IAsyncCommand Create(Func execute) /// /// The Function executed when Execute or ExecuteAsync is called. This does not check canExecute before executing and will execute even if canExecute is false /// IAsyncCommand - public static IAsyncCommand Create(Func execute) + public static IAsyncCommand Create(Func execute) { - Func canExecute = null; + Func? canExecute = null; return Create(execute, canExecute, null, false, true); } @@ -136,7 +136,7 @@ public static IAsyncCommand Create(Func exec /// The Function executed when Execute or ExecuteAsync is called. This does not check canExecute before executing and will execute even if canExecute is false /// The Function that verifies whether or not AsyncCommand should execute. /// IAsyncCommand - public static IAsyncCommand Create(Func execute, Func canExecute) => + public static IAsyncCommand Create(Func execute, Func canExecute) => Create(execute, canExecute, null, false, true); /// @@ -145,7 +145,7 @@ public static IAsyncCommand Create(Func exec /// The Function executed when Execute or ExecuteAsync is called. This does not check canExecute before executing and will execute even if canExecute is false /// The Function that verifies whether or not AsyncCommand should execute. /// IAsyncCommand - public static IAsyncCommand Create(Func execute, Func canExecute) => + public static IAsyncCommand Create(Func execute, Func canExecute) => Create(execute, canExecute, null, false, true); /// @@ -154,7 +154,7 @@ public static IAsyncCommand Create(Func exec /// The Function executed when Execute or ExecuteAsync is called. This does not check canExecute before executing and will execute even if canExecute is false /// The Function that verifies whether or not AsyncCommand should execute. /// IAsyncCommand - public static IAsyncCommand Create(Func execute, Func canExecute) => + public static IAsyncCommand Create(Func execute, Func canExecute) => Create(execute, canExecute, null, false, true); #endregion } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncValueCommand.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncValueCommand.shared.cs index b237836cf..20b82a79d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncValueCommand.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/CommandFactory.IAsyncValueCommand.shared.cs @@ -18,8 +18,8 @@ public partial class CommandFactory /// IAsyncValueCommand public static IAsyncValueCommand Create( Func execute, - Func canExecute = null, - Action onException = null, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncValueCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -35,7 +35,7 @@ public partial class CommandFactory public static IAsyncValueCommand Create( Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncValueCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -49,9 +49,9 @@ public partial class CommandFactory /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// IAsyncValueCommand public static IAsyncValueCommand Create( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncValueCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -65,9 +65,9 @@ public partial class CommandFactory /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// IAsyncValueCommand public static IAsyncValueCommand Create( - Func execute, + Func execute, Func canExecute, - Action onException = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncValueCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); @@ -81,9 +81,9 @@ public partial class CommandFactory /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// IAsyncValueCommand> public static IAsyncValueCommand Create( - Func execute, - Func canExecute = null, - Action onException = null, + Func execute, + Func? canExecute = null, + Action? onException = null, bool continueOnCapturedContext = false, bool allowsMultipleExecutions = true) => new AsyncValueCommand(execute, canExecute, onException, continueOnCapturedContext, allowsMultipleExecutions); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncCommand.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncCommand.shared.cs index eb6f8dbf8..04547dca9 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncCommand.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncCommand.shared.cs @@ -13,8 +13,8 @@ namespace Xamarin.CommunityToolkit.ObjectModel.Internals [EditorBrowsable(EditorBrowsableState.Never)] public class BaseAsyncCommand : BaseCommand, ICommand { - readonly Func execute; - readonly Action onException; + readonly Func execute; + readonly Action? onException; readonly bool continueOnCapturedContext; /// @@ -24,10 +24,10 @@ public class BaseAsyncCommand : BaseCommand, /// The Function that verifies whether or not AsyncCommand should execute. /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread - public BaseAsyncCommand( - Func execute, - Func canExecute, - Action onException, + protected BaseAsyncCommand( + Func? execute, + Func? canExecute, + Action? onException, bool continueOnCapturedContext, bool allowsMultipleExecutions) : base(canExecute, allowsMultipleExecutions) @@ -42,7 +42,7 @@ public class BaseAsyncCommand : BaseCommand, /// /// /// The Execute parameter required for ICommand - private protected static Func ConvertExecute(Func execute) + private protected static Func? ConvertExecute(Func? execute) { if (execute == null) return null; @@ -55,7 +55,7 @@ public class BaseAsyncCommand : BaseCommand, /// /// /// The CanExecute parameter required for ICommand - private protected static Func ConvertCanExecute(Func canExecute) + private protected static Func? ConvertCanExecute(Func? canExecute) { if (canExecute == null) return null; @@ -68,7 +68,7 @@ public class BaseAsyncCommand : BaseCommand, /// /// The executed Task /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - private protected async Task ExecuteAsync(TExecute parameter) + private protected async Task ExecuteAsync(TExecute? parameter) { ExecutionCount++; @@ -90,7 +90,7 @@ private protected async Task ExecuteAsync(TExecute parameter) bool ICommand.CanExecute(object parameter) => parameter switch { TCanExecute validParameter => CanExecute(validParameter), - null when !typeof(TCanExecute).GetTypeInfo().IsValueType => CanExecute((TCanExecute)parameter), + null when !typeof(TCanExecute).GetTypeInfo().IsValueType => CanExecute((TCanExecute?)parameter), null => throw new InvalidCommandParameterException(typeof(TCanExecute)), _ => throw new InvalidCommandParameterException(typeof(TCanExecute), parameter.GetType()), }; @@ -104,7 +104,7 @@ void ICommand.Execute(object parameter) break; case null when !typeof(TExecute).GetTypeInfo().IsValueType: - Execute((TExecute)parameter); + Execute((TExecute?)parameter); break; case null: @@ -115,7 +115,7 @@ void ICommand.Execute(object parameter) } // Use local method to defer async void from ICommand.Execute, allowing InvalidCommandParameterException to be thrown on the calling thread context before reaching an async method - async void Execute(TExecute parameter) => await ExecuteAsync(parameter).ConfigureAwait(continueOnCapturedContext); + async void Execute(TExecute? parameter) => await ExecuteAsync(parameter).ConfigureAwait(continueOnCapturedContext); } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncValueCommand.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncValueCommand.shared.cs index c32ae7000..a8032c2cd 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncValueCommand.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseAsyncValueCommand.shared.cs @@ -13,8 +13,8 @@ namespace Xamarin.CommunityToolkit.ObjectModel.Internals [EditorBrowsable(EditorBrowsableState.Never)] public abstract class BaseAsyncValueCommand : BaseCommand, ICommand { - readonly Func execute; - readonly Action onException; + readonly Func execute; + readonly Action? onException; readonly bool continueOnCapturedContext; /// @@ -24,10 +24,10 @@ public abstract class BaseAsyncValueCommand : BaseCommand /// The Function that verifies whether or not AsyncCommand should execute. /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread - public BaseAsyncValueCommand( - Func execute, - Func canExecute, - Action onException, + protected BaseAsyncValueCommand( + Func? execute, + Func? canExecute, + Action? onException, bool continueOnCapturedContext, bool allowsMultipleExecutions) : base(canExecute, allowsMultipleExecutions) @@ -42,7 +42,7 @@ public abstract class BaseAsyncValueCommand : BaseCommand /// /// /// The Execute parameter required for ICommand - private protected static Func ConvertExecute(Func execute) + private protected static Func? ConvertExecute(Func? execute) { if (execute == null) return null; @@ -55,7 +55,7 @@ public abstract class BaseAsyncValueCommand : BaseCommand /// /// /// The CanExecute parameter required for ICommand - private protected static Func ConvertCanExecute(Func canExecute) + private protected static Func? ConvertCanExecute(Func? canExecute) { if (canExecute == null) return null; @@ -68,7 +68,7 @@ public abstract class BaseAsyncValueCommand : BaseCommand /// /// The executed Value /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - private protected async ValueTask ExecuteAsync(TExecute parameter) + private protected async ValueTask ExecuteAsync(TExecute? parameter) { ExecutionCount++; @@ -90,7 +90,7 @@ private protected async ValueTask ExecuteAsync(TExecute parameter) bool ICommand.CanExecute(object parameter) => parameter switch { TCanExecute validParameter => CanExecute(validParameter), - null when !typeof(TCanExecute).GetTypeInfo().IsValueType => CanExecute((TCanExecute)parameter), + null when !typeof(TCanExecute).GetTypeInfo().IsValueType => CanExecute((TCanExecute?)parameter), null => throw new InvalidCommandParameterException(typeof(TCanExecute)), _ => throw new InvalidCommandParameterException(typeof(TCanExecute), parameter.GetType()), }; @@ -104,7 +104,7 @@ void ICommand.Execute(object parameter) break; case null when !typeof(TExecute).GetTypeInfo().IsValueType: - Execute((TExecute)parameter); + Execute((TExecute?)parameter); break; case null: @@ -115,7 +115,7 @@ void ICommand.Execute(object parameter) } // Use local method to defer async void from ICommand.Execute, allowing InvalidCommandParameterException to be thrown on the calling thread context before reaching an async method - async void Execute(TExecute parameter) => await ExecuteAsync(parameter).ConfigureAwait(continueOnCapturedContext); + async void Execute(TExecute? parameter) => await ExecuteAsync(parameter).ConfigureAwait(continueOnCapturedContext); } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.android.cs index 77fde7ebc..a5b3b10ba 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.android.cs @@ -6,14 +6,14 @@ namespace Xamarin.CommunityToolkit.ObjectModel.Internals { public abstract partial class BaseCommand { - static volatile Handler handler; + static volatile Handler? handler; static bool IsMainThread { get { if (Build.VERSION.SdkInt >= BuildVersionCodes.M) - return Looper.MainLooper.IsCurrentThread; + return Looper.MainLooper?.IsCurrentThread ?? false; return Looper.MyLooper() == Looper.MainLooper; } @@ -21,8 +21,12 @@ static bool IsMainThread static void BeginInvokeOnMainThread(Action action) { - if (handler?.Looper != Looper.MainLooper) + if (handler == null || handler.Looper != Looper.MainLooper) + { +#pragma warning disable CS8604 // Possible null reference argument. handler = new Handler(Looper.MainLooper); +#pragma warning restore CS8604 // Possible null reference argument. + } handler.Post(action); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.shared.cs index 1f094d662..c703cab82 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/Internals/BaseCommand.shared.cs @@ -11,7 +11,7 @@ namespace Xamarin.CommunityToolkit.ObjectModel.Internals [EditorBrowsable(EditorBrowsableState.Never)] public abstract partial class BaseCommand { - readonly Func canExecute; + readonly Func canExecute; readonly WeakEventManager weakEventManager = new WeakEventManager(); int executionCount; @@ -21,7 +21,7 @@ public abstract partial class BaseCommand /// /// /// - public BaseCommand(Func canExecute, bool allowsMultipleExecutions) + protected BaseCommand(Func? canExecute, bool allowsMultipleExecutions) { this.canExecute = canExecute ?? (_ => true); AllowsMultipleExecutions = allowsMultipleExecutions; @@ -71,7 +71,7 @@ protected int ExecutionCount /// /// true, if this command can be executed; otherwise, false. /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - public bool CanExecute(TCanExecute parameter) => (AllowsMultipleExecutions, IsExecuting) switch + public bool CanExecute(TCanExecute? parameter) => (AllowsMultipleExecutions, IsExecuting) switch { (true, _) => canExecute(parameter), (false, true) => false, diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/ObservableObject.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/ObservableObject.shared.cs index 66deaaa75..06bcc4040 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/ObservableObject.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/ObjectModel/ObservableObject.shared.cs @@ -37,7 +37,7 @@ public abstract class ObservableObject : INotifyPropertyChanged protected virtual bool SetProperty( ref T backingStore, T value, - [CallerMemberName] string propertyName = "", + [CallerMemberName] string? propertyName = "", Action? onChanging = null, Action? onChanged = null, Func? validateValue = null) @@ -61,7 +61,7 @@ public abstract class ObservableObject : INotifyPropertyChanged /// Raises the property changed event. /// /// Property name. - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") => + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = "") => weakEventManager.RaiseEvent(this, new PropertyChangedEventArgs(propertyName), nameof(PropertyChanged)); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/AvatarView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/AvatarView.shared.cs index d287e241a..7a4f8a133 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/AvatarView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/AvatarView.shared.cs @@ -19,9 +19,9 @@ public class AvatarView : BaseTemplatedView readonly SemaphoreSlim imageSourceSemaphore = new SemaphoreSlim(1); - CancellationTokenSource imageLoadingTokenSource; + CancellationTokenSource? imageLoadingTokenSource; - object sourceBindingContext; + object? sourceBindingContext; // Indicates if any thread already waits for the semaphore is released (0 == False | 1 == True). int isWaitingForSourceUpdateValue; @@ -403,19 +403,18 @@ async void OnSourcePropertyChanged(bool isBindingContextChanged) return size * .4; } - Task GetImageStreamLoadingTask(ImageSource source, CancellationToken token) - => source switch - { - IStreamImageSource streamImageSource => streamImageSource.GetStreamAsync(token), - UriImageSource uriImageSource => uriImageSource.Uri != null - ? new UriImageSource - { - Uri = uriImageSource.Uri, - CachingEnabled = uriImageSource.CachingEnabled, - CacheValidity = uriImageSource.CacheValidity - }.GetStreamAsync(token) - : Task.FromResult(null), - _ => null - }; + Task GetImageStreamLoadingTask(ImageSource? source, CancellationToken token) => source switch + { + IStreamImageSource streamImageSource => streamImageSource.GetStreamAsync(token), + UriImageSource uriImageSource => uriImageSource.Uri != null + ? new UriImageSource + { + Uri = uriImageSource.Uri, + CachingEnabled = uriImageSource.CachingEnabled, + CacheValidity = uriImageSource.CacheValidity + }.GetStreamAsync(token) + : Task.FromResult(null), + _ => Task.FromResult(null) + }; } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/IImageSourceValidator.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/IImageSourceValidator.shared.cs index 10b23478c..5b806eca4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/IImageSourceValidator.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/IImageSourceValidator.shared.cs @@ -5,6 +5,6 @@ namespace Xamarin.CommunityToolkit.UI.Views { interface IImageSourceValidator { - Task IsImageSourceValidAsync(ImageSource source); + Task IsImageSourceValidAsync(ImageSource? source); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.android.ios.macos.uwp.wpf.gtk.tizen.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.android.ios.macos.uwp.wpf.gtk.tizen.cs index b1150dd83..0182b96fa 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.android.ios.macos.uwp.wpf.gtk.tizen.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.android.ios.macos.uwp.wpf.gtk.tizen.cs @@ -31,7 +31,7 @@ namespace Xamarin.CommunityToolkit.UI.Views { class ImageSourceValidator : IImageSourceValidator { - public async Task IsImageSourceValidAsync(ImageSource source) + public async Task IsImageSourceValidAsync(ImageSource? source) { var handler = GetHandler(source); if (handler == null) @@ -48,7 +48,7 @@ public async Task IsImageSourceValidAsync(ImageSource source) #endif } - IImageSourceHandler GetHandler(ImageSource source) + IImageSourceHandler? GetHandler(ImageSource? source) { if (source is UriImageSource) return new UriImageSourceHandler(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.shared.cs index e0b7550a3..034088092 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/AvatarView/ImageSourceValidator.shared.cs @@ -6,7 +6,7 @@ namespace Xamarin.CommunityToolkit.UI.Views #if NETSTANDARD || __TVOS__ || __WATCHOS__ class ImageSourceValidator : IImageSourceValidator { - public Task IsImageSourceValidAsync(ImageSource source) => Task.FromResult(false); + public Task IsImageSourceValidAsync(ImageSource? source) => Task.FromResult(false); } #endif } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BadgeView/BadgeView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BadgeView/BadgeView.shared.cs index cefdf0c8e..37c976936 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BadgeView/BadgeView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BadgeView/BadgeView.shared.cs @@ -67,7 +67,11 @@ public bool AutoHide set => SetValue(AutoHideProperty, value); } - static async void OnAutoHideChanged(BindableObject bindable, object oldValue, object newValue) => await (bindable as BadgeView)?.UpdateVisibilityAsync(); + static async void OnAutoHideChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is BadgeView badgeView) + await badgeView.UpdateVisibilityAsync(); + } /// /// Backing BindableProperty for the property. diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BaseTemplatedView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BaseTemplatedView.shared.cs index 397e98325..29e99e3c3 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BaseTemplatedView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/BaseTemplatedView.shared.cs @@ -1,4 +1,5 @@ -using Xamarin.Forms; +using System; +using Xamarin.Forms; namespace Xamarin.CommunityToolkit.UI.Views.Internals { @@ -8,7 +9,9 @@ namespace Xamarin.CommunityToolkit.UI.Views.Internals /// The type of the control that this template will be used for public abstract class BaseTemplatedView : TemplatedView where TControl : View, new() { - protected TControl Control { get; private set; } + TControl? control; + + protected TControl Control => control ?? throw new NullReferenceException(); /// /// Constructor of @@ -19,14 +22,16 @@ public BaseTemplatedView() protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); - Control.BindingContext = BindingContext; + + if (control != null) + Control.BindingContext = BindingContext; } protected override void OnChildAdded(Element child) { - if (Control == null && child is TControl content) + if (control == null && child is TControl content) { - Control = content; + control = content; OnControlInitialized(Control); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/AutoFitTextureView.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/AutoFitTextureView.android.cs index 6723a21da..742f24bbc 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/AutoFitTextureView.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/AutoFitTextureView.android.cs @@ -1,10 +1,8 @@ using System; using Android.Content; -using Android.Graphics; using Android.Runtime; using Android.Util; using Android.Views; -using AColor = Android.Graphics.Color; namespace Xamarin.CommunityToolkit.UI.Views { @@ -18,12 +16,12 @@ public AutoFitTextureView(Context context) { } - public AutoFitTextureView(Context context, IAttributeSet attrs) + public AutoFitTextureView(Context context, IAttributeSet? attrs) : this(context, attrs, 0) { } - public AutoFitTextureView(Context context, IAttributeSet attrs, int defStyle) + public AutoFitTextureView(Context context, IAttributeSet? attrs, int defStyle) : base(context, attrs, defStyle) { } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureListener.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureListener.android.cs index 911681df2..796197773 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureListener.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureListener.android.cs @@ -5,7 +5,7 @@ namespace Xamarin.CommunityToolkit.UI.Views { class CameraCaptureListener : CameraCaptureSession.CaptureCallback { - public Action OnCompleted; + public Action? OnCompleted; public override void OnCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) => OnCompleted?.Invoke(result); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureStateListener.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureStateListener.android.cs index 3256bdcc4..c805e2cc4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureStateListener.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraCaptureStateListener.android.cs @@ -5,8 +5,8 @@ namespace Xamarin.CommunityToolkit.UI.Views { class CameraCaptureStateListener : CameraCaptureSession.StateCallback { - public Action OnConfigureFailedAction; - public Action OnConfiguredAction; + public Action? OnConfigureFailedAction; + public Action? OnConfiguredAction; public override void OnConfigureFailed(CameraCaptureSession session) => OnConfigureFailedAction?.Invoke(session); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs index 198a4a725..e8fffa282 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs @@ -134,7 +134,7 @@ CameraView Element } } - public override bool OnTouchEvent(MotionEvent e) + public override bool OnTouchEvent(MotionEvent? e) { if (visualElementRenderer.OnTouchEvent(e) || base.OnTouchEvent(e)) return true; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/ImageAvailableListener.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/ImageAvailableListener.android.cs index 5ae24c702..878174420 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/ImageAvailableListener.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/ImageAvailableListener.android.cs @@ -6,16 +6,22 @@ namespace Xamarin.CommunityToolkit.UI.Views { class ImageAvailableListener : Java.Lang.Object, ImageReader.IOnImageAvailableListener { - public event EventHandler Photo; + public event EventHandler? Photo; - public void OnImageAvailable(ImageReader reader) + public void OnImageAvailable(ImageReader? reader) { - AImage image = null; + AImage? image = null; try { - image = reader.AcquireNextImage(); - var buffer = image.GetPlanes()[0].Buffer; + image = reader?.AcquireNextImage(); + if (image == null) + return; + + var buffer = image.GetPlanes()?[0].Buffer; + if (buffer == null) + return; + var imageData = new byte[buffer.Capacity()]; buffer.Get(imageData); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs index 4e3768299..1b2a3b440 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs @@ -9,7 +9,7 @@ class MotionEventHelper VisualElement element; bool isInViewCell; - public bool HandleMotionEvent(IViewParent parent, MotionEvent motionEvent) + public bool HandleMotionEvent(IViewParent parent, MotionEvent? motionEvent) { if (isInViewCell || element == null || motionEvent == null || motionEvent.Action == MotionEventActions.Cancel) return false; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/CameraView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/CameraView.shared.cs index c21a6f21a..3f8028401 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/CameraView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/CameraView.shared.cs @@ -7,13 +7,13 @@ namespace Xamarin.CommunityToolkit.UI.Views { public class CameraView : View { - public event EventHandler MediaCaptured; + public event EventHandler? MediaCaptured; - public event EventHandler MediaCaptureFailed; + public event EventHandler? MediaCaptureFailed; - public event EventHandler OnAvailable; + public event EventHandler? OnAvailable; - internal event EventHandler ShutterClicked; + internal event EventHandler? ShutterClicked; internal static readonly BindablePropertyKey ShutterCommandPropertyKey = BindableProperty.CreateReadOnly(nameof(ShutterCommand), diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/MediaCapturedEventArgs.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/MediaCapturedEventArgs.shared.cs index 10a786a47..5693d2e1d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/MediaCapturedEventArgs.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/MediaCapturedEventArgs.shared.cs @@ -7,13 +7,13 @@ namespace Xamarin.CommunityToolkit.UI.Views { public class MediaCapturedEventArgs : EventArgs { - readonly string path; + readonly string? path; readonly Lazy imageSource; - readonly Lazy mediaSource; + readonly Lazy mediaSource; internal MediaCapturedEventArgs( - string path = null, - byte[] imageData = null, + string? path = null, + byte[]? imageData = null, double rotation = 0) { // Path = path; @@ -21,7 +21,7 @@ public class MediaCapturedEventArgs : EventArgs Rotation = rotation; ImageData = imageData; imageSource = new Lazy(GetImageSource); - mediaSource = new Lazy(GetMediaSource); + mediaSource = new Lazy(GetMediaSource); } // TODO See note on CameraView.SavePhotoToFile. @@ -35,7 +35,7 @@ public class MediaCapturedEventArgs : EventArgs /// /// Raw image data, only filled when taking a picture and SavePhotoToFile is false /// - public byte[] ImageData { get; } + public byte[]? ImageData { get; } /// /// Applied image rotation for correct orientation on Android devices @@ -44,7 +44,7 @@ public class MediaCapturedEventArgs : EventArgs public ImageSource Image => imageSource.Value; - public XCT.FileMediaSource Video => mediaSource.Value; + public XCT.FileMediaSource? Video => mediaSource.Value; ImageSource GetImageSource() { @@ -54,6 +54,12 @@ ImageSource GetImageSource() return !string.IsNullOrEmpty(path) ? path : null; } - XCT.FileMediaSource GetMediaSource() => !string.IsNullOrEmpty(path) ? path : null; + XCT.FileMediaSource? GetMediaSource() + { + if (path != null && !string.IsNullOrEmpty(path)) + return path; + else + return null; + } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/CameraViewRenderer.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/CameraViewRenderer.ios.cs index 52a930331..85737951b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/CameraViewRenderer.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/CameraViewRenderer.ios.cs @@ -23,15 +23,15 @@ protected override void OnElementChanged(ElementChangedEventArgs e) if (Control == null && !disposed) { SetNativeControl(new FormsCameraView()); - Control.Busy += OnBusy; - Control.Available += OnAvailability; - Control.FinishCapture += FinishCapture; - - Control.SwitchFlash(Element.FlashMode); - Control.SetBounds(Element.WidthRequest, Element.HeightRequest); - Control.VideoStabilization = Element.VideoStabilization; - Control.Zoom = (float)Element.Zoom; - Control.RetrieveCameraDevice(Element.CameraOptions); + Control!.Busy += OnBusy; + Control!.Available += OnAvailability; + Control!.FinishCapture += FinishCapture; + + Control!.SwitchFlash(Element.FlashMode); + Control!.SetBounds(Element.WidthRequest, Element.HeightRequest); + Control!.VideoStabilization = Element.VideoStabilization; + Control!.Zoom = (float)Element.Zoom; + Control!.RetrieveCameraDevice(Element.CameraOptions); } if (e.OldElement != null) @@ -53,7 +53,7 @@ void OnAvailability(object sender, bool available) Element.IsAvailable = available; } - void FinishCapture(object sender, Tuple e) + void FinishCapture(object sender, Tuple e) { if (Element == null || Control == null) return; @@ -70,7 +70,7 @@ void FinishCapture(object sender, Tuple e) // if (!Element.SavePhotoToFile && photoData != null) if (photoData != null) { - var data = UIImage.LoadFromData(photoData).AsJPEG().ToArray(); + var data = UIImage.LoadFromData(photoData)?.AsJPEG().ToArray(); Device.BeginInvokeOnMainThread(() => { Element.RaiseMediaCaptured(new MediaCapturedEventArgs(imageData: data)); @@ -78,7 +78,7 @@ void FinishCapture(object sender, Tuple e) return; } - PHObjectPlaceholder placeholder = null; + PHObjectPlaceholder? placeholder = null; PHPhotoLibrary.RequestAuthorization(status => { if (status != PHAuthorizationStatus.Authorized) @@ -118,7 +118,8 @@ void FinishCapture(object sender, Tuple e) return; } - if (!(PHAsset.FetchAssetsUsingLocalIdentifiers(new[] { placeholder.LocalIdentifier }, null).firstObject is PHAsset asset)) + _ = placeholder ?? throw new NullReferenceException(); + if (PHAsset.FetchAssetsUsingLocalIdentifiers(new[] { placeholder.LocalIdentifier }, null).firstObject is not PHAsset asset) { Element.RaiseMediaCaptureFailed($"Could not save media to photo library"); return; @@ -132,7 +133,7 @@ void FinishCapture(object sender, Tuple e) { Device.BeginInvokeOnMainThread(() => { - Element.RaiseMediaCaptured(new MediaCapturedEventArgs(input.FullSizeImageUrl.Path)); + Element.RaiseMediaCaptured(new MediaCapturedEventArgs(input.FullSizeImageUrl?.Path)); }); }); } @@ -143,7 +144,7 @@ void FinishCapture(object sender, Tuple e) Version = PHVideoRequestOptionsVersion.Original }, (avAsset, mix, info) => { - if (!(avAsset is AVUrlAsset urlAsset)) + if (avAsset is not AVUrlAsset urlAsset) { Element.RaiseMediaCaptureFailed($"Could not save media to photo library"); return; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/FormsCameraView.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/FormsCameraView.ios.cs index 0f8036389..f6a61e5fd 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/FormsCameraView.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/iOS/FormsCameraView.ios.cs @@ -15,12 +15,12 @@ public sealed class FormsCameraView : UIView, IAVCaptureFileOutputRecordingDeleg readonly AVCaptureVideoPreviewLayer previewLayer; readonly AVCaptureSession captureSession; readonly UIView mainView; - AVCaptureDeviceInput input; - AVCaptureStillImageOutput imageOutput; - AVCapturePhotoOutput photoOutput; - AVCaptureMovieFileOutput videoOutput; - AVCaptureConnection captureConnection; - AVCaptureDevice device; + AVCaptureDeviceInput? input; + AVCaptureStillImageOutput? imageOutput; + AVCapturePhotoOutput? photoOutput; + AVCaptureMovieFileOutput? videoOutput; + AVCaptureConnection? captureConnection; + AVCaptureDevice? device; AVCaptureDevicePosition? lastPosition; bool isBusy; bool isAvailable; @@ -28,11 +28,11 @@ public sealed class FormsCameraView : UIView, IAVCaptureFileOutputRecordingDeleg CameraFlashMode flashMode; readonly float imgScale = 1f; - public event EventHandler Busy; + public event EventHandler? Busy; - public event EventHandler Available; + public event EventHandler? Available; - public event EventHandler> FinishCapture; + public event EventHandler>? FinishCapture; public bool VideoRecorded => videoOutput?.Recording == true; @@ -89,7 +89,7 @@ void SetStartOrientation() } } - void LogError(string message, Exception error = null) + void LogError(string message, Exception? error = null) { var errorMessage = error == null ? string.Empty @@ -116,6 +116,8 @@ bool IsBusy UIImage RotateImage(UIImage image) { var imgRef = image.CGImage; + _ = imgRef ?? throw new NullReferenceException(); + var transform = CGAffineTransform.MakeIdentity(); var imgHeight = imgRef.Height * imgScale; @@ -198,7 +200,7 @@ public async Task TakePhoto() { var photoOutputConnection = photoOutput.ConnectionFromMediaType(AVMediaType.Video); if (photoOutputConnection != null) - photoOutputConnection.VideoOrientation = previewLayer.Connection.VideoOrientation; + photoOutputConnection.VideoOrientation = previewLayer.Connection?.VideoOrientation ?? throw new NullReferenceException(); var photoSettings = AVCapturePhotoSettings.Create(); photoSettings.FlashMode = (AVCaptureFlashMode)flashMode; @@ -208,7 +210,7 @@ public async Task TakePhoto() { OnFinishCapture = (data, error) => { - FinishCapture?.Invoke(this, new Tuple(data, error)); + FinishCapture?.Invoke(this, new Tuple(data, error)); IsBusy = false; }, WillCapturePhotoAnimation = () => Animate(0.25, () => previewLayer.Opacity = 1) @@ -221,15 +223,15 @@ public async Task TakePhoto() // iOS < 10 try { - var connection = imageOutput.Connections[0]; - connection.VideoOrientation = previewLayer.Connection.VideoOrientation; + var connection = imageOutput?.Connections[0] ?? throw new NullReferenceException(); + connection.VideoOrientation = previewLayer.Connection?.VideoOrientation ?? throw new NullReferenceException(); var sampleBuffer = await imageOutput.CaptureStillImageTaskAsync(connection); var imageData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer); - FinishCapture?.Invoke(this, new Tuple(imageData, null)); + FinishCapture?.Invoke(this, new Tuple(imageData, null)); } catch (Exception) { - FinishCapture?.Invoke(this, new Tuple(null, new NSError(new NSString("faled create image"), 0))); + FinishCapture?.Invoke(this, new Tuple(null, new NSError(new NSString("faled create image"), 0))); } IsBusy = false; } @@ -268,7 +270,7 @@ public void StartRecord() IsBusy = true; try { - videoOutput.Connections[0].VideoOrientation = previewLayer.Connection.VideoOrientation; + videoOutput.Connections[0].VideoOrientation = previewLayer.Connection?.VideoOrientation ?? throw new NullReferenceException(); var connection = videoOutput.Connections[0]; if (connection.SupportsVideoOrientation) @@ -296,9 +298,12 @@ public void StopRecord() } } - public void FinishedRecording(AVCaptureFileOutput captureOutput, NSUrl outputFileUrl, NSObject[] connections, NSError error) + public void FinishedRecording(AVCaptureFileOutput captureOutput, NSUrl outputFileUrl, NSObject[] connections, NSError? error) { - FinishCapture?.Invoke(this, new Tuple(outputFileUrl, error)); + FinishCapture?.Invoke(this, new Tuple(outputFileUrl, error)); + + _ = videoOutput ?? throw new NullReferenceException(); + captureSession.RemoveOutput(videoOutput); videoOutput = null; IsBusy = false; @@ -316,6 +321,7 @@ void UpdateFlash(CameraFlashMode? newFlashMode = null) { var desiredFlashMode = newFlashMode ?? flashMode; + _ = device ?? throw new NullReferenceException(); device.LockForConfiguration(out var err); if (CheckFlashModeSupported(desiredFlashMode)) @@ -340,10 +346,12 @@ void UpdateFlash(CameraFlashMode? newFlashMode = null) flashMode = desiredFlashMode; } - if (desiredFlashMode != CameraFlashMode.Torch && - device.TorchMode == AVCaptureTorchMode.On && - device.IsTorchModeSupported(AVCaptureTorchMode.Off)) + if (desiredFlashMode != CameraFlashMode.Torch + && device.TorchMode == AVCaptureTorchMode.On + && device.IsTorchModeSupported(AVCaptureTorchMode.Off)) + { device.TorchMode = AVCaptureTorchMode.Off; + } device.UnlockForConfiguration(); } @@ -354,7 +362,10 @@ void UpdateFlash(CameraFlashMode? newFlashMode = null) } bool CheckFlashModeSupported(CameraFlashMode flashMode) - => flashMode switch + { + _ = device ?? throw new NullReferenceException(); + + return flashMode switch { CameraFlashMode.Off => device.IsFlashModeSupported(AVCaptureFlashMode.Off), CameraFlashMode.On => device.IsFlashModeSupported(AVCaptureFlashMode.On), @@ -362,6 +373,7 @@ bool CheckFlashModeSupported(CameraFlashMode flashMode) CameraFlashMode.Torch => device.IsTorchModeSupported(AVCaptureTorchMode.On), _ => device.IsFlashModeSupported(AVCaptureFlashMode.Off) }; + } public bool VideoStabilization { get; set; } @@ -378,6 +390,7 @@ public void ChangeFocusPoint(Point point) try { + _ = device ?? throw new NullReferenceException(); device.LockForConfiguration(out var err); var focus_x = point.X / Bounds.Width; @@ -565,13 +578,13 @@ protected override void Dispose(bool disposing) class PhotoCaptureDelegate : NSObject, IAVCapturePhotoCaptureDelegate { - public Action OnFinishCapture; - public Action WillCapturePhotoAnimation; + public Action? OnFinishCapture; + public Action? WillCapturePhotoAnimation; - NSData photoData; + NSData? photoData; [Export("captureOutput:willCapturePhotoForResolvedSettings:")] - public void WillCapturePhoto(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings) => WillCapturePhotoAnimation(); + public void WillCapturePhoto(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings) => WillCapturePhotoAnimation?.Invoke(); [Export("captureOutput:didFinishProcessingPhotoSampleBuffer:previewPhotoSampleBuffer:resolvedSettings:bracketSettings:error:")] public void DidFinishProcessingPhoto(AVCapturePhotoOutput captureOutput, CMSampleBuffer photoSampleBuffer, CMSampleBuffer previewPhotoSampleBuffer, AVCaptureResolvedPhotoSettings resolvedSettings, AVCaptureBracketedStillImageSettings bracketSettings, NSError error) @@ -584,6 +597,6 @@ public void DidFinishProcessingPhoto(AVCapturePhotoOutput captureOutput, CMSampl [Export("captureOutput:didFinishCaptureForResolvedSettings:error:")] public void DidFinishCapture(AVCapturePhotoOutput captureOutput, AVCaptureResolvedPhotoSettings resolvedSettings, NSError error) - => OnFinishCapture(photoData, error); + => OnFinishCapture?.Invoke(photoData, error); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Expander/Expander.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Expander/Expander.shared.cs index fdfe53f74..fbd1ca787 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Expander/Expander.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Expander/Expander.shared.cs @@ -22,11 +22,11 @@ public class Expander : BaseTemplatedView remove => tappedEventManager.RemoveEventHandler(value); } - ContentView contentHolder; + ContentView? contentHolder; - GestureRecognizer headerTapGestureRecognizer; + GestureRecognizer? headerTapGestureRecognizer; - DataTemplate previousTemplate; + DataTemplate? previousTemplate; double lastVisibleSize = -1; @@ -80,8 +80,8 @@ public class Expander : BaseTemplatedView : Width; double ContentSize => Direction.IsVertical() - ? contentHolder.Height - : contentHolder.Width; + ? contentHolder?.Height ?? throw new NullReferenceException() + : contentHolder?.Width ?? throw new NullReferenceException(); double ContentSizeRequest { @@ -91,7 +91,7 @@ public class Expander : BaseTemplatedView ? Content.HeightRequest : Content.WidthRequest; - if (sizeRequest < 0 || !(Content is Layout layout)) + if (sizeRequest < 0 || Content is not Layout layout) return sizeRequest; return sizeRequest + (Direction.IsVertical() @@ -101,6 +101,8 @@ public class Expander : BaseTemplatedView set { + _ = contentHolder ?? throw new NullReferenceException(); + if (Direction.IsVertical()) { contentHolder.HeightRequest = value; @@ -111,8 +113,8 @@ public class Expander : BaseTemplatedView } double MeasuredContentSize => Direction.IsVertical() - ? contentHolder.Measure(Width, double.PositiveInfinity).Request.Height - : contentHolder.Measure(double.PositiveInfinity, Height).Request.Width; + ? contentHolder?.Measure(Width, double.PositiveInfinity).Request.Height ?? throw new NullReferenceException() + : contentHolder?.Measure(double.PositiveInfinity, Height).Request.Width ?? throw new NullReferenceException(); public View Header { @@ -206,7 +208,7 @@ protected override void OnControlInitialized(StackLayout control) CommandParameter = this, Command = new Command(parameter => { - var parent = (parameter as View).Parent; + var parent = ((View)parameter).Parent; while (parent != null && !(parent is Page)) { if (parent is Expander ancestorExpander) @@ -380,7 +382,7 @@ void SetContent() SetContent(true); } - View CreateContent() + View? CreateContent() { var template = ContentTemplate; while (template is DataTemplateSelector selector) @@ -390,7 +392,7 @@ View CreateContent() return null; previousTemplate = template; - return (View)template?.CreateContent(); + return (View?)template?.CreateContent(); } void SetDirection(ExpandDirection oldDirection) @@ -422,6 +424,8 @@ void InvokeAnimation(double startSize, double endSize, bool shouldIgnoreAnimatio ? ExpandState.Expanded : ExpandState.Collapsed; ContentSizeRequest = endSize; + + _ = contentHolder ?? throw new NullReferenceException(); contentHolder.IsVisible = IsExpanded; return; } @@ -447,6 +451,7 @@ void InvokeAnimation(double startSize, double endSize, bool shouldIgnoreAnimatio if (!IsExpanded) { + _ = contentHolder ?? throw new NullReferenceException(); contentHolder.IsVisible = false; State = ExpandState.Collapsed; return; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.android.ios.macos.tizen.uwp.wpf.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.android.ios.macos.tizen.uwp.wpf.cs index 383c3b587..119d94380 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.android.ios.macos.tizen.uwp.wpf.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.android.ios.macos.tizen.uwp.wpf.cs @@ -15,7 +15,7 @@ public partial class GravatarImageSourceHandler static readonly Lazy lazyHttp = new Lazy(() => new HttpClient()); static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1); - public static async Task LoadInternal(ImageSource imageSource, float scale, string cacheDirectory) + public static async Task LoadInternal(ImageSource imageSource, float scale, string cacheDirectory) { if (imageSource is GravatarImageSource gis) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.ios.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.ios.macos.cs index fc80a2131..a7b633e45 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.ios.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Shared/GravatarImageSourceHandler.ios.macos.cs @@ -1,4 +1,5 @@ -using Foundation; +using System; +using Foundation; namespace Xamarin.CommunityToolkit.UI.Views { @@ -8,10 +9,8 @@ static string GetCacheDirectory() { var dirs = NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User); if (dirs == null || dirs.Length == 0) - { - // this should never happen... - return null; - } + throw new NotSupportedException(); + return dirs[0]; } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/iOS/GravatarImageSourceHandler.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/iOS/GravatarImageSourceHandler.ios.cs index 1f0d06ddc..020ba5f60 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/iOS/GravatarImageSourceHandler.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/iOS/GravatarImageSourceHandler.ios.cs @@ -8,11 +8,11 @@ namespace Xamarin.CommunityToolkit.UI.Views { public partial class GravatarImageSourceHandler : IImageSourceHandler { - public async Task LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default, float scale = 1) + public async Task LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default, float scale = 1) { var fileInfo = await LoadInternal(imagesource, scale, GetCacheDirectory()); - UIImage image = null; + UIImage? image = null; try { await semaphore.WaitAsync(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/FormsVideoView.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/FormsVideoView.android.cs index 4707a51a4..c26ce5e54 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/FormsVideoView.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/FormsVideoView.android.cs @@ -9,7 +9,7 @@ namespace Xamarin.CommunityToolkit.UI.Views { public class FormsVideoView : VideoView { - public event EventHandler MetadataRetrieved; + public event EventHandler? MetadataRetrieved; public FormsVideoView(Context context) : base(context) @@ -17,7 +17,7 @@ public FormsVideoView(Context context) SetBackgroundColor(global::Android.Graphics.Color.Transparent); } - public override void SetVideoPath(string path) + public override void SetVideoPath(string? path) { base.SetVideoPath(path); @@ -50,32 +50,29 @@ protected void ExtractMetadata(MediaMetadataRetriever retriever) DurationTimeSpan = null; } - public override void SetVideoURI(global::Android.Net.Uri uri, IDictionary headers) + public override void SetVideoURI(global::Android.Net.Uri? uri, IDictionary? headers) { GetMetaData(uri, headers); base.SetVideoURI(uri, headers); } - protected void GetMetaData(global::Android.Net.Uri uri, IDictionary headers) + protected async void GetMetaData(global::Android.Net.Uri? uri, IDictionary? headers) => await Task.Run(() => { - Task.Run(() => - { - var retriever = new MediaMetadataRetriever(); + var retriever = new MediaMetadataRetriever(); - if (uri.Scheme != null && uri.Scheme.StartsWith("http")) - { - retriever.SetDataSource(uri.ToString(), headers ?? new Dictionary()); - } - else - { - retriever.SetDataSource(Context, uri); - } + if (uri?.Scheme != null && uri.Scheme.StartsWith("http")) + { + retriever.SetDataSource(uri.ToString(), headers ?? new Dictionary()); + } + else + { + retriever.SetDataSource(Context, uri); + } - ExtractMetadata(retriever); + ExtractMetadata(retriever); - MetadataRetrieved?.Invoke(this, EventArgs.Empty); - }); - } + MetadataRetrieved?.Invoke(this, EventArgs.Empty); + }); public int VideoHeight { get; private set; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs index b5ef6c0cb..3830b61c8 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs @@ -17,9 +17,9 @@ namespace Xamarin.CommunityToolkit.UI.Views { public class MediaElementRenderer : FrameLayout, IVisualElementRenderer, IViewRenderer, MediaPlayer.IOnCompletionListener, MediaPlayer.IOnInfoListener, MediaPlayer.IOnPreparedListener, MediaPlayer.IOnErrorListener { - VisualElementTracker tracker; - protected MediaController controller; - protected MediaPlayer mediaPlayer; + VisualElementTracker? tracker; + protected MediaController? controller; + protected MediaPlayer? mediaPlayer; protected FormsVideoView view; bool isDisposed; int? defaultLabelFor; @@ -27,7 +27,7 @@ public class MediaElementRenderer : FrameLayout, IVisualElementRenderer, IViewRe public MediaElementRenderer(Context context) : base(context) { - view = new FormsVideoView(Context); + view = new FormsVideoView(context); view.SetZOrderMediaOverlay(true); view.SetOnCompletionListener(this); view.SetOnInfoListener(this); @@ -47,30 +47,31 @@ public MediaElementRenderer(Context context) public override float Alpha { get => view.Alpha; - set => - + set + { // VideoView opens a separate Window above the current one. // This is because it is based on the SurfaceView. // And we cannot set alpha or perform animations with it because it is not synchronized with your other UI elements. // We may set 0 or 1 alpha only. view.Alpha = Math.Sign(Math.Abs(value)); + } } - protected ToolKitMediaElement MediaElement { get; set; } + protected ToolKitMediaElement? MediaElement { get; set; } - IMediaElementController Controller => MediaElement; + IMediaElementController? Controller => MediaElement; - public VisualElement Element => MediaElement; + public VisualElement? Element => MediaElement; - VisualElementTracker IVisualElementRenderer.Tracker => tracker; + VisualElementTracker? IVisualElementRenderer.Tracker => tracker; - ViewGroup IVisualElementRenderer.ViewGroup => null; + ViewGroup? IVisualElementRenderer.ViewGroup => null; AView IVisualElementRenderer.View => this; - public event EventHandler ElementChanged; + public event EventHandler? ElementChanged; - public event EventHandler ElementPropertyChanged; + public event EventHandler? ElementPropertyChanged; SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint) { @@ -125,7 +126,7 @@ void IVisualElementRenderer.SetElement(VisualElement element) if (tracker == null) SetTracker(new VisualElementTracker(this)); - OnElementChanged(new ElementChangedEventArgs(oldElement, MediaElement)); + OnElementChanged(new ElementChangedEventArgs(oldElement, MediaElement)); } void StateRequested(object sender, StateRequested e) @@ -133,6 +134,7 @@ void StateRequested(object sender, StateRequested e) if (view == null) return; + _ = Controller ?? throw new NullReferenceException(); switch (e.State) { case MediaElementState.Playing: @@ -161,7 +163,7 @@ void StateRequested(object sender, StateRequested e) void OnPositionRequested(object sender, EventArgs e) { - if (view == null) + if (view == null && Controller == null) return; Controller.Position = view.Position; @@ -208,13 +210,13 @@ protected override void Dispose(bool disposing) tracker?.Dispose(); if (Element != null) - UnsubscribeFromEvents(Element as MediaElement); + UnsubscribeFromEvents((ToolKitMediaElement)Element); } base.Dispose(disposing); } - protected virtual void OnElementChanged(ElementChangedEventArgs e) + protected virtual void OnElementChanged(ElementChangedEventArgs e) { if (e.NewElement != null) { @@ -375,7 +377,7 @@ protected string ResolveMsAppDataUri(Uri uri) throw new ArgumentException("uri"); } - void MediaPlayer.IOnCompletionListener.OnCompletion(MediaPlayer mp) + void MediaPlayer.IOnCompletionListener.OnCompletion(MediaPlayer? mp) { if (Controller == null) return; @@ -384,9 +386,9 @@ void MediaPlayer.IOnCompletionListener.OnCompletion(MediaPlayer mp) Controller.OnMediaEnded(); } - void MediaPlayer.IOnPreparedListener.OnPrepared(MediaPlayer mp) + void MediaPlayer.IOnPreparedListener.OnPrepared(MediaPlayer? mp) { - if (Controller == null) + if (Controller == null || mp == null) return; Controller.OnMediaOpened(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs index 136dd8b0e..db955addf 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs @@ -118,19 +118,19 @@ public double Volume set => SetValue(VolumeProperty, value); } - internal event EventHandler SeekRequested; + internal event EventHandler? SeekRequested; - internal event EventHandler StateRequested; + internal event EventHandler? StateRequested; - internal event EventHandler PositionRequested; + internal event EventHandler? PositionRequested; - public event EventHandler MediaEnded; + public event EventHandler? MediaEnded; - public event EventHandler MediaFailed; + public event EventHandler? MediaFailed; - public event EventHandler MediaOpened; + public event EventHandler? MediaOpened; - public event EventHandler SeekCompleted; + public event EventHandler? SeekCompleted; public void Play() => StateRequested?.Invoke(this, new StateRequested(MediaElementState.Playing)); @@ -245,7 +245,7 @@ void OnSourcePropertyChanging(MediaSource oldvalue) static void CurrentStateChanged(BindableObject bindable, object oldValue, object newValue) { - var element = bindable as MediaElement; + var element = (MediaElement)bindable; switch ((MediaElementState)newValue) { @@ -269,7 +269,7 @@ static void CurrentStateChanged(BindableObject bindable, object oldValue, object static void PositionChanged(BindableObject bindable, object oldValue, object newValue) { - var element = bindable as MediaElement; + var element = (MediaElement)bindable; var oldval = (TimeSpan)oldValue; var newval = (TimeSpan)newValue; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/UriTypeConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/UriTypeConverter.shared.cs index 49fc834a0..2c4b67802 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/UriTypeConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/UriTypeConverter.shared.cs @@ -7,7 +7,7 @@ namespace Xamarin.CommunityToolkit.UI.Views [TypeConversion(typeof(Uri))] public class UriTypeConverter : TypeConverter { - public override object ConvertFromInvariantString(string value) => - string.IsNullOrWhiteSpace(value) ? null : (object)new Uri(value, UriKind.RelativeOrAbsolute); + public override object? ConvertFromInvariantString(string value) => + string.IsNullOrWhiteSpace(value) ? null : new Uri(value, UriKind.RelativeOrAbsolute); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/iOS/MediaElementRenderer.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/iOS/MediaElementRenderer.ios.cs index aea4657f7..483ec042e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/iOS/MediaElementRenderer.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/iOS/MediaElementRenderer.ios.cs @@ -21,12 +21,12 @@ public class MediaElementRenderer : ViewRenderer IMediaElementController Controller => Element; protected readonly AVPlayerViewController avPlayerViewController = new AVPlayerViewController(); - protected NSObject playedToEndObserver; - protected IDisposable statusObserver; - protected IDisposable rateObserver; - protected IDisposable volumeObserver; + protected NSObject? playedToEndObserver; + protected IDisposable? statusObserver; + protected IDisposable? rateObserver; + protected IDisposable? volumeObserver; bool idleTimerDisabled = false; - AVPlayerItem playerItem; + AVPlayerItem? playerItem; public MediaElementRenderer() => AddPlayedToEndObserver(); @@ -51,11 +51,11 @@ protected virtual void UpdateSource() { if (Element.Source != null) { - AVAsset asset = null; + AVAsset? asset = null; if (Element.Source is XCT.UriMediaSource uriSource) { - if (uriSource.Uri.Scheme == "ms-appx") + if (uriSource.Uri.Scheme is "ms-appx") { if (uriSource.Uri.LocalPath.Length <= 1) return; @@ -81,6 +81,8 @@ protected virtual void UpdateSource() asset = AVAsset.FromUrl(NSUrl.FromFilename(fileSource.File)); } + _ = asset ?? throw new NullReferenceException(); + playerItem = new AVPlayerItem(asset); AddStatusObserver(); @@ -109,7 +111,7 @@ protected virtual void UpdateSource() protected string ResolveMsAppDataUri(Uri uri) { - if (uri.Scheme == "ms-appdata") + if (uri.Scheme is "ms-appdata") { string filePath; @@ -133,7 +135,7 @@ protected virtual void ObserveRate(NSObservedChange e) { if (Controller is object) { - switch (avPlayerViewController.Player.Rate) + switch (avPlayerViewController.Player?.Rate) { case 0.0f: Controller.CurrentState = MediaElementState.Paused; @@ -150,7 +152,7 @@ protected virtual void ObserveRate(NSObservedChange e) void ObserveVolume(NSObservedChange e) { - if (Controller == null) + if (Controller == null || avPlayerViewController.Player == null) return; Controller.Volume = avPlayerViewController.Player.Volume; @@ -158,6 +160,7 @@ void ObserveVolume(NSObservedChange e) protected void ObserveStatus(NSObservedChange e) { + _ = avPlayerViewController.Player?.CurrentItem ?? throw new NullReferenceException(); Controller.Volume = avPlayerViewController.Player.Volume; switch (avPlayerViewController.Player.Status) @@ -325,8 +328,8 @@ void MediaElementStateRequested(object sender, StateRequested e) SetKeepScreenOn(false); // iOS has no stop... - avPlayerViewController?.Player.Pause(); - avPlayerViewController?.Player.Seek(CMTime.Zero); + avPlayerViewController.Player?.Pause(); + avPlayerViewController.Player?.Seek(CMTime.Zero); Controller.CurrentState = MediaElementState.Stopped; var err = AVAudioSession.SharedInstance().SetActive(false); @@ -386,7 +389,7 @@ protected override void OnElementChanged(ElementChangedEventArgs e if (e.NewElement != null) { - SetNativeControl(avPlayerViewController.View); + SetNativeControl(avPlayerViewController?.View ?? throw new NullReferenceException()); Element.PropertyChanged += OnElementPropertyChanged; Element.SeekRequested += MediaElementSeekRequested; @@ -408,13 +411,13 @@ protected override void OnElementChanged(ElementChangedEventArgs e protected virtual void UpdateBackgroundColor() => BackgroundColor = Element.BackgroundColor.ToUIColor(); - protected void DisposeObservers(ref IDisposable disposable) + protected void DisposeObservers(ref IDisposable? disposable) { disposable?.Dispose(); disposable = null; } - protected void DisposeObservers(ref NSObject disposable) + protected void DisposeObservers(ref NSObject? disposable) { disposable?.Dispose(); disposable = null; @@ -437,14 +440,11 @@ void AddRateObserver() void AddStatusObserver() { DestroyStatusObserver(); - statusObserver = playerItem.AddObserver("status", NSKeyValueObservingOptions.New, ObserveStatus); + statusObserver = playerItem?.AddObserver("status", NSKeyValueObservingOptions.New, ObserveStatus); } void AddPlayedToEndObserver() { - DestroyPlayedToEndObserver(); - playedToEndObserver = - NSNotificationCenter.DefaultCenter.AddObserver(AVPlayerItem.DidPlayToEndTimeNotification, PlayedToEnd); } void DestroyVolumeObserver() => DisposeObservers(ref volumeObserver); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs index 5801c5308..ba7a49ebf 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs @@ -20,25 +20,25 @@ namespace Xamarin.CommunityToolkit.UI.Views public class PopupRenderer : Dialog, IVisualElementRenderer, IDialogInterfaceOnCancelListener { int? defaultLabelFor; - VisualElementTracker tracker; - ContainerView container; + VisualElementTracker? tracker; + ContainerView? container; bool isDisposed; - public BasePopup Element { get; private set; } + public BasePopup? Element { get; private set; } void IVisualElementRenderer.UpdateLayout() => tracker?.UpdateLayout(); - VisualElement IVisualElementRenderer.Element => Element; + VisualElement? IVisualElementRenderer.Element => Element; - AView IVisualElementRenderer.View => container; + AView? IVisualElementRenderer.View => container; - ViewGroup IVisualElementRenderer.ViewGroup => null; + ViewGroup? IVisualElementRenderer.ViewGroup => null; - VisualElementTracker IVisualElementRenderer.Tracker => tracker; + VisualElementTracker? IVisualElementRenderer.Tracker => tracker; - public event EventHandler ElementChanged; + public event EventHandler? ElementChanged; - public event EventHandler ElementPropertyChanged; + public event EventHandler? ElementPropertyChanged; public PopupRenderer(Context context) : base(context) @@ -50,12 +50,12 @@ void IVisualElementRenderer.SetElement(VisualElement element) if (element == null) throw new ArgumentNullException(nameof(element)); - if (!(element is BasePopup popup)) + if (element is not BasePopup popup) throw new ArgumentNullException("Element is not of type " + typeof(BasePopup), nameof(element)); var oldElement = Element; Element = popup; - CreateControl(); + CreateControl(Element); if (oldElement != null) oldElement.PropertyChanged -= OnElementPropertyChanged; @@ -65,18 +65,18 @@ void IVisualElementRenderer.SetElement(VisualElement element) if (tracker == null) tracker = new VisualElementTracker(this); - OnElementChanged(new ElementChangedEventArgs(oldElement, Element)); + OnElementChanged(new ElementChangedEventArgs(oldElement, Element)); } - protected virtual void OnElementChanged(ElementChangedEventArgs e) + protected virtual void OnElementChanged(ElementChangedEventArgs e) { - if (e.NewElement != null && !isDisposed) + if (e.NewElement != null && !isDisposed && Element is BasePopup basePopup) { - SetEvents(); - SetColor(); - SetSize(); - SetAnchor(); - SetLightDismiss(); + SetEvents(basePopup); + SetColor(basePopup); + SetSize(basePopup); + SetAnchor(basePopup); + SetLightDismiss(basePopup); Show(); } @@ -92,61 +92,64 @@ public override void Show() protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) { - if (args.PropertyName == BasePopup.VerticalOptionsProperty.PropertyName || - args.PropertyName == BasePopup.HorizontalOptionsProperty.PropertyName || - args.PropertyName == BasePopup.SizeProperty.PropertyName) + if (Element is BasePopup basePopup) { - SetSize(); - SetAnchor(); - } - else if (args.PropertyName == BasePopup.ColorProperty.PropertyName) - { - SetColor(); + if (args.PropertyName == BasePopup.VerticalOptionsProperty.PropertyName + || args.PropertyName == BasePopup.HorizontalOptionsProperty.PropertyName + || args.PropertyName == BasePopup.SizeProperty.PropertyName) + { + SetSize(basePopup); + SetAnchor(basePopup); + } + else if (args.PropertyName == BasePopup.ColorProperty.PropertyName) + { + SetColor(basePopup); + } } ElementPropertyChanged?.Invoke(this, args); } - void CreateControl() + void CreateControl(in BasePopup basePopup) { if (container == null) { - container = new ContainerView(Context, Element.Content); + container = new ContainerView(Context, basePopup.Content); SetContentView(container); } } - void SetEvents() + void SetEvents(in BasePopup basePopup) { SetOnCancelListener(this); - Element.Dismissed += OnDismissed; + basePopup.Dismissed += OnDismissed; } - void SetColor() + void SetColor(in BasePopup basePopup) { - Window.SetBackgroundDrawable(new ColorDrawable(Element.Color.ToAndroid())); + Window.SetBackgroundDrawable(new ColorDrawable(basePopup.Color.ToAndroid())); } - void SetSize() + void SetSize(in BasePopup basePopup) { - if (Element.Size != default) + if (basePopup.Size != default) { - var decorView = (ViewGroup)Window.DecorView; - var child = (FrameLayout)decorView.GetChildAt(0); + var decorView = (ViewGroup)(Window?.DecorView ?? throw new NullReferenceException()); + var child = (FrameLayout)(decorView?.GetChildAt(0) ?? throw new NullReferenceException()); - var realWidth = (int)Context.ToPixels(Element.Size.Width); - var realHeight = (int)Context.ToPixels(Element.Size.Height); + var realWidth = (int)Context.ToPixels(basePopup.Size.Width); + var realHeight = (int)Context.ToPixels(basePopup.Size.Height); - var realContentWidth = (int)Context.ToPixels(Element.Content.WidthRequest); - var realContentHeight = (int)Context.ToPixels(Element.Content.HeightRequest); + var realContentWidth = (int)Context.ToPixels(basePopup.Content.WidthRequest); + var realContentHeight = (int)Context.ToPixels(basePopup.Content.HeightRequest); - var childLayoutParams = (FrameLayout.LayoutParams)child.LayoutParameters; + var childLayoutParams = (FrameLayout.LayoutParams)(child?.LayoutParameters ?? throw new NullReferenceException()); childLayoutParams.Width = realWidth; childLayoutParams.Height = realHeight; child.LayoutParameters = childLayoutParams; var horizontalParams = -1; - switch (Element.Content.HorizontalOptions.Alignment) + switch (basePopup.Content.HorizontalOptions.Alignment) { case LayoutAlignment.Center: case LayoutAlignment.End: @@ -159,7 +162,7 @@ void SetSize() } var verticalParams = -1; - switch (Element.Content.VerticalOptions.Alignment) + switch (basePopup.Content.VerticalOptions.Alignment) { case LayoutAlignment.Center: case LayoutAlignment.End: @@ -171,6 +174,7 @@ void SetSize() break; } + _ = container ?? throw new NullReferenceException(); if (realContentWidth > -1) { var inputMeasuredWidth = realContentWidth > realWidth ? @@ -199,7 +203,7 @@ void SetSize() var containerLayoutParams = new FrameLayout.LayoutParams(horizontalParams, verticalParams); - switch (Element.Content.VerticalOptions.Alignment) + switch (basePopup.Content.VerticalOptions.Alignment) { case LayoutAlignment.Start: containerLayoutParams.Gravity = GravityFlags.Top; @@ -215,7 +219,7 @@ void SetSize() break; } - switch (Element.Content.HorizontalOptions.Alignment) + switch (basePopup.Content.HorizontalOptions.Alignment) { case LayoutAlignment.Start: containerLayoutParams.Gravity |= GravityFlags.Left; @@ -235,16 +239,16 @@ void SetSize() } } - void SetAnchor() + void SetAnchor(in BasePopup basePopup) { - if (Element.Anchor != null) + if (basePopup.Anchor != null) { - var anchorView = FormsPlatform.GetRenderer(Element.Anchor).View; + var anchorView = FormsPlatform.GetRenderer(Element?.Anchor).View; var locationOnScreen = new int[2]; anchorView.GetLocationOnScreen(locationOnScreen); - Window.SetGravity(GravityFlags.Top | GravityFlags.Left); - Window.DecorView.Measure((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified); + Window?.SetGravity(GravityFlags.Top | GravityFlags.Left); + Window?.DecorView.Measure((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified); // This logic is tricky, please read these notes if you need to modify // Android window coordinate starts (0,0) at the top left and (max,max) at the bottom right. All of the positions @@ -254,64 +258,48 @@ void SetAnchor() // 2. Calculate the Actual Center of the Anchor by adding the width /2 and height / 2 // 3. Calculate the top-left point of where the dialog should be positioned by subtracting the Width / 2 and height / 2 // of the dialog that is about to be drawn. + _ = Window?.Attributes ?? throw new NullReferenceException(); + Window.Attributes.X = locationOnScreen[0] + (anchorView.Width / 2) - (Window.DecorView.MeasuredWidth / 2); Window.Attributes.Y = locationOnScreen[1] + (anchorView.Height / 2) - (Window.DecorView.MeasuredHeight / 2); } else { - SetDialogPosition(); + SetDialogPosition(basePopup); } } - void SetLightDismiss() + void SetLightDismiss(in BasePopup basePopup) { - if (Element.IsLightDismissEnabled) + if (basePopup.IsLightDismissEnabled) return; SetCancelable(false); SetCanceledOnTouchOutside(false); } - void SetDialogPosition() + void SetDialogPosition(in BasePopup basePopup) { - var gravityFlags = GravityFlags.Center; - switch (Element.VerticalOptions.Alignment) + var gravityFlags = basePopup.VerticalOptions.Alignment switch { - case LayoutAlignment.Start: - gravityFlags = GravityFlags.Top; - break; - case LayoutAlignment.End: - gravityFlags = GravityFlags.Bottom; - break; - default: - gravityFlags = GravityFlags.CenterVertical; - break; - } - - switch (Element.HorizontalOptions.Alignment) + LayoutAlignment.Start => GravityFlags.Top, + LayoutAlignment.End => GravityFlags.Bottom, + _ => GravityFlags.CenterVertical, + }; + gravityFlags |= basePopup.HorizontalOptions.Alignment switch { - case LayoutAlignment.Start: - gravityFlags |= GravityFlags.Left; - break; - case LayoutAlignment.End: - gravityFlags |= GravityFlags.Right; - break; - default: - gravityFlags |= GravityFlags.CenterHorizontal; - break; - } - - Window.SetGravity(gravityFlags); + LayoutAlignment.Start => GravityFlags.Left, + LayoutAlignment.End => GravityFlags.Right, + _ => GravityFlags.CenterHorizontal, + }; + Window?.SetGravity(gravityFlags); } - void OnDismissed(object sender, PopupDismissedEventArgs e) - { - Dismiss(); - } + void OnDismissed(object sender, PopupDismissedEventArgs e) => Dismiss(); - public void OnCancel(IDialogInterface dialog) + public void OnCancel(IDialogInterface? dialog) { - if (Element.IsLightDismissEnabled) + if (Element?.IsLightDismissEnabled is true) Element.LightDismiss(); } @@ -347,6 +335,8 @@ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heigh void IVisualElementRenderer.SetLabelFor(int? id) { + _ = container ?? throw new NullReferenceException(); + if (defaultLabelFor == null) defaultLabelFor = container.LabelFor; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/BasePopup.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/BasePopup.shared.cs index da137d302..2bdfaf6db 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/BasePopup.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/BasePopup.shared.cs @@ -82,7 +82,7 @@ public LayoutOptions HorizontalOptions /// The Anchor is where the Popup will render closest to. When an Anchor is configured /// the popup will appear centered over that control or as close as possible. /// - public View Anchor { get; set; } + public View? Anchor { get; set; } /// /// Gets or sets the of the Popup Display. @@ -132,7 +132,7 @@ public Size Size /// /// The results to add to the . /// - protected void OnDismissed(object result) => + protected void OnDismissed(object? result) => dismissWeakEventManager.RaiseEvent(this, new PopupDismissedEventArgs(result), nameof(Dismissed)); /// diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupDismissedEventArgs.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupDismissedEventArgs.shared.cs index bf063487b..a6ea5783e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupDismissedEventArgs.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupDismissedEventArgs.shared.cs @@ -5,9 +5,9 @@ namespace Xamarin.CommunityToolkit.UI.Views /// /// Popup dismissed event arguments used when a popup is dismissed. /// - public class PopupDismissedEventArgs : PopupDismissedEventArgs + public class PopupDismissedEventArgs : PopupDismissedEventArgs { - public PopupDismissedEventArgs(object result) + public PopupDismissedEventArgs(object? result) : base(result) { } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs index cb0cd4c2b..f091a38e4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs @@ -5,19 +5,19 @@ namespace Xamarin.CommunityToolkit.UI.Views /// public abstract class Popup : BasePopup { - TaskCompletionSource taskCompletionSource; + TaskCompletionSource taskCompletionSource; /// /// Initalizes a default implementation of . /// protected Popup() => - taskCompletionSource = new TaskCompletionSource(); + taskCompletionSource = new TaskCompletionSource(); /// /// Resets the Popup. /// public void Reset() => - taskCompletionSource = new TaskCompletionSource(); + taskCompletionSource = new TaskCompletionSource(); /// /// Dismiss the current popup. @@ -34,7 +34,7 @@ public void Dismiss(T result) /// /// Gets the final result of the dismissed popup. /// - public Task Result => taskCompletionSource.Task; + public Task Result => taskCompletionSource.Task; /// protected internal override void LightDismiss() => @@ -50,6 +50,6 @@ public void Dismiss(T result) /// When a user dismisses the Popup via the light dismiss, this /// method will return a default value. /// - protected virtual T GetLightDismissResult() => default(T); + protected virtual T? GetLightDismissResult() => default(T); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/iOS/PopupRenderer.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/iOS/PopupRenderer.ios.cs index 526465974..9582d64b4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/iOS/PopupRenderer.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/iOS/PopupRenderer.ios.cs @@ -16,19 +16,19 @@ public class PopupRenderer : UIViewController, IVisualElementRenderer { bool isDisposed; - public IVisualElementRenderer Control { get; private set; } + public IVisualElementRenderer? Control { get; private set; } - public BasePopup Element { get; private set; } + public BasePopup? Element { get; private set; } - VisualElement IVisualElementRenderer.Element => Element; + VisualElement? IVisualElementRenderer.Element => Element; - public UIView NativeView => View; + public UIView? NativeView => View; - public UIViewController ViewController { get; private set; } + public UIViewController? ViewController { get; private set; } - public event EventHandler ElementChanged; + public event EventHandler? ElementChanged; - public event EventHandler ElementPropertyChanged; + public event EventHandler? ElementPropertyChanged; [Preserve(Conditional = true)] public PopupRenderer() @@ -41,6 +41,8 @@ public PopupRenderer() public override void ViewDidLayoutSubviews() { base.ViewDidLayoutSubviews(); + + _ = View ?? throw new NullReferenceException(); SetElementSize(new Size(View.Bounds.Width, View.Bounds.Height)); } @@ -48,6 +50,7 @@ public override void ViewDidAppear(bool animated) { base.ViewDidAppear(animated); + _ = Element ?? throw new NullReferenceException(); ModalInPopover = !Element.IsLightDismissEnabled; } @@ -59,7 +62,7 @@ void IVisualElementRenderer.SetElement(VisualElement element) if (element == null) throw new ArgumentNullException(nameof(element)); - if (!(element is BasePopup popup)) + if (element is not BasePopup popup) throw new ArgumentNullException("Element is not of type " + typeof(BasePopup), nameof(element)); var oldElement = Element; @@ -71,10 +74,10 @@ void IVisualElementRenderer.SetElement(VisualElement element) element.PropertyChanged += OnElementPropertyChanged; - OnElementChanged(new ElementChangedEventArgs(oldElement, Element)); + OnElementChanged(new ElementChangedEventArgs(oldElement, Element)); } - protected virtual void OnElementChanged(ElementChangedEventArgs e) + protected virtual void OnElementChanged(ElementChangedEventArgs e) { if (e.NewElement != null && !isDisposed) { @@ -115,6 +118,8 @@ protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEv void CreateControl() { + _ = Element ?? throw new NullReferenceException(); + var view = Element.Content; var contentPage = new ContentPage { Content = view, Padding = new Thickness(25) }; @@ -129,11 +134,15 @@ void SetViewController() ViewController = currentPageRenderer.ViewController; } - void SetEvents() => + void SetEvents() + { + _ = Element ?? throw new NullReferenceException(); Element.Dismissed += OnDismissed; + } void SetSize() { + _ = Element ?? throw new NullReferenceException(); if (!Element.Size.IsZero) { PreferredContentSize = new CGSize(Element.Size.Width, Element.Size.Height); @@ -144,6 +153,7 @@ void SetLayout() { ((UIPopoverPresentationController)PresentationController).SourceRect = new CGRect(0, 0, PreferredContentSize.Width, PreferredContentSize.Height); + _ = Element ?? throw new NullReferenceException(); if (Element.Anchor == null) { var originY = Element.VerticalOptions.Alignment switch @@ -182,12 +192,20 @@ void SetLayout() } } - void SetBackgroundColor() => + void SetBackgroundColor() + { + _ = Element ?? throw new NullReferenceException(); + _ = Control ?? throw new NullReferenceException(); + Control.NativeView.BackgroundColor = Element.Color.ToUIColor(); + } void SetView() { - View.AddSubview(Control.ViewController.View); + _ = View ?? throw new NullReferenceException(); + _ = Control ?? throw new NullReferenceException(); + + View.AddSubview(Control.ViewController.View ?? throw new NullReferenceException()); View.Bounds = new CGRect(0, 0, PreferredContentSize.Width, PreferredContentSize.Height); AddChildViewController(Control.ViewController); } @@ -197,22 +215,32 @@ void SetPresentationController() var popOverDelegate = new PopoverDelegate(); popOverDelegate.PopoverDismissed += HandlePopoverDelegateDismissed; - ((UIPopoverPresentationController)PresentationController).SourceView = ViewController.View; + ((UIPopoverPresentationController)PresentationController).SourceView = ViewController?.View ?? throw new NullReferenceException(); ((UIPopoverPresentationController)PresentationController).Delegate = popOverDelegate; } void HandlePopoverDelegateDismissed(object sender, UIPresentationController e) { + _ = Element ?? throw new NullReferenceException(); + if (IsViewLoaded && Element.IsLightDismissEnabled) Element.LightDismiss(); } - void AddToCurrentPageViewController() => + void AddToCurrentPageViewController() + { + _ = ViewController ?? throw new NullReferenceException(); + _ = Element ?? throw new NullReferenceException(); + ViewController.PresentViewController(this, true, () => Element.OnOpened()); + } - async void OnDismissed(object sender, PopupDismissedEventArgs e) => - await ViewController.DismissViewControllerAsync(true); + async void OnDismissed(object sender, PopupDismissedEventArgs e) + { + if (ViewController != null) + await ViewController.DismissViewControllerAsync(true); + } protected override void Dispose(bool disposing) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/RangeSlider.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/RangeSlider.shared.cs index ef142e338..c0133af3b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/RangeSlider.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/RangeSlider.shared.cs @@ -16,23 +16,23 @@ public class RangeSlider : BaseTemplatedView const double disabledOpacity = .6; - public event EventHandler ValueChanged; + public event EventHandler? ValueChanged; - public event EventHandler LowerValueChanged; + public event EventHandler? LowerValueChanged; - public event EventHandler UpperValueChanged; + public event EventHandler? UpperValueChanged; - public event EventHandler DragStarted; + public event EventHandler? DragStarted; - public event EventHandler LowerDragStarted; + public event EventHandler? LowerDragStarted; - public event EventHandler UpperDragStarted; + public event EventHandler? UpperDragStarted; - public event EventHandler DragCompleted; + public event EventHandler? DragCompleted; - public event EventHandler LowerDragCompleted; + public event EventHandler? LowerDragCompleted; - public event EventHandler UpperDragCompleted; + public event EventHandler? UpperDragCompleted; public static BindableProperty MinimumValueProperty = BindableProperty.Create(nameof(MinimumValue), typeof(double), typeof(RangeSlider), .0, propertyChanged: OnMinimumMaximumValuePropertyChanged); @@ -334,7 +334,7 @@ public double TrackRadius double TrackWidth => Width - LowerThumb.Width - UpperThumb.Width; - protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") { base.OnPropertyChanged(propertyName); switch (propertyName) @@ -633,7 +633,7 @@ Color GetColorOrDefault(Color color, Color defaultColor) ? defaultSize : value; - void RaiseEvent(EventHandler eventHandler) + void RaiseEvent(EventHandler? eventHandler) => eventHandler?.Invoke(this, EventArgs.Empty); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs index a9c9d0dbb..716cf6b92 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs @@ -232,7 +232,7 @@ public object CommandParameter /// /// Event that is triggered when the is tapped. This is a bindable property. /// - public event EventHandler Tapped; + public event EventHandler? Tapped; Grid ShieldSubjectContainer { get; } = CreateSubjectContainerElement(); @@ -296,7 +296,7 @@ protected override void OnControlInitialized(Frame control) UpdateIsEnabled(); } - protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") { base.OnPropertyChanged(propertyName); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs index b4f817b4c..339bb2b72 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs @@ -38,17 +38,7 @@ public class SideMenuView : BaseTemplatedView readonly SideMenuElementCollection children = new SideMenuElementCollection(); - View overlayView; - - View mainView; - - View leftMenu; - - View rightMenu; - - View activeMenu; - - View inactiveMenu; + View? overlayView, mainView, leftMenu, rightMenu, activeMenu, inactiveMenu; double zeroShift; @@ -344,7 +334,10 @@ void PerformUpdate(bool isAnimated = true) } void SetOverlayViewInputTransparent(SideMenuState state) - => overlayView.InputTransparent = state == SideMenuState.MainViewShown; + { + _ = overlayView ?? throw new NullReferenceException(); + overlayView.InputTransparent = state == SideMenuState.MainViewShown; + } SideMenuState ResolveSwipeState(bool isRightSwipe) { @@ -382,6 +375,9 @@ bool TryUpdateShift(double sift, bool shouldUpdatePreviousShift, bool shouldChec if (shouldUpdatePreviousShift) previousShift = sift; + _ = mainView ?? throw new NullReferenceException(); + _ = overlayView ?? throw new NullReferenceException(); + mainView.TranslationX = sift; overlayView.TranslationX = sift; return true; @@ -439,7 +435,7 @@ void SetActiveView(bool isLeft) if (inactiveMenu == null || activeMenu == null || - leftMenu.X + leftMenu.Width <= rightMenu.X || + leftMenu?.X + leftMenu?.Width <= rightMenu?.X || Control.Children.IndexOf(inactiveMenu) < Control.Children.IndexOf(activeMenu)) return; @@ -574,7 +570,7 @@ void OnLayoutChanged(object sender, EventArgs e) Control.RaiseChild(overlayView); } - bool CheckMenuGestureEnabled(View menuView) + bool CheckMenuGestureEnabled(View? menuView) => menuView != null && GetMenuGestureEnabled(menuView); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.ios.cs index 9da312c3f..795dc4776 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.ios.cs @@ -15,9 +15,9 @@ public class SideMenuViewRenderer : VisualElementRenderer { const double defaultGestureThreshold = 7.0; - UISwipeGestureRecognizer leftSwipeGestureRecognizer; + UISwipeGestureRecognizer? leftSwipeGestureRecognizer; - UISwipeGestureRecognizer rightSwipeGestureRecognizer; + UISwipeGestureRecognizer? rightSwipeGestureRecognizer; public SideMenuViewRenderer() { @@ -61,7 +61,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - void Dispose(ref UISwipeGestureRecognizer gestureRecognizer) + void Dispose(ref UISwipeGestureRecognizer? gestureRecognizer) { if (gestureRecognizer != null) { @@ -85,7 +85,7 @@ bool ShouldBeRequiredToFailBy(UIGestureRecognizer gestureRecognizer, UIGestureRe bool ShouldRecognizeSimultaneously(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer) { - if (!(gestureRecognizer is UIPanGestureRecognizer panGesture)) + if (gestureRecognizer is not UIPanGestureRecognizer panGesture) return true; var parent = Element?.Parent; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/NativeSnackButton.ios.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/NativeSnackButton.ios.macos.cs index 02dd58db3..06ba6da0c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/NativeSnackButton.ios.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/NativeSnackButton.ios.macos.cs @@ -1,10 +1,10 @@ using System; using System.Threading.Tasks; -using CoreGraphics; #if __IOS__ using Xamarin.CommunityToolkit.UI.Views.Helpers.iOS; using UIKit; #elif __MACOS__ +using CoreGraphics; using Xamarin.CommunityToolkit.UI.Views.Helpers.macOS; using AppKit; #endif @@ -31,14 +31,16 @@ public NativeSnackButton(double left, double top, double right, double bottom) ContentEdgeInsets = new UIEdgeInsets((nfloat)top, (nfloat)left, (nfloat)bottom, (nfloat)right); TouchUpInside += async (s, e) => { - await SnackButtonAction(); + if (SnackButtonAction != null) + await SnackButtonAction(); }; } #else WantsLayer = true; Activated += async (s, e) => { - await SnackButtonAction(); + if (SnackButtonAction != null) + await SnackButtonAction(); }; } @@ -55,7 +57,7 @@ public NativeSnackButton(double left, double top, double right, double bottom) public double Bottom { get; } - public Func SnackButtonAction { get; protected set; } + public Func? SnackButtonAction { get; protected set; } public NativeSnackButton SetAction(Func action) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/IOSSnackBar.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/IOSSnackBar.ios.cs index 2ff26cf1c..9a228aaee 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/IOSSnackBar.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/IOSSnackBar.ios.cs @@ -12,11 +12,11 @@ namespace Xamarin.CommunityToolkit.UI.Views.Helpers.iOS { class NativeSnackBar { - NSTimer timer; + NSTimer? timer; public List Actions { get; protected set; } = new List(); - public Func TimeoutAction { get; protected set; } + public Func? TimeoutAction { get; protected set; } public NativeSnackBarAppearance Appearance { get; protected set; } = new NativeSnackBarAppearance(); @@ -24,11 +24,11 @@ class NativeSnackBar public SnackBarLayout Layout { get; } = new SnackBarLayout(); - public string Message { get; protected set; } + public string Message { get; protected set; } = string.Empty; - public UIViewController ParentController { get; protected set; } + public UIViewController? ParentController { get; protected set; } - protected BaseSnackBarView SnackBarView { get; set; } + protected BaseSnackBarView? SnackBarView { get; set; } public void Dismiss() { @@ -70,14 +70,15 @@ public NativeSnackBar Show() { SnackBarView = GetSnackBarView(); - SnackBarView.ParentView.AddSubview(SnackBarView); - SnackBarView.ParentView.BringSubviewToFront(SnackBarView); + SnackBarView.ParentView?.AddSubview(SnackBarView); + SnackBarView.ParentView?.BringSubviewToFront(SnackBarView); SnackBarView.Setup(); timer = NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(Duration), async t => { - await TimeoutAction(); + if (TimeoutAction != null) + await TimeoutAction(); Dismiss(); }); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/ActionMessageSnackBarView.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/ActionMessageSnackBarView.ios.cs index 56a4020c3..6cea42669 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/ActionMessageSnackBarView.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/ActionMessageSnackBarView.ios.cs @@ -1,6 +1,5 @@ -using UIKit; +using System; using Xamarin.CommunityToolkit.UI.Views.Helpers.iOS.SnackBarViews; -using Xamarin.CommunityToolkit.Views.Snackbar.Helpers; namespace Xamarin.CommunityToolkit.UI.Views.Helpers.iOS { @@ -15,6 +14,8 @@ protected override void Initialize() { base.Initialize(); + _ = StackView ?? throw new NullReferenceException(); + foreach (var actionButton in SnackBar.Actions) { StackView.AddArrangedSubview(actionButton); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/BaseSnackBarView.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/BaseSnackBarView.ios.cs index 42e99b091..55c7ac1f3 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/BaseSnackBarView.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/BaseSnackBarView.ios.cs @@ -1,4 +1,5 @@ -using UIKit; +using System; +using UIKit; using Xamarin.CommunityToolkit.UI.Views.Helpers.iOS.Extensions; namespace Xamarin.CommunityToolkit.UI.Views.Helpers.iOS.SnackBar @@ -7,13 +8,13 @@ abstract class BaseSnackBarView : UIView { public BaseSnackBarView(NativeSnackBar snackBar) => SnackBar = snackBar; - public virtual UIView ParentView => SnackBar.ParentController != null + public virtual UIView? ParentView => SnackBar.ParentController != null ? SnackBar.ParentController.View : UIApplication.SharedApplication.KeyWindow; protected NativeSnackBar SnackBar { get; } - protected UIStackView StackView { get; set; } + protected UIStackView? StackView { get; set; } public virtual void Dismiss() => RemoveFromSuperview(); @@ -30,6 +31,9 @@ protected virtual void ConstrainChildren() protected virtual void ConstrainInParent() { + _ = StackView ?? throw new System.Exception("BaseSnackBarView.Initialize() not called"); + _ = ParentView ?? throw new System.NullReferenceException(); + this.SafeBottomAnchor().ConstraintEqualTo(GetBottomAnchor(), -SnackBar.Layout.MarginBottom).Active = true; this.SafeTopAnchor().ConstraintGreaterThanOrEqualTo(GetTopAnchor(), SnackBar.Layout.MarginTop).Active = true; this.SafeLeadingAnchor().ConstraintGreaterThanOrEqualTo(ParentView.SafeLeadingAnchor(), SnackBar.Layout.MarginLeft).Active = true; @@ -46,6 +50,7 @@ protected virtual NSLayoutYAxisAnchor GetBottomAnchor() { if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0) || SnackBar.ParentController == null) { + _ = ParentView ?? throw new System.NullReferenceException(); return ParentView.SafeBottomAnchor(); } @@ -56,16 +61,18 @@ protected virtual NSLayoutYAxisAnchor GetCenterYAnchor() { if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0) || SnackBar.ParentController == null) { + _ = ParentView ?? throw new NullReferenceException(); return ParentView.SafeCenterYAnchor(); } - return SnackBar.ParentController.View?.CenterYAnchor; + return SnackBar.ParentController.View?.CenterYAnchor ?? throw new NullReferenceException(); } protected virtual NSLayoutYAxisAnchor GetTopAnchor() { if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0) || SnackBar.ParentController == null) { + _ = ParentView ?? throw new NullReferenceException(); return ParentView.SafeTopAnchor(); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/MessageSnackBarView.ios.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/MessageSnackBarView.ios.cs index 97b9ceb1e..fadf61a57 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/MessageSnackBarView.ios.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/iOS/SnackbarViews/MessageSnackBarView.ios.cs @@ -1,4 +1,5 @@ -using Xamarin.CommunityToolkit.UI.Views.Helpers.iOS.SnackBar; +using System; +using Xamarin.CommunityToolkit.UI.Views.Helpers.iOS.SnackBar; namespace Xamarin.CommunityToolkit.UI.Views.Helpers.iOS.SnackBarViews { @@ -38,6 +39,7 @@ protected override void Initialize() messageLabel.Font = SnackBar.Appearance.Font; } + _ = StackView ?? throw new NullReferenceException(); StackView.AddArrangedSubview(messageLabel); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/MessageOptions.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/MessageOptions.shared.cs index 89e487f35..448fdfe98 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/MessageOptions.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/MessageOptions.shared.cs @@ -9,7 +9,7 @@ public class MessageOptions /// public string Message { get; set; } = DefaultMessage; - public static string DefaultMessage { get; set; } + public static string DefaultMessage { get; set; } = string.Empty; /// /// Gets or sets the font for the SnackBar message. diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/SnackBarActionOptions.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/SnackBarActionOptions.shared.cs index 06bf598c8..59ca5a76f 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/SnackBarActionOptions.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Options/SnackBarActionOptions.shared.cs @@ -9,16 +9,16 @@ public class SnackBarActionOptions /// /// Gets or sets the action for the SnackBar action button. /// - public Func Action { get; set; } = DefaultAction; + public Func? Action { get; set; } = DefaultAction; - public static Func DefaultAction { get; set; } = null; + public static Func? DefaultAction { get; set; } = null; /// /// Gets or sets the text for the SnackBar action button. /// public string Text { get; set; } = DefaultText; - public static string DefaultText { get; set; } + public static string DefaultText { get; set; } = string.Empty; /// /// Gets or sets the font for the SnackBar action button. diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs index 84146e37b..1bb39fbbe 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs @@ -113,7 +113,9 @@ internal void Show(Page sender, SnackBarOptions arguments) actionButton.SetAction(async () => { snackBar.Dismiss(); - await action.Action(); + + await (action.Action?.Invoke() ?? Task.CompletedTask); + arguments.SetResult(true); }); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/StateLayout/StateLayoutController.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/StateLayout/StateLayoutController.shared.cs index be0d2c52d..a57c1fb7d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/StateLayout/StateLayoutController.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/StateLayout/StateLayoutController.shared.cs @@ -11,11 +11,11 @@ public class StateLayoutController { readonly WeakReference> layoutWeakReference; bool layoutIsGrid; - LayoutState previousState; - IList originalContent; - CancellationTokenSource animationTokenSource; + LayoutState? previousState; + IList originalContent = Enumerable.Empty().ToList(); + CancellationTokenSource? animationTokenSource; - public IList StateViews { get; set; } + public IList StateViews { get; set; } = Enumerable.Empty().ToList(); public StateLayoutController(Layout layout) => layoutWeakReference = new WeakReference>(layout); @@ -48,7 +48,7 @@ public async void SwitchToContent(bool animate) public void SwitchToTemplate(string customState, bool animate) => SwitchToTemplate(LayoutState.Custom, customState, animate); - public async void SwitchToTemplate(LayoutState state, string customState, bool animate) + public async void SwitchToTemplate(LayoutState state, string? customState, bool animate) { if (!layoutWeakReference.TryGetTarget(out var layout)) return; @@ -161,7 +161,7 @@ public async void SwitchToTemplate(LayoutState state, string customState, bool a } } - StateView GetViewForState(LayoutState state, string customState) + StateView GetViewForState(LayoutState state, string? customState) { var view = StateViews.FirstOrDefault(x => (x.StateKey == state && state != LayoutState.Custom) || (state == LayoutState.Custom && x.CustomStateKey == customState)); @@ -169,7 +169,7 @@ StateView GetViewForState(LayoutState state, string customState) return view; } - int GetRepeatCount(LayoutState state, string customState) + int GetRepeatCount(LayoutState state, string? customState) { var template = StateViews.FirstOrDefault(x => (x.StateKey == state && state != LayoutState.Custom) || (state == LayoutState.Custom && x.CustomStateKey == customState)); @@ -180,7 +180,7 @@ int GetRepeatCount(LayoutState state, string customState) return 1; } - DataTemplate GetTemplate(LayoutState state, string customState) + DataTemplate? GetTemplate(LayoutState state, string? customState) { var view = StateViews.FirstOrDefault(x => (x.StateKey == state && state != LayoutState.Custom) || (state == LayoutState.Custom && x.CustomStateKey == customState)); @@ -191,7 +191,7 @@ DataTemplate GetTemplate(LayoutState state, string customState) return null; } - View CreateItemView(LayoutState state, string customState) + View CreateItemView(LayoutState state, string? customState) { var view = StateViews.FirstOrDefault(x => (x.StateKey == state && state != LayoutState.Custom) || (state == LayoutState.Custom && x.CustomStateKey == customState)); @@ -201,7 +201,7 @@ View CreateItemView(LayoutState state, string customState) if (view != null) return view; - return new Label() { Text = $"View for {state}{customState} not defined." }; + return new Label{ Text = $"View for {state}{customState} not defined." }; } async Task ChildrenFadeTo(Layout layout, bool animate, bool isHide) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabBadgeView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabBadgeView.shared.cs index b1097b000..6a47b7b52 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabBadgeView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabBadgeView.shared.cs @@ -13,8 +13,8 @@ public class TabBadgeView : TemplatedView internal const string ElementBorder = "PART_Border"; internal const string ElementText = "PART_Text"; - Frame badgeBorder; - Label badgeText; + Frame? badgeBorder; + Label? badgeText; bool isVisible; public TabBadgeView() => ControlTemplate = new ControlTemplate(typeof(TabBadgeTemplate)); @@ -38,7 +38,11 @@ public bool AutoHide set => SetValue(AutoHideProperty, value); } - static async void OnAutoHideChanged(BindableObject bindable, object oldValue, object newValue) => await (bindable as TabBadgeView)?.UpdateVisibilityAsync(); + static async void OnAutoHideChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabBadgeView tabBadgeView) + await tabBadgeView.UpdateVisibilityAsync(); + } public static BindableProperty IsAnimatedProperty = BindableProperty.Create(nameof(IsAnimated), typeof(bool), typeof(TabBadgeView), defaultValue: true); @@ -110,23 +114,23 @@ protected override void OnApplyTemplate() { base.OnApplyTemplate(); - badgeBorder = GetTemplateChild(ElementBorder) as Frame; - badgeText = GetTemplateChild(ElementText) as Label; + badgeBorder = (Frame)GetTemplateChild(ElementBorder); + badgeText = (Label)GetTemplateChild(ElementText); UpdateSize(); - UpdatePosition(); - UpdateIsEnabled(); + UpdatePosition(badgeBorder); + UpdateIsEnabled(badgeText); } - protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") { base.OnPropertyChanged(propertyName); - if (propertyName == IsEnabledProperty.PropertyName) - UpdateIsEnabled(); + if (propertyName == IsEnabledProperty.PropertyName && badgeText is Label label) + UpdateIsEnabled(label); } - void UpdateIsEnabled() + void UpdateIsEnabled(in Label badgeText) { if (IsEnabled) badgeText.PropertyChanged += OnBadgeTextPropertyChanged; @@ -136,19 +140,16 @@ void UpdateIsEnabled() void OnBadgeTextPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) + if (e.PropertyName is nameof(Height) or nameof(Width) && badgeBorder is Frame frame) { - case nameof(Height): - case nameof(Width): - UpdateSize(); - UpdatePosition(); - break; + UpdateSize(); + UpdatePosition(frame); } } void UpdateSize() { - if (badgeText == null || badgeText.Width <= 0 || badgeText.Height <= 0) + if (badgeBorder == null || badgeText == null || badgeText.Width <= 0 || badgeText.Height <= 0) return; var badgeTextHeight = badgeText.Height + (badgeBorder.Padding.VerticalThickness / 2); @@ -160,7 +161,7 @@ void UpdateSize() badgeBorder.CornerRadius = (int)Math.Round(badgeTextHeight / 2); } - void UpdatePosition() + void UpdatePosition(Frame badgeBorder) { if (PlacementTarget == null) return; @@ -173,23 +174,38 @@ void UpdatePosition() badgeBorder.Margin = new Thickness(x, 0, 0, 0); } - void UpdateBackgroundColor(Color backgroundColor) => badgeBorder.BackgroundColor = backgroundColor; + void UpdateBackgroundColor(Color backgroundColor) + { + if (badgeBorder != null) + badgeBorder.BackgroundColor = backgroundColor; + } - void UpdateBorderColor(Color borderColor) => badgeBorder.BorderColor = borderColor; + void UpdateBorderColor(Color borderColor) + { + if (badgeBorder != null) + badgeBorder.BorderColor = borderColor; + } - void UpdateTextColor(Color textColor) => badgeText.TextColor = textColor; + void UpdateTextColor(Color textColor) + { + if (badgeText != null) + badgeText.TextColor = textColor; + } async void UpdateText(string text) { - badgeText.Text = text; - await UpdateVisibilityAsync(); + if (badgeText != null) + { + badgeText.Text = text; + await UpdateVisibilityAsync(); + } } async Task UpdateVisibilityAsync() { - var badgeText = this.badgeText.Text; + var badgeText = this.badgeText?.Text; - if (string.IsNullOrEmpty(badgeText)) + if (badgeText == null || string.IsNullOrEmpty(badgeText)) { IsVisible = false; return; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs index a05c84a6f..4716a0db1 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs @@ -29,8 +29,8 @@ public class TabView : ContentView, IDisposable readonly CarouselView contentContainer; readonly List contentWidthCollection; - IList tabItemsSource; - ObservableCollection contentTabItems; + IList? tabItemsSource; + ObservableCollection? contentTabItems; public TabView() { @@ -173,7 +173,7 @@ public void Dispose() if (TabItems != null) TabItems.CollectionChanged -= OnTabItemsCollectionChanged; - var lazyView = (((TabViewItem)contentContainer.CurrentItem).Content as BaseLazyView) ?? (TabItems[SelectedIndex].Content as BaseLazyView); + var lazyView = ((contentContainer?.CurrentItem as TabViewItem)?.Content as BaseLazyView) ?? (TabItems?[SelectedIndex].Content as BaseLazyView); lazyView?.Dispose(); } @@ -416,13 +416,13 @@ public bool IsSwipeEnabled public delegate void TabSelectionChangedEventHandler(object sender, TabSelectionChangedEventArgs e); - public event TabSelectionChangedEventHandler SelectionChanged; + public event TabSelectionChangedEventHandler? SelectionChanged; public delegate void TabViewScrolledEventHandler(object sender, ItemsViewScrolledEventArgs e); - public event TabViewScrolledEventHandler Scrolled; + public event TabViewScrolledEventHandler? Scrolled; - protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") { base.OnPropertyChanged(propertyName); @@ -671,7 +671,7 @@ void UpdateIsEnabled() contentContainer.IsEnabled = IsEnabled; } - void UpdateTabViewItemTabWidth(TabViewItem tabViewItem) + void UpdateTabViewItemTabWidth(TabViewItem? tabViewItem) { if (tabViewItem == null) return; @@ -679,7 +679,7 @@ void UpdateTabViewItemTabWidth(TabViewItem tabViewItem) var index = tabStripContent.Children.IndexOf(tabViewItem); var colummns = tabStripContent.ColumnDefinitions; - ColumnDefinition column = null; + ColumnDefinition? column = null; if (index < colummns.Count) column = colummns[index]; @@ -770,14 +770,14 @@ void UpdateSelectedIndex(int position, bool hasCurrentItem = false) if (TabItems.Count > 0) { - TabViewItem currentItem = null; + TabViewItem? currentItem = null; if (hasCurrentItem) currentItem = (TabViewItem)contentContainer.CurrentItem; var tabViewItem = TabItems[position]; - var lazyView = (currentItem?.Content as BaseLazyView) ?? (tabViewItem?.Content as BaseLazyView); + var lazyView = (currentItem?.Content as BaseLazyView) ?? (tabViewItem.Content as BaseLazyView); contentIndex = contentTabItems.IndexOf(currentItem ?? tabViewItem); tabStripIndex = TabItems.IndexOf(currentItem ?? tabViewItem); @@ -792,7 +792,7 @@ void UpdateSelectedIndex(int position, bool hasCurrentItem = false) TabItems[index].IsSelected = false; } - if (!lazyView?.IsLoaded ?? false) + if (lazyView != null && !lazyView.IsLoaded) await lazyView.LoadViewAsync(); var currentTabItem = TabItems[position]; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabViewItem.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabViewItem.shared.cs index 30061db71..62969719d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabViewItem.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabViewItem.shared.cs @@ -311,17 +311,17 @@ public Color CurrentBadgeBorderColor public static readonly BindableProperty CurrentContentProperty = CurrentContentPropertyKey.BindableProperty; - public View CurrentContent + public View? CurrentContent { - get => (View)GetValue(CurrentContentProperty); + get => (View?)GetValue(CurrentContentProperty); private set => SetValue(CurrentContentPropertyKey, value); } public delegate void TabTappedEventHandler(object sender, TabTappedEventArgs e); - public event TabTappedEventHandler TabTapped; + public event TabTappedEventHandler? TabTapped; - protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected override void OnPropertyChanged([CallerMemberName] string propertyName = "") { base.OnPropertyChanged(propertyName); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj b/src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj index ac07310c1..966b8770c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj @@ -32,6 +32,9 @@ false portable SA1123 + enable + nullable + latest From e862f48c355e4beb83d28f3ba3d3bc02fd52f1cd Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 15:07:34 -0800 Subject: [PATCH 07/13] Resolve Possible Null References --- .../IconTintColorEffectRouter.android.cs | 2 + .../LifeCycleEffectRouter.android.cs | 19 +- .../RemoveBorderEffect.android.cs | 13 +- .../SelectAllTextEffect.android.cs | 2 +- .../Shadow/PlatformShadowEffect.ios.macos.cs | 54 +- .../Effects/Touch/GestureManager.shared.cs | 81 +-- .../Touch/PlatformTouchEffect.android.cs | 64 +-- .../Touch/PlatformTouchEffect.macos.cs | 23 +- .../Touch/PlatformTouchEffect.tizen.cs | 26 +- .../Effects/Touch/TouchEffect.shared.cs | 489 +++++++++--------- .../Startup/ToolkitPlatform.android.cs | 4 +- .../Android/CameraFragment.android.cs | 33 +- .../Android/CameraStateListener.android.cs | 13 +- .../Android/MotionEventHelper.android.cs | 9 +- .../GravatarImageSourceHandler.android.cs | 9 +- .../MacOS/GravatarImageSourceHandler.macos.cs | 4 +- .../Android/MediaElementRenderer.android.cs | 61 ++- .../Popup/Android/PopupRenderer.android.cs | 5 +- .../Views/RangeSlider/ThumbFrame.shared.cs | 5 +- .../Views/SideMenuView/SideMenuView.shared.cs | 2 +- .../SideMenuViewRenderer.android.cs | 2 +- .../Helpers/macOS/MacOSSnackBar.macos.cs | 11 +- .../ActionMessageSnackBarView.macos.cs | 7 +- .../SnackbarViews/BaseSnackBarView.macos.cs | 23 +- .../MessageSnackBarView.macos.cs | 8 +- .../Views/Snackbar/SnackBar.android.cs | 11 +- .../Views/Snackbar/SnackBar.ios.macos.cs | 5 +- .../Views/Snackbar/SnackBar.tizen.cs | 5 +- 28 files changed, 522 insertions(+), 468 deletions(-) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/IconTintColor/IconTintColorEffectRouter.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/IconTintColor/IconTintColorEffectRouter.android.cs index 129ffd7f5..66bc5a251 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/IconTintColor/IconTintColorEffectRouter.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/IconTintColor/IconTintColorEffectRouter.android.cs @@ -68,7 +68,9 @@ void SetImageViewTintColor(ImageView image, Forms.Color color) if (color == Forms.Color.Default) image.ClearColorFilter(); +#pragma warning disable CS8604 // Possible null reference argument. image.SetColorFilter(new PorterDuffColorFilter(color.ToAndroid(), PorterDuff.Mode.SrcIn)); +#pragma warning restore CS8604 // Possible null reference argument. } void SetButtonTintColor(Button button, Forms.Color color) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.android.cs index 19b944552..a6466811e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.android.cs @@ -15,8 +15,8 @@ namespace Xamarin.CommunityToolkit.Android.Effects /// public class LifeCycleEffectRouter : PlatformEffect { - View nativeView; - LifecycleEffect lifeCycleEffect; + View? nativeView; + LifecycleEffect? lifeCycleEffect; protected override void OnAttached() { @@ -29,13 +29,20 @@ protected override void OnAttached() nativeView.ViewDetachedFromWindow += OnNativeViewViewDetachedFromWindow; } - void OnNativeViewViewAttachedToWindow(object sender, View.ViewAttachedToWindowEventArgs e) => lifeCycleEffect.RaiseLoadedEvent(Element); + void OnNativeViewViewAttachedToWindow(object sender, View.ViewAttachedToWindowEventArgs e) => lifeCycleEffect?.RaiseLoadedEvent(Element); void OnNativeViewViewDetachedFromWindow(object sender, View.ViewDetachedFromWindowEventArgs e) { - lifeCycleEffect.RaiseUnloadedEvent(Element); - nativeView.ViewDetachedFromWindow -= OnNativeViewViewDetachedFromWindow; - nativeView.ViewAttachedToWindow -= OnNativeViewViewAttachedToWindow; + if (lifeCycleEffect != null) + lifeCycleEffect.RaiseUnloadedEvent(Element); + + if (nativeView != null) + { + nativeView.ViewDetachedFromWindow -= OnNativeViewViewDetachedFromWindow; + nativeView.ViewAttachedToWindow -= OnNativeViewViewAttachedToWindow; + nativeView.Dispose(); + } + nativeView = null; lifeCycleEffect = null; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.android.cs index af2759c2c..64174e120 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/RemoveBorder/RemoveBorderEffect.android.cs @@ -1,7 +1,6 @@ using Android.Graphics; using Android.Graphics.Drawables; using Android.Graphics.Drawables.Shapes; -using Android.Runtime; using Xamarin.CommunityToolkit.Effects; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; @@ -13,16 +12,20 @@ namespace Xamarin.CommunityToolkit.Android.Effects { public class RemoveBorderEffect : PlatformEffect { - Drawable originalBackground; + Drawable? originalBackground; protected override void OnAttached() { originalBackground = Control.Background; var shape = new ShapeDrawable(new RectShape()); - shape.Paint.Color = global::Android.Graphics.Color.Transparent; - shape.Paint.StrokeWidth = 0; - shape.Paint.SetStyle(Paint.Style.Stroke); + if (shape.Paint != null) + { + shape.Paint.Color = global::Android.Graphics.Color.Transparent; + shape.Paint.StrokeWidth = 0; + shape.Paint.SetStyle(Paint.Style.Stroke); + } + Control.Background = shape; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.android.cs index e23daa03a..a3daf0b0c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/SelectAllText/SelectAllTextEffect.android.cs @@ -10,7 +10,7 @@ namespace Xamarin.CommunityToolkit.Android.Effects { public class SelectAllTextEffect : PlatformEffect { - EditText EditText => Control as EditText; + EditText? EditText => Control as EditText; protected override void OnAttached() => EditText?.SetSelectAllOnFocus(true); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Shadow/PlatformShadowEffect.ios.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Shadow/PlatformShadowEffect.ios.macos.cs index 0f10cc7b1..bd639e4df 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Shadow/PlatformShadowEffect.ios.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Shadow/PlatformShadowEffect.ios.macos.cs @@ -28,17 +28,17 @@ public class PlatformShadowEffect : PlatformEffect const float defaultOpacity = .5f; - NativeView View => Control ?? Container; + NativeView? View => Control ?? Container; protected override void OnAttached() { if (View == null) return; - UpdateColor(); - UpdateOpacity(); - UpdateRadius(); - UpdateOffset(); + UpdateColor(View); + UpdateOpacity(View); + UpdateRadius(View); + UpdateOffset(View); } protected override void OnDetached() @@ -59,41 +59,49 @@ protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) switch (args.PropertyName) { case nameof(ShadowEffect.ColorPropertyName): - UpdateColor(); + UpdateColor(View); break; case nameof(ShadowEffect.OpacityPropertyName): - UpdateOpacity(); + UpdateOpacity(View); break; case nameof(ShadowEffect.RadiusPropertyName): - UpdateRadius(); + UpdateRadius(View); break; case nameof(ShadowEffect.OffsetXPropertyName): case nameof(ShadowEffect.OffsetYPropertyName): - UpdateOffset(); + UpdateOffset(View); break; } } - void UpdateColor() - => View.Layer.ShadowColor = ShadowEffect.GetColor(Element).ToCGColor(); + void UpdateColor(in NativeView view) + { + if (view.Layer != null) + view.Layer.ShadowColor = ShadowEffect.GetColor(Element).ToCGColor(); + } - void UpdateOpacity() + void UpdateOpacity(in NativeView view) { - var opacity = (float)ShadowEffect.GetOpacity(Element); - View.Layer.ShadowOpacity = opacity < 0 - ? defaultOpacity - : opacity; + if (view.Layer != null) + { + var opacity = (float)ShadowEffect.GetOpacity(Element); + view.Layer.ShadowOpacity = opacity < 0 ? defaultOpacity : opacity; + } } - void UpdateRadius() + void UpdateRadius(in NativeView view) { - var radius = (nfloat)ShadowEffect.GetRadius(Element); - View.Layer.ShadowRadius = radius < 0 - ? defaultRadius - : radius; + if (view.Layer != null) + { + var radius = (nfloat)ShadowEffect.GetRadius(Element); + view.Layer.ShadowRadius = radius < 0 ? defaultRadius : radius; + } } - void UpdateOffset() - => View.Layer.ShadowOffset = new CGSize((double)ShadowEffect.GetOffsetX(Element), (double)ShadowEffect.GetOffsetY(Element)); + void UpdateOffset(in NativeView view) + { + if (view.Layer != null) + view.Layer.ShadowOffset = new CGSize((double)ShadowEffect.GetOffsetX(Element), (double)ShadowEffect.GetOffsetY(Element)); + } } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs index 0eec16061..50c8f4818 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/GestureManager.shared.cs @@ -92,7 +92,7 @@ internal void HandleUserInteraction(TouchEffect sender, TouchInteractionStatus i internal void HandleHover(TouchEffect sender, HoverStatus status) { - if (!sender.Element.IsEnabled) + if (!sender.Element?.IsEnabled ?? true) return; var hoverState = status == HoverStatus.Entered @@ -123,7 +123,8 @@ internal async Task ChangeStateAsync(TouchEffect sender, bool animated) var isToggled = sender.IsToggled; - UpdateVisualState(sender.Element, state, hoverState); + if (sender.Element != null) + UpdateVisualState(sender.Element, state, hoverState); if (!animated) { @@ -225,7 +226,7 @@ internal void OnTapped(TouchEffect sender) void HandleCollectionViewSelection(TouchEffect sender) { - if (!sender.Element.TryFindParentElementWithParentOfType(out var result, out CollectionView? parent)) + if (sender.Element == null || !sender.Element.TryFindParentElementWithParentOfType(out var result, out CollectionView? parent)) return; var collectionView = parent ?? throw new NullReferenceException(); @@ -298,22 +299,22 @@ async Task SetBackgroundImageAsync(TouchEffect sender, TouchState touchState, Ho var source = normalBackgroundImageSource; if (touchState == TouchState.Pressed) { - if (sender.Element.IsSet(TouchEffect.PressedBackgroundImageAspectProperty)) + if (sender.Element?.IsSet(TouchEffect.PressedBackgroundImageAspectProperty) ?? false) aspect = sender.PressedBackgroundImageAspect; source = pressedBackgroundImageSource; } else if (hoverState == HoverState.Hovered) { - if (sender.Element.IsSet(TouchEffect.HoveredBackgroundImageAspectProperty)) + if (sender.Element?.IsSet(TouchEffect.HoveredBackgroundImageAspectProperty) ?? false) aspect = sender.HoveredBackgroundImageAspect; - if (sender.Element.IsSet(TouchEffect.HoveredBackgroundImageSourceProperty)) + if (sender.Element?.IsSet(TouchEffect.HoveredBackgroundImageSourceProperty) ?? false) source = hoveredBackgroundImageSource; } else { - if (sender.Element.IsSet(TouchEffect.NormalBackgroundImageAspectProperty)) + if (sender.Element?.IsSet(TouchEffect.NormalBackgroundImageAspectProperty) ?? false) aspect = sender.NormalBackgroundImageAspect; } @@ -343,10 +344,13 @@ Task SetBackgroundColor(TouchEffect sender, TouchState touchState, HoverState ho var pressedBackgroundColor = sender.PressedBackgroundColor; var hoveredBackgroundColor = sender.HoveredBackgroundColor; - if (normalBackgroundColor == Color.Default && - pressedBackgroundColor == Color.Default && - hoveredBackgroundColor == Color.Default) + if (sender.Element == null + || (normalBackgroundColor == Color.Default + && pressedBackgroundColor == Color.Default + && hoveredBackgroundColor == Color.Default)) + { return Task.FromResult(false); + } var element = sender.Element; if (defaultBackgroundColor == default) @@ -383,11 +387,11 @@ Task SetOpacity(TouchEffect sender, TouchState touchState, HoverState hoverState if (touchState == TouchState.Pressed) opacity = pressedOpacity; - else if (hoverState == HoverState.Hovered && sender.Element.IsSet(TouchEffect.HoveredOpacityProperty)) + else if (hoverState == HoverState.Hovered && (sender.Element?.IsSet(TouchEffect.HoveredOpacityProperty) ?? false)) opacity = hoveredOpacity; var element = sender.Element; - if (duration <= 0) + if (duration <= 0 && element != null) { element.Opacity = opacity; return Task.FromResult(true); @@ -411,10 +415,13 @@ Task SetScale(TouchEffect sender, TouchState touchState, HoverState hoverState, if (touchState == TouchState.Pressed) scale = pressedScale; - else if (hoverState == HoverState.Hovered && sender.Element.IsSet(TouchEffect.HoveredScaleProperty)) + else if (hoverState == HoverState.Hovered && (sender.Element?.IsSet(TouchEffect.HoveredScaleProperty) ?? false)) scale = hoveredScale; var element = sender.Element; + if (element == null) + return Task.FromResult(false); + if (duration <= 0) { element.Scale = scale; @@ -442,13 +449,15 @@ Task SetTranslation(TouchEffect sender, TouchState touchState, HoverState hoverS var pressedTranslationY = sender.PressedTranslationY; var hoveredTranslationY = sender.HoveredTranslationY; - if (Abs(normalTranslationX) <= double.Epsilon && - Abs(pressedTranslationX) <= double.Epsilon && - Abs(hoveredTranslationX) <= double.Epsilon && - Abs(normalTranslationY) <= double.Epsilon && - Abs(pressedTranslationY) <= double.Epsilon && - Abs(hoveredTranslationY) <= double.Epsilon) + if (Abs(normalTranslationX) <= double.Epsilon + && Abs(pressedTranslationX) <= double.Epsilon + && Abs(hoveredTranslationX) <= double.Epsilon + && Abs(normalTranslationY) <= double.Epsilon + && Abs(pressedTranslationY) <= double.Epsilon + && Abs(hoveredTranslationY) <= double.Epsilon) + { return Task.FromResult(false); + } var translationX = normalTranslationX; var translationY = normalTranslationY; @@ -460,22 +469,22 @@ Task SetTranslation(TouchEffect sender, TouchState touchState, HoverState hoverS } else if (hoverState == HoverState.Hovered) { - if (sender.Element.IsSet(TouchEffect.HoveredTranslationXProperty)) + if (sender.Element?.IsSet(TouchEffect.HoveredTranslationXProperty) ?? false) translationX = hoveredTranslationX; - if (sender.Element.IsSet(TouchEffect.HoveredTranslationYProperty)) + if (sender.Element?.IsSet(TouchEffect.HoveredTranslationYProperty) ?? false) translationY = hoveredTranslationY; } var element = sender.Element; - if (duration <= 0) + if (duration <= 0 && element != null) { element.TranslationX = translationX; element.TranslationY = translationY; return Task.FromResult(true); } - return element.TranslateTo(translationX, translationY, (uint)Abs(duration), easing); + return element?.TranslateTo(translationX, translationY, (uint)Abs(duration), easing) ?? Task.FromResult(false); } Task SetRotation(TouchEffect sender, TouchState touchState, HoverState hoverState, int duration, Easing easing) @@ -484,26 +493,28 @@ Task SetRotation(TouchEffect sender, TouchState touchState, HoverState hoverStat var pressedRotation = sender.PressedRotation; var hoveredRotation = sender.HoveredRotation; - if (Abs(normalRotation) <= double.Epsilon && - Abs(pressedRotation) <= double.Epsilon && - Abs(hoveredRotation) <= double.Epsilon) + if (Abs(normalRotation) <= double.Epsilon + && Abs(pressedRotation) <= double.Epsilon + && Abs(hoveredRotation) <= double.Epsilon) + { return Task.FromResult(false); + } var rotation = normalRotation; if (touchState == TouchState.Pressed) rotation = pressedRotation; - else if (hoverState == HoverState.Hovered && sender.Element.IsSet(TouchEffect.HoveredRotationProperty)) + else if (hoverState == HoverState.Hovered && (sender.Element?.IsSet(TouchEffect.HoveredRotationProperty) ?? false)) rotation = hoveredRotation; var element = sender.Element; - if (duration <= 0) + if (duration <= 0 && element != null) { element.Rotation = rotation; return Task.FromResult(true); } - return element.RotateTo(rotation, (uint)Abs(duration), easing); + return element?.RotateTo(rotation, (uint)Abs(duration), easing) ?? Task.FromResult(false); } Task SetRotationX(TouchEffect sender, TouchState touchState, HoverState hoverState, int duration, Easing easing) @@ -521,17 +532,17 @@ Task SetRotationX(TouchEffect sender, TouchState touchState, HoverState hoverSta if (touchState == TouchState.Pressed) rotationX = pressedRotationX; - else if (hoverState == HoverState.Hovered && sender.Element.IsSet(TouchEffect.HoveredRotationXProperty)) + else if (hoverState == HoverState.Hovered && (sender.Element?.IsSet(TouchEffect.HoveredRotationXProperty) ?? false)) rotationX = hoveredRotationX; var element = sender.Element; - if (duration <= 0) + if (duration <= 0 && element != null) { element.RotationX = rotationX; return Task.FromResult(true); } - return element.RotateXTo(rotationX, (uint)Abs(duration), easing); + return element?.RotateXTo(rotationX, (uint)Abs(duration), easing) ?? Task.FromResult(false); } Task SetRotationY(TouchEffect sender, TouchState touchState, HoverState hoverState, int duration, Easing easing) @@ -549,17 +560,17 @@ Task SetRotationY(TouchEffect sender, TouchState touchState, HoverState hoverSta if (touchState == TouchState.Pressed) rotationY = pressedRotationY; - else if (hoverState == HoverState.Hovered && sender.Element.IsSet(TouchEffect.HoveredRotationYProperty)) + else if (hoverState == HoverState.Hovered && (sender.Element?.IsSet(TouchEffect.HoveredRotationYProperty) ?? false)) rotationY = hoveredRotationY; var element = sender.Element; - if (duration <= 0) + if (duration <= 0 && element != null) { element.RotationY = rotationY; return Task.FromResult(true); } - return element.RotateYTo(rotationY, (uint)Abs(duration), easing); + return element?.RotateYTo(rotationY, (uint)Abs(duration), easing) ?? Task.FromResult(false); } Color GetBackgroundColor(Color color) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.android.cs index 4df067254..f73f7d2e4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.android.cs @@ -23,12 +23,12 @@ public class PlatformTouchEffect : PlatformEffect { static readonly Forms.Color defaultNativeAnimationColor = Forms.Color.FromRgba(128, 128, 128, 64); - AccessibilityManager accessibilityManager; - AccessibilityListener accessibilityListener; - TouchEffect effect; + AccessibilityManager? accessibilityManager; + AccessibilityListener? accessibilityListener; + TouchEffect? effect; bool isHoverSupported; - RippleDrawable ripple; - AView rippleView; + RippleDrawable? ripple; + AView? rippleView; float startX; float startY; Forms.Color rippleColor; @@ -36,7 +36,7 @@ public class PlatformTouchEffect : PlatformEffect AView View => Control ?? Container; - ViewGroup Group => Container ?? Control as ViewGroup; + ViewGroup Group => Container ?? (ViewGroup)Control; internal bool IsCanceled { get; set; } @@ -59,7 +59,7 @@ protected override void OnAttached() View.Touch += OnTouch; UpdateClickHandler(); - accessibilityManager = View.Context.GetSystemService(Context.AccessibilityService) as AccessibilityManager; + accessibilityManager = View.Context?.GetSystemService(Context.AccessibilityService) as AccessibilityManager; if (accessibilityManager != null) { accessibilityListener = new AccessibilityListener(this); @@ -80,7 +80,7 @@ protected override void OnAttached() return; } - rippleView = new FrameLayout(Group.Context) + rippleView = new FrameLayout(Group.Context ?? throw new NullReferenceException()) { LayoutParameters = new ViewGroup.LayoutParams(-1, -1), Clickable = false, @@ -100,7 +100,7 @@ protected override void OnDetached() try { - if (accessibilityManager != null) + if (accessibilityManager != null && accessibilityListener != null) { accessibilityManager.RemoveAccessibilityStateChangeListener(accessibilityListener); accessibilityManager.RemoveTouchExplorationStateChangeListener(accessibilityListener); @@ -154,7 +154,7 @@ protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) void UpdateClickHandler() { View.Click -= OnClick; - if (IsAccessibilityMode || (effect.IsAvailable && effect.Element.IsEnabled)) + if (IsAccessibilityMode || ((effect?.IsAvailable ?? false) && (effect?.Element?.IsEnabled ?? false))) { View.Click += OnClick; return; @@ -171,7 +171,7 @@ void OnTouch(object sender, AView.TouchEventArgs e) if (IsAccessibilityMode) return; - switch (e.Event.ActionMasked) + switch (e.Event?.ActionMasked) { case MotionEventActions.Down: OnTouchDown(e); @@ -196,50 +196,52 @@ void OnTouch(object sender, AView.TouchEventArgs e) void OnTouchDown(AView.TouchEventArgs e) { + _ = e.Event ?? throw new NullReferenceException(); + IsCanceled = false; startX = e.Event.GetX(); startY = e.Event.GetY(); effect?.HandleUserInteraction(TouchInteractionStatus.Started); effect?.HandleTouch(TouchStatus.Started); StartRipple(e.Event.GetX(), e.Event.GetY()); - if (effect.DisallowTouchThreshold > 0) + if (effect?.DisallowTouchThreshold > 0) Group?.Parent?.RequestDisallowInterceptTouchEvent(true); } void OnTouchUp() - => HandleEnd(effect.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled); + => HandleEnd(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled); void OnTouchCancel() => HandleEnd(TouchStatus.Canceled); void OnTouchMove(object sender, AView.TouchEventArgs e) { - if (IsCanceled) + if (IsCanceled || e.Event == null) return; - var diffX = Math.Abs(e.Event.GetX() - startX) / View.Context.Resources.DisplayMetrics.Density; - var diffY = Math.Abs(e.Event.GetY() - startY) / View.Context.Resources.DisplayMetrics.Density; + var diffX = Math.Abs(e.Event.GetX() - startX) / View.Context?.Resources?.DisplayMetrics?.Density ?? throw new NullReferenceException(); + var diffY = Math.Abs(e.Event.GetY() - startY) / View.Context?.Resources?.DisplayMetrics?.Density ?? throw new NullReferenceException(); var maxDiff = Math.Max(diffX, diffY); - var disallowTouchThreshold = effect.DisallowTouchThreshold; + + var disallowTouchThreshold = effect?.DisallowTouchThreshold; if (disallowTouchThreshold > 0 && maxDiff > disallowTouchThreshold) { HandleEnd(TouchStatus.Canceled); return; } - var view = sender as AView; - if (view == null) + if (sender is not AView view) return; var screenPointerCoords = new Point(view.Left + e.Event.GetX(), view.Top + e.Event.GetY()); var viewRect = new Rectangle(view.Left, view.Top, view.Right - view.Left, view.Bottom - view.Top); var status = viewRect.Contains(screenPointerCoords) ? TouchStatus.Started : TouchStatus.Canceled; - if (isHoverSupported && ((status == TouchStatus.Canceled && effect.HoverStatus == HoverStatus.Entered) - || (status == TouchStatus.Started && effect.HoverStatus == HoverStatus.Exited))) + if (isHoverSupported && ((status == TouchStatus.Canceled && effect?.HoverStatus == HoverStatus.Entered) + || (status == TouchStatus.Started && effect?.HoverStatus == HoverStatus.Exited))) effect?.HandleHover(status == TouchStatus.Started ? HoverStatus.Entered : HoverStatus.Exited); - if (effect.Status != status) + if (effect?.Status != status) { effect?.HandleTouch(status); if (status == TouchStatus.Started) @@ -279,7 +281,7 @@ void HandleEnd(TouchStatus status) return; IsCanceled = true; - if (effect.DisallowTouchThreshold > 0) + if (effect?.DisallowTouchThreshold > 0) Group?.Parent?.RequestDisallowInterceptTouchEvent(false); effect?.HandleTouch(status); @@ -297,7 +299,7 @@ void StartRipple(float x, float y) UpdateRipple(); rippleView.Enabled = true; rippleView.BringToFront(); - ripple.SetHotspot(x, y); + ripple?.SetHotspot(x, y); rippleView.Pressed = true; } } @@ -319,8 +321,8 @@ void CreateRipple() var drawable = Group != null ? View?.Background : View?.Foreground; var isEmptyDrawable = Element is Layout || drawable == null; - if (drawable is RippleDrawable) - ripple = (RippleDrawable)drawable.GetConstantState().NewDrawable(); + if (drawable is RippleDrawable rippleDrawable && rippleDrawable.GetConstantState() is Drawable.ConstantState constantState) + ripple = (RippleDrawable)constantState.NewDrawable(); else ripple = new RippleDrawable(GetColorStateList(), isEmptyDrawable ? null : drawable, isEmptyDrawable ? new ColorDrawable(Color.White) : null); @@ -337,13 +339,15 @@ void UpdateRipple() rippleColor = effect.NativeAnimationColor; rippleRadius = effect.NativeAnimationRadius; - ripple.SetColor(GetColorStateList()); - if (Build.VERSION.SdkInt >= BuildVersionCodes.M) - ripple.Radius = (int)(View.Context.Resources.DisplayMetrics.Density * effect.NativeAnimationRadius); + ripple?.SetColor(GetColorStateList()); + if (Build.VERSION.SdkInt >= BuildVersionCodes.M && ripple != null) + ripple.Radius = (int)(View.Context?.Resources?.DisplayMetrics?.Density * effect?.NativeAnimationRadius ?? throw new NullReferenceException()); } ColorStateList GetColorStateList() { + _ = effect?.NativeAnimationColor ?? throw new NullReferenceException(); + var nativeAnimationColor = effect.NativeAnimationColor; if (nativeAnimationColor == Forms.Color.Default) nativeAnimationColor = defaultNativeAnimationColor; @@ -367,7 +371,7 @@ sealed class AccessibilityListener : Java.Lang.Object, AccessibilityManager.IAccessibilityStateChangeListener, AccessibilityManager.ITouchExplorationStateChangeListener { - PlatformTouchEffect platformTouchEffect; + PlatformTouchEffect? platformTouchEffect; internal AccessibilityListener(PlatformTouchEffect platformTouchEffect) => this.platformTouchEffect = platformTouchEffect; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.macos.cs index 065abfb0f..25eae71d3 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.macos.cs @@ -1,4 +1,5 @@ -using AppKit; +using System; +using AppKit; using Xamarin.CommunityToolkit.Effects; using Xamarin.CommunityToolkit.macOS.Effects; using Xamarin.Forms; @@ -10,11 +11,11 @@ namespace Xamarin.CommunityToolkit.macOS.Effects { public class PlatformTouchEffect : PlatformEffect { - NSGestureRecognizer gesture; + NSGestureRecognizer? gesture; - TouchEffect effect; + TouchEffect? effect; - MouseTrackingView mouseTrackingView; + MouseTrackingView? mouseTrackingView; protected override void OnAttached() { @@ -52,8 +53,8 @@ protected override void OnDetached() sealed class MouseTrackingView : NSView { - NSTrackingArea trackingArea; - TouchEffect effect; + NSTrackingArea? trackingArea; + TouchEffect? effect; public MouseTrackingView(TouchEffect effect) { @@ -105,8 +106,8 @@ protected override void Dispose(bool disposing) sealed class TouchNSClickGestureRecognizer : NSGestureRecognizer { - TouchEffect effect; - NSView container; + TouchEffect? effect; + NSView? container; public TouchNSClickGestureRecognizer(TouchEffect effect, NSView container) { @@ -118,8 +119,8 @@ Rectangle ViewRect { get { - var frame = container.Frame; - var parent = container.Superview; + var frame = container?.Frame ?? throw new NullReferenceException(); + var parent = container?.Superview; while (parent != null) { frame = new CoreGraphics.CGRect(frame.X + parent.Frame.X, frame.Y + parent.Frame.Y, frame.Width, frame.Height); @@ -169,7 +170,7 @@ public override void MouseDragged(NSEvent mouseEvent) (status == TouchStatus.Started && effect.HoverStatus == HoverStatus.Exited)) effect?.HandleHover(status == TouchStatus.Started ? HoverStatus.Entered : HoverStatus.Exited); - if (effect.Status != status) + if (effect?.Status != status) effect?.HandleTouch(status); base.MouseDragged(mouseEvent); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.tizen.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.tizen.cs index af6746e2d..eb5c81f12 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.tizen.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.tizen.cs @@ -11,9 +11,9 @@ namespace Xamarin.CommunityToolkit.Tizen.Effects { public class PlatformTouchEffect : PlatformEffect { - GestureLayer gestureLayer; + GestureLayer? gestureLayer; - TouchEffect effect; + TouchEffect? effect; protected override void OnAttached() { @@ -43,20 +43,20 @@ protected override void OnDetached() sealed class TouchTapGestureRecognizer : GestureLayer { - readonly TouchEffect effect; + readonly TouchEffect? effect; bool tapCompleted; bool longTapStarted; public TouchTapGestureRecognizer(EvasObject parent) : base(parent) { - SetTapCallback(GestureType.Tap, GestureLayer.GestureState.Start, OnTapStarted); - SetTapCallback(GestureType.Tap, GestureLayer.GestureState.End, OnGestureEnded); - SetTapCallback(GestureType.Tap, GestureLayer.GestureState.Abort, OnGestureAborted); + SetTapCallback(GestureType.Tap, GestureState.Start, OnTapStarted); + SetTapCallback(GestureType.Tap, GestureState.End, OnGestureEnded); + SetTapCallback(GestureType.Tap, GestureState.Abort, OnGestureAborted); - SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.Start, OnLongTapStarted); - SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.End, OnGestureEnded); - SetTapCallback(GestureType.LongTap, GestureLayer.GestureState.Abort, OnGestureAborted); + SetTapCallback(GestureType.LongTap, GestureState.Start, OnLongTapStarted); + SetTapCallback(GestureType.LongTap, GestureState.End, OnGestureEnded); + SetTapCallback(GestureType.LongTap, GestureState.Abort, OnGestureAborted); } public TouchTapGestureRecognizer(EvasObject parent, TouchEffect effect) @@ -90,10 +90,10 @@ void OnLongTapStarted(TapData data) void OnGestureEnded(TapData data) { - if (effect?.IsDisabled ?? true) + if (effect == null || effect.IsDisabled) return; - HandleTouch(effect?.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled, TouchInteractionStatus.Completed); + HandleTouch(effect.Status == TouchStatus.Started ? TouchStatus.Completed : TouchStatus.Canceled, TouchInteractionStatus.Completed); IsCanceled = true; tapCompleted = true; } @@ -119,12 +119,12 @@ public void HandleTouch(TouchStatus status, TouchInteractionStatus? touchInterac if (IsCanceled || effect == null) return; - if (effect?.IsDisabled ?? true) + if (effect.IsDisabled) return; if (touchInteractionStatus == TouchInteractionStatus.Started) { - effect?.HandleUserInteraction(TouchInteractionStatus.Started); + effect.HandleUserInteraction(TouchInteractionStatus.Started); touchInteractionStatus = null; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs index 50e58d1ab..7c8b6e7c8 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/TouchEffect.shared.cs @@ -465,7 +465,7 @@ public class TouchEffect : RoutingEffect VisualElement? element; public TouchEffect() - : base(EffectIds.TouchEffect) + : base(EffectIds.TouchEffect) { #region Required work-around to prevent linker from removing the platform-specific implementation #if __ANDROID__ @@ -487,361 +487,361 @@ public TouchEffect() #endregion } - public static bool GetIsAvailable(BindableObject bindable) - => (bool)bindable.GetValue(IsAvailableProperty); + public static bool GetIsAvailable(BindableObject? bindable) + => (bool)(bindable?.GetValue(IsAvailableProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetIsAvailable(BindableObject bindable, bool value) - => bindable.SetValue(IsAvailableProperty, value); + public static void SetIsAvailable(BindableObject? bindable, bool value) + => bindable?.SetValue(IsAvailableProperty, value); - public static bool GetShouldMakeChildrenInputTransparent(BindableObject bindable) - => (bool)bindable.GetValue(ShouldMakeChildrenInputTransparentProperty); + public static bool GetShouldMakeChildrenInputTransparent(BindableObject? bindable) + => (bool)(bindable?.GetValue(ShouldMakeChildrenInputTransparentProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetShouldMakeChildrenInputTransparent(BindableObject bindable, bool value) - => bindable.SetValue(ShouldMakeChildrenInputTransparentProperty, value); + public static void SetShouldMakeChildrenInputTransparent(BindableObject? bindable, bool value) + => bindable?.SetValue(ShouldMakeChildrenInputTransparentProperty, value); - public static ICommand GetCommand(BindableObject bindable) - => (ICommand)bindable.GetValue(CommandProperty); + public static ICommand GetCommand(BindableObject? bindable) + => (ICommand)(bindable?.GetValue(CommandProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetCommand(BindableObject bindable, ICommand value) - => bindable.SetValue(CommandProperty, value); + public static void SetCommand(BindableObject? bindable, ICommand value) + => bindable?.SetValue(CommandProperty, value); - public static ICommand GetLongPressCommand(BindableObject bindable) - => (ICommand)bindable.GetValue(LongPressCommandProperty); + public static ICommand GetLongPressCommand(BindableObject? bindable) + => (ICommand)(bindable?.GetValue(LongPressCommandProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetLongPressCommand(BindableObject bindable, ICommand value) - => bindable.SetValue(LongPressCommandProperty, value); + public static void SetLongPressCommand(BindableObject? bindable, ICommand value) + => bindable?.SetValue(LongPressCommandProperty, value); - public static object GetCommandParameter(BindableObject bindable) - => bindable.GetValue(CommandParameterProperty); + public static object GetCommandParameter(BindableObject? bindable) + => bindable?.GetValue(CommandParameterProperty) ?? throw new ArgumentNullException(nameof(bindable)); - public static void SetCommandParameter(BindableObject bindable, object value) - => bindable.SetValue(CommandParameterProperty, value); + public static void SetCommandParameter(BindableObject? bindable, object value) + => bindable?.SetValue(CommandParameterProperty, value); - public static object GetLongPressCommandParameter(BindableObject bindable) - => bindable.GetValue(LongPressCommandParameterProperty); + public static object GetLongPressCommandParameter(BindableObject? bindable) + => bindable?.GetValue(LongPressCommandParameterProperty) ?? throw new ArgumentNullException(nameof(bindable)); - public static void SetLongPressCommandParameter(BindableObject bindable, object value) - => bindable.SetValue(LongPressCommandParameterProperty, value); + public static void SetLongPressCommandParameter(BindableObject? bindable, object value) + => bindable?.SetValue(LongPressCommandParameterProperty, value); - public static int GetLongPressDuration(BindableObject bindable) - => (int)bindable.GetValue(LongPressDurationProperty); + public static int GetLongPressDuration(BindableObject? bindable) + => (int)(bindable?.GetValue(LongPressDurationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetLongPressDuration(BindableObject bindable, int value) - => bindable.SetValue(LongPressDurationProperty, value); + public static void SetLongPressDuration(BindableObject? bindable, int value) + => bindable?.SetValue(LongPressDurationProperty, value); - public static TouchStatus GetStatus(BindableObject bindable) - => (TouchStatus)bindable.GetValue(StatusProperty); + public static TouchStatus GetStatus(BindableObject? bindable) + => (TouchStatus)(bindable?.GetValue(StatusProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetStatus(BindableObject bindable, TouchStatus value) - => bindable.SetValue(StatusProperty, value); + public static void SetStatus(BindableObject? bindable, TouchStatus value) + => bindable?.SetValue(StatusProperty, value); - public static TouchState GetState(BindableObject bindable) - => (TouchState)bindable.GetValue(StateProperty); + public static TouchState GetState(BindableObject? bindable) + => (TouchState)(bindable?.GetValue(StateProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetState(BindableObject bindable, TouchState value) - => bindable.SetValue(StateProperty, value); + public static void SetState(BindableObject? bindable, TouchState value) + => bindable?.SetValue(StateProperty, value); - public static TouchInteractionStatus GetInteractionStatus(BindableObject bindable) - => (TouchInteractionStatus)bindable.GetValue(InteractionStatusProperty); + public static TouchInteractionStatus GetInteractionStatus(BindableObject? bindable) + => (TouchInteractionStatus)(bindable?.GetValue(InteractionStatusProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetInteractionStatus(BindableObject bindable, TouchInteractionStatus value) - => bindable.SetValue(InteractionStatusProperty, value); + public static void SetInteractionStatus(BindableObject? bindable, TouchInteractionStatus value) + => bindable?.SetValue(InteractionStatusProperty, value); - public static HoverStatus GetHoverStatus(BindableObject bindable) - => (HoverStatus)bindable.GetValue(HoverStatusProperty); + public static HoverStatus GetHoverStatus(BindableObject? bindable) + => (HoverStatus)(bindable?.GetValue(HoverStatusProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoverStatus(BindableObject bindable, HoverStatus value) - => bindable.SetValue(HoverStatusProperty, value); + public static void SetHoverStatus(BindableObject? bindable, HoverStatus value) + => bindable?.SetValue(HoverStatusProperty, value); - public static HoverState GetHoverState(BindableObject bindable) - => (HoverState)bindable.GetValue(HoverStateProperty); + public static HoverState GetHoverState(BindableObject? bindable) + => (HoverState)(bindable?.GetValue(HoverStateProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoverState(BindableObject bindable, HoverState value) - => bindable.SetValue(HoverStateProperty, value); + public static void SetHoverState(BindableObject? bindable, HoverState value) + => bindable?.SetValue(HoverStateProperty, value); - public static Color GetNormalBackgroundColor(BindableObject bindable) - => (Color)bindable.GetValue(NormalBackgroundColorProperty); + public static Color GetNormalBackgroundColor(BindableObject? bindable) + => (Color)(bindable?.GetValue(NormalBackgroundColorProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalBackgroundColor(BindableObject bindable, Color value) - => bindable.SetValue(NormalBackgroundColorProperty, value); + public static void SetNormalBackgroundColor(BindableObject? bindable, Color value) + => bindable?.SetValue(NormalBackgroundColorProperty, value); - public static Color GetHoveredBackgroundColor(BindableObject bindable) - => (Color)bindable.GetValue(HoveredBackgroundColorProperty); + public static Color GetHoveredBackgroundColor(BindableObject? bindable) + => (Color)(bindable?.GetValue(HoveredBackgroundColorProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredBackgroundColor(BindableObject bindable, Color value) - => bindable.SetValue(HoveredBackgroundColorProperty, value); + public static void SetHoveredBackgroundColor(BindableObject? bindable, Color value) + => bindable?.SetValue(HoveredBackgroundColorProperty, value); - public static Color GetPressedBackgroundColor(BindableObject bindable) - => (Color)bindable.GetValue(PressedBackgroundColorProperty); + public static Color GetPressedBackgroundColor(BindableObject? bindable) + => (Color)(bindable?.GetValue(PressedBackgroundColorProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedBackgroundColor(BindableObject bindable, Color value) - => bindable.SetValue(PressedBackgroundColorProperty, value); + public static void SetPressedBackgroundColor(BindableObject? bindable, Color value) + => bindable?.SetValue(PressedBackgroundColorProperty, value); - public static double GetNormalOpacity(BindableObject bindable) - => (double)bindable.GetValue(NormalOpacityProperty); + public static double GetNormalOpacity(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalOpacityProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalOpacity(BindableObject bindable, double value) - => bindable.SetValue(NormalOpacityProperty, value); + public static void SetNormalOpacity(BindableObject? bindable, double value) + => bindable?.SetValue(NormalOpacityProperty, value); - public static double GetHoveredOpacity(BindableObject bindable) - => (double)bindable.GetValue(HoveredOpacityProperty); + public static double GetHoveredOpacity(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredOpacityProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredOpacity(BindableObject bindable, double value) - => bindable.SetValue(HoveredOpacityProperty, value); + public static void SetHoveredOpacity(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredOpacityProperty, value); - public static double GetPressedOpacity(BindableObject bindable) - => (double)bindable.GetValue(PressedOpacityProperty); + public static double GetPressedOpacity(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedOpacityProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedOpacity(BindableObject bindable, double value) - => bindable.SetValue(PressedOpacityProperty, value); + public static void SetPressedOpacity(BindableObject? bindable, double value) + => bindable?.SetValue(PressedOpacityProperty, value); - public static double GetNormalScale(BindableObject bindable) - => (double)bindable.GetValue(NormalScaleProperty); + public static double GetNormalScale(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalScaleProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalScale(BindableObject bindable, double value) - => bindable.SetValue(NormalScaleProperty, value); + public static void SetNormalScale(BindableObject? bindable, double value) + => bindable?.SetValue(NormalScaleProperty, value); - public static double GetHoveredScale(BindableObject bindable) - => (double)bindable.GetValue(HoveredScaleProperty); + public static double GetHoveredScale(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredScaleProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredScale(BindableObject bindable, double value) - => bindable.SetValue(HoveredScaleProperty, value); + public static void SetHoveredScale(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredScaleProperty, value); - public static double GetPressedScale(BindableObject bindable) - => (double)bindable.GetValue(PressedScaleProperty); + public static double GetPressedScale(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedScaleProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedScale(BindableObject bindable, double value) - => bindable.SetValue(PressedScaleProperty, value); + public static void SetPressedScale(BindableObject? bindable, double value) + => bindable?.SetValue(PressedScaleProperty, value); - public static double GetNormalTranslationX(BindableObject bindable) - => (double)bindable.GetValue(NormalTranslationXProperty); + public static double GetNormalTranslationX(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalTranslationXProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalTranslationX(BindableObject bindable, double value) - => bindable.SetValue(NormalTranslationXProperty, value); + public static void SetNormalTranslationX(BindableObject? bindable, double value) + => bindable?.SetValue(NormalTranslationXProperty, value); - public static double GetHoveredTranslationX(BindableObject bindable) - => (double)bindable.GetValue(HoveredTranslationXProperty); + public static double GetHoveredTranslationX(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredTranslationXProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredTranslationX(BindableObject bindable, double value) - => bindable.SetValue(HoveredTranslationXProperty, value); + public static void SetHoveredTranslationX(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredTranslationXProperty, value); - public static double GetPressedTranslationX(BindableObject bindable) - => (double)bindable.GetValue(PressedTranslationXProperty); + public static double GetPressedTranslationX(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedTranslationXProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedTranslationX(BindableObject bindable, double value) - => bindable.SetValue(PressedTranslationXProperty, value); + public static void SetPressedTranslationX(BindableObject? bindable, double value) + => bindable?.SetValue(PressedTranslationXProperty, value); - public static double GetNormalTranslationY(BindableObject bindable) - => (double)bindable.GetValue(NormalTranslationYProperty); + public static double GetNormalTranslationY(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalTranslationYProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalTranslationY(BindableObject bindable, double value) - => bindable.SetValue(NormalTranslationYProperty, value); + public static void SetNormalTranslationY(BindableObject? bindable, double value) + => bindable?.SetValue(NormalTranslationYProperty, value); - public static double GetHoveredTranslationY(BindableObject bindable) - => (double)bindable.GetValue(HoveredTranslationYProperty); + public static double GetHoveredTranslationY(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredTranslationYProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredTranslationY(BindableObject bindable, double value) - => bindable.SetValue(HoveredTranslationYProperty, value); + public static void SetHoveredTranslationY(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredTranslationYProperty, value); - public static double GetPressedTranslationY(BindableObject bindable) - => (double)bindable.GetValue(PressedTranslationYProperty); + public static double GetPressedTranslationY(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedTranslationYProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedTranslationY(BindableObject bindable, double value) - => bindable.SetValue(PressedTranslationYProperty, value); + public static void SetPressedTranslationY(BindableObject? bindable, double value) + => bindable?.SetValue(PressedTranslationYProperty, value); - public static double GetNormalRotation(BindableObject bindable) - => (double)bindable.GetValue(NormalRotationProperty); + public static double GetNormalRotation(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalRotationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalRotation(BindableObject bindable, double value) - => bindable.SetValue(NormalRotationProperty, value); + public static void SetNormalRotation(BindableObject? bindable, double value) + => bindable?.SetValue(NormalRotationProperty, value); - public static double GetHoveredRotation(BindableObject bindable) - => (double)bindable.GetValue(HoveredRotationProperty); + public static double GetHoveredRotation(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredRotationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredRotation(BindableObject bindable, double value) - => bindable.SetValue(HoveredRotationProperty, value); + public static void SetHoveredRotation(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredRotationProperty, value); - public static double GetPressedRotation(BindableObject bindable) - => (double)bindable.GetValue(PressedRotationProperty); + public static double GetPressedRotation(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedRotationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedRotation(BindableObject bindable, double value) - => bindable.SetValue(PressedRotationProperty, value); + public static void SetPressedRotation(BindableObject? bindable, double value) + => bindable?.SetValue(PressedRotationProperty, value); - public static double GetNormalRotationX(BindableObject bindable) - => (double)bindable.GetValue(NormalRotationXProperty); + public static double GetNormalRotationX(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalRotationXProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalRotationX(BindableObject bindable, double value) - => bindable.SetValue(NormalRotationXProperty, value); + public static void SetNormalRotationX(BindableObject? bindable, double value) + => bindable?.SetValue(NormalRotationXProperty, value); - public static double GetHoveredRotationX(BindableObject bindable) - => (double)bindable.GetValue(HoveredRotationXProperty); + public static double GetHoveredRotationX(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredRotationXProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredRotationX(BindableObject bindable, double value) - => bindable.SetValue(HoveredRotationXProperty, value); + public static void SetHoveredRotationX(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredRotationXProperty, value); - public static double GetPressedRotationX(BindableObject bindable) - => (double)bindable.GetValue(PressedRotationXProperty); + public static double GetPressedRotationX(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedRotationXProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedRotationX(BindableObject bindable, double value) - => bindable.SetValue(PressedRotationXProperty, value); + public static void SetPressedRotationX(BindableObject? bindable, double value) + => bindable?.SetValue(PressedRotationXProperty, value); - public static double GetNormalRotationY(BindableObject bindable) - => (double)bindable.GetValue(NormalRotationYProperty); + public static double GetNormalRotationY(BindableObject? bindable) + => (double)(bindable?.GetValue(NormalRotationYProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalRotationY(BindableObject bindable, double value) - => bindable.SetValue(NormalRotationYProperty, value); + public static void SetNormalRotationY(BindableObject? bindable, double value) + => bindable?.SetValue(NormalRotationYProperty, value); - public static double GetHoveredRotationY(BindableObject bindable) - => (double)bindable.GetValue(HoveredRotationYProperty); + public static double GetHoveredRotationY(BindableObject? bindable) + => (double)(bindable?.GetValue(HoveredRotationYProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredRotationY(BindableObject bindable, double value) - => bindable.SetValue(HoveredRotationYProperty, value); + public static void SetHoveredRotationY(BindableObject? bindable, double value) + => bindable?.SetValue(HoveredRotationYProperty, value); - public static double GetPressedRotationY(BindableObject bindable) - => (double)bindable.GetValue(PressedRotationYProperty); + public static double GetPressedRotationY(BindableObject? bindable) + => (double)(bindable?.GetValue(PressedRotationYProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedRotationY(BindableObject bindable, double value) - => bindable.SetValue(PressedRotationYProperty, value); + public static void SetPressedRotationY(BindableObject? bindable, double value) + => bindable?.SetValue(PressedRotationYProperty, value); - public static int GetAnimationDuration(BindableObject bindable) - => (int)bindable.GetValue(AnimationDurationProperty); + public static int GetAnimationDuration(BindableObject? bindable) + => (int)(bindable?.GetValue(AnimationDurationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetAnimationDuration(BindableObject bindable, int value) - => bindable.SetValue(AnimationDurationProperty, value); + public static void SetAnimationDuration(BindableObject? bindable, int value) + => bindable?.SetValue(AnimationDurationProperty, value); - public static Easing GetAnimationEasing(BindableObject bindable) - => (Easing)bindable.GetValue(AnimationEasingProperty); + public static Easing GetAnimationEasing(BindableObject? bindable) + => (Easing)(bindable?.GetValue(AnimationEasingProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetAnimationEasing(BindableObject bindable, Easing value) - => bindable.SetValue(AnimationEasingProperty, value); + public static void SetAnimationEasing(BindableObject? bindable, Easing value) + => bindable?.SetValue(AnimationEasingProperty, value); - public static int GetPressedAnimationDuration(BindableObject bindable) - => (int)bindable.GetValue(PressedAnimationDurationProperty); + public static int GetPressedAnimationDuration(BindableObject? bindable) + => (int)(bindable?.GetValue(PressedAnimationDurationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedAnimationDuration(BindableObject bindable, int value) - => bindable.SetValue(PressedAnimationDurationProperty, value); + public static void SetPressedAnimationDuration(BindableObject? bindable, int value) + => bindable?.SetValue(PressedAnimationDurationProperty, value); - public static Easing GetPressedAnimationEasing(BindableObject bindable) - => (Easing)bindable.GetValue(PressedAnimationEasingProperty); + public static Easing GetPressedAnimationEasing(BindableObject? bindable) + => (Easing)(bindable?.GetValue(PressedAnimationEasingProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedAnimationEasing(BindableObject bindable, Easing value) - => bindable.SetValue(PressedAnimationEasingProperty, value); + public static void SetPressedAnimationEasing(BindableObject? bindable, Easing value) + => bindable?.SetValue(PressedAnimationEasingProperty, value); - public static int GetNormalAnimationDuration(BindableObject bindable) - => (int)bindable.GetValue(NormalAnimationDurationProperty); + public static int GetNormalAnimationDuration(BindableObject? bindable) + => (int)(bindable?.GetValue(NormalAnimationDurationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalAnimationDuration(BindableObject bindable, int value) - => bindable.SetValue(NormalAnimationDurationProperty, value); + public static void SetNormalAnimationDuration(BindableObject? bindable, int value) + => bindable?.SetValue(NormalAnimationDurationProperty, value); - public static Easing GetNormalAnimationEasing(BindableObject bindable) - => (Easing)bindable.GetValue(NormalAnimationEasingProperty); + public static Easing GetNormalAnimationEasing(BindableObject? bindable) + => (Easing)(bindable?.GetValue(NormalAnimationEasingProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalAnimationEasing(BindableObject bindable, Easing value) - => bindable.SetValue(NormalAnimationEasingProperty, value); + public static void SetNormalAnimationEasing(BindableObject? bindable, Easing value) + => bindable?.SetValue(NormalAnimationEasingProperty, value); - public static int GetHoveredAnimationDuration(BindableObject bindable) - => (int)bindable.GetValue(HoveredAnimationDurationProperty); + public static int GetHoveredAnimationDuration(BindableObject? bindable) + => (int)(bindable?.GetValue(HoveredAnimationDurationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredAnimationDuration(BindableObject bindable, int value) - => bindable.SetValue(HoveredAnimationDurationProperty, value); + public static void SetHoveredAnimationDuration(BindableObject? bindable, int value) + => bindable?.SetValue(HoveredAnimationDurationProperty, value); - public static Easing GetHoveredAnimationEasing(BindableObject bindable) - => (Easing)bindable.GetValue(HoveredAnimationEasingProperty); + public static Easing GetHoveredAnimationEasing(BindableObject? bindable) + => (Easing)(bindable?.GetValue(HoveredAnimationEasingProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredAnimationEasing(BindableObject bindable, Easing value) - => bindable.SetValue(HoveredAnimationEasingProperty, value); + public static void SetHoveredAnimationEasing(BindableObject? bindable, Easing value) + => bindable?.SetValue(HoveredAnimationEasingProperty, value); - public static int GetPulseCount(BindableObject bindable) - => (int)bindable.GetValue(PulseCountProperty); + public static int GetPulseCount(BindableObject? bindable) + => (int)(bindable?.GetValue(PulseCountProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPulseCount(BindableObject bindable, int value) - => bindable.SetValue(PulseCountProperty, value); + public static void SetPulseCount(BindableObject? bindable, int value) + => bindable?.SetValue(PulseCountProperty, value); - public static bool? GetIsToggled(BindableObject bindable) - => (bool?)bindable.GetValue(IsToggledProperty); + public static bool? GetIsToggled(BindableObject? bindable) + => (bool?)(bindable?.GetValue(IsToggledProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetIsToggled(BindableObject bindable, bool? value) - => bindable.SetValue(IsToggledProperty, value); + public static void SetIsToggled(BindableObject? bindable, bool? value) + => bindable?.SetValue(IsToggledProperty, value); - public static int GetDisallowTouchThreshold(BindableObject bindable) - => (int)bindable.GetValue(DisallowTouchThresholdProperty); + public static int GetDisallowTouchThreshold(BindableObject? bindable) + => (int)(bindable?.GetValue(DisallowTouchThresholdProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetDisallowTouchThreshold(BindableObject bindable, int value) - => bindable.SetValue(DisallowTouchThresholdProperty, value); + public static void SetDisallowTouchThreshold(BindableObject? bindable, int value) + => bindable?.SetValue(DisallowTouchThresholdProperty, value); - public static bool GetNativeAnimation(BindableObject bindable) - => (bool)bindable.GetValue(NativeAnimationProperty); + public static bool GetNativeAnimation(BindableObject? bindable) + => (bool)(bindable?.GetValue(NativeAnimationProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNativeAnimation(BindableObject bindable, bool value) - => bindable.SetValue(NativeAnimationProperty, value); + public static void SetNativeAnimation(BindableObject? bindable, bool value) + => bindable?.SetValue(NativeAnimationProperty, value); - public static Color GetNativeAnimationColor(BindableObject bindable) - => (Color)bindable.GetValue(NativeAnimationColorProperty); + public static Color GetNativeAnimationColor(BindableObject? bindable) + => (Color)(bindable?.GetValue(NativeAnimationColorProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNativeAnimationColor(BindableObject bindable, Color value) - => bindable.SetValue(NativeAnimationColorProperty, value); + public static void SetNativeAnimationColor(BindableObject? bindable, Color value) + => bindable?.SetValue(NativeAnimationColorProperty, value); - public static int GetNativeAnimationRadius(BindableObject bindable) - => (int)bindable.GetValue(NativeAnimationRadiusProperty); + public static int GetNativeAnimationRadius(BindableObject? bindable) + => (int)(bindable?.GetValue(NativeAnimationRadiusProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNativeAnimationRadius(BindableObject bindable, int value) - => bindable.SetValue(NativeAnimationRadiusProperty, value); + public static void SetNativeAnimationRadius(BindableObject? bindable, int value) + => bindable?.SetValue(NativeAnimationRadiusProperty, value); - public static int GetNativeAnimationShadowRadius(BindableObject bindable) - => (int)bindable.GetValue(NativeAnimationShadowRadiusProperty); + public static int GetNativeAnimationShadowRadius(BindableObject? bindable) + => (int)(bindable?.GetValue(NativeAnimationShadowRadiusProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNativeAnimationShadowRadius(BindableObject bindable, int value) - => bindable.SetValue(NativeAnimationShadowRadiusProperty, value); + public static void SetNativeAnimationShadowRadius(BindableObject? bindable, int value) + => bindable?.SetValue(NativeAnimationShadowRadiusProperty, value); - public static ImageSource GetNormalBackgroundImageSource(BindableObject bindable) - => (ImageSource)bindable.GetValue(NormalBackgroundImageSourceProperty); + public static ImageSource GetNormalBackgroundImageSource(BindableObject? bindable) + => (ImageSource)(bindable?.GetValue(NormalBackgroundImageSourceProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalBackgroundImageSource(BindableObject bindable, ImageSource value) - => bindable.SetValue(NormalBackgroundImageSourceProperty, value); + public static void SetNormalBackgroundImageSource(BindableObject? bindable, ImageSource value) + => bindable?.SetValue(NormalBackgroundImageSourceProperty, value); - public static ImageSource GetHoveredBackgroundImageSource(BindableObject bindable) - => (ImageSource)bindable.GetValue(HoveredBackgroundImageSourceProperty); + public static ImageSource GetHoveredBackgroundImageSource(BindableObject? bindable) + => (ImageSource)(bindable?.GetValue(HoveredBackgroundImageSourceProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredBackgroundImageSource(BindableObject bindable, ImageSource value) - => bindable.SetValue(HoveredBackgroundImageSourceProperty, value); + public static void SetHoveredBackgroundImageSource(BindableObject? bindable, ImageSource value) + => bindable?.SetValue(HoveredBackgroundImageSourceProperty, value); - public static ImageSource GetPressedBackgroundImageSource(BindableObject bindable) - => (ImageSource)bindable.GetValue(PressedBackgroundImageSourceProperty); + public static ImageSource GetPressedBackgroundImageSource(BindableObject? bindable) + => (ImageSource)(bindable?.GetValue(PressedBackgroundImageSourceProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedBackgroundImageSource(BindableObject bindable, ImageSource value) - => bindable.SetValue(PressedBackgroundImageSourceProperty, value); + public static void SetPressedBackgroundImageSource(BindableObject? bindable, ImageSource value) + => bindable?.SetValue(PressedBackgroundImageSourceProperty, value); - public static Aspect GetBackgroundImageAspect(BindableObject bindable) - => (Aspect)bindable.GetValue(BackgroundImageAspectProperty); + public static Aspect GetBackgroundImageAspect(BindableObject? bindable) + => (Aspect)(bindable?.GetValue(BackgroundImageAspectProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetBackgroundImageAspect(BindableObject bindable, Aspect value) - => bindable.SetValue(BackgroundImageAspectProperty, value); + public static void SetBackgroundImageAspect(BindableObject? bindable, Aspect value) + => bindable?.SetValue(BackgroundImageAspectProperty, value); - public static Aspect GetNormalBackgroundImageAspect(BindableObject bindable) - => (Aspect)bindable.GetValue(NormalBackgroundImageAspectProperty); + public static Aspect GetNormalBackgroundImageAspect(BindableObject? bindable) + => (Aspect)(bindable?.GetValue(NormalBackgroundImageAspectProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetNormalBackgroundImageAspect(BindableObject bindable, Aspect value) - => bindable.SetValue(NormalBackgroundImageAspectProperty, value); + public static void SetNormalBackgroundImageAspect(BindableObject? bindable, Aspect value) + => bindable?.SetValue(NormalBackgroundImageAspectProperty, value); - public static Aspect GetHoveredBackgroundImageAspect(BindableObject bindable) - => (Aspect)bindable.GetValue(HoveredBackgroundImageAspectProperty); + public static Aspect GetHoveredBackgroundImageAspect(BindableObject? bindable) + => (Aspect)(bindable?.GetValue(HoveredBackgroundImageAspectProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetHoveredBackgroundImageAspect(BindableObject bindable, Aspect value) - => bindable.SetValue(HoveredBackgroundImageAspectProperty, value); + public static void SetHoveredBackgroundImageAspect(BindableObject? bindable, Aspect value) + => bindable?.SetValue(HoveredBackgroundImageAspectProperty, value); - public static Aspect GetPressedBackgroundImageAspect(BindableObject bindable) - => (Aspect)bindable.GetValue(PressedBackgroundImageAspectProperty); + public static Aspect GetPressedBackgroundImageAspect(BindableObject? bindable) + => (Aspect)(bindable?.GetValue(PressedBackgroundImageAspectProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetPressedBackgroundImageAspect(BindableObject bindable, Aspect value) - => bindable.SetValue(PressedBackgroundImageAspectProperty, value); + public static void SetPressedBackgroundImageAspect(BindableObject? bindable, Aspect value) + => bindable?.SetValue(PressedBackgroundImageAspectProperty, value); - public static bool GetShouldSetImageOnAnimationEnd(BindableObject bindable) - => (bool)bindable.GetValue(ShouldSetImageOnAnimationEndProperty); + public static bool GetShouldSetImageOnAnimationEnd(BindableObject? bindable) + => (bool)(bindable?.GetValue(ShouldSetImageOnAnimationEndProperty) ?? throw new ArgumentNullException(nameof(bindable))); - public static void SetShouldSetImageOnAnimationEnd(BindableObject bindable, bool value) - => bindable.SetValue(ShouldSetImageOnAnimationEndProperty, value); + public static void SetShouldSetImageOnAnimationEnd(BindableObject? bindable, bool value) + => bindable?.SetValue(ShouldSetImageOnAnimationEndProperty, value); - static void TryGenerateEffect(BindableObject bindable, object oldValue, object newValue) + static void TryGenerateEffect(BindableObject? bindable, object oldValue, object newValue) { if (bindable is not VisualElement view || view.Effects.OfType().Any()) return; @@ -1015,12 +1015,11 @@ public HoverState HoverState public bool ShouldSetImageOnAnimationEnd => GetShouldSetImageOnAnimationEnd(Element); - internal bool CanExecute - => IsAvailable && - Element.IsEnabled && - (Command?.CanExecute(CommandParameter) ?? true); + internal bool CanExecute => IsAvailable + && (Element?.IsEnabled ?? false) + && (Command?.CanExecute(CommandParameter) ?? true); - internal new VisualElement Element + internal new VisualElement? Element { get => element; set @@ -1047,13 +1046,13 @@ internal new VisualElement Element } } - internal static TouchEffect? GetFrom(BindableObject bindable) + internal static TouchEffect? GetFrom(BindableObject? bindable) { var effects = (bindable as VisualElement)?.Effects?.OfType(); return effects?.FirstOrDefault(x => !x.IsAutoGenerated) ?? effects?.FirstOrDefault(); } - internal static TouchEffect? PickFrom(BindableObject bindable) + internal static TouchEffect? PickFrom(BindableObject? bindable) { var effects = (bindable as VisualElement)?.Effects?.OfType(); return effects?.FirstOrDefault(x => !x.IsAutoGenerated && !x.IsUsed) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Startup/ToolkitPlatform.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Startup/ToolkitPlatform.android.cs index 60d866add..1a96aee86 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Startup/ToolkitPlatform.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Startup/ToolkitPlatform.android.cs @@ -6,12 +6,12 @@ namespace Xamarin.CommunityToolkit /// /// Platform extension methods. /// - internal static class ToolkitPlatform + static class ToolkitPlatform { /// /// Gets the . /// - internal static Context Context + internal static Context? Context { get { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs index b748c50dd..2add86c53 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs @@ -45,9 +45,10 @@ namespace Xamarin.CommunityToolkit.UI.Views class CameraFragment : Fragment, TextureView.ISurfaceTextureListener { // Max preview width that is guaranteed by Camera2 API - const int MAX_PREVIEW_HEIGHT = 1080; + const int maxPreviewHeight = 1080; + // Max preview height that is guaranteed by Camera2 API - const int MAX_PREVIEW_WIDTH = 1920; + const int maxPrevieWidth = 1920; CameraDevice device; CaptureRequest.Builder sessionBuilder; @@ -72,7 +73,7 @@ class CameraFragment : Fragment, TextureView.ISurfaceTextureListener Java.Util.Concurrent.Semaphore captureSessionOpenCloseLock = new Java.Util.Concurrent.Semaphore(1); CameraTemplate cameraTemplate; HandlerThread backgroundThread; - Handler backgroundHandler = null; + Handler? backgroundHandler = null; float zoom = 1; @@ -246,14 +247,14 @@ public async Task RetrieveCameraDevice(bool force = false) maxPreviewHeight = displaySize.X; } - if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) + if (maxPreviewHeight > CameraFragment.maxPreviewHeight) { - maxPreviewHeight = MAX_PREVIEW_HEIGHT; + maxPreviewHeight = CameraFragment.maxPreviewHeight; } - if (maxPreviewWidth > MAX_PREVIEW_WIDTH) + if (maxPreviewWidth > maxPrevieWidth) { - maxPreviewWidth = MAX_PREVIEW_WIDTH; + maxPreviewWidth = maxPrevieWidth; } photoSize = GetMaxSize(map.GetOutputSizes((int)ImageFormatType.Jpeg)); @@ -718,24 +719,24 @@ public void ApplyZoom() sessionBuilder?.Set(CaptureRequest.ScalerCropRegion, GetZoomRect()); } - string GetCameraId() + string? GetCameraId() { var cameraIdList = Manager.GetCameraIdList(); if (cameraIdList.Length == 0) return null; - string FilterCameraByLens(LensFacing lensFacing) + string? FilterCameraByLens(LensFacing lensFacing) { foreach (var id in cameraIdList) { var characteristics = Manager.GetCameraCharacteristics(id); - if (lensFacing == (LensFacing)(int)characteristics.Get(CameraCharacteristics.LensFacing)) + if (lensFacing == (LensFacing)(int)(characteristics?.Get(CameraCharacteristics.LensFacing) ?? throw new NullReferenceException())) return id; } return null; } - return Element.CameraOptions switch + return Element?.CameraOptions switch { CameraOptions.Front => FilterCameraByLens(LensFacing.Front), CameraOptions.Back => FilterCameraByLens(LensFacing.Back), @@ -745,23 +746,23 @@ string FilterCameraByLens(LensFacing lensFacing) } #region TextureView.ISurfaceTextureListener - async void TextureView.ISurfaceTextureListener.OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) + async void TextureView.ISurfaceTextureListener.OnSurfaceTextureAvailable(SurfaceTexture? surface, int width, int height) { UpdateBackgroundColor(); UpdateCaptureOptions(); await RetrieveCameraDevice(); } - void TextureView.ISurfaceTextureListener.OnSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) => + void TextureView.ISurfaceTextureListener.OnSurfaceTextureSizeChanged(SurfaceTexture? surface, int width, int height) => ConfigureTransform(width, height); - bool TextureView.ISurfaceTextureListener.OnSurfaceTextureDestroyed(SurfaceTexture surface) + bool TextureView.ISurfaceTextureListener.OnSurfaceTextureDestroyed(SurfaceTexture? surface) { CloseDevice(); return true; } - void TextureView.ISurfaceTextureListener.OnSurfaceTextureUpdated(SurfaceTexture surface) + void TextureView.ISurfaceTextureListener.OnSurfaceTextureUpdated(SurfaceTexture? surface) { } #endregion @@ -820,7 +821,7 @@ public override void OnRequestPermissionsResult(int requestCode, string[] permis #endregion #region Helpers - void LogError(string desc, Java.Lang.Exception ex = null) + void LogError(string desc, Java.Lang.Exception? ex = null) { var newLine = System.Environment.NewLine; var sb = new StringBuilder(desc); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraStateListener.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraStateListener.android.cs index d8c051be1..b5423fa06 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraStateListener.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraStateListener.android.cs @@ -1,22 +1,21 @@ using System; -using System.Collections.Generic; using Android.Hardware.Camera2; namespace Xamarin.CommunityToolkit.UI.Views { class CameraStateListener : CameraDevice.StateCallback { - public Action OnOpenedAction; - public Action OnDisconnectedAction; - public Action OnErrorAction; - public Action OnClosedAction; + public Action? OnOpenedAction; + public Action? OnDisconnectedAction; + public Action? OnErrorAction; + public Action? OnClosedAction; public override void OnOpened(CameraDevice camera) => OnOpenedAction?.Invoke(camera); public override void OnDisconnected(CameraDevice camera) => OnDisconnectedAction?.Invoke(camera); - public override void OnError(CameraDevice camera, CameraError error) => OnErrorAction(camera, error); + public override void OnError(CameraDevice camera, CameraError error) => OnErrorAction?.Invoke(camera, error); - public override void OnClosed(CameraDevice camera) => OnClosedAction(camera); + public override void OnClosed(CameraDevice camera) => OnClosedAction?.Invoke(camera); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs index 1b2a3b440..2a6db4659 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs @@ -6,7 +6,7 @@ namespace Xamarin.CommunityToolkit.UI.Views { class MotionEventHelper { - VisualElement element; + VisualElement? element; bool isInViewCell; public bool HandleMotionEvent(IViewParent parent, MotionEvent? motionEvent) @@ -14,12 +14,11 @@ public bool HandleMotionEvent(IViewParent parent, MotionEvent? motionEvent) if (isInViewCell || element == null || motionEvent == null || motionEvent.Action == MotionEventActions.Cancel) return false; - var renderer = parent as VisualElementRenderer; - if (renderer == null || ShouldPassThroughElement()) + if (parent is not VisualElementRenderer renderer || ShouldPassThroughElement()) return false; // Let the container know that we're "fake" handling this event - // renderer.NotifyFakeHandling(); + //renderer.NotifyFakeHandling(); return true; } @@ -55,7 +54,7 @@ bool ShouldPassThroughElement() } // This is not a layout and it's transparent; the event can just pass through - if (element.InputTransparent) + if (element?.InputTransparent ?? false) return true; return false; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Android/GravatarImageSourceHandler.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Android/GravatarImageSourceHandler.android.cs index 356937c6c..1ade839bc 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Android/GravatarImageSourceHandler.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Android/GravatarImageSourceHandler.android.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Android.Content; using Android.Graphics; @@ -10,11 +11,11 @@ namespace Xamarin.CommunityToolkit.UI.Views { public partial class GravatarImageSourceHandler : IImageSourceHandler { - public async Task LoadImageAsync(ImageSource imagesource, Context context, CancellationToken cancelationToken = default) + public async Task LoadImageAsync(ImageSource imagesource, Context context, CancellationToken cancelationToken = default) { - var fileInfo = await LoadInternal(imagesource, 1, Application.Context.CacheDir.AbsolutePath); + var fileInfo = await LoadInternal(imagesource, 1, Application.Context.CacheDir?.AbsolutePath ?? throw new NullReferenceException()); - Bitmap bitmap = null; + Bitmap? bitmap = null; try { await semaphore.WaitAsync(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/MacOS/GravatarImageSourceHandler.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/MacOS/GravatarImageSourceHandler.macos.cs index 330b57075..e77db2578 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/MacOS/GravatarImageSourceHandler.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/MacOS/GravatarImageSourceHandler.macos.cs @@ -8,11 +8,11 @@ namespace Xamarin.CommunityToolkit.UI.Views { public partial class GravatarImageSourceHandler : IImageSourceHandler { - public async Task LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default, float scale = 1) + public async Task LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = default, float scale = 1) { var fileInfo = await LoadInternal(imagesource, 1, GetCacheDirectory()); - NSImage image = null; + NSImage? image = null; try { await semaphore.WaitAsync(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs index 3830b61c8..b7cc3a6e2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/Android/MediaElementRenderer.android.cs @@ -126,7 +126,7 @@ void IVisualElementRenderer.SetElement(VisualElement element) if (tracker == null) SetTracker(new VisualElementTracker(this)); - OnElementChanged(new ElementChangedEventArgs(oldElement, MediaElement)); + OnElementChanged(new ElementChangedEventArgs(oldElement, MediaElement)); } void StateRequested(object sender, StateRequested e) @@ -163,7 +163,7 @@ void StateRequested(object sender, StateRequested e) void OnPositionRequested(object sender, EventArgs e) { - if (view == null && Controller == null) + if (view == null || Controller == null) return; Controller.Position = view.Position; @@ -171,7 +171,7 @@ void OnPositionRequested(object sender, EventArgs e) void SeekRequested(object sender, SeekRequested e) { - if (view == null) + if (view == null || Controller == null) return; view.SeekTo((int)e.Position.TotalMilliseconds); @@ -189,7 +189,11 @@ void IVisualElementRenderer.SetLabelFor(int? id) void SetTracker(VisualElementTracker tracker) => this.tracker = tracker; - protected virtual void UpdateBackgroundColor() => SetBackgroundColor(Element.BackgroundColor.ToAndroid()); + protected virtual void UpdateBackgroundColor() + { + if (Element != null) + SetBackgroundColor(Element.BackgroundColor.ToAndroid()); + } void IVisualElementRenderer.UpdateLayout() => tracker?.UpdateLayout(); @@ -216,7 +220,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - protected virtual void OnElementChanged(ElementChangedEventArgs e) + protected virtual void OnElementChanged(ElementChangedEventArgs e) { if (e.NewElement != null) { @@ -236,7 +240,7 @@ protected virtual void OnElementChanged(ElementChangedEventArgs Controller.BufferingProgress = e.Percent / 100f; + void OnMpBufferingUpdate(object sender, MediaPlayer.BufferingUpdateEventArgs e) + { + if (Controller != null) + Controller.BufferingProgress = e.Percent / 100f; + } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs index ba7a49ebf..9afa91448 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/Android/PopupRenderer.android.cs @@ -125,10 +125,7 @@ void SetEvents(in BasePopup basePopup) basePopup.Dismissed += OnDismissed; } - void SetColor(in BasePopup basePopup) - { - Window.SetBackgroundDrawable(new ColorDrawable(basePopup.Color.ToAndroid())); - } + void SetColor(in BasePopup basePopup) => Window?.SetBackgroundDrawable(new ColorDrawable(basePopup.Color.ToAndroid())); void SetSize(in BasePopup basePopup) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/ThumbFrame.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/ThumbFrame.shared.cs index 09b9dcd38..3b8ede1e3 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/ThumbFrame.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/RangeSlider/ThumbFrame.shared.cs @@ -1,4 +1,5 @@ -using Xamarin.Forms; +using System; +using Xamarin.Forms; namespace Xamarin.CommunityToolkit.UI.Views { @@ -9,7 +10,7 @@ public ThumbFrame() #region Required work-around to prevent linker from removing the platform-specific implementation #if __ANDROID__ if (System.DateTime.Now.Ticks < 0) - _ = new ThumbFrameRenderer(null); + _ = new ThumbFrameRenderer(ToolkitPlatform.Context ?? throw new NullReferenceException()); #endif #endregion } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs index 339bb2b72..3b89e4165 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs @@ -82,7 +82,7 @@ public SideMenuView() #region Required work-around to prevent linker from removing the platform-specific implementation #if __ANDROID__ if (System.DateTime.Now.Ticks < 0) - _ = new Xamarin.CommunityToolkit.Android.UI.Views.SideMenuViewRenderer(null); + _ = new Xamarin.CommunityToolkit.Android.UI.Views.SideMenuViewRenderer(ToolkitPlatform.Context ?? throw new NullReferenceException()); #elif __IOS__ if (System.DateTime.Now.Ticks < 0) _ = new Xamarin.CommunityToolkit.iOS.UI.Views.SideMenuViewRenderer(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.android.cs index 1b4649fbe..39151aaa1 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuViewRenderer.android.cs @@ -31,7 +31,7 @@ public class SideMenuViewRenderer : VisualElementRenderer public SideMenuViewRenderer(Context context) : base(context) - => density = context.Resources.DisplayMetrics.Density; + => density = context.Resources?.DisplayMetrics?.Density ?? throw new NullReferenceException(); double GestureThreshold => Element.GestureThreshold >= 0 ? Element.GestureThreshold diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/MacOSSnackBar.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/MacOSSnackBar.macos.cs index 7d3410055..28763162c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/MacOSSnackBar.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/MacOSSnackBar.macos.cs @@ -10,9 +10,9 @@ namespace Xamarin.CommunityToolkit.UI.Views.Helpers.macOS { class NativeSnackBar { - NSTimer timer; + NSTimer? timer; - public Func TimeoutAction { get; protected set; } + public Func? TimeoutAction { get; protected set; } public List Actions { get; protected set; } = new List(); @@ -22,9 +22,9 @@ class NativeSnackBar public SnackBarLayout Layout { get; } = new SnackBarLayout(); - public string Message { get; protected set; } + public string Message { get; protected set; } = string.Empty; - protected BaseSnackBarView SnackBarView { get; set; } + protected BaseSnackBarView? SnackBarView { get; set; } public void Dismiss() { @@ -66,7 +66,8 @@ public NativeSnackBar Show() timer = NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(Duration), async t => { - await TimeoutAction(); + if (TimeoutAction != null) + await TimeoutAction(); Dismiss(); }); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/ActionMessageSnackBarView.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/ActionMessageSnackBarView.macos.cs index 1c821a91d..00f646dc1 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/ActionMessageSnackBarView.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/ActionMessageSnackBarView.macos.cs @@ -1,7 +1,4 @@ -using System; -using AppKit; - -namespace Xamarin.CommunityToolkit.UI.Views.Helpers.macOS.SnackBarViews +namespace Xamarin.CommunityToolkit.UI.Views.Helpers.macOS.SnackBarViews { class ActionMessageSnackBarView : MessageSnackBarView { @@ -15,7 +12,7 @@ protected override void Initialize() base.Initialize(); foreach (var actionButton in SnackBar.Actions) { - StackView.AddArrangedSubview(actionButton); + StackView?.AddArrangedSubview(actionButton); } } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/BaseSnackBarView.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/BaseSnackBarView.macos.cs index 8e9f4995e..1217526a7 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/BaseSnackBarView.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/BaseSnackBarView.macos.cs @@ -10,7 +10,7 @@ abstract class BaseSnackBarView : NSView protected NativeSnackBar SnackBar { get; } - public NSStackView StackView { get; set; } + public NSStackView? StackView { get; set; } public virtual void Dismiss() => RemoveFromSuperview(); @@ -33,18 +33,25 @@ protected virtual void ConstrainInParent() TrailingAnchor.ConstraintGreaterThanOrEqualToAnchor(ParentView.TrailingAnchor, -SnackBar.Layout.MarginRight).Active = true; CenterXAnchor.ConstraintEqualToAnchor(ParentView.CenterXAnchor).Active = true; - StackView.LeadingAnchor.ConstraintEqualToAnchor(LeadingAnchor, SnackBar.Layout.PaddingLeft).Active = true; - StackView.TrailingAnchor.ConstraintEqualToAnchor(TrailingAnchor, -SnackBar.Layout.PaddingRight).Active = true; - StackView.BottomAnchor.ConstraintEqualToAnchor(BottomAnchor, -SnackBar.Layout.PaddingBottom).Active = true; - StackView.TopAnchor.ConstraintEqualToAnchor(TopAnchor, SnackBar.Layout.PaddingTop).Active = true; + if (StackView != null) + { + StackView.LeadingAnchor.ConstraintEqualToAnchor(LeadingAnchor, SnackBar.Layout.PaddingLeft).Active = true; + StackView.TrailingAnchor.ConstraintEqualToAnchor(TrailingAnchor, -SnackBar.Layout.PaddingRight).Active = true; + StackView.BottomAnchor.ConstraintEqualToAnchor(BottomAnchor, -SnackBar.Layout.PaddingBottom).Active = true; + StackView.TopAnchor.ConstraintEqualToAnchor(TopAnchor, SnackBar.Layout.PaddingTop).Active = true; + } } protected virtual void Initialize() { - StackView = new NSStackView(); - StackView.WantsLayer = true; + StackView = new NSStackView + { + WantsLayer = true + }; + AddSubview(StackView); - if (SnackBar.Appearance.Background != NativeSnackBarAppearance.DefaultColor) + + if (SnackBar.Appearance.Background != NativeSnackBarAppearance.DefaultColor && StackView.Layer != null) { StackView.Layer.BackgroundColor = SnackBar.Appearance.Background.CGColor; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/MessageSnackBarView.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/MessageSnackBarView.macos.cs index 17c09f5e6..dd470e02c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/MessageSnackBarView.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/macOS/SnackbarViews/MessageSnackBarView.macos.cs @@ -1,8 +1,4 @@ -using System; -using AppKit; -using CoreGraphics; - -namespace Xamarin.CommunityToolkit.UI.Views.Helpers.macOS.SnackBarViews +namespace Xamarin.CommunityToolkit.UI.Views.Helpers.macOS.SnackBarViews { class MessageSnackBarView : BaseSnackBarView { @@ -39,7 +35,7 @@ protected override void Initialize() messageLabel.Font = SnackBar.Appearance.Font; } - StackView.AddArrangedSubview(messageLabel); + StackView?.AddArrangedSubview(messageLabel); } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.android.cs index 27d9cc21a..d332bad54 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.android.cs @@ -4,6 +4,7 @@ using Xamarin.Forms.Platform.Android; using Xamarin.CommunityToolkit.UI.Views.Options; using Android.Util; +using System; #if MONOANDROID10_0 using AndroidSnackBar = Google.Android.Material.Snackbar.Snackbar; #else @@ -24,7 +25,7 @@ internal void Show(Page sender, SnackBarOptions arguments) snackBarView.SetBackgroundColor(arguments.BackgroundColor.ToAndroid()); } - var snackTextView = snackBarView.FindViewById(Resource.Id.snackbar_text); + var snackTextView = snackBarView.FindViewById(Resource.Id.snackbar_text) ?? throw new NullReferenceException(); snackTextView.SetMaxLines(10); if (arguments.MessageOptions.Padding != MessageOptions.DefaultPadding) @@ -56,13 +57,17 @@ internal void Show(Page sender, SnackBarOptions arguments) foreach (var action in arguments.Actions) { - snackBar.SetAction(action.Text, async v => await action.Action()); + snackBar.SetAction(action.Text, async v => + { + if (action?.Action != null) + await action.Action(); + }); if (action.ForegroundColor != Forms.Color.Default) { snackBar.SetActionTextColor(action.ForegroundColor.ToAndroid()); } - var snackActionButtonView = snackBarView.FindViewById(Resource.Id.snackbar_action); + var snackActionButtonView = snackBarView.FindViewById(Resource.Id.snackbar_action) ?? throw new NullReferenceException(); if (arguments.BackgroundColor != Forms.Color.Default) { snackActionButtonView.SetBackgroundColor(action.BackgroundColor.ToAndroid()); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs index 1bb39fbbe..42db8d690 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.ios.macos.cs @@ -100,7 +100,7 @@ internal void Show(Page sender, SnackBarOptions arguments) actionButton.SetTitleColor(action.ForegroundColor.ToUIColor(), UIControlState.Normal); } #elif __MACOS__ - if (action.BackgroundColor != Color.Default) + if (action.BackgroundColor != Color.Default && actionButton.Layer != null) { actionButton.Layer.BackgroundColor = action.BackgroundColor.ToCGColor(); } @@ -114,7 +114,8 @@ internal void Show(Page sender, SnackBarOptions arguments) { snackBar.Dismiss(); - await (action.Action?.Invoke() ?? Task.CompletedTask); + if (action.Action != null) + await action.Action(); arguments.SetResult(true); }); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.tizen.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.tizen.cs index 8c1161cd6..408e31fb0 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.tizen.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.tizen.cs @@ -27,7 +27,10 @@ internal void Show(Forms.Page sender, SnackBarOptions arguments) ok.Clicked += async (s, evt) => { snackBarDialog.Dismiss(); - await action.Action(); + + if (action?.Action != null) + await action.Action(); + arguments.SetResult(true); }; } From b06ab5970dc9af1a5c65018520f41b09f72f1009 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 16:21:31 -0800 Subject: [PATCH 08/13] Removed Possible Null References --- .../LifeCycle/LifeCycleEffectRouter.uwp.cs | 20 +++-- .../Effects/Touch/PlatformTouchEffect.uwp.cs | 26 +++--- .../Navigation/NavigationExtensions.uwp.cs | 4 +- .../Helpers/SafeArea.shared.cs | 6 +- .../Helpers/WeakEventManagerService.shared.cs | 8 +- .../CameraView/UWP/CameraViewRenderer.uwp.cs | 86 ++++++++++--------- .../UWP/GravatarImageSourceHandler.uwp.cs | 4 +- .../Wpf/GravatarImageSourceHandler.wpf.cs | 4 +- .../Views/Popup/UWP/Popup.shared.cs | 11 +-- .../Views/Popup/UWP/PopupRenderer.uwp.cs | 68 +++++++++------ .../Views/Shield.shared.cs | 2 +- .../Views/SideMenuView/SideMenuView.shared.cs | 6 +- .../Helpers/SnackBarLayout.uwp.wpf.cs | 5 +- .../Views/Snackbar/SnackBar.gtk.cs | 33 ++++--- .../Views/Snackbar/SnackBar.uwp.cs | 6 +- .../Views/Snackbar/SnackBar.wpf.cs | 2 +- .../Views/ViewToRendererConverter.uwp.cs | 51 +++++------ 17 files changed, 188 insertions(+), 154 deletions(-) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.uwp.cs index 6326189d8..77ecb7892 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/LifeCycle/LifeCycleEffectRouter.uwp.cs @@ -15,8 +15,8 @@ namespace Xamarin.CommunityToolkit.UWP.Effects /// public class LifeCycleEffectRouter : PlatformEffect { - FrameworkElement nativeView; - LifecycleEffect lifeCycleEffect; + FrameworkElement? nativeView; + LifecycleEffect? lifeCycleEffect; protected override void OnAttached() { @@ -29,13 +29,21 @@ protected override void OnAttached() nativeView.Unloaded += OnNativeViewUnloaded; } - void OnNativeViewLoaded(object sender, RoutedEventArgs e) => lifeCycleEffect.RaiseLoadedEvent(Element); + void OnNativeViewLoaded(object sender, RoutedEventArgs e) => lifeCycleEffect?.RaiseLoadedEvent(Element); void OnNativeViewUnloaded(object sender, RoutedEventArgs e) { - lifeCycleEffect.RaiseUnloadedEvent(Element); - nativeView.Unloaded -= OnNativeViewUnloaded; - nativeView.Loaded -= OnNativeViewLoaded; + if (lifeCycleEffect != null) + { + lifeCycleEffect.RaiseUnloadedEvent(Element); + } + + if (nativeView != null) + { + nativeView.Unloaded -= OnNativeViewUnloaded; + nativeView.Loaded -= OnNativeViewLoaded; + } + lifeCycleEffect = null; nativeView = null; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.uwp.cs index 795c7310b..f72cc8c9a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Effects/Touch/PlatformTouchEffect.uwp.cs @@ -14,19 +14,19 @@ namespace Xamarin.CommunityToolkit.UWP.Effects { public class PlatformTouchEffect : PlatformEffect { - const string PointerDownAnimationKey = "PointerDownAnimation"; + const string pointerDownAnimationKey = "PointerDownAnimation"; - const string PointerUpAnimationKey = "PointerUpAnimation"; + const string pointerUpAnimationKey = "PointerUpAnimation"; - TouchEffect effect; + TouchEffect? effect; bool isPressed; bool isIntentionalCaptureLoss; - Storyboard pointerDownStoryboard; + Storyboard? pointerDownStoryboard; - Storyboard pointerUpStoryboard; + Storyboard? pointerUpStoryboard; protected override void OnAttached() { @@ -41,26 +41,26 @@ protected override void OnAttached() if (string.IsNullOrEmpty(nativeControl.Name)) nativeControl.Name = Guid.NewGuid().ToString(); - if (nativeControl.Resources.ContainsKey(PointerDownAnimationKey)) - pointerDownStoryboard = (Storyboard)nativeControl.Resources[PointerDownAnimationKey]; + if (nativeControl.Resources.ContainsKey(pointerDownAnimationKey)) + pointerDownStoryboard = (Storyboard)nativeControl.Resources[pointerDownAnimationKey]; else { pointerDownStoryboard = new Storyboard(); var downThemeAnimation = new PointerDownThemeAnimation(); Storyboard.SetTargetName(downThemeAnimation, nativeControl.Name); pointerDownStoryboard.Children.Add(downThemeAnimation); - nativeControl.Resources.Add(new KeyValuePair(PointerDownAnimationKey, pointerDownStoryboard)); + nativeControl.Resources.Add(new KeyValuePair(pointerDownAnimationKey, pointerDownStoryboard)); } - if (nativeControl.Resources.ContainsKey(PointerUpAnimationKey)) - pointerUpStoryboard = (Storyboard)nativeControl.Resources[PointerUpAnimationKey]; + if (nativeControl.Resources.ContainsKey(pointerUpAnimationKey)) + pointerUpStoryboard = (Storyboard)nativeControl.Resources[pointerUpAnimationKey]; else { pointerUpStoryboard = new Storyboard(); var upThemeAnimation = new PointerUpThemeAnimation(); Storyboard.SetTargetName(upThemeAnimation, nativeControl.Name); pointerUpStoryboard.Children.Add(upThemeAnimation); - nativeControl.Resources.Add(new KeyValuePair(PointerUpAnimationKey, pointerUpStoryboard)); + nativeControl.Resources.Add(new KeyValuePair(pointerUpAnimationKey, pointerUpStoryboard)); } } @@ -150,7 +150,7 @@ void OnPointerCaptureLost(object sender, PointerRoutedEventArgs e) effect?.HandleUserInteraction(TouchInteractionStatus.Completed); - if (effect.HoverStatus != HoverStatus.Exited) + if (effect?.HoverStatus != HoverStatus.Exited) effect?.HandleHover(HoverStatus.Exited); AnimateTilt(pointerUpStoryboard); @@ -190,7 +190,7 @@ void OnPointerPressed(object sender, PointerRoutedEventArgs e) isIntentionalCaptureLoss = false; } - void AnimateTilt(Storyboard storyboard) + void AnimateTilt(Storyboard? storyboard) { if ((effect?.NativeAnimation ?? false) && storyboard != null) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.uwp.cs index fb6c4decf..642b10350 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Extensions/Navigation/NavigationExtensions.uwp.cs @@ -18,7 +18,9 @@ Page GetCurrentPage(Page currentPage) { if (currentPage.NavigationProxy.ModalStack.LastOrDefault() is Page modal) return modal; +#pragma warning disable CS0618 // Type or member is obsolete else if (currentPage is MasterDetailPage mdp) +#pragma warning restore CS0618 // Type or member is obsolete return GetCurrentPage(mdp.Detail); else if (currentPage is FlyoutPage fp) return GetCurrentPage(fp.Detail); @@ -31,7 +33,7 @@ Page GetCurrentPage(Page currentPage) } } - static Task PlatformShowPopupAsync(Popup popup) + static Task PlatformShowPopupAsync(Popup popup) { PlatformShowPopup(popup); return popup.Result; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/SafeArea.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/SafeArea.shared.cs index 71b1d0742..c0d9f33e3 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/SafeArea.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/SafeArea.shared.cs @@ -51,9 +51,9 @@ bool Equals(SafeArea other) Bottom == other.Bottom); public override bool Equals(object obj) - => !ReferenceEquals(null, obj) && - obj is SafeArea safeArea && - Equals(safeArea); + => obj is not null + && obj is SafeArea safeArea + && Equals(safeArea); public override int GetHashCode() { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs index 8f51b7b1b..47c252f9d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/WeakEventManagerService.shared.cs @@ -164,15 +164,13 @@ static void AddRemoveEvents(in string eventName, in Dictionary f.Name is "m_owner").GetValue(rtDynamicMethod) - : null; + return (typeInfoRTDynamicMethod != null && typeInfoRTDynamicMethod.IsAssignableFrom(rtDynamicMethod.GetType().GetTypeInfo())) + ? (DynamicMethod)typeRTDynamicMethod.GetRuntimeFields().First(f => f.Name is "m_owner").GetValue(rtDynamicMethod) + : null; } static bool IsLightweightMethod(this MethodBase method) { - _ = method ?? throw new ArgumentNullException(nameof(method)); - var typeInfoRTDynamicMethod = typeof(DynamicMethod).GetTypeInfo().GetDeclaredNestedType("RTDynamicMethod"); return method is DynamicMethod || (typeInfoRTDynamicMethod?.IsAssignableFrom(method.GetType().GetTypeInfo()) ?? false); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/UWP/CameraViewRenderer.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/UWP/CameraViewRenderer.uwp.cs index 66138156d..194ce5cba 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/UWP/CameraViewRenderer.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/UWP/CameraViewRenderer.uwp.cs @@ -26,21 +26,19 @@ namespace Xamarin.CommunityToolkit.UI.Views { public class CameraViewRenderer : ViewRenderer { - MediaCapture mediaCapture; + readonly MediaEncodingProfile encodingProfile; + + MediaCapture? mediaCapture; bool isPreviewing; - Lamp flash; - LowLagMediaRecording mediaRecording; - string filePath; + Lamp? flash; + LowLagMediaRecording? mediaRecording; + string? filePath; bool busy; - VideoStabilizationEffect videoStabilizationEffect; - MediaEncodingProfile encodingProfile; - VideoEncodingProperties inputPropertiesBackup; - VideoEncodingProperties outputPropertiesBackup; + VideoStabilizationEffect? videoStabilizationEffect; + VideoEncodingProperties? inputPropertiesBackup; + VideoEncodingProperties? outputPropertiesBackup; - public CameraViewRenderer() - { - encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto); - } + public CameraViewRenderer() => encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto); bool IsBusy { @@ -72,13 +70,15 @@ protected override async void OnElementChanged(ElementChangedEventArgs> GetImage() + async Task> GetImage() { + _ = mediaCapture ?? throw new NullReferenceException(); + IsBusy = true; var imageProp = ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8); var lowLagCapture = await mediaCapture.PrepareLowLagPhotoCaptureAsync(imageProp); var capturedPhoto = await lowLagCapture.CaptureAsync(); await lowLagCapture.FinishAsync(); - string filePath = null; + string? filePath = null; // See TODO on CameraView.SavePhotoToFile /*if (Element.SavePhotoToFile) @@ -159,24 +161,24 @@ async Task HandleVideo() outputEncoder.SetSoftwareBitmap(capturedPhoto.Frame.SoftwareBitmap); await outputEncoder.FlushAsync(); - byte[] imageData = null; - // See TODO on CameraView.SavePhotoToFile // if (!Element.SavePhotoToFile) // { using var memoryStream = new MemoryStream(); await outputStream.AsStream().CopyToAsync(memoryStream); - imageData = memoryStream.ToArray(); + var imageData = memoryStream.ToArray(); // } IsBusy = false; - return new Tuple(filePath, imageData); + return new Tuple(filePath, imageData); } async Task StartRecord() { + _ = mediaCapture ?? throw new NullReferenceException(); + // TODO replace platform specifics // var localFolder = Element.On().GetVideoFolder(); var localFolder = "Video"; @@ -205,9 +207,9 @@ async Task StartRecord() await mediaRecording.StartAsync(); } - async Task StopRecord() + async Task StopRecord() { - if (mediaRecording == null) + if (mediaRecording == null || mediaCapture == null) return null; await mediaRecording.StopAsync(); @@ -264,6 +266,7 @@ protected override async void OnElementPropertyChanged(object sender, PropertyCh void UpdateZoom() { + _ = mediaCapture ?? throw new NullReferenceException(); var zoomControl = mediaCapture.VideoDeviceController.ZoomControl; if (!zoomControl.Supported) return; @@ -290,7 +293,7 @@ static float Clamp(double value, float min, float max) } } - DeviceInformation FilterCamera(DeviceInformationCollection cameraDevices, Windows.Devices.Enumeration.Panel panel) + DeviceInformation? FilterCamera(DeviceInformationCollection cameraDevices, Windows.Devices.Enumeration.Panel panel) { foreach (var cam in cameraDevices) { @@ -314,23 +317,15 @@ async Task InitializeCameraAsync() } IsBusy = true; - DeviceInformation device = null; - switch (Element.CameraOptions) + + var device = Element.CameraOptions switch { - default: - case CameraOptions.Default: - device = cameraDevices[0]; - break; - case CameraOptions.Front: - device = FilterCamera(cameraDevices, Windows.Devices.Enumeration.Panel.Front); - break; - case CameraOptions.Back: - device = FilterCamera(cameraDevices, Windows.Devices.Enumeration.Panel.Back); - break; - case CameraOptions.External: - device = FilterCamera(cameraDevices, Windows.Devices.Enumeration.Panel.Unknown); - break; - } + CameraOptions.Front => FilterCamera(cameraDevices, Windows.Devices.Enumeration.Panel.Front), + CameraOptions.Back => FilterCamera(cameraDevices, Windows.Devices.Enumeration.Panel.Back), + CameraOptions.External => FilterCamera(cameraDevices, Windows.Devices.Enumeration.Panel.Unknown), + _ => cameraDevices?[0], + }; + if (device == null) { Element?.RaiseMediaCaptureFailed($"{Element.CameraOptions} camera not found."); @@ -353,8 +348,10 @@ async Task InitializeCameraAsync() AudioDeviceId = selectedAudioDevice }); flash = await Lamp.GetDefaultAsync(); - if (mediaCapture?.VideoDeviceController.ZoomControl.Supported ?? false) + + if (mediaCapture.VideoDeviceController.ZoomControl.Supported) Element.MaxZoom = mediaCapture.VideoDeviceController.ZoomControl.Max; + DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape; } catch (UnauthorizedAccessException ex) @@ -415,9 +412,18 @@ protected override async void Dispose(bool disposing) async void CaptureDeviceExclusiveControlStatusChanged(MediaCapture sender, MediaCaptureDeviceExclusiveControlStatusChangedEventArgs args) { if (args.Status == MediaCaptureDeviceExclusiveControlStatus.SharedReadOnlyAvailable) + { Element?.RaiseMediaCaptureFailed("The camera preview can't be displayed because another app has exclusive access"); + } else if (args.Status == MediaCaptureDeviceExclusiveControlStatus.ExclusiveControlAvailable && !isPreviewing) - await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await mediaCapture.StartPreviewAsync()); + { + await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => + { + if (mediaCapture != null) + await mediaCapture.StartPreviewAsync(); + }); + } + IsBusy = false; } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/UWP/GravatarImageSourceHandler.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/UWP/GravatarImageSourceHandler.uwp.cs index 6a9301a74..f291022ac 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/UWP/GravatarImageSourceHandler.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/UWP/GravatarImageSourceHandler.uwp.cs @@ -12,11 +12,11 @@ namespace Xamarin.CommunityToolkit.UI.Views { public partial class GravatarImageSourceHandler : IImageSourceHandler { - public async Task LoadImageAsync(FormsImageSource imagesource, CancellationToken cancellationToken = default) + public async Task LoadImageAsync(FormsImageSource imagesource, CancellationToken cancellationToken = default) { var fileInfo = await LoadInternal(imagesource, 1, ApplicationData.Current.LocalCacheFolder.Path); - BitmapImage bitmap = null; + BitmapImage? bitmap = null; try { await semaphore.WaitAsync(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Wpf/GravatarImageSourceHandler.wpf.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Wpf/GravatarImageSourceHandler.wpf.cs index d2b78f88e..cd50af624 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Wpf/GravatarImageSourceHandler.wpf.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/GravatarImageSource/Wpf/GravatarImageSourceHandler.wpf.cs @@ -12,12 +12,12 @@ namespace Xamarin.CommunityToolkit.UI.Views { public partial class GravatarImageSourceHandler : IImageSourceHandler { - public async Task LoadImageAsync(FormsImageSource imagesource, CancellationToken cancellationToken = default) + public async Task LoadImageAsync(FormsImageSource imagesource, CancellationToken cancellationToken = default) { var appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var fileInfo = await LoadInternal(imagesource, 1, appdata); - BitmapImage bitmap = null; + BitmapImage? bitmap = null; try { await semaphore.WaitAsync(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/Popup.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/Popup.shared.cs index 0217ff2e1..452c9c677 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/Popup.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/Popup.shared.cs @@ -1,4 +1,5 @@ -using Xamarin.Forms; +using System; +using Xamarin.Forms; namespace Xamarin.CommunityToolkit.UI.Views.WindowsSpecific { @@ -7,10 +8,10 @@ public static class Popup public static readonly BindableProperty BorderColorProperty = BindableProperty.Create( "BorderColor", typeof(Color), typeof(Views.Popup), default(Color)); - public static void SetBorderColor(BindableObject element, Color color) => - element.SetValue(BorderColorProperty, color); + public static void SetBorderColor(BindableObject? element, Color color) => + element?.SetValue(BorderColorProperty, color); - public static Color GetBorderColor(BindableObject element) => - (Color)element.GetValue(BorderColorProperty); + public static Color GetBorderColor(BindableObject? element) => + (Color)(element?.GetValue(BorderColorProperty) ?? throw new NullReferenceException()); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/PopupRenderer.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/PopupRenderer.uwp.cs index ef2b602ac..00d982d86 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/PopupRenderer.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/UWP/PopupRenderer.uwp.cs @@ -19,20 +19,20 @@ public class PopupRenderer : Flyout, IVisualElementRenderer const double defaultBorderThickness = 2; const double defaultSize = 600; bool isDisposed = false; - XamlStyle flyoutStyle; - XamlStyle panelStyle; + XamlStyle? flyoutStyle; + XamlStyle? panelStyle; - public BasePopup Element { get; private set; } + public BasePopup? Element { get; private set; } - internal ViewToRendererConverter.WrapperControl Control { get; private set; } + internal ViewToRendererConverter.WrapperControl? Control { get; private set; } - FrameworkElement IVisualElementRenderer.ContainerElement => null; + FrameworkElement? IVisualElementRenderer.ContainerElement => null; - VisualElement IVisualElementRenderer.Element => Element; + VisualElement? IVisualElementRenderer.Element => Element; - public event EventHandler ElementChanged; + public event EventHandler? ElementChanged; - public event EventHandler ElementPropertyChanged; + public event EventHandler? ElementPropertyChanged; public PopupRenderer() { @@ -43,7 +43,7 @@ void IVisualElementRenderer.SetElement(VisualElement element) if (element == null) throw new ArgumentNullException(nameof(element)); - if (!(element is BasePopup popup)) + if (element is not BasePopup popup) throw new ArgumentNullException("Element is not of type " + typeof(BasePopup), nameof(element)); var oldElement = Element; @@ -55,14 +55,14 @@ void IVisualElementRenderer.SetElement(VisualElement element) element.PropertyChanged += OnElementPropertyChanged; - OnElementChanged(new ElementChangedEventArgs(oldElement, Element)); + OnElementChanged(new ElementChangedEventArgs(oldElement, Element)); } void CreateControl() { - if (Control == null) + if (Control == null && Element != null) { - Control = new Xamarin.CommunityToolkit.UI.Views.ViewToRendererConverter.WrapperControl(Element.Content); + Control = new ViewToRendererConverter.WrapperControl(Element.Content); Content = Control; } } @@ -73,7 +73,7 @@ void InitializeStyles() panelStyle = new XamlStyle { TargetType = typeof(Panel) }; } - protected virtual void OnElementChanged(ElementChangedEventArgs e) + protected virtual void OnElementChanged(ElementChangedEventArgs e) { if (e.NewElement != null && !isDisposed) { @@ -110,14 +110,18 @@ void ConfigureControl() void SetEvents() { - if (Element.IsLightDismissEnabled) + if (Element?.IsLightDismissEnabled is true) Closing += OnClosing; - Element.Dismissed += OnDismissed; + if (Element != null) + Element.Dismissed += OnDismissed; } void SetSize() { + _ = Element ?? throw new NullReferenceException(); + _ = Control ?? throw new NullReferenceException(); + _ = flyoutStyle ?? throw new NullReferenceException(); var standardSize = new Size { Width = defaultSize, Height = defaultSize / 2 }; var currentSize = Element.Size != default(Size) ? Element.Size : standardSize; @@ -133,15 +137,19 @@ void SetSize() void SetLayout() { LightDismissOverlayMode = LightDismissOverlayMode.On; - SetDialogPosition(Element.VerticalOptions, Element.HorizontalOptions); + + if (Element != null) + SetDialogPosition(Element.VerticalOptions, Element.HorizontalOptions); } void SetBorderColor() { + _ = flyoutStyle ?? throw new NullReferenceException(); + flyoutStyle.Setters.Add(new Windows.UI.Xaml.Setter(FlyoutPresenter.PaddingProperty, 0)); flyoutStyle.Setters.Add(new Windows.UI.Xaml.Setter(FlyoutPresenter.BorderThicknessProperty, new UWPThickness(defaultBorderThickness))); - var borderColor = Views.WindowsSpecific.Popup.GetBorderColor(Element); + var borderColor = WindowsSpecific.Popup.GetBorderColor(Element); if (borderColor == default(Color)) flyoutStyle.Setters.Add(new Windows.UI.Xaml.Setter(FlyoutPresenter.BorderBrushProperty, Color.FromHex("#2e6da0").ToWindowsColor())); else @@ -150,6 +158,10 @@ void SetBorderColor() void SetColor() { + _ = Element ?? throw new NullReferenceException(); + _ = panelStyle ?? throw new NullReferenceException(); + _ = flyoutStyle ?? throw new NullReferenceException(); + if (Element.Content.BackgroundColor == default(Color)) panelStyle.Setters.Add(new Windows.UI.Xaml.Setter(Panel.BackgroundProperty, Element.Color.ToWindowsColor())); @@ -163,13 +175,14 @@ void SetColor() void ApplyStyles() { + _ = Control ?? throw new NullReferenceException(); Control.Style = panelStyle; FlyoutPresenterStyle = flyoutStyle; } void Show() { - if (Element.Anchor != null) + if (Element?.Anchor != null) { var anchor = Platform.GetRenderer(Element.Anchor).ContainerElement; FlyoutBase.SetAttachedFlyout(anchor, this); @@ -177,12 +190,12 @@ void Show() } else { - var frameworkElement = Platform.GetRenderer(Element.Parent as VisualElement).ContainerElement; + var frameworkElement = Platform.GetRenderer(Element?.Parent as VisualElement)?.ContainerElement; FlyoutBase.SetAttachedFlyout(frameworkElement, this); FlyoutBase.ShowAttachedFlyout(frameworkElement); } - Element.OnOpened(); + Element?.OnOpened(); } void SetDialogPosition(LayoutOptions verticalOptions, LayoutOptions horizontalOptions) @@ -203,7 +216,7 @@ void SetDialogPosition(LayoutOptions verticalOptions, LayoutOptions horizontalOp Placement = FlyoutPlacementMode.BottomEdgeAlignedLeft; else if (IsLeft()) Placement = FlyoutPlacementMode.Left; - else if (Element.Anchor == null) + else if (Element?.Anchor == null) Placement = FlyoutPlacementMode.Full; else Placement = FlyoutPlacementMode.Top; @@ -230,7 +243,7 @@ SizeRequest IVisualElementRenderer.GetDesiredSize(double widthConstraint, double return new SizeRequest(size); } - UIElement IVisualElementRenderer.GetNativeElement() => Control; + UIElement? IVisualElementRenderer.GetNativeElement() => Control; void OnDismissed(object sender, PopupDismissedEventArgs e) { @@ -239,7 +252,7 @@ void OnDismissed(object sender, PopupDismissedEventArgs e) void OnClosing(object sender, object e) { - if (IsOpen && Element.IsLightDismissEnabled) + if (IsOpen && Element?.IsLightDismissEnabled is true) Element.LightDismiss(); } @@ -253,10 +266,13 @@ protected virtual void Dispose(bool disposing) { if (!isDisposed && disposing) { - Element.Dismissed -= OnDismissed; - Element = null; + if (Element != null) + Element.Dismissed -= OnDismissed; + + if (Control != null) + Control.CleanUp(); - Control.CleanUp(); + Element = null; Control = null; Closed -= OnClosing; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs index 716cf6b92..8d75f9c01 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Shield.shared.cs @@ -342,7 +342,7 @@ void UpdateIsEnabled() GestureRecognizers.Clear(); } - void OnCloseButtonTapped(object sender, EventArgs e) + void OnCloseButtonTapped(object? sender, EventArgs e) { Tapped?.Invoke(this, EventArgs.Empty); Command?.Execute(CommandParameter); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs index 3b89e4165..d9c4ce28c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/SideMenuView/SideMenuView.shared.cs @@ -147,7 +147,7 @@ public static bool GetMenuGestureEnabled(BindableObject bindable) public static void SetMenuGestureEnabled(BindableObject bindable, bool value) => bindable.SetValue(MenuGestureEnabledProperty, value); - internal void OnPanUpdated(object sender, PanUpdatedEventArgs e) + internal void OnPanUpdated(object? sender, PanUpdatedEventArgs e) { var shift = e.TotalX; var verticalShift = e.TotalY; @@ -507,7 +507,7 @@ void CleanTimeShiftItems() } } - void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + void OnChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { HandleChildren(e.OldItems, RemoveChild); HandleChildren(e.NewItems, AddChild); @@ -561,7 +561,7 @@ void RemoveChild(View view) inactiveMenu = null; } - void OnLayoutChanged(object sender, EventArgs e) + void OnLayoutChanged(object? sender, EventArgs e) { if (mainView == null) return; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/SnackBarLayout.uwp.wpf.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/SnackBarLayout.uwp.wpf.cs index c9280f9a7..1d6c43371 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/SnackBarLayout.uwp.wpf.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/Helpers/SnackBarLayout.uwp.wpf.cs @@ -72,7 +72,8 @@ public SnackBarLayout(SnackBarOptions options) Command = new Forms.Command(async () => { OnSnackBarActionExecuted?.Invoke(); - await action.Action(); + if (action.Action != null) + await action.Action(); }), Padding = new Thickness(action.Padding.Left, action.Padding.Top, @@ -101,6 +102,6 @@ public SnackBarLayout(SnackBarOptions options) } } - public Action OnSnackBarActionExecuted; + public Action? OnSnackBarActionExecuted; } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.gtk.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.gtk.cs index 47387c01f..62f50c825 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.gtk.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.gtk.cs @@ -1,4 +1,5 @@ -using System.Timers; +using System.Linq; +using System.Timers; using Gtk; using Pango; using Xamarin.CommunityToolkit.UI.Views.Options; @@ -10,24 +11,27 @@ namespace Xamarin.CommunityToolkit.UI.Views { class SnackBar { - Timer snackBarTimer; + Timer? snackBarTimer; public void Show(Page page, SnackBarOptions arguments) { var mainWindow = (Platform.GetRenderer(page).Container.Child as Forms.Platform.GTK.Controls.Page)?.Children[0] as VBox; var snackBarLayout = GetSnackBarLayout(mainWindow, arguments); + AddSnackBarContainer(mainWindow, snackBarLayout); + snackBarTimer = new Timer(arguments.Duration.TotalMilliseconds); snackBarTimer.Elapsed += (sender, e) => { - mainWindow.Remove(snackBarLayout); + mainWindow?.Remove(snackBarLayout); snackBarTimer.Stop(); arguments.SetResult(false); }; + snackBarTimer.Start(); } - HBox GetSnackBarLayout(Container container, SnackBarOptions arguments) + HBox GetSnackBarLayout(Container? container, SnackBarOptions arguments) { var snackBarLayout = new HBox(); snackBarLayout.ModifyBg(StateType.Normal, arguments.BackgroundColor.ToGtkColor()); @@ -51,10 +55,13 @@ HBox GetSnackBarLayout(Container container, SnackBarOptions arguments) button.Clicked += async (sender, e) => { - snackBarTimer.Stop(); - await action.Action(); + snackBarTimer?.Stop(); + + if (action.Action != null) + await action.Action(); + arguments.SetResult(true); - container.Remove(snackBarLayout); + container?.Remove(snackBarLayout); }; snackBarLayout.Add(button); @@ -64,20 +71,20 @@ HBox GetSnackBarLayout(Container container, SnackBarOptions arguments) return snackBarLayout; } - void AddSnackBarContainer(Container mainWindow, Widget snackBarLayout) + void AddSnackBarContainer(Container? mainWindow, Widget snackBarLayout) { - var children = mainWindow.Children; - foreach (var child in mainWindow.Children) + var children = mainWindow?.Children ?? Enumerable.Empty(); + foreach (var child in children) { - mainWindow.Remove(child); + mainWindow?.Remove(child); } foreach (var child in children) { - mainWindow.Add(child); + mainWindow?.Add(child); } - mainWindow.Add(snackBarLayout); + mainWindow?.Add(snackBarLayout); snackBarLayout.ShowAll(); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.uwp.cs index 83515a45e..b1218de27 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.uwp.cs @@ -10,9 +10,9 @@ namespace Xamarin.CommunityToolkit.UI.Views { class SnackBar { - DispatcherTimer snackBarTimer; + DispatcherTimer? snackBarTimer; - T FindVisualChildByName(DependencyObject parent, string name) where T : DependencyObject + T? FindVisualChildByName(DependencyObject parent, string name) where T : DependencyObject { var childrenCount = VisualTreeHelper.GetChildrenCount(parent); @@ -38,7 +38,7 @@ internal void Show(Forms.Page page, SnackBarOptions arguments) { var snackBarLayout = new SnackBarLayout(arguments); var pageControl = Platform.GetRenderer(page).ContainerElement.Parent; - var grid = FindVisualChildByName(pageControl, "BottomCommandBarArea").Parent as Grid; + var grid = (Grid)(FindVisualChildByName(pageControl, "BottomCommandBarArea")?.Parent ?? throw new NullReferenceException()); var snackBarRow = new RowDefinition() { Height = GridLength.Auto }; snackBarTimer = new DispatcherTimer { Interval = arguments.Duration }; snackBarTimer.Tick += (sender, e) => diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.wpf.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.wpf.cs index 464dc6659..9a40be781 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.wpf.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Snackbar/SnackBar.wpf.cs @@ -9,7 +9,7 @@ namespace Xamarin.CommunityToolkit.UI.Views { class SnackBar { - Timer snackBarTimer; + Timer? snackBarTimer; internal void Show(Page page, SnackBarOptions arguments) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/ViewToRendererConverter.uwp.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/ViewToRendererConverter.uwp.cs index d55bb8d81..d9d30c0b9 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/ViewToRendererConverter.uwp.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/ViewToRendererConverter.uwp.cs @@ -14,22 +14,14 @@ public class ViewToRendererConverter // This is used in the PopupRenderer.uwp.cs internal class WrapperControl : Panel { - readonly View _view; + readonly View view; FrameworkElement FrameworkElement { get; } - internal void CleanUp() - { - _view?.Cleanup(); - - if (_view != null) - _view.MeasureInvalidated -= OnMeasureInvalidated; - } - public WrapperControl(View view) { - _view = view; - _view.MeasureInvalidated += OnMeasureInvalidated; + this.view = view; + this.view.MeasureInvalidated += OnMeasureInvalidated; var renderer = Platform.CreateRenderer(view); Platform.SetRenderer(view, renderer); @@ -38,17 +30,20 @@ public WrapperControl(View view) Children.Add(renderer.ContainerElement); // make sure we re-measure once the template is applied - if (FrameworkElement != null) + FrameworkElement.Loaded += (sender, args) => { - FrameworkElement.Loaded += (sender, args) => - { - // If the view is a layout (stacklayout, grid, etc) we need to trigger a layout pass - // with all the controls in a consistent native state (i.e., loaded) so they'll actually - // have Bounds set - (_view as Layout)?.ForceLayout(); - InvalidateMeasure(); - }; - } + // If the view is a layout (stacklayout, grid, etc) we need to trigger a layout pass + // with all the controls in a consistent native state (i.e., loaded) so they'll actually + // have Bounds set + (this.view as Layout)?.ForceLayout(); + InvalidateMeasure(); + }; + } + + internal void CleanUp() + { + view.Cleanup(); + view.MeasureInvalidated -= OnMeasureInvalidated; } void OnMeasureInvalidated(object sender, EventArgs e) @@ -58,10 +53,10 @@ void OnMeasureInvalidated(object sender, EventArgs e) protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Size finalSize) { - _view.IsInNativeLayout = true; - Layout.LayoutChildIntoBoundingRegion(_view, new Rectangle(0, 0, finalSize.Width, finalSize.Height)); + view.IsInNativeLayout = true; + Layout.LayoutChildIntoBoundingRegion(view, new Rectangle(0, 0, finalSize.Width, finalSize.Height)); - if (_view.Width <= 0 || _view.Height <= 0) + if (view.Width <= 0 || view.Height <= 0) { // Hide Panel when size _view is empty. // It is necessary that this element does not overlap other elements when it should be hidden. @@ -70,16 +65,16 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si else { Opacity = 1; - FrameworkElement?.Arrange(new WRect(_view.X, _view.Y, _view.Width, _view.Height)); + FrameworkElement?.Arrange(new WRect(view.X, view.Y, view.Width, view.Height)); } - _view.IsInNativeLayout = false; + view.IsInNativeLayout = false; return finalSize; } protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize) { - var request = _view.Measure(availableSize.Width, availableSize.Height, MeasureFlags.IncludeMargins).Request; + var request = view.Measure(availableSize.Width, availableSize.Height, MeasureFlags.IncludeMargins).Request; if (request.Height < 0) { @@ -87,7 +82,7 @@ protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Si } Windows.Foundation.Size result; - if (_view.HorizontalOptions.Alignment == LayoutAlignment.Fill && !double.IsInfinity(availableSize.Width) && availableSize.Width != 0) + if (view.HorizontalOptions.Alignment == LayoutAlignment.Fill && !double.IsInfinity(availableSize.Width) && availableSize.Width != 0) { result = new Windows.Foundation.Size(availableSize.Width, request.Height); } From 96b9cc6fc968ef4b2cd3a3ebe98e0e24d427c2fb Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 17:25:42 -0800 Subject: [PATCH 09/13] Update AppResources.Designer.cs --- .../XCT.Sample/Resx/AppResources.Designer.cs | 62 +++++-------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/samples/XCT.Sample/Resx/AppResources.Designer.cs b/samples/XCT.Sample/Resx/AppResources.Designer.cs index 150cb2cf6..2f28eebc9 100644 --- a/samples/XCT.Sample/Resx/AppResources.Designer.cs +++ b/samples/XCT.Sample/Resx/AppResources.Designer.cs @@ -10,48 +10,35 @@ namespace Xamarin.CommunityToolkit.Sample.Resx { using System; + using System.Reflection; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class AppResources { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal AppResources() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xamarin.CommunityToolkit.Sample.Resx.AppResources", typeof(AppResources).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Xamarin.CommunityToolkit.Sample.Resx.AppResources", typeof(AppResources).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,45 +47,30 @@ public class AppResources { } } - /// - /// Looks up a localized string similar to Change language below, hit Save and see the texts in this page change. This will not affect the rest of the application, it just serves as a demo.. - /// public static string ChangeLanguage { get { return ResourceManager.GetString("ChangeLanguage", resourceCulture); } } - /// - /// Looks up a localized string similar to English. - /// public static string English { get { return ResourceManager.GetString("English", resourceCulture); } } - /// - /// Looks up a localized string similar to Save. - /// - public static string Save { + public static string Spanish { get { - return ResourceManager.GetString("Save", resourceCulture); + return ResourceManager.GetString("Spanish", resourceCulture); } } - /// - /// Looks up a localized string similar to Spanish. - /// - public static string Spanish { + public static string Save { get { - return ResourceManager.GetString("Spanish", resourceCulture); + return ResourceManager.GetString("Save", resourceCulture); } } - /// - /// Looks up a localized string similar to App version: {0}. - /// public static string Version { get { return ResourceManager.GetString("Version", resourceCulture); From c9d0a46a18f750d8a07ad0756943d9bda1b0a4e7 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 17:26:15 -0800 Subject: [PATCH 10/13] Handle Nullability --- .../IndexToArrayItemConverter.shared.cs | 6 +- .../Android/CameraFragment.android.cs | 273 ++++++++++-------- .../Android/CameraViewRenderer.android.cs | 60 ++-- .../Android/MotionEventHelper.android.cs | 2 +- 4 files changed, 189 insertions(+), 152 deletions(-) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs index 3fd9a0e24..fe12beb60 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs @@ -20,10 +20,10 @@ public class IndexToArrayItemConverter : ValueConverterExtension, IValueConverte /// The item from the array that corresponds to passed index. public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (!(value is int index)) + if (value is not int index) throw new ArgumentException("Value is not a valid integer", nameof(value)); - if (!(parameter is Array array)) + if (parameter is not Array array) throw new ArgumentException("Parameter is not a valid array", nameof(parameter)); if (index < 0 || index >= array.Length) @@ -42,7 +42,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// The index of the item from the array. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if (!(parameter is Array array)) + if (parameter is not Array array) throw new ArgumentException("Parameter is not a valid array", nameof(parameter)); for (var i = 0; i < array.Length; i++) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs index 2add86c53..e83bb3cc5 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs @@ -50,16 +50,19 @@ class CameraFragment : Fragment, TextureView.ISurfaceTextureListener // Max preview height that is guaranteed by Camera2 API const int maxPrevieWidth = 1920; - CameraDevice device; - CaptureRequest.Builder sessionBuilder; - CameraCaptureSession session; + readonly Java.Util.Concurrent.Semaphore captureSessionOpenCloseLock = new Java.Util.Concurrent.Semaphore(1); + readonly MediaActionSound mediaSound = new MediaActionSound(); - AutoFitTextureView texture; - ImageReader photoReader; - MediaRecorder mediaRecorder; + CameraDevice? device; + CaptureRequest.Builder? sessionBuilder; + CameraCaptureSession? session; + + AutoFitTextureView? texture; + ImageReader? photoReader; + MediaRecorder? mediaRecorder; bool audioPermissionsGranted; bool cameraPermissionsGranted; - ASize previewSize, videoSize, photoSize; + ASize? previewSize, videoSize, photoSize; int sensorOrientation; LensFacing cameraType; @@ -68,34 +71,21 @@ class CameraFragment : Fragment, TextureView.ISurfaceTextureListener bool stabilizationSupported; bool repeatingIsRunning; FlashMode flashMode; - string cameraId; - string videoFile; - Java.Util.Concurrent.Semaphore captureSessionOpenCloseLock = new Java.Util.Concurrent.Semaphore(1); - CameraTemplate cameraTemplate; - HandlerThread backgroundThread; + string? cameraId; + string videoFile = string.Empty; + CameraTemplate? cameraTemplate; + HandlerThread? backgroundThread; Handler? backgroundHandler = null; float zoom = 1; - bool ZoomSupported => maxDigitalZoom != 0; - float maxDigitalZoom; - Rect activeRect; - - public bool IsRecordingVideo { get; set; } - - bool UseSystemSound { get; set; } + Rect? activeRect; - CameraManager manager; + CameraManager? manager; - CameraManager Manager => manager ??= (CameraManager)Context.GetSystemService(Context.CameraService); - - MediaActionSound mediaSound; - - MediaActionSound MediaSound => mediaSound ??= new MediaActionSound(); - - TaskCompletionSource initTaskSource; - TaskCompletionSource permissionsRequested; + TaskCompletionSource? initTaskSource; + TaskCompletionSource? permissionsRequested; public CameraFragment() { @@ -122,14 +112,22 @@ bool Available get => Element?.IsAvailable ?? false; set { - if (Element?.IsAvailable != value) + if (Element != null && Element.IsAvailable != value) Element.IsAvailable = value; } } - public CameraView Element { get; set; } + public bool IsRecordingVideo { get; set; } + + bool UseSystemSound { get; set; } + + public CameraView? Element { get; set; } - public override AView OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) => + CameraManager Manager => manager ??= (CameraManager)(Context.GetSystemService(Context.CameraService) ?? throw new NullReferenceException()); + + bool ZoomSupported => maxDigitalZoom != 0; + + public override AView? OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) => inflater.Inflate(Resource.Layout.CameraFragment, null); public override void OnViewCreated(AView view, Bundle savedInstanceState) => @@ -162,7 +160,9 @@ void StartBackgroundThread() { backgroundThread = new HandlerThread("CameraBackground"); backgroundThread.Start(); +#pragma warning disable CS8604 // Possible null reference argument. backgroundHandler = new Handler(backgroundThread.Looper); +#pragma warning restore CS8604 // Possible null reference argument. } void StopBackgroundThread() @@ -201,39 +201,44 @@ public async Task RetrieveCameraDevice(bool force = false) IsBusy = true; cameraId = GetCameraId(); - if (string.IsNullOrEmpty(cameraId)) + if (cameraId == null || string.IsNullOrEmpty(cameraId)) { IsBusy = false; captureSessionOpenCloseLock.Release(); // _texture.ClearCanvas(Element.BackgroundColor.ToAndroid()); // HANG after select valid camera... - Element.RaiseMediaCaptureFailed($"No {Element.CameraOptions} camera found"); + Element?.RaiseMediaCaptureFailed($"No {Element.CameraOptions} camera found"); } else { try { var characteristics = Manager.GetCameraCharacteristics(cameraId); - var map = (StreamConfigurationMap)characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap); + var map = (StreamConfigurationMap)(characteristics?.Get(CameraCharacteristics.ScalerStreamConfigurationMap) ?? throw new NullReferenceException()); flashSupported = characteristics.Get(CameraCharacteristics.FlashInfoAvailable) == Java.Lang.Boolean.True; stabilizationSupported = false; var stabilizationModes = characteristics.Get(CameraCharacteristics.ControlAvailableVideoStabilizationModes); - if (stabilizationModes != null) + + if (stabilizationModes is IEnumerable modes) { - var modes = (int[])stabilizationModes; foreach (var mode in modes) { if (mode == (int)ControlVideoStabilizationMode.On) stabilizationSupported = true; } } - Element.MaxZoom = maxDigitalZoom = (float)characteristics.Get(CameraCharacteristics.ScalerAvailableMaxDigitalZoom); - activeRect = (Rect)characteristics.Get(CameraCharacteristics.SensorInfoActiveArraySize); - sensorOrientation = (int)characteristics.Get(CameraCharacteristics.SensorOrientation); + + if (Element != null) + Element.MaxZoom = maxDigitalZoom = (float)(characteristics.Get(CameraCharacteristics.ScalerAvailableMaxDigitalZoom) ?? throw new NullReferenceException()); + + activeRect = (Rect)(characteristics.Get(CameraCharacteristics.SensorInfoActiveArraySize) ?? throw new NullReferenceException()); + sensorOrientation = (int)(characteristics.Get(CameraCharacteristics.SensorOrientation) ?? throw new NullReferenceException()); var displaySize = new APoint(); - Activity.WindowManager.DefaultDisplay.GetSize(displaySize); + Activity.WindowManager?.DefaultDisplay?.GetSize(displaySize); + + _ = texture ?? throw new NullReferenceException(); var rotatedViewWidth = texture.Width; var rotatedViewHeight = texture.Height; var maxPreviewWidth = displaySize.X; @@ -260,20 +265,20 @@ public async Task RetrieveCameraDevice(bool force = false) photoSize = GetMaxSize(map.GetOutputSizes((int)ImageFormatType.Jpeg)); videoSize = GetMaxSize(map.GetOutputSizes(Class.FromType(typeof(MediaRecorder)))); previewSize = ChooseOptimalSize( - map.GetOutputSizes(Class.FromType(typeof(SurfaceTexture))), + map.GetOutputSizes(Class.FromType(typeof(SurfaceTexture))) ?? throw new NullReferenceException(), rotatedViewWidth, rotatedViewHeight, maxPreviewWidth, maxPreviewHeight, cameraTemplate == CameraTemplate.Record ? videoSize : photoSize); - cameraType = (LensFacing)(int)characteristics.Get(CameraCharacteristics.LensFacing); + cameraType = (LensFacing)(int)(characteristics.Get(CameraCharacteristics.LensFacing) ?? throw new NullReferenceException()); - if (Resources.Configuration.Orientation == AOrientation.Landscape) + if (Resources.Configuration?.Orientation == AOrientation.Landscape) texture.SetAspectRatio(previewSize.Width, previewSize.Height); else texture.SetAspectRatio(previewSize.Height, previewSize.Width); - initTaskSource = new TaskCompletionSource(); + initTaskSource = new TaskCompletionSource(); Manager.OpenCamera( cameraId, @@ -319,16 +324,11 @@ public async Task RetrieveCameraDevice(bool force = false) public void UpdateCaptureOptions() { - switch (Element.CaptureMode) + cameraTemplate = Element?.CaptureMode switch { - default: - case CameraCaptureMode.Photo: - cameraTemplate = CameraTemplate.Preview; - break; - case CameraCaptureMode.Video: - cameraTemplate = CameraTemplate.Record; - break; - } + CameraCaptureMode.Video => CameraTemplate.Record, + _ => CameraTemplate.Preview, + }; } public void TakePhoto() @@ -338,12 +338,12 @@ public void TakePhoto() try { - if (device != null) + if (device != null && session != null && sessionBuilder != null && photoReader?.Surface != null) { session.StopRepeating(); repeatingIsRunning = false; sessionBuilder.AddTarget(photoReader.Surface); - sessionBuilder.Set(CaptureRequest.FlashMode, (int)flashMode); + sessionBuilder.Set(CaptureRequest.FlashMode ?? throw new NullReferenceException(), (int)flashMode); /*sessionBuilder.Set(CaptureRequest.JpegOrientation, GetJpegOrientation());*/ session.Capture(sessionBuilder.Build(), null, null); sessionBuilder.RemoveTarget(photoReader.Surface); @@ -356,7 +356,7 @@ public void TakePhoto() } } - void OnPhoto(object sender, Tuple tuple) => + void OnPhoto(object sender, Tuple tuple) => Device.BeginInvokeOnMainThread(() => Element?.RaiseMediaCaptured(new MediaCapturedEventArgs(tuple.Item1, tuple.Item2, tuple.Item3))); @@ -368,12 +368,13 @@ void SetupImageReader() { DisposeImageReader(); + _ = photoSize ?? throw new NullReferenceException(); photoReader = ImageReader.NewInstance(photoSize.Width, photoSize.Height, ImageFormatType.Jpeg, maxImages: 1); var readerListener = new ImageAvailableListener(); readerListener.Photo += (_, bytes) => { - string filePath = null; + string? filePath = null; // Calculate image rotation based on sensor and device orientation var rotation = GetRotationCompensation(); @@ -389,21 +390,25 @@ void SetupImageReader() OnPhoto(this, new Tuple(filePath, Element.SavePhotoToFile ? null : bytes));*/ Sound(MediaActionSoundType.ShutterClick); - OnPhoto(this, new Tuple(filePath, bytes, rotation)); + OnPhoto(this, new Tuple(filePath, bytes, rotation)); }; photoReader.SetOnImageAvailableListener(readerListener, backgroundHandler); } - private int GetRotationCompensation() + int GetRotationCompensation() { + _ = cameraId ?? throw new NullReferenceException(); + var rotationCompensation = GetDisplayRotationDegrees(); - var c = Manager.GetCameraCharacteristics(cameraId); + var cameraCharacteristics = Manager.GetCameraCharacteristics(cameraId); + // Get the device's sensor orientation. - var sensorOrientation = (int)c.Get(CameraCharacteristics.SensorOrientation); + var sensorOrientation = (int)(cameraCharacteristics.Get(CameraCharacteristics.SensorOrientation) ?? throw new NullReferenceException()); + var lensFacing = (Integer)(cameraCharacteristics.Get(CameraCharacteristics.LensFacing) ?? throw new NullReferenceException()); - var facingFront = ((Integer)c.Get(CameraCharacteristics.LensFacing)).IntValue() == (int)LensFacing.Front; - if (facingFront) + var isfacingFront = lensFacing.IntValue() == (int)LensFacing.Front; + if (isfacingFront) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } @@ -431,6 +436,8 @@ void SetupMediaRecorder(Surface previewSurface) mediaRecorder.SetProfile(profile); else { + _ = videoSize ?? throw new NullReferenceException(); + mediaRecorder.SetOutputFormat(OutputFormat.Mpeg4); mediaRecorder.SetVideoEncodingBitRate(10000000); mediaRecorder.SetVideoFrameRate(30); @@ -448,7 +455,7 @@ void SetupMediaRecorder(Surface previewSurface) mediaRecorder.Prepare(); } - CamcorderProfile GetCamcoderProfile() + CamcorderProfile? GetCamcoderProfile() { var cameraId = Convert.ToInt32(this.cameraId); if (CamcorderProfile.HasProfile(cameraId, CamcorderQuality.HighSpeed1080p)) @@ -530,7 +537,10 @@ async Task PrepareSession() { CloseSession(); - sessionBuilder = device.CreateCaptureRequest(cameraTemplate); + if (mediaRecorder == null || device == null || cameraTemplate is not CameraTemplate cameraTemplate_nonNull) + throw new NullReferenceException(); + + sessionBuilder = device.CreateCaptureRequest(cameraTemplate_nonNull); SetFlash(); SetVideoStabilization(); @@ -539,32 +549,38 @@ async Task PrepareSession() var surfaces = new List(); // preview texture - if (texture.IsAvailable && previewSize != null) + if (previewSize != null && texture?.IsAvailable is true) { - var texture = this.texture.SurfaceTexture; + var texture = this.texture.SurfaceTexture ?? throw new NullReferenceException(); texture.SetDefaultBufferSize(previewSize.Width, previewSize.Height); var previewSurface = new Surface(texture); surfaces.Add(previewSurface); sessionBuilder.AddTarget(previewSurface); // video mode - if (cameraTemplate == CameraTemplate.Record) + if (cameraTemplate is CameraTemplate.Record) { SetupMediaRecorder(previewSurface); var mediaSurface = mediaRecorder.Surface; - surfaces.Add(mediaSurface); - sessionBuilder.AddTarget(mediaSurface); + + if (mediaSurface != null) + { + surfaces.Add(mediaSurface); + sessionBuilder.AddTarget(mediaSurface); + } } // photo mode else { SetupImageReader(); - surfaces.Add(photoReader.Surface); + + if (photoReader?.Surface != null) + surfaces.Add(photoReader.Surface); } } - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); device.CreateCaptureSession( surfaces, @@ -573,7 +589,7 @@ async Task PrepareSession() OnConfigureFailedAction = captureSession => { tcs.SetResult(null); - Element.RaiseMediaCaptureFailed("Failed to create captire sesstion"); + Element?.RaiseMediaCaptureFailed("Failed to create captire sesstion"); }, OnConfiguredAction = captureSession => tcs.SetResult(captureSession) }, @@ -631,10 +647,10 @@ public void UpdateRepeatingRequest() if (repeatingIsRunning) session.StopRepeating(); - sessionBuilder.Set(CaptureRequest.ControlMode, (int)ControlMode.Auto); - sessionBuilder.Set(CaptureRequest.ControlAeMode, (int)ControlAEMode.On); + sessionBuilder.Set(CaptureRequest.ControlMode ?? throw new NullReferenceException(), (int)ControlMode.Auto); + sessionBuilder.Set(CaptureRequest.ControlAeMode ?? throw new NullReferenceException(), (int)ControlAEMode.On); if (cameraTemplate == CameraTemplate.Record) - sessionBuilder.Set(CaptureRequest.FlashMode, (int)flashMode); + sessionBuilder.Set(CaptureRequest.FlashMode ?? throw new NullReferenceException(), (int)flashMode); session.SetRepeatingRequest(sessionBuilder.Build(), listener: null, backgroundHandler); repeatingIsRunning = true; @@ -688,17 +704,20 @@ public void CloseDevice() } } - void UpdateBackgroundColor() => - View?.SetBackgroundColor(Element.BackgroundColor.ToAndroid()); + void UpdateBackgroundColor() + { + if (Element != null) + View?.SetBackgroundColor(Element.BackgroundColor.ToAndroid()); + } public void SetFlash() { if (!flashSupported) return; - flashMode = Element.FlashMode switch + flashMode = Element?.FlashMode switch { - CameraFlashMode.Off => FlashMode.Off, + CameraFlashMode.Off or null => FlashMode.Off, CameraFlashMode.Torch => FlashMode.Torch, _ => FlashMode.Single, }; @@ -708,15 +727,17 @@ public void SetVideoStabilization() { if (sessionBuilder == null || !stabilizationSupported) return; - sessionBuilder.Set(CaptureRequest.ControlVideoStabilizationMode, - (int)(Element.VideoStabilization ? ControlVideoStabilizationMode.On : ControlVideoStabilizationMode.Off)); + sessionBuilder.Set(CaptureRequest.ControlVideoStabilizationMode ?? throw new NullReferenceException(), + (int)((Element?.VideoStabilization ?? false) ? ControlVideoStabilizationMode.On : ControlVideoStabilizationMode.Off)); } public void ApplyZoom() { + _ = Element ?? throw new NullReferenceException(); + zoom = (float)System.Math.Max(1f, System.Math.Min(Element.Zoom, maxDigitalZoom)); if (ZoomSupported) - sessionBuilder?.Set(CaptureRequest.ScalerCropRegion, GetZoomRect()); + sessionBuilder?.Set(CaptureRequest.ScalerCropRegion ?? throw new NullReferenceException(), GetZoomRect()); } string? GetCameraId() @@ -777,7 +798,7 @@ async Task RequestCameraPermissions() cameraPermissionsGranted = ContextCompat.CheckSelfPermission(Context, Manifest.Permission.Camera) == Permission.Granted; if (!cameraPermissionsGranted) permissionsToRequest.Add(Manifest.Permission.Camera); - if (Element.CaptureMode == CameraCaptureMode.Video) + if (Element?.CaptureMode == CameraCaptureMode.Video) { audioPermissionsGranted = ContextCompat.CheckSelfPermission(Context, Manifest.Permission.RecordAudio) == Permission.Granted; if (!audioPermissionsGranted) @@ -805,14 +826,14 @@ public override void OnRequestPermissionsResult(int requestCode, string[] permis { cameraPermissionsGranted = grantResults[i] == Permission.Granted; if (!cameraPermissionsGranted) - Element.RaiseMediaCaptureFailed($"No permission to use the camera."); + Element?.RaiseMediaCaptureFailed($"No permission to use the camera."); } else if (permissions[i] == Manifest.Permission.RecordAudio) { audioPermissionsGranted = grantResults[i] == Permission.Granted; if (!audioPermissionsGranted) { - Element.RaiseMediaCaptureFailed($"No permission to record audio."); + Element?.RaiseMediaCaptureFailed($"No permission to record audio."); } } } @@ -869,60 +890,66 @@ string ConstructMediaFilename(string prefix, string extension) { // "To improve user privacy, direct access to shared/external storage devices is deprecated" // Env.GetExternalStoragePublicDirectory(Env.DirectoryDcim).AbsolutePath - var path = Context.GetExternalFilesDir(Env.DirectoryDcim).AbsolutePath; + var path = Context.GetExternalFilesDir(Env.DirectoryDcim)?.AbsolutePath ?? throw new NullReferenceException(); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + var fileName = DateTime.Now.ToString("yyyyddMM_HHmmss"); + if (!string.IsNullOrEmpty(prefix)) fileName = $"{prefix}_{fileName}"; + return System.IO.Path.Combine(path, $"{fileName}.{extension}"); } - Rect GetZoomRect() + Rect? GetZoomRect() { if (activeRect == null) return null; + var width = activeRect.Width(); var heigth = activeRect.Height(); var newWidth = (int)(width / zoom); var newHeight = (int)(heigth / zoom); var x = (width - newWidth) / 2; var y = (heigth - newHeight) / 2; + return new Rect(x, y, x + newWidth, y + newHeight); } - SurfaceOrientation GetDisplayRotation() - => App.Context.GetSystemService(Context.WindowService).JavaCast().DefaultDisplay.Rotation; + SurfaceOrientation? GetDisplayRotation() + => App.Context.GetSystemService(Context.WindowService).JavaCast()?.DefaultDisplay?.Rotation; - int GetDisplayRotationDegrees() => - GetDisplayRotation() switch - { - SurfaceOrientation.Rotation90 => 90, - SurfaceOrientation.Rotation180 => 180, - SurfaceOrientation.Rotation270 => 270, - _ => 0, - }; + int GetDisplayRotationDegrees() => GetDisplayRotation() switch + { + SurfaceOrientation.Rotation90 => 90, + SurfaceOrientation.Rotation180 => 180, + SurfaceOrientation.Rotation270 => 270, + _ => 0, + }; - int GetJpegRotationDegrees() => - GetDisplayRotation() switch - { - SurfaceOrientation.Rotation90 => 0, - SurfaceOrientation.Rotation180 => 270, - SurfaceOrientation.Rotation270 => 180, - _ => 90, - }; + int GetJpegRotationDegrees() => GetDisplayRotation() switch + { + SurfaceOrientation.Rotation90 => 0, + SurfaceOrientation.Rotation180 => 270, + SurfaceOrientation.Rotation270 => 180, + _ => 90, + }; - int GetPreviewOrientation() => - GetDisplayRotation() switch - { - SurfaceOrientation.Rotation90 => 270, - SurfaceOrientation.Rotation180 => 180, - SurfaceOrientation.Rotation270 => 90, - _ => 0, - }; + int GetPreviewOrientation() => GetDisplayRotation() switch + { + SurfaceOrientation.Rotation90 => 270, + SurfaceOrientation.Rotation180 => 180, + SurfaceOrientation.Rotation270 => 90, + _ => 0, + }; - public void ConfigureTransform() => + public void ConfigureTransform() + { + _ = texture ?? throw new NullReferenceException(); ConfigureTransform(texture.Width, texture.Height); + } void ConfigureTransform(int viewWidth, int viewHeight) { @@ -931,7 +958,7 @@ void ConfigureTransform(int viewWidth, int viewHeight) if (texture == null || previewSize == null || activity == null) return; - var rotation = (int)activity.WindowManager.DefaultDisplay.Rotation; + var rotation = (int?)activity.WindowManager?.DefaultDisplay?.Rotation; var matrix = new Matrix(); var viewRect = new RectF(0, 0, viewWidth, viewHeight); var bufferRect = new RectF(0, 0, previewSize.Height, previewSize.Width); @@ -944,7 +971,7 @@ void ConfigureTransform(int viewWidth, int viewHeight) matrix.SetRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.Fill); var scale = System.Math.Max((float)viewHeight / previewSize.Height, (float)viewWidth / previewSize.Width); matrix.PostScale(scale, scale, centerX, centerY); - matrix.PostRotate(90 * (rotation - 2), centerX, centerY); + matrix.PostRotate(90 * (rotation.Value - 2), centerX, centerY); } else if (rotation == (int)SurfaceOrientation.Rotation180) matrix.PostRotate(180, centerX, centerY); @@ -966,11 +993,12 @@ void Sound(MediaActionSoundType soundType) mediaSound.Play(soundType); } - ASize GetMaxSize(ASize[] imageSizes) + ASize GetMaxSize(ASize[]? imageSizes) { - ASize maxSize = null; + ASize? maxSize = null; long maxPixels = 0; - for (var i = 0; i < imageSizes.Length; i++) + + for (var i = 0; i < imageSizes?.Length; i++) { long currentPixels = imageSizes[i].Width * imageSizes[i].Height; if (currentPixels > maxPixels) @@ -979,7 +1007,8 @@ ASize GetMaxSize(ASize[] imageSizes) maxPixels = currentPixels; } } - return maxSize; + + return maxSize ?? throw new NullReferenceException(); } // chooses the smallest one whose width and height are at least as large as the respective requested values @@ -987,8 +1016,10 @@ ASize ChooseOptimalSize(ASize[] choices, int width, int height, int maxWidth, in { var bigEnough = new List(); var notBigEnough = new List(); + var w = aspectRatio.Width; var h = aspectRatio.Height; + foreach (var option in choices) { if (option.Width <= maxWidth && option.Height <= maxHeight && diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs index e8fffa282..c5bdb8e8e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraViewRenderer.android.cs @@ -24,17 +24,19 @@ namespace Xamarin.CommunityToolkit.UI.Views { public class CameraViewRenderer : FrameLayout, IVisualElementRenderer, IViewRenderer { + readonly MotionEventHelper motionEventHelper; + int? defaultLabelFor; bool disposed; - CameraView element; - VisualElementTracker visualElementTracker; - VisualElementRenderer visualElementRenderer; - readonly MotionEventHelper motionEventHelper; - FragmentManager fragmentManager; + CameraView? element; + VisualElementTracker? visualElementTracker; + VisualElementRenderer? visualElementRenderer; + + FragmentManager? fragmentManager; FragmentManager FragmentManager => fragmentManager ??= Context.GetFragmentManager(); - CameraFragment camerafragment; + CameraFragment? camerafragment; public CameraViewRenderer(Context context) : base(context) @@ -43,12 +45,14 @@ public CameraViewRenderer(Context context) visualElementRenderer = new VisualElementRenderer(this); } - public event EventHandler ElementChanged; + public event EventHandler? ElementChanged; - public event EventHandler ElementPropertyChanged; + public event EventHandler? ElementPropertyChanged; async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { + _ = camerafragment ?? throw new NullReferenceException(); + ElementPropertyChanged?.Invoke(this, e); switch (e.PropertyName) @@ -62,7 +66,7 @@ async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) break; case nameof(CameraView.FlashMode): camerafragment.SetFlash(); - if (Element.CaptureMode == CameraCaptureMode.Video) + if (Element?.CaptureMode == CameraCaptureMode.Video) camerafragment.UpdateRepeatingRequest(); break; case nameof(CameraView.Zoom): @@ -71,7 +75,7 @@ async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) break; case nameof(CameraView.VideoStabilization): camerafragment.SetVideoStabilization(); - if (Element.CaptureMode == CameraCaptureMode.Video) + if (Element?.CaptureMode == CameraCaptureMode.Video) camerafragment.UpdateRepeatingRequest(); break; @@ -86,15 +90,16 @@ async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) } } - void OnElementChanged(ElementChangedEventArgs e) + void OnElementChanged(ElementChangedEventArgs e) { - CameraFragment newfragment = null; + CameraFragment? newfragment = null; if (e.OldElement != null) { e.OldElement.PropertyChanged -= OnElementPropertyChanged; e.OldElement.ShutterClicked -= OnShutterClicked; - camerafragment.Dispose(); + camerafragment?.Dispose(); + camerafragment = null; } if (e.NewElement != null) @@ -115,7 +120,7 @@ void OnElementChanged(ElementChangedEventArgs e) ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement)); } - CameraView Element + CameraView? Element { get => element; set @@ -126,7 +131,7 @@ CameraView Element var oldElement = element; element = value; - OnElementChanged(new ElementChangedEventArgs(oldElement, element)); + OnElementChanged(new ElementChangedEventArgs(oldElement, element)); // this is just used to set ID's to the NativeViews along time ago for UITest with Test Cloud // https://discordapp.com/channels/732297728826277939/738043671575920700/747629874709266449 @@ -136,7 +141,7 @@ CameraView Element public override bool OnTouchEvent(MotionEvent? e) { - if (visualElementRenderer.OnTouchEvent(e) || base.OnTouchEvent(e)) + if (visualElementRenderer?.OnTouchEvent(e) is true || base.OnTouchEvent(e)) return true; return motionEventHelper.HandleMotionEvent(Parent, e); @@ -147,7 +152,8 @@ protected override void Dispose(bool disposing) if (disposed) return; - camerafragment.Dispose(); + camerafragment?.Dispose(); + camerafragment = null; disposed = true; @@ -182,25 +188,25 @@ protected override void Dispose(bool disposing) void OnShutterClicked(object sender, EventArgs e) { - switch (Element.CaptureMode) + switch (Element?.CaptureMode) { default: case CameraCaptureMode.Default: case CameraCaptureMode.Photo: - camerafragment.TakePhoto(); + camerafragment?.TakePhoto(); break; case CameraCaptureMode.Video: - if (!camerafragment.IsRecordingVideo) - camerafragment.StartRecord(); + if (camerafragment?.IsRecordingVideo is false) + camerafragment?.StartRecord(); else - camerafragment.StopRecord(); + camerafragment?.StopRecord(); break; } } void IViewRenderer.MeasureExactly() => MeasureExactly(this, Element, Context); - static void MeasureExactly(AView control, VisualElement element, Context context) + static void MeasureExactly(AView control, VisualElement? element, Context? context) { if (control == null || element == null) return; @@ -221,11 +227,11 @@ static void MeasureExactly(AView control, VisualElement element, Context context } #region IVisualElementRenderer - VisualElement IVisualElementRenderer.Element => Element; + VisualElement? IVisualElementRenderer.Element => Element; - ViewGroup IVisualElementRenderer.ViewGroup => null; + ViewGroup? IVisualElementRenderer.ViewGroup => null; - VisualElementTracker IVisualElementRenderer.Tracker => visualElementTracker; + VisualElementTracker? IVisualElementRenderer.Tracker => visualElementTracker; AView IVisualElementRenderer.View => this; @@ -238,7 +244,7 @@ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heigh void IVisualElementRenderer.SetElement(VisualElement element) { - if (!(element is CameraView camera)) + if (element is not CameraView camera) throw new ArgumentException($"{nameof(element)} must be of type {nameof(CameraView)}"); // Performance.Start(out var reference); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs index 2a6db4659..01e96266f 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/MotionEventHelper.android.cs @@ -9,7 +9,7 @@ class MotionEventHelper VisualElement? element; bool isInViewCell; - public bool HandleMotionEvent(IViewParent parent, MotionEvent? motionEvent) + public bool HandleMotionEvent(IViewParent? parent, MotionEvent? motionEvent) { if (isInViewCell || element == null || motionEvent == null || motionEvent.Action == MotionEventActions.Cancel) return false; From eab03b443e8758f1a0af6d41df7b1b902b9b3eca Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 17:59:37 -0800 Subject: [PATCH 11/13] Updated Nullabiltiy --- samples/XCT.Sample/Pages/Base/BasePage.cs | 9 ++++++++- .../Converters/ItemSelectedEventArgsViewModel.cs | 2 +- .../Converters/ItemTappedEventArgsViewModel.cs | 2 +- .../ViewModels/Views/PopupControlViewModel.cs | 2 +- .../CommandFactory_AsyncValueCommand_Tests.cs | 2 ++ .../Behaviors/MaxLengthReachedBehavior.shared.cs | 4 ++-- .../Behaviors/UserStoppedTypingBehavior.shared.cs | 6 +++--- .../Converters/BoolToObjectConverter.shared.cs | 4 ++-- .../ByteArrayToImageSourceConverter.shared.cs | 4 ++-- .../Converters/DateTimeOffsetConverter.shared.cs | 4 ++-- .../Converters/DoubleToIntConverter.shared.cs | 6 +++--- .../Converters/EnumToBoolConverter.shared.cs | 6 +++--- .../Converters/EqualConverter.shared.cs | 4 ++-- .../Converters/IndexToArrayItemConverter.shared.cs | 4 ++-- .../Converters/IntToBoolConverter.shared.cs | 4 ++-- .../Converters/InvertedBoolConverter.shared.cs | 6 +++--- .../Converters/IsNotNullOrEmptyConverter.shared.cs | 4 ++-- .../Converters/IsNullOrEmptyConverter.shared.cs | 4 ++-- .../ItemSelectedEventArgsConverter.shared.cs | 4 ++-- .../ItemTappedEventArgsConverter.shared.cs | 4 ++-- .../ListIsNotNullOrEmptyConverter.shared.cs | 4 ++-- .../Converters/ListIsNullOrEmptyConverter.shared.cs | 4 ++-- .../Converters/ListToStringConverter.shared.cs | 4 ++-- .../Converters/MultiConverter.shared.cs | 6 +++--- .../Converters/NotEqualConverter.shared.cs | 4 ++-- .../Converters/StateToBooleanConverter.shared.cs | 6 +++--- .../Converters/TextCaseConverter.shared.cs | 12 +++++------- .../Converters/TimeSpanToDoubleConverter.shared.cs | 4 ++-- .../Converters/VariableMultiValueConverter.shared.cs | 6 +++--- .../Views/MediaElement/MediaElement.shared.cs | 4 ++-- .../Views/Popup/PopupOfT.shared.cs | 2 +- 31 files changed, 74 insertions(+), 67 deletions(-) diff --git a/samples/XCT.Sample/Pages/Base/BasePage.cs b/samples/XCT.Sample/Pages/Base/BasePage.cs index 8e7a5071f..5d24e0070 100644 --- a/samples/XCT.Sample/Pages/Base/BasePage.cs +++ b/samples/XCT.Sample/Pages/Base/BasePage.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using System.Windows.Input; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.CommunityToolkit.Sample.Models; @@ -9,7 +10,13 @@ namespace Xamarin.CommunityToolkit.Sample.Pages public class BasePage : ContentPage { public BasePage() => - NavigateCommand = CommandFactory.Create(sectionModel => Navigation.PushAsync(PreparePage(sectionModel))); + NavigateCommand = CommandFactory.Create(sectionModel => + { + if (sectionModel != null) + return Navigation.PushAsync(PreparePage(sectionModel)); + + return Task.CompletedTask; + }); public Color DetailColor { get; set; } diff --git a/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs index 6569e2053..101fb04ab 100644 --- a/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs @@ -16,6 +16,6 @@ public class ItemSelectedEventArgsViewModel }; public ICommand ItemSelectedCommand { get; } = - CommandFactory.Create(person => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person.Name, "Cancelf")); + CommandFactory.Create(person => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person?.Name, "Cancel")); } } \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs index 42500cfd7..eedfb6995 100644 --- a/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs @@ -15,7 +15,7 @@ public class ItemTappedEventArgsViewModel }; public ICommand ItemTappedCommand { get; } = - CommandFactory.Create(person => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person.Name, "Cancel")); + CommandFactory.Create(person => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person?.Name, "Cancel")); } public class Person diff --git a/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs b/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs index 85e924594..5a42b7ffd 100644 --- a/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs @@ -35,7 +35,7 @@ async void OnDisplayPopup(Type popupType) { var view = (VisualElement)Activator.CreateInstance(popupType); - if (view is Popup popup) + if (view is Popup popup) { var result = await Navigation.ShowPopupAsync(popup); await Application.Current.MainPage.DisplayAlert("Popup Result", result, "OKAY"); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs index 387663ec4..d03b364b9 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs @@ -118,7 +118,9 @@ public void AsyncValueCommandT_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs index 8dc352dd2..47ef5c83a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/MaxLengthReachedBehavior.shared.cs @@ -21,9 +21,9 @@ public class MaxLengthReachedBehavior : BaseBehavior /// /// Command that is triggered when the value configured in is reached. Both the event and this command are triggered. This is a bindable property. /// - public ICommand Command + public ICommand? Command { - get => (ICommand)GetValue(CommandProperty); + get => (ICommand?)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs index 6a82b6f77..2062125ce 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Behaviors/UserStoppedTypingBehavior.shared.cs @@ -47,16 +47,16 @@ public class UserStoppedTypingBehavior : BaseBehavior /// /// Command that is triggered when the is reached. When is set, it's only triggered when both conditions are met. This is a bindable property. /// - public ICommand Command + public ICommand? Command { - get => (ICommand)GetValue(CommandProperty); + get => (ICommand?)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } /// /// An optional parameter to forward to the . This is a bindable property. /// - public object CommandParameter + public object? CommandParameter { get => GetValue(CommandParameterProperty); set => SetValue(CommandParameterProperty, value); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs index 108b55739..c4b268374 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs @@ -35,7 +35,7 @@ public class BoolToObjectConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// The object assigned to if value equals True, otherwise the value assigned to . - 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 bool result) return result ? TrueObject : FalseObject; @@ -51,7 +51,7 @@ public class BoolToObjectConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// True if value equals , otherwise False. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is TObject result) return result.Equals(TrueObject); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs index 74dbd2898..a374fb4d1 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs @@ -20,7 +20,7 @@ public class ByteArrayToImageSourceConverter : ValueConverterExtension, IValueCo /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An object of type . - public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return null; @@ -39,7 +39,7 @@ public class ByteArrayToImageSourceConverter : ValueConverterExtension, IValueCo /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An object of type . - public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DateTimeOffsetConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DateTimeOffsetConverter.shared.cs index c16ec6331..261be88fc 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DateTimeOffsetConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DateTimeOffsetConverter.shared.cs @@ -17,7 +17,7 @@ public class DateTimeOffsetConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// The value. - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture) => value is DateTimeOffset dateTimeOffset ? dateTimeOffset.DateTime : throw new ArgumentException("Value is not a valid DateTimeOffset", nameof(value)); @@ -30,7 +30,7 @@ public object Convert(object value, Type targetType, object parameter, System.Gl /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented.. /// The value. - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture) => value is DateTime dateTime ? dateTime.Kind switch { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs index 9697ddea0..9a5e37764 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs @@ -24,7 +24,7 @@ public class DoubleToIntConverter : ValueConverterExtension, IValueConverter /// Multiplier (Equals 1 by default). /// The culture to use in the converter. This is not implemented. /// value. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value is double result ? (int)Math.Round(result * GetParameter(parameter)) : throw new ArgumentException("Value is not a valid double", nameof(value)); @@ -37,12 +37,12 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// Denominator (Equals 1 by default). /// The culture to use in the converter. This is not implemented. /// value. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => value is int result ? result / GetParameter(parameter) : throw new ArgumentException("Value is not a valid integer", nameof(value)); - double GetParameter(object parameter) + double GetParameter(object? parameter) => parameter == null ? Ratio : parameter switch diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs index ac7b8c28b..c5e355084 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs @@ -33,9 +33,9 @@ public class EnumToBoolConverter : ValueConverterExtension, IValueConverter /// value not equal to parameter. /// /// If value is not an - 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 Enum enumValue)) + if (value is not Enum enumValue) throw new ArgumentException("The value should be of type Enum", nameof(value)); return TrueValues.Count == 0 @@ -59,7 +59,7 @@ static bool CompareTwoEnums(Enum valueToCheck, object? referenceValue) } /// - 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(); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs index e8af98d33..9c3b0ee3c 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs @@ -18,7 +18,7 @@ public class EqualConverter : ValueConverterExtension, IValueConverter /// The second object to compare. /// The culture to use in the converter. This is not implemented. /// True if and are equal, False if they are not equal. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => (value != null && value.Equals(parameter)) || (value == null && parameter == null); /// @@ -29,7 +29,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs index fe12beb60..4e0138eea 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs @@ -18,7 +18,7 @@ public class IndexToArrayItemConverter : ValueConverterExtension, IValueConverte /// The items array. /// The culture to use in the converter. This is not implemented. /// The item from the array that corresponds to passed index. - 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 not int index) throw new ArgumentException("Value is not a valid integer", nameof(value)); @@ -40,7 +40,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// The items array. /// The culture to use in the converter. This is not implemented. /// The index of the item from the array. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (parameter is not Array array) throw new ArgumentException("Parameter is not a valid array", nameof(parameter)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs index 453df7906..204706624 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs @@ -18,7 +18,7 @@ public class IntToBoolConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// False if the value is 0, otherwise if the value is anything but 0 it returns True. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value is int result ? result != 0 : throw new ArgumentException("Value is not a valid integer", nameof(value)); @@ -31,7 +31,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// 0 if the value is False, otherwise 1 if the value is True. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is bool result) return result ? 1 : 0; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs index 66ff4e97e..887718f63 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs @@ -18,7 +18,7 @@ public class InvertedBoolConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An inverted from the one coming in. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => InverseBool(value); /// @@ -29,7 +29,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An inverted from the one coming in. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => InverseBool(value); /// @@ -37,7 +37,7 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu /// /// The value to inverse. /// The inverted value of the incoming . - bool InverseBool(object value) + bool InverseBool(object? value) { if (value is bool result) return !result; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs index 42634a917..9e775d581 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs @@ -18,7 +18,7 @@ public class IsNotNullOrEmptyConverter : ValueConverterExtension, IValueConverte /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is not null and not empty. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value is string str ? !string.IsNullOrWhiteSpace(str) : value != null; /// @@ -29,7 +29,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs index a4fed1064..61db4689e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs @@ -18,7 +18,7 @@ public class IsNullOrEmptyConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is null or empty. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value == null || (value is string str && string.IsNullOrWhiteSpace(str)); /// @@ -29,7 +29,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs index 7512d8566..40bb1b6f4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs @@ -18,7 +18,7 @@ public class ItemSelectedEventArgsConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A object from object of type . - public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return null; @@ -36,7 +36,7 @@ public class ItemSelectedEventArgsConverter : ValueConverterExtension, IValueCon /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs index 09dc63970..51dc8fa5e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs @@ -18,7 +18,7 @@ public class ItemTappedEventArgsConverter : ValueConverterExtension, IValueConve /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A object from object of type . - public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return null; @@ -36,7 +36,7 @@ public class ItemTappedEventArgsConverter : ValueConverterExtension, IValueConve /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs index b3b28aa3f..9a25a6fb3 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs @@ -19,7 +19,7 @@ public class ListIsNotNullOrEmptyConverter : ValueConverterExtension, IValueConv /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is not null and not empty. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return false; @@ -38,7 +38,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs index 27da69ad3..7ac28595b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs @@ -19,7 +19,7 @@ public class ListIsNullOrEmptyConverter : ValueConverterExtension, IValueConvert /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is null or empty. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return true; @@ -38,7 +38,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs index d83c02047..5fbbfc45e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs @@ -25,7 +25,7 @@ public class ListToStringConverter : ValueConverterExtension, IValueConverter /// The separator that should be between each collection item. This overrides the value in . /// The culture to use in the converter. This is not implemented. /// Concatenated members string separated by or, if set, . - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value == null) return string.Empty; @@ -52,7 +52,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverter.shared.cs index f4d406ffe..c1d7c93fd 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/MultiConverter.shared.cs @@ -18,8 +18,8 @@ public class MultiConverter : List, IValueConverter /// Parameter to pass into subsequent converters. /// The culture to use in the converter. /// The converted value. - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) - => parameter is IList parameters + public object? Convert(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture) + => parameter is IList parameters ? this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameters.FirstOrDefault(x => x.ConverterType == converter.GetType())?.Value, culture)) : this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture)); @@ -32,7 +32,7 @@ public object Convert(object value, Type targetType, object parameter, System.Gl /// N/A /// N/A /// N/A - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + public object? ConvertBack(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture) => throw new NotImplementedException(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs index c09446242..6f71ce580 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs @@ -18,7 +18,7 @@ public class NotEqualConverter : ValueConverterExtension, IValueConverter /// The second object to compare. /// The culture to use in the converter. This is not implemented. /// True if and are not equal, False if they are equal. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => !((value != null && value.Equals(parameter)) || (value == null && parameter == null)); /// @@ -29,7 +29,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs index 21fe1fea0..398cbe7ee 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs @@ -23,9 +23,9 @@ public class StateToBooleanConverter : IValueConverter /// Optionally, a can be supplied here to compare against. /// The culture to use in the converter. This is not implemented. /// True if the provided s match, otherwise False if they don't match. - 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 LayoutState state)) + if (value is not LayoutState state) throw new ArgumentException("Value is not a valid State", nameof(value)); if (parameter is LayoutState stateToCompare) @@ -42,7 +42,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs index 36210689d..5fd8d4c80 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs @@ -24,7 +24,7 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// The desired text case that the text should be converted to. Must match enum value. /// The culture to use in the converter. This is not implemented. /// The converted text representation with the desired casing. - public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value == null || value is string || value is char ? Convert(value?.ToString(), parameter) : throw new ArgumentException("Value is neither a string nor a char", nameof(value)); @@ -37,20 +37,18 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// N/A /// N/A /// N/A - 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(); - object? Convert(string? value, object parameter) => GetParameter(parameter) switch + object? Convert(string? value, object? parameter) => GetParameter(parameter) switch { TextCaseType.Lower => value?.ToLowerInvariant(), TextCaseType.Upper => value?.ToUpperInvariant(), - TextCaseType.FirstUpperRestLower => value != null && !string.IsNullOrWhiteSpace(value) - ? value.Substring(0, 1).ToUpperInvariant() + value.Substring(1).ToLowerInvariant() - : value, + TextCaseType.FirstUpperRestLower when value != null && !string.IsNullOrWhiteSpace(value) => value.Substring(0, 1).ToUpperInvariant() + value.Substring(1).ToLowerInvariant(), _ => value }; - TextCaseType GetParameter(object parameter) => parameter == null ? Type : parameter switch + TextCaseType GetParameter(object? parameter) => parameter == null ? Type : parameter switch { TextCaseType type => type, string typeString => Enum.TryParse(typeString, out TextCaseType result) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs index 14d026cf9..0310a7e0a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs @@ -17,7 +17,7 @@ public class TimeSpanToDoubleConverter : IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A value expressed in seconds. - 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 TimeSpan timespan) { @@ -35,7 +35,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// The value representing the converted value. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is double doubleValue) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs index 409290caa..5cf2641b0 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/VariableMultiValueConverter.shared.cs @@ -31,7 +31,7 @@ public class VariableMultiValueConverter : MultiValueConverterExtension, IMultiV /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A single value dependant on the configuration for this converter. - public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + public object Convert(object[]? values, Type targetType, object? parameter, CultureInfo culture) { if (values == null || values.Length == 0) return false; @@ -41,7 +41,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur if (boolValues.Length != values.Length) return false; - var count = boolValues.Count(v => v); + var count = boolValues.Count(); return ConditionType switch { @@ -62,7 +62,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// All bindings that evaluate to true if is true. Or null if is not a value or is false. - public object[]? ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + public object[]? ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture) { if (value is not bool boolValue || targetTypes.Any(t => !t.IsAssignableFrom(typeof(bool)))) return null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs index db955addf..497935c60 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/MediaElement/MediaElement.shared.cs @@ -102,9 +102,9 @@ public TimeSpan Position } [Forms.TypeConverter(typeof(MediaSourceConverter))] - public MediaSource Source + public MediaSource? Source { - get => (MediaSource)GetValue(SourceProperty); + get => (MediaSource?)GetValue(SourceProperty); set => SetValue(SourceProperty, value); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs index f091a38e4..d2c62dd92 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/Popup/PopupOfT.shared.cs @@ -25,7 +25,7 @@ public abstract class Popup : BasePopup /// /// The result to return. /// - public void Dismiss(T result) + public void Dismiss(T? result) { taskCompletionSource.TrySetResult(result); OnDismissed(result); From 8685f866a565a27eb100235ba4bb159262673dc4 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Thu, 4 Mar 2021 18:33:45 -0800 Subject: [PATCH 12/13] Update Converters & Unit Tests --- .../ByteArrayToImageSourceConverter_Tests.cs | 22 +++++++++++-------- ...DelegateWeakEventManager_Delegate_Tests.cs | 16 ++++---------- ...gateWeakEventManager_EventHandler_Tests.cs | 6 +++++ .../WeakEventManager_ActionT_Tests.cs | 10 +++++++++ .../WeakEventManager_EventHandlerT_Tests.cs | 20 +++++++++++------ .../AsyncCommandTests/AsyncCommand_Tests.cs | 12 +++++----- .../AsyncValueCommand_Tests.cs | 8 +++---- .../BaseAsyncValueCommandTests.cs | 2 +- .../ICommandTests/BaseCommandTests.cs | 12 +++++----- .../CommandFactory_AsyncCommand_Tests.cs | 16 ++++++++++++++ .../CommandFactory_AsyncValueCommand_Tests.cs | 12 ++++++++++ .../CommandFactory_Command_Tests.cs | 12 ++++++++++ .../Views/MediaElement_Tests.cs | 2 +- .../Views/MediaSource_Tests.cs | 12 +++++----- .../BoolToObjectConverter.shared.cs | 4 ++-- .../ByteArrayToImageSourceConverter.shared.cs | 4 ++-- .../Converters/DoubleToIntConverter.shared.cs | 4 ++-- .../Converters/EnumToBoolConverter.shared.cs | 2 +- .../Converters/EqualConverter.shared.cs | 4 ++-- .../IndexToArrayItemConverter.shared.cs | 4 ++-- .../Converters/IntToBoolConverter.shared.cs | 4 ++-- .../InvertedBoolConverter.shared.cs | 4 ++-- .../IsNotNullOrEmptyConverter.shared.cs | 4 ++-- .../IsNullOrEmptyConverter.shared.cs | 4 ++-- .../ItemSelectedEventArgsConverter.shared.cs | 4 ++-- .../ItemTappedEventArgsConverter.shared.cs | 4 ++-- .../ListIsNotNullOrEmptyConverter.shared.cs | 4 ++-- .../ListIsNullOrEmptyConverter.shared.cs | 4 ++-- .../ListToStringConverter.shared.cs | 4 ++-- .../Converters/NotEqualConverter.shared.cs | 4 ++-- .../StateToBooleanConverter.shared.cs | 4 ++-- .../Converters/TextCaseConverter.shared.cs | 4 ++-- .../TimeSpanToDoubleConverter.shared.cs | 4 ++-- .../Core/FileMediaSource.shared.cs | 4 ++-- .../Core/MediaSource.shared.cs | 15 ++++++++----- .../Helpers/LocalizedString.shared.cs | 8 +++---- .../FuncConverter.cs | 20 ++++++++--------- 37 files changed, 174 insertions(+), 109 deletions(-) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs index a30e013ee..83be6ff6d 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs @@ -22,7 +22,7 @@ public void ByteArrayToImageSourceConverter() var result = byteArrayToImageSourceConverter.Convert(byteArray, typeof(ByteArrayToImageSourceConverter), null, CultureInfo.CurrentCulture); - Assert.True(StreamEquals(GetStreamFromImageSource((ImageSource)result), memoryStream)); + Assert.True(StreamEquals(GetStreamFromImageSource((ImageSource?)result), memoryStream)); } [Theory] @@ -34,28 +34,32 @@ public void InvalidConverterValuesReturnsNull(object value) Assert.Throws(() => byteArrayToImageSourceConverter.Convert(value, typeof(ByteArrayToImageSourceConverter), null, CultureInfo.CurrentCulture)); } - Stream GetStreamFromImageSource(ImageSource imageSource) + Stream? GetStreamFromImageSource(ImageSource? imageSource) { - var streamImageSource = (StreamImageSource)imageSource; + var streamImageSource = (StreamImageSource?)imageSource; var cancellationToken = System.Threading.CancellationToken.None; - var task = streamImageSource.Stream(cancellationToken); - return task.Result; + var task = streamImageSource?.Stream(cancellationToken); + return task?.Result; } - bool StreamEquals(Stream a, Stream b) + bool StreamEquals(Stream? a, Stream? b) { if (a == b) return true; - if (a == null || - b == null || - a.Length != b.Length) + if (a == null + || b == null + || a.Length != b.Length) + { return false; + } for (var i = 0; i < a.Length; i++) + { if (a.ReadByte() != b.ReadByte()) return false; + } return true; } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_Delegate_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_Delegate_Tests.cs index 417cca45c..2b424fd2a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_Delegate_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_Delegate_Tests.cs @@ -58,7 +58,9 @@ void HandleDelegateTest(object sender, PropertyChangedEventArgs e) } // Act +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. propertyChangedWeakEventManager.RaiseEvent(null, new PropertyChangedEventArgs("Test"), nameof(PropertyChanged)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Assert Assert.True(didEventFire); @@ -173,7 +175,9 @@ public void WeakEventManagerDelegate_UnassignedEventManager() void HandleDelegateTest(object sender, PropertyChangedEventArgs e) => didEventFire = true; // Act +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. unassignedEventManager.RaiseEvent(null, null, nameof(PropertyChanged)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Assert Assert.False(didEventFire); @@ -205,9 +209,7 @@ public void WeakEventManagerDelegate_AddEventHandler_NullHandler() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => propertyChangedWeakEventManager.AddEventHandler(null)); -#pragma warning restore CS8625 } [Fact] @@ -231,9 +233,7 @@ public void WeakEventManagerDelegate_AddEventHandler_EmptyEventName() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => propertyChangedWeakEventManager.AddEventHandler(null, string.Empty)); -#pragma warning restore CS8625 } [Fact] @@ -244,9 +244,7 @@ public void WeakEventManagerDelegate_AddEventHandler_WhitespaceEventName() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => propertyChangedWeakEventManager.AddEventHandler(null, " ")); -#pragma warning restore CS8625 } [Fact] @@ -257,9 +255,7 @@ public void WeakEventManagerDelegate_RemoveEventHandler_NullHandler() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => propertyChangedWeakEventManager.RemoveEventHandler(null)); -#pragma warning restore CS8625 } [Fact] @@ -283,9 +279,7 @@ public void WeakEventManagerDelegate_RemoveEventHandler_EmptyEventName() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => propertyChangedWeakEventManager.RemoveEventHandler(null, string.Empty)); -#pragma warning restore CS8625 } [Fact] @@ -296,9 +290,7 @@ public void WeakEventManagerDelegate_RemoveEventHandler_WhiteSpaceEventName() // Act // Assert -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference Assert.Throws(() => propertyChangedWeakEventManager.RemoveEventHandler(null, " ")); -#pragma warning restore CS8625 } } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_EventHandler_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_EventHandler_Tests.cs index aabdcea8a..41197a627 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_EventHandler_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/DelegateWeakEventManager_EventHandler_Tests.cs @@ -52,7 +52,9 @@ void HandleTestEvent(object? sender, EventArgs e) } // Act +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. TestWeakEventManager.RaiseEvent(null, new EventArgs(), nameof(TestEvent)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Assert Assert.True(didEventFire); @@ -145,7 +147,9 @@ public void WeakEventManager_UnassignedEvent() void HandleTestEvent(object? sender, EventArgs e) => didEventFire = true; // Act +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. TestWeakEventManager.RaiseEvent(null, null, nameof(TestEvent)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Assert Assert.False(didEventFire); @@ -162,7 +166,9 @@ public void WeakEventManager_UnassignedEventManager() void HandleTestEvent(object? sender, EventArgs e) => didEventFire = true; // Act +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. unassignedEventManager.RaiseEvent(null, null, nameof(TestEvent)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Assert Assert.False(didEventFire); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs index d03445aaa..65fae73ca 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_ActionT_Tests.cs @@ -140,7 +140,9 @@ public void WeakEventManagerActionT_AddEventHandler_NullHandler() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => actionEventManager.AddEventHandler(nullAction, nameof(ActionEvent))); +#pragma warning restore CS8604 // Possible null reference argument. } @@ -152,7 +154,9 @@ public void WeakEventManagerActionT_AddEventHandler_NullEventName() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => actionEventManager.AddEventHandler(s => { var temp = s; }, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] @@ -164,7 +168,9 @@ public void WeakEventManagerActionT_AddEventHandler_EmptyEventName() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => actionEventManager.AddEventHandler(nullAction, string.Empty)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -187,7 +193,9 @@ public void WeakEventManagerActionT_RemoveEventHandler_NullHandler() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => actionEventManager.RemoveEventHandler(nullAction)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -198,7 +206,9 @@ public void WeakEventManagerActionT_RemoveEventHandler_NullEventName() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => actionEventManager.RemoveEventHandler(s => { var temp = s; }, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs index 0247f9962..898746144 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Helpers/WeakEventManagerTests/WeakEventManager_EventHandlerT_Tests.cs @@ -61,7 +61,9 @@ void HandleTestEvent(object? sender, string e) } // Act +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. TestStringWeakEventManager.RaiseEvent(null, stringEventArg, nameof(TestStringEvent)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Assert Assert.True(didEventFire); @@ -125,7 +127,7 @@ public void WeakEventManager_NullEventManager() // Assert #pragma warning disable CS8602 //Dereference of a possible null reference - Assert.Throws(() => unassignedEventManager.RaiseEvent(null, string.Empty, nameof(TestEvent))); + Assert.Throws(() => unassignedEventManager.RaiseEvent(this, string.Empty, nameof(TestEvent))); #pragma warning restore CS8602 } @@ -174,9 +176,9 @@ public void WeakEventManagerT_AddEventHandler_NullHandler() // Act // Assert -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. - Assert.Throws(() => TestStringWeakEventManager.AddEventHandler((EventHandler)null)); -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + Assert.Throws(() => TestStringWeakEventManager.AddEventHandler((EventHandler?)null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] @@ -187,7 +189,9 @@ public void WeakEventManagerT_AddEventHandler_NullEventName() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => TestStringWeakEventManager.AddEventHandler(s => { var temp = s; }, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] @@ -220,9 +224,9 @@ public void WeakEventManagerT_RemoveEventHandler_NullHandler() // Act // Assert -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. - Assert.Throws(() => TestStringWeakEventManager.RemoveEventHandler((EventHandler)null)); -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + Assert.Throws(() => TestStringWeakEventManager.RemoveEventHandler((EventHandler?)null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] @@ -233,7 +237,9 @@ public void WeakEventManagerT_RemoveEventHandler_NullEventName() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => TestStringWeakEventManager.AddEventHandler(s => { var temp = s; }, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs index 53ddb4f9d..0c17a19d2 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncCommandTests/AsyncCommand_Tests.cs @@ -153,7 +153,9 @@ public void AsyncCommand_NoParameter_NoCanExecute_Test() { // Arrange Func? canExecute = null; +#pragma warning disable CS8604 // Possible null reference argument. var command = new AsyncCommand(NoParameterTask, canExecute); +#pragma warning restore CS8604 // Possible null reference argument. // Act @@ -171,7 +173,7 @@ public void AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_MainThreadExe var command = new AsyncCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); @@ -204,7 +206,7 @@ public void AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_MainThreadExe var command = new AsyncCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); @@ -236,7 +238,7 @@ public async Task AsyncCommand_RaiseCanExecuteChanged_MainThreadCreation_Backgro var command = new AsyncCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); @@ -276,7 +278,7 @@ public async Task AsyncCommand_RaiseCanExecuteChanged_BackgroundThreadCreation_M command = new AsyncCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); @@ -313,7 +315,7 @@ public async Task AsyncCommand_ChangeCanExecute_Test() var command = new AsyncCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs index 1e83d0c7b..48686f86a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/AsyncValueCommand_Tests.cs @@ -176,7 +176,9 @@ public void AsyncValueCommandNoParameter_NoCanExecute_Test() { // Arrange Func? canExecute = null; +#pragma warning disable CS8604 // Possible null reference argument. var command = new AsyncValueCommand(NoParameterTask, canExecute); +#pragma warning restore CS8604 // Possible null reference argument. // Act @@ -196,7 +198,7 @@ public async Task AsyncValueCommand_RaiseCanExecuteChanged_Test() var command = new AsyncValueCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); @@ -234,7 +236,7 @@ public async Task AsyncValueCommand_ChangeCanExecute_Test() var command = new AsyncValueCommand(NoParameterTask, commandCanExecute); command.CanExecuteChanged += handleCanExecuteChanged; - bool commandCanExecute(object parameter) => canCommandExecute; + bool commandCanExecute(object? parameter) => canCommandExecute; Assert.False(command.CanExecute(null)); @@ -246,10 +248,8 @@ public async Task AsyncValueCommand_ChangeCanExecute_Test() Assert.False(didCanExecuteChangeFire); // Act -#pragma warning disable CS0618 // Type or member is obsolete command.ChangeCanExecute(); await handleCanExecuteChangedTCS.Task; -#pragma warning restore CS0618 // Type or member is obsolete // Assert Assert.True(didCanExecuteChangeFire); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/BaseAsyncValueCommandTests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/BaseAsyncValueCommandTests.cs index a92271fca..064659102 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/BaseAsyncValueCommandTests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/AsyncValueCommandTests/BaseAsyncValueCommandTests.cs @@ -9,7 +9,7 @@ public abstract class BaseAsyncValueCommandTests : BaseCommandTests protected new ValueTask IntParameterTask(int delay) => ValueTaskDelay(delay); - protected new ValueTask StringParameterTask(string text) => ValueTaskDelay(Delay); + protected new ValueTask StringParameterTask(string? text) => ValueTaskDelay(Delay); protected new ValueTask NoParameterImmediateNullReferenceExceptionTask() => throw new NullReferenceException(); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/BaseCommandTests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/BaseCommandTests.cs index 12ac5912d..1e5d88ba6 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/BaseCommandTests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/BaseCommandTests.cs @@ -15,7 +15,7 @@ public abstract class BaseCommandTests protected Task IntParameterTask(int delay) => Task.Delay(delay); - protected Task StringParameterTask(string text) => Task.Delay(Delay); + protected Task StringParameterTask(string? text) => Task.Delay(Delay); protected Task NoParameterImmediateNullReferenceExceptionTask() => throw new NullReferenceException(); @@ -53,17 +53,17 @@ protected async Task IntParameterDelayedNullReferenceExceptionTask(int delay) protected bool CanExecuteTrue(bool parameter) => true; - protected bool CanExecuteTrue(string parameter) => true; + protected bool CanExecuteTrue(string? parameter) => true; - protected bool CanExecuteTrue(object parameter) => true; + protected bool CanExecuteTrue(object? parameter) => true; protected bool CanExecuteFalse(bool parameter) => false; - protected bool CanExecuteFalse(string parameter) => false; + protected bool CanExecuteFalse(string? parameter) => false; - protected bool CanExecuteFalse(object parameter) => false; + protected bool CanExecuteFalse(object? parameter) => false; - protected bool CanExecuteDynamic(object booleanParameter) + protected bool CanExecuteDynamic(object? booleanParameter) { if (booleanParameter is bool parameter) return parameter; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs index 2f4f65408..690f4ef99 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncCommand_Tests.cs @@ -18,7 +18,9 @@ public void AsyncCommand_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -66,7 +68,9 @@ public void AsyncCommand_FuncBool_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute, () => true)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -74,7 +78,9 @@ public async Task AsyncCommand_FuncBool_NullCanExecuteParameter() { // Arrange Func? canExecute = null; +#pragma warning disable CS8604 // Possible null reference argument. var command = CommandFactory.Create(NoParameterTask, canExecute); +#pragma warning restore CS8604 // Possible null reference argument. // Act await command.ExecuteAsync(); @@ -117,7 +123,9 @@ public void AsyncCommandT_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -167,7 +175,9 @@ public void AsyncCommandT_FuncBool_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute, () => true)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -175,7 +185,9 @@ public async Task AsyncCommandT_FuncBool_NullCanExecuteParameter() { // Arrange Func? canExecute = null; +#pragma warning disable CS8604 // Possible null reference argument. var command = CommandFactory.Create(IntParameterTask, canExecute); +#pragma warning restore CS8604 // Possible null reference argument. // Act await command.ExecuteAsync(0); @@ -218,14 +230,18 @@ public void AsyncCommandTExecuteTCanExecute_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] public async Task AsyncCommandTExecuteTCanExecute_NullCanExecuteParameter() { // Arrange +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. var command = CommandFactory.Create(IntParameterTask, null); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. // Act await command.ExecuteAsync(0); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs index d03b364b9..90879ce59 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_AsyncValueCommand_Tests.cs @@ -19,7 +19,9 @@ public void AsyncValueCommand_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -67,7 +69,9 @@ public void AsyncValueCommand_FuncBool_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute, () => true)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -75,7 +79,9 @@ public async Task AsyncValueCommand_FuncBool_NullCanExecuteParameter() { // Arrange Func? canExecute = null; +#pragma warning disable CS8604 // Possible null reference argument. var command = CommandFactory.Create(NoParameterTask, canExecute); +#pragma warning restore CS8604 // Possible null reference argument. // Act await command.ExecuteAsync(); @@ -170,7 +176,9 @@ public void AsyncValueCommandT_FuncBool_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute, () => true)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -178,7 +186,9 @@ public async Task AsyncValueCommandT_FuncBool_NullCanExecuteParameter() { // Arrange Func? canExecute = null; +#pragma warning disable CS8604 // Possible null reference argument. var command = CommandFactory.Create(IntParameterTask, canExecute); +#pragma warning restore CS8604 // Possible null reference argument. // Act await command.ExecuteAsync(0); @@ -221,7 +231,9 @@ public void AsyncValueCommandTExecuteTCanExecute_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs index 635b6fada..884935a3b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/ObjectModel/ICommandTests/CommandFactoryTests/CommandFactory_Command_Tests.cs @@ -16,7 +16,9 @@ public void Action_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -45,7 +47,9 @@ public void Action_NullCanExecuteParameter() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => CommandFactory.Create(NoParameterAction, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] @@ -75,7 +79,9 @@ public void ActionObject_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -104,7 +110,9 @@ public void ActionObject_NullCanExecuteParameter() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => CommandFactory.Create(ObjectParameterAction, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] @@ -136,7 +144,9 @@ public void ActionInt_NullExecuteParameter() // Act // Assert +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => CommandFactory.Create(execute, CanExecuteTrue)); +#pragma warning restore CS8604 // Possible null reference argument. } [Fact] @@ -147,7 +157,9 @@ public void ActionInt_NullCanExecuteParameter() // Act // Assert +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. Assert.Throws(() => CommandFactory.Create(IntParameterAction, null)); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaElement_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaElement_Tests.cs index 6b94c4e45..186e8ceeb 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaElement_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaElement_Tests.cs @@ -71,7 +71,7 @@ public void TestSourceRoundTrip() media.Source = uri; Assert.NotNull(media.Source); Assert.IsType(media.Source); - Assert.Equal(uri, ((UriMediaSource)media.Source).Uri); + Assert.Equal(uri, ((UriMediaSource?)media.Source)?.Uri); } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs index 1fc571a25..003d55a38 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs @@ -52,7 +52,7 @@ public void TestImplicitUriConversion() var mediaElement = new UI.Views.MediaElement { Source = new Uri("http://xamarin.com/media.mp4") }; Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)mediaElement.Source).Uri.AbsoluteUri); + Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource?)mediaElement.Source)?.Uri.AbsoluteUri); } [Fact] @@ -68,7 +68,7 @@ public void TestImplicitStringUriConversion() public void TestImplicitUriConversionWhenNull() { Uri? u = null; - var sut = (Core.MediaSource)u; + var sut = (Core.MediaSource?)u; Assert.Null(sut); } @@ -79,7 +79,7 @@ public void TestSetStringValue() mediaElement.SetValue(UI.Views.MediaElement.SourceProperty, "media.mp4"); Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("media.mp4", ((Core.FileMediaSource)mediaElement.Source).File); + Assert.Equal("media.mp4", ((Core.FileMediaSource?)mediaElement.Source)?.File); } [Fact] @@ -91,7 +91,7 @@ public void TextBindToStringValue() mediaElement.BindingContext = "media.mp4"; Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("media.mp4", ((Core.FileMediaSource)mediaElement.Source).File); + Assert.Equal("media.mp4", ((Core.FileMediaSource?)mediaElement.Source)?.File); } [Fact] @@ -103,7 +103,7 @@ public void TextBindToStringUriValue() mediaElement.BindingContext = "http://xamarin.com/media.mp4"; Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)mediaElement.Source).Uri.AbsoluteUri); + Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource?)mediaElement.Source)?.Uri.AbsoluteUri); } [Fact] @@ -115,7 +115,7 @@ public void TextBindToUriValue() mediaElement.BindingContext = new Uri("http://xamarin.com/media.mp4"); Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)mediaElement.Source).Uri.AbsoluteUri); + Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource?)mediaElement.Source)?.Uri.AbsoluteUri); } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs index c4b268374..4ce274c39 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/BoolToObjectConverter.shared.cs @@ -35,7 +35,7 @@ public class BoolToObjectConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// The object assigned to if value equals True, otherwise the value assigned to . - 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 bool result) return result ? TrueObject : FalseObject; @@ -51,7 +51,7 @@ public class BoolToObjectConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// True if value equals , otherwise False. - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value is TObject result) return result.Equals(TrueObject); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs index a374fb4d1..2df999c12 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ByteArrayToImageSourceConverter.shared.cs @@ -20,7 +20,7 @@ public class ByteArrayToImageSourceConverter : ValueConverterExtension, IValueCo /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An object of type . - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return null; @@ -39,7 +39,7 @@ public class ByteArrayToImageSourceConverter : ValueConverterExtension, IValueCo /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An object of type . - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return null; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs index 9a5e37764..ce189f125 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/DoubleToIntConverter.shared.cs @@ -24,7 +24,7 @@ public class DoubleToIntConverter : ValueConverterExtension, IValueConverter /// Multiplier (Equals 1 by default). /// The culture to use in the converter. This is not implemented. /// value. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => value is double result ? (int)Math.Round(result * GetParameter(parameter)) : throw new ArgumentException("Value is not a valid double", nameof(value)); @@ -37,7 +37,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// Denominator (Equals 1 by default). /// The culture to use in the converter. This is not implemented. /// value. - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) => value is int result ? result / GetParameter(parameter) : throw new ArgumentException("Value is not a valid integer", nameof(value)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs index c5e355084..e9cc10989 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EnumToBoolConverter.shared.cs @@ -59,7 +59,7 @@ static bool CompareTwoEnums(Enum valueToCheck, object? referenceValue) } /// - 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(); } } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs index 9c3b0ee3c..4705eab46 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/EqualConverter.shared.cs @@ -18,7 +18,7 @@ public class EqualConverter : ValueConverterExtension, IValueConverter /// The second object to compare. /// The culture to use in the converter. This is not implemented. /// True if and are equal, False if they are not equal. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => (value != null && value.Equals(parameter)) || (value == null && parameter == null); /// @@ -29,7 +29,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs index 4e0138eea..958f1dc9a 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IndexToArrayItemConverter.shared.cs @@ -18,7 +18,7 @@ public class IndexToArrayItemConverter : ValueConverterExtension, IValueConverte /// The items array. /// The culture to use in the converter. This is not implemented. /// The item from the array that corresponds to passed index. - 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 not int index) throw new ArgumentException("Value is not a valid integer", nameof(value)); @@ -40,7 +40,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// The items array. /// The culture to use in the converter. This is not implemented. /// The index of the item from the array. - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (parameter is not Array array) throw new ArgumentException("Parameter is not a valid array", nameof(parameter)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs index 204706624..58de3abde 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IntToBoolConverter.shared.cs @@ -18,7 +18,7 @@ public class IntToBoolConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// False if the value is 0, otherwise if the value is anything but 0 it returns True. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => value is int result ? result != 0 : throw new ArgumentException("Value is not a valid integer", nameof(value)); @@ -31,7 +31,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// 0 if the value is False, otherwise 1 if the value is True. - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value is bool result) return result ? 1 : 0; diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs index 887718f63..7991605ef 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/InvertedBoolConverter.shared.cs @@ -18,7 +18,7 @@ public class InvertedBoolConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An inverted from the one coming in. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => InverseBool(value); /// @@ -29,7 +29,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// An inverted from the one coming in. - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) => InverseBool(value); /// diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs index 9e775d581..7b370d287 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNotNullOrEmptyConverter.shared.cs @@ -18,7 +18,7 @@ public class IsNotNullOrEmptyConverter : ValueConverterExtension, IValueConverte /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is not null and not empty. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => value is string str ? !string.IsNullOrWhiteSpace(str) : value != null; /// @@ -29,7 +29,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs index 61db4689e..05aa4f926 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/IsNullOrEmptyConverter.shared.cs @@ -18,7 +18,7 @@ public class IsNullOrEmptyConverter : ValueConverterExtension, IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is null or empty. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => value == null || (value is string str && string.IsNullOrWhiteSpace(str)); /// @@ -29,7 +29,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs index 40bb1b6f4..7de63b824 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemSelectedEventArgsConverter.shared.cs @@ -18,7 +18,7 @@ public class ItemSelectedEventArgsConverter : ValueConverterExtension, IValueCon /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A object from object of type . - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return null; @@ -36,7 +36,7 @@ public class ItemSelectedEventArgsConverter : ValueConverterExtension, IValueCon /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs index 51dc8fa5e..800a0c4d6 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ItemTappedEventArgsConverter.shared.cs @@ -18,7 +18,7 @@ public class ItemTappedEventArgsConverter : ValueConverterExtension, IValueConve /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A object from object of type . - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return null; @@ -36,7 +36,7 @@ public class ItemTappedEventArgsConverter : ValueConverterExtension, IValueConve /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs index 9a25a6fb3..9b5146f79 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNotNullOrEmptyConverter.shared.cs @@ -19,7 +19,7 @@ public class ListIsNotNullOrEmptyConverter : ValueConverterExtension, IValueConv /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is not null and not empty. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return false; @@ -38,7 +38,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs index 7ac28595b..99d4adaee 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListIsNullOrEmptyConverter.shared.cs @@ -19,7 +19,7 @@ public class ListIsNullOrEmptyConverter : ValueConverterExtension, IValueConvert /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A indicating if the incoming value is null or empty. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return true; @@ -38,7 +38,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs index 5fbbfc45e..8144c5832 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/ListToStringConverter.shared.cs @@ -25,7 +25,7 @@ public class ListToStringConverter : ValueConverterExtension, IValueConverter /// The separator that should be between each collection item. This overrides the value in . /// The culture to use in the converter. This is not implemented. /// Concatenated members string separated by or, if set, . - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value == null) return string.Empty; @@ -52,7 +52,7 @@ public class ListToStringConverter : ValueConverterExtension, IValueConverter /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs index 6f71ce580..635756403 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/NotEqualConverter.shared.cs @@ -18,7 +18,7 @@ public class NotEqualConverter : ValueConverterExtension, IValueConverter /// The second object to compare. /// The culture to use in the converter. This is not implemented. /// True if and are not equal, False if they are equal. - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => !((value != null && value.Equals(parameter)) || (value == null && parameter == null)); /// @@ -29,7 +29,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs index 398cbe7ee..02beb5595 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/StateToBooleanConverter.shared.cs @@ -23,7 +23,7 @@ public class StateToBooleanConverter : IValueConverter /// Optionally, a can be supplied here to compare against. /// The culture to use in the converter. This is not implemented. /// True if the provided s match, otherwise False if they don't match. - 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 not LayoutState state) throw new ArgumentException("Value is not a valid State", nameof(value)); @@ -42,7 +42,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// N/A /// N/A /// N/A - 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(); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs index 5fd8d4c80..c42732ec4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TextCaseConverter.shared.cs @@ -24,7 +24,7 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// The desired text case that the text should be converted to. Must match enum value. /// The culture to use in the converter. This is not implemented. /// The converted text representation with the desired casing. - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => value == null || value is string || value is char ? Convert(value?.ToString(), parameter) : throw new ArgumentException("Value is neither a string nor a char", nameof(value)); @@ -37,7 +37,7 @@ public class TextCaseConverter : ValueConverterExtension, IValueConverter /// N/A /// N/A /// N/A - 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(); object? Convert(string? value, object? parameter) => GetParameter(parameter) switch diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs index 0310a7e0a..fa1363495 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Converters/TimeSpanToDoubleConverter.shared.cs @@ -17,7 +17,7 @@ public class TimeSpanToDoubleConverter : IValueConverter /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// A value expressed in seconds. - 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 TimeSpan timespan) { @@ -35,7 +35,7 @@ public object Convert(object? value, Type targetType, object? parameter, Culture /// Additional parameter for the converter to handle. This is not implemented. /// The culture to use in the converter. This is not implemented. /// The value representing the converted value. - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (value is double doubleValue) { diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs index f8aeb5edf..e875603c4 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/FileMediaSource.shared.cs @@ -9,9 +9,9 @@ public sealed class FileMediaSource : MediaSource public static readonly BindableProperty FileProperty = BindableProperty.Create(nameof(File), typeof(string), typeof(FileMediaSource), propertyChanged: OnFileMediaSourceChanged); - public string File + public string? File { - get => (string)GetValue(FileProperty); + get => (string?)GetValue(FileProperty); set => SetValue(FileProperty, value); } diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs index 53b693e02..3ef0abe36 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs @@ -10,22 +10,27 @@ public abstract class MediaSource : Element { readonly WeakEventManager weakEventManager = new WeakEventManager(); - public static MediaSource FromFile(string file) => + public static MediaSource FromFile(string? file) => new FileMediaSource { File = file }; - public static MediaSource FromUri(Uri uri) => - !uri.IsAbsoluteUri ? throw new ArgumentException("Uri must be be absolute", nameof(uri)) : new UriMediaSource { Uri = uri }; + public static MediaSource FromUri(Uri? uri) + { + if (uri == null) + throw new ArgumentNullException(nameof(uri)); + + return !uri.IsAbsoluteUri ? throw new ArgumentException("Uri must be be absolute", nameof(uri)) : new UriMediaSource { Uri = uri }; + } public static MediaSource FromUri(string uri) => FromUri(new Uri(uri)); [Preserve(Conditional = true)] - public static implicit operator MediaSource(string source) => + public static implicit operator MediaSource(string? source) => Uri.TryCreate(source, UriKind.Absolute, out var uri) && uri.Scheme != "file" ? FromUri(uri) : FromFile(source); [Preserve(Conditional = true)] - public static implicit operator MediaSource?(Uri uri) => uri == null ? null : FromUri(uri); + public static implicit operator MediaSource?(Uri? uri) => FromUri(uri); protected void OnSourceChanged() => weakEventManager.RaiseEvent(this, EventArgs.Empty, nameof(SourceChanged)); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs index 0fcfa473c..563cc8774 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Helpers/LocalizedString.shared.cs @@ -7,14 +7,14 @@ namespace Xamarin.CommunityToolkit.Helpers #if !NETSTANDARD1_0 public class LocalizedString : ObservableObject { - readonly Func? generator; + readonly Func? generator; - public LocalizedString(Func? generator = null) + public LocalizedString(Func? generator = null) : this(LocalizationResourceManager.Current, generator) { } - public LocalizedString(LocalizationResourceManager localizationManager, Func? generator = null) + public LocalizedString(LocalizationResourceManager localizationManager, Func? generator = null) { this.generator = generator; @@ -26,7 +26,7 @@ public LocalizedString(LocalizationResourceManager localizationManager, Func generator?.Invoke(); [Preserve(Conditional = true)] - public static implicit operator LocalizedString(Func func) => new LocalizedString(func); + public static implicit operator LocalizedString(Func? func) => new LocalizedString(func); } #endif } diff --git a/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs b/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs index d435ea093..b5bef35c6 100644 --- a/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs +++ b/src/Markup/Xamarin.CommunityToolkit.Markup/FuncConverter.cs @@ -6,25 +6,25 @@ namespace Xamarin.CommunityToolkit.Markup { public class FuncConverter : IValueConverter { - readonly Func? convert; - readonly Func? convertBack; + readonly Func? convert; + readonly Func? convertBack; - readonly Func? convertWithParam; - readonly Func? convertBackWithParam; + readonly Func? convertWithParam; + readonly Func? convertBackWithParam; - readonly Func? convertWithParamAndCulture; - readonly Func? convertBackWithParamAndCulture; + readonly Func? convertWithParamAndCulture; + readonly Func? convertBackWithParamAndCulture; - public FuncConverter(Func? convertWithParamAndCulture = null, Func? convertBackWithParamAndCulture = null) + public FuncConverter(Func? convertWithParamAndCulture = null, Func? convertBackWithParamAndCulture = null) { this.convertWithParamAndCulture = convertWithParamAndCulture; this.convertBackWithParamAndCulture = convertBackWithParamAndCulture; } public FuncConverter(Func? convertWithParam = null, Func? convertBackWithParam = null) { this.convertWithParam = convertWithParam; this.convertBackWithParam = convertBackWithParam; } - public FuncConverter(Func? convert = null, Func? convertBack = null) + public FuncConverter(Func? convert = null, Func? convertBack = null) { this.convert = convert; this.convertBack = convertBack; } - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) { if (convert != null) { @@ -50,7 +50,7 @@ public FuncConverter(Func? convert = null, Func Date: Thu, 4 Mar 2021 18:42:02 -0800 Subject: [PATCH 13/13] Resolve MediaSource Unit Tests --- .../Pages/TestCases/MediaElementSourcePage.xaml.cs | 2 +- .../Views/MediaSource_Tests.cs | 12 ++++++------ .../Core/MediaSource.shared.cs | 8 ++++---- .../Core/MediaSourceConverter.shared.cs | 3 +-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs b/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs index 35799ea00..55352ae45 100644 --- a/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs +++ b/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs @@ -12,6 +12,6 @@ class MediaElementViewModel : BindableObject { public string VideoAsString { get; set; } = "https://tipcalculator.appwithkiss.com/video/Hint_1_2_EN_12.mov"; - public MediaSource VideoAsMediaSource => MediaSource.FromUri(VideoAsString); + public MediaSource? VideoAsMediaSource => MediaSource.FromUri(VideoAsString); } } \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs index 003d55a38..500436d5b 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Views/MediaSource_Tests.cs @@ -25,7 +25,7 @@ public void TestHelpers() var urisource = Core.MediaSource.FromUri(new Uri("http://xamarin.com/media.mp4")); Assert.IsType(urisource); - Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)urisource).Uri.AbsoluteUri); + Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource?)urisource)?.Uri.AbsoluteUri); } [Fact] @@ -34,16 +34,16 @@ public void TestImplicitFileConversion() var mediaElement = new UI.Views.MediaElement { Source = "File.mp4" }; Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("File.mp4", ((Core.FileMediaSource)mediaElement.Source).File); + Assert.Equal("File.mp4", ((Core.FileMediaSource?)mediaElement.Source)?.File); } [Fact] public void TestImplicitStringConversionWhenNull() { string? s = null; - var sut = (Core.MediaSource)s; - Assert.IsType(sut); - Assert.Null(((Core.FileMediaSource)sut).File); + var sut = (Core.MediaSource?)s; + Assert.IsType(sut); + Assert.Null(((Core.FileMediaSource?)sut)?.File); } [Fact] @@ -61,7 +61,7 @@ public void TestImplicitStringUriConversion() var mediaElement = new UI.Views.MediaElement { Source = "http://xamarin.com/media.mp4" }; Assert.NotNull(mediaElement.Source); Assert.IsType(mediaElement.Source); - Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource)mediaElement.Source).Uri.AbsoluteUri); + Assert.Equal("http://xamarin.com/media.mp4", ((Core.UriMediaSource?)mediaElement.Source)?.Uri.AbsoluteUri); } [Fact] diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs index 3ef0abe36..adc286b8e 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSource.shared.cs @@ -13,18 +13,18 @@ public abstract class MediaSource : Element public static MediaSource FromFile(string? file) => new FileMediaSource { File = file }; - public static MediaSource FromUri(Uri? uri) + public static MediaSource? FromUri(Uri? uri) { if (uri == null) - throw new ArgumentNullException(nameof(uri)); + return null; return !uri.IsAbsoluteUri ? throw new ArgumentException("Uri must be be absolute", nameof(uri)) : new UriMediaSource { Uri = uri }; } - public static MediaSource FromUri(string uri) => FromUri(new Uri(uri)); + public static MediaSource? FromUri(string uri) => FromUri(new Uri(uri)); [Preserve(Conditional = true)] - public static implicit operator MediaSource(string? source) => + public static implicit operator MediaSource?(string? source) => Uri.TryCreate(source, UriKind.Absolute, out var uri) && uri.Scheme != "file" ? FromUri(uri) : FromFile(source); diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSourceConverter.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSourceConverter.shared.cs index bf26d70e4..4881b7ae0 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSourceConverter.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Core/MediaSourceConverter.shared.cs @@ -1,12 +1,11 @@ using System; using Xamarin.Forms; -using Xamarin.Forms.Internals; namespace Xamarin.CommunityToolkit.Core { public sealed class MediaSourceConverter : TypeConverter { - public override object ConvertFromInvariantString(string value) + public override object? ConvertFromInvariantString(string value) { if (value == null) throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(MediaSource)}");