diff --git a/.editorconfig b/.editorconfig
index c71598a71..a596b627e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -107,3 +107,9 @@ csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
+
+# SA1011: Closing square brackets should be spaced correctly
+dotnet_diagnostic.SA1011.severity = none
+
+# CS4014: Because this call is not awaited, execution of the current method continues before the call is completed
+dotnet_diagnostic.CS4014.severity = error
diff --git a/Directory.Build.props b/Directory.Build.props
index cc26f3910..e7f7d987f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,9 +2,12 @@
- 8.0
+ 9.0
+ enable
+ nullable
+
$(MSBuildThisFileDirectory)Xamarin.CommunityToolkit.ruleset
false
diff --git a/Xamarin.CommunityToolkit.ruleset b/Xamarin.CommunityToolkit.ruleset
index 0d4b31f43..047684820 100644
--- a/Xamarin.CommunityToolkit.ruleset
+++ b/Xamarin.CommunityToolkit.ruleset
@@ -15,7 +15,6 @@
-
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 956ed9cd8..2e4f772ed 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -6,11 +6,16 @@ variables:
NugetPackageVersion: '$(CurrentSemanticVersion)'
#MONO_VERSION: 6_4_0
#XCODE_VERSION: 11.4
- NETCORE_VERSION: '3.1.x'
- NETCORE_TEST_VERSION: '3.1.x'
+ NETCORE_VERSION: '5.0.x'
+ NETCORE_TEST_VERSION_3_1: '3.1.x'
+ NETCORE_TEST_VERSION_2_1: '2.1.x'
RunPoliCheck: 'false'
- PathToCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj'
PathToMarkupCsproj: 'src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj'
+ PathToCommunityToolkitCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj'
+ PathToSamplesSln: 'samples/XCT.Sample.sln'
+ PathToCommunityToolkitUnitTestCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj'
+ PathToMarkupUnitTestCsproj: 'src/Markup/Xamarin.CommunityToolkit.Markup.UnitTests/Xamarin.CommunityToolkit.Markup.UnitTests.csproj'
+ PathToMsBuildOnMacOS: 'mono /Applications/Visual\ studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/MSBuild.dll'
PathToSln: 'samples/XCT.Sample.sln'
resources:
@@ -68,6 +73,21 @@ jobs:
pool:
vmImage: windows-2019
steps:
+ - task: UseDotNet@2
+ displayName: 'Install .NET SDK'
+ inputs:
+ version: $(NETCORE_VERSION)
+ includePreviewVersions: false
+ - task: UseDotNet@2
+ displayName: 'Install .NET 3.1 Test SDK'
+ inputs:
+ version: $(NETCORE_TEST_VERSION_3_1)
+ includePreviewVersions: false
+ - task: UseDotNet@2
+ displayName: 'Install .NET 2.1 Test SDK'
+ inputs:
+ version: $(NETCORE_TEST_VERSION_2_1)
+ includePreviewVersions: false
# if this is a tagged build, then update the version number
- powershell: |
$buildSourceBranch = "$(Build.SourceBranch)"
@@ -78,9 +98,9 @@ jobs:
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/')
# restore, build and pack the packages
- task: MSBuild@1
- displayName: Build Solution
+ displayName: Build Xamarin.CommunityToolkit.csproj
inputs:
- solution: $(PathToCsproj)
+ solution: $(PathToCommunityToolkitCsproj)
configuration: Release
msbuildArguments: '/restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
- task: CopyFiles@2
@@ -88,9 +108,9 @@ jobs:
Contents: 'SignList.xml'
TargetFolder: '$(Build.ArtifactStagingDirectory)/nuget'
- task: MSBuild@1
- displayName: Pack NuGets
+ displayName: Pack Community Toolkit NuGets
inputs:
- solution: $(PathToCsproj)
+ solution: $(PathToCommunityToolkitCsproj)
configuration: Release
msbuildArguments: '/t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'
- task: MSBuild@1
@@ -112,12 +132,14 @@ jobs:
# command: 'custom'
# custom: 'nuget'
# arguments: 'push --source https://nuget.pkg.github.com/xamarin/index.json --api-key $(GitHub.NuGet.Token) "$(Build.ArtifactStagingDirectory)\nuget\*.nupkg"'
- - task: DotNetCoreCLI@2
- displayName: Run Tests
+ - task: CmdLine@2
+ displayName: 'Run Markup Unit Tests'
+ inputs:
+ script: dotnet test $(PathToMarkupUnitTestCsproj) -c Release --collect "Code coverage" -p:BuildInParallel=false
+ - task: CmdLine@2
+ displayName: 'Run Community Toolkit Unit Tests'
inputs:
- command: test
- projects: '**/*.UnitTests.csproj'
- arguments: '--configuration Release --collect "Code coverage"'
+ script: dotnet test $(PathToCommunityToolkitUnitTestCsproj) -c Release --collect "Code coverage" -p:BuildInParallel=false
# publish the packages
- task: PublishBuildArtifacts@1
displayName: 'Publish Unsigned NuGets'
@@ -161,27 +183,44 @@ jobs:
# displayName: Switch to the latest Xcode
# restore, build and pack the packages
- task: UseDotNet@2
- displayName: 'Use .Net Core sdk'
+ displayName: 'Install .NET SDK'
inputs:
version: $(NETCORE_VERSION)
includePreviewVersions: false
- task: UseDotNet@2
- displayName: 'Use .Net Core sdk'
+ displayName: 'Install .NET 3.1 Test SDK'
inputs:
- version: $(NETCORE_TEST_VERSION)
+ version: $(NETCORE_TEST_VERSION_3_1)
includePreviewVersions: false
- - task: MSBuild@1
- displayName: Build Solution
+ - task: UseDotNet@2
+ displayName: 'Install .NET 2.1 Test SDK'
inputs:
- solution: $(PathToCsproj)
- configuration: Release
- msbuildArguments: '/restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
- - task: MSBuild@1
- displayName: Pack NuGets
+ version: $(NETCORE_TEST_VERSION_2_1)
+ includePreviewVersions: false
+ - task: CmdLine@2
+ displayName: 'Build Markup'
inputs:
- solution: $(PathToCsproj)
- configuration: Release
- msbuildArguments: '/t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'
+ script: '$(PathToMsBuildOnMacOS) $(PathToMarkupCsproj) /p:Configuration=Release /restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
+ - task: CmdLine@2
+ displayName: 'Build Community Toolkit'
+ inputs:
+ script: '$(PathToMsBuildOnMacOS) $(PathToCommunityToolkitCsproj) /p:Configuration=Release /restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false'
+ - task: CmdLine@2
+ displayName: 'Run Markup Unit Tests'
+ inputs:
+ script: 'dotnet test $(PathToMarkupUnitTestCsproj) /p:Configuration=Release -p:BuildInParallel=false'
+ - task: CmdLine@2
+ displayName: 'Run Community Toolkit Unit Tests'
+ inputs:
+ script: 'dotnet test $(PathToCommunityToolkitUnitTestCsproj) /p:Configuration=Release -p:BuildInParallel=false'
+ - task: CmdLine@2
+ displayName: 'Pack Markup NuGets'
+ inputs:
+ script: '$(PathToMsBuildOnMacOS) $(PathToMarkupUnitTestCsproj) /p:Configuration=Release /t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'
+ - task: CmdLine@2
+ displayName: 'Pack CommunityToolkit NuGets'
+ inputs:
+ script: '$(PathToMsBuildOnMacOS) $(PathToCommunityToolkitCsproj) /p:Configuration=Release /t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"'
- ${{ if eq(variables['System.TeamProject'], 'devdiv') }}:
- template: sign-artifacts/jobs/v2.yml@internal-templates
diff --git a/samples/XCT.Sample.Android/MainActivity.cs b/samples/XCT.Sample.Android/MainActivity.cs
index 9a00b8c73..d2392c841 100644
--- a/samples/XCT.Sample.Android/MainActivity.cs
+++ b/samples/XCT.Sample.Android/MainActivity.cs
@@ -2,7 +2,6 @@
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
-using Xamarin.Essentials;
namespace Xamarin.CommunityToolkit.Sample.Droid
{
@@ -17,14 +16,14 @@ protected override void OnCreate(Bundle savedInstanceState)
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
- Platform.Init(this, savedInstanceState);
+ Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
- Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+ Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
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 8fe84cb44..2a3c8b3ea 100644
--- a/samples/XCT.Sample.Android/Xamarin.CommunityToolkit.Sample.Android.csproj
+++ b/samples/XCT.Sample.Android/Xamarin.CommunityToolkit.Sample.Android.csproj
@@ -25,7 +25,7 @@
true
- portable
+ full
false
bin\Debug
DEBUG;
diff --git a/samples/XCT.Sample.UWP/App.xaml.cs b/samples/XCT.Sample.UWP/App.xaml.cs
index 2a60dbd76..29871212c 100644
--- a/samples/XCT.Sample.UWP/App.xaml.cs
+++ b/samples/XCT.Sample.UWP/App.xaml.cs
@@ -85,7 +85,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
///
/// The Frame which failed navigation
/// Details about the navigation failure
- void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ void OnNavigationFailed(object? sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
@@ -97,7 +97,7 @@ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
///
/// The source of the suspend request.
/// Details about the suspend request.
- void OnSuspending(object sender, SuspendingEventArgs e)
+ void OnSuspending(object? sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
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.sln b/samples/XCT.Sample.sln
index fcf418bc7..4fcef2ef2 100644
--- a/samples/XCT.Sample.sln
+++ b/samples/XCT.Sample.sln
@@ -18,9 +18,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.CommunityToolkit.Sa
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F695F5E8-420F-475F-A4CF-F5BB3FA6E818}"
ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- Directory.Build.props = Directory.Build.props
- Xamarin.CommunityToolkit.ruleset = Xamarin.CommunityToolkit.ruleset
+ ..\.editorconfig = ..\.editorconfig
+ ..\Directory.Build.props = ..\Directory.Build.props
+ ..\Xamarin.CommunityToolkit.ruleset = ..\Xamarin.CommunityToolkit.ruleset
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.CommunityToolkit.Sample.WPF", "XCT.Sample.WPF\Xamarin.CommunityToolkit.Sample.WPF.csproj", "{C4D6CD2D-8DF4-4D46-936C-1AB31C87B5EA}"
@@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.CommunityToolkit.Sa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.CommunityToolkit.Markup", "..\src\Markup\Xamarin.CommunityToolkit.Markup\Xamarin.CommunityToolkit.Markup.csproj", "{A5AAB927-15D7-498C-8295-4209F21836CE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.CommunityToolkit.Markup.UnitTests", "..\src\Markup\Xamarin.CommunityToolkit.Markup.UnitTests\Xamarin.CommunityToolkit.Markup.UnitTests.csproj", "{AAE423C4-E9B4-434E-885C-2164C12BF79C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -62,6 +64,7 @@ Global
{8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Debug|x86.Build.0 = Debug|Any CPU
{8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|Any CPU.Deploy.0 = Release|Any CPU
{8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|ARM.ActiveCfg = Release|Any CPU
{8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|ARM.Build.0 = Release|Any CPU
{8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|iPhone.ActiveCfg = Release|Any CPU
@@ -191,6 +194,8 @@ Global
{91C748B4-E9ED-4543-880A-26747B03DE3A}.Debug|x86.Build.0 = Debug|x86
{91C748B4-E9ED-4543-880A-26747B03DE3A}.Debug|x86.Deploy.0 = Debug|x86
{91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|Any CPU.ActiveCfg = Release|x86
+ {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|Any CPU.Build.0 = Release|x86
+ {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|Any CPU.Deploy.0 = Release|x86
{91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|ARM.ActiveCfg = Release|ARM
{91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|ARM.Build.0 = Release|ARM
{91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|ARM.Deploy.0 = Release|ARM
@@ -298,12 +303,37 @@ Global
{A5AAB927-15D7-498C-8295-4209F21836CE}.Release|x64.Build.0 = Release|Any CPU
{A5AAB927-15D7-498C-8295-4209F21836CE}.Release|x86.ActiveCfg = Release|Any CPU
{A5AAB927-15D7-498C-8295-4209F21836CE}.Release|x86.Build.0 = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|ARM.Build.0 = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|x64.Build.0 = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Debug|x86.Build.0 = Debug|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|ARM.ActiveCfg = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|ARM.Build.0 = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|iPhone.Build.0 = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|x64.ActiveCfg = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|x64.Build.0 = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|x86.ActiveCfg = Release|Any CPU
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{54B7812B-45A5-4FE2-9CEA-C5F17D65BDE9} = {47DFE508-04F1-433D-8C55-0C1ACD033573}
+ {AAE423C4-E9B4-434E-885C-2164C12BF79C} = {47DFE508-04F1-433D-8C55-0C1ACD033573}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {449686DB-B85A-4DFA-AA26-9BC92468CC2A}
diff --git a/samples/XCT.Sample/App.xaml.cs b/samples/XCT.Sample/App.xaml.cs
index 5ec66b27a..6e2137b3b 100644
--- a/samples/XCT.Sample/App.xaml.cs
+++ b/samples/XCT.Sample/App.xaml.cs
@@ -1,4 +1,5 @@
-using Xamarin.CommunityToolkit.Helpers;
+using System.Globalization;
+using Xamarin.CommunityToolkit.Helpers;
using Xamarin.CommunityToolkit.Sample.Pages;
using Xamarin.CommunityToolkit.Sample.Resx;
using Xamarin.Forms.PlatformConfiguration;
@@ -11,7 +12,10 @@ public partial class App : Forms.Application
public App()
{
On().SetImageDirectory("Assets");
+
+ LocalizationResourceManager.Current.PropertyChanged += (sender, e) => AppResources.Culture = LocalizationResourceManager.Current.CurrentCulture;
LocalizationResourceManager.Current.Init(AppResources.ResourceManager);
+ LocalizationResourceManager.Current.CurrentCulture = new CultureInfo("en");
InitializeComponent();
MainPage = new BaseNavigationPage(new WelcomePage());
diff --git a/samples/XCT.Sample/Helpers/RelayCommand.cs b/samples/XCT.Sample/Helpers/RelayCommand.cs
index 453460545..d82836760 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
- {
+ else if (asyncExecute != null)
await asyncExecute(parameter);
- }
+ else
+ 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/Images/logo.png b/samples/XCT.Sample/Images/logo.png
new file mode 100644
index 000000000..633b9c0b0
Binary files /dev/null and b/samples/XCT.Sample/Images/logo.png differ
diff --git a/samples/XCT.Sample/Pages/AboutPage.xaml b/samples/XCT.Sample/Pages/AboutPage.xaml
index 8fbf440c9..9abebc964 100644
--- a/samples/XCT.Sample/Pages/AboutPage.xaml
+++ b/samples/XCT.Sample/Pages/AboutPage.xaml
@@ -14,7 +14,11 @@
-
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/SettingPage.xaml.cs b/samples/XCT.Sample/Pages/SettingPage.xaml.cs
index d6e7b2309..7ecd0bcaa 100644
--- a/samples/XCT.Sample/Pages/SettingPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/SettingPage.xaml.cs
@@ -9,7 +9,6 @@ public SettingPage()
InitializeComponent();
}
- async void OnCloseClicked(object sender, EventArgs e)
- => await Navigation.PopModalAsync();
+ async void OnCloseClicked(object? sender, EventArgs e) => await Navigation.PopModalAsync();
}
}
\ 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..55352ae45 100644
--- a/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs
+++ b/samples/XCT.Sample/Pages/TestCases/MediaElementSourcePage.xaml.cs
@@ -1,27 +1,17 @@
-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";
- public MediaSource VideoAsMediaSource => MediaSource.FromUri(VideoAsString);
+ public MediaSource? VideoAsMediaSource => MediaSource.FromUri(VideoAsString);
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/TestCases/TouchEffectButtonPage.xaml.cs b/samples/XCT.Sample/Pages/TestCases/TouchEffectButtonPage.xaml.cs
index e26068c55..61de4d00e 100644
--- a/samples/XCT.Sample/Pages/TestCases/TouchEffectButtonPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/TestCases/TouchEffectButtonPage.xaml.cs
@@ -1,15 +1,16 @@
using System.Windows.Input;
-using Xamarin.Forms;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.Pages.TestCases
{
public partial class TouchEffectButtonPage
{
- ICommand command;
-
public TouchEffectButtonPage()
- => InitializeComponent();
+ {
+ Command = CommandFactory.Create(() => DisplayAlert("Command executed ", null, "OK"));
+ InitializeComponent();
+ }
- public ICommand Command => command ??= new Command(() => this.DisplayAlert("Command executed ", null, "OK"));
+ public ICommand Command { get; }
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/TestCases/TouchEffectCollectionViewPage.xaml.cs b/samples/XCT.Sample/Pages/TestCases/TouchEffectCollectionViewPage.xaml.cs
index ada32eb11..2639c42ac 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 = CommandFactory.Create(() => DisplayAlert("Long Press", null, "OK"));
+ }
+
+ public ICommand LongPressCommand { get; }
}
}
diff --git a/samples/XCT.Sample/Pages/Views/AvatarViewPage.xaml b/samples/XCT.Sample/Pages/Views/AvatarViewPage.xaml
index 3cd31eb5e..d58530fea 100644
--- a/samples/XCT.Sample/Pages/Views/AvatarViewPage.xaml
+++ b/samples/XCT.Sample/Pages/Views/AvatarViewPage.xaml
@@ -46,7 +46,7 @@
-
+
+ Text="99">
diff --git a/samples/XCT.Sample/Pages/Views/CameraViewPage.xaml.cs b/samples/XCT.Sample/Pages/Views/CameraViewPage.xaml.cs
index d4e9e4e1b..80b0585fe 100644
--- a/samples/XCT.Sample/Pages/Views/CameraViewPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/CameraViewPage.xaml.cs
@@ -14,13 +14,13 @@ public CameraViewPage()
zoomLabel.Text = string.Format("Zoom: {0}", zoomSlider.Value);
}
- void ZoomSlider_ValueChanged(object sender, ValueChangedEventArgs e)
+ void ZoomSlider_ValueChanged(object? sender, ValueChangedEventArgs e)
{
cameraView.Zoom = (float)zoomSlider.Value;
zoomLabel.Text = string.Format("Zoom: {0}", Math.Round(zoomSlider.Value));
}
- void VideoSwitch_Toggled(object sender, ToggledEventArgs e)
+ void VideoSwitch_Toggled(object? sender, ToggledEventArgs e)
{
var captureVideo = e.Value;
@@ -36,14 +36,14 @@ void VideoSwitch_Toggled(object sender, ToggledEventArgs e)
}
// You can also set it to Default and External
- void FrontCameraSwitch_Toggled(object sender, ToggledEventArgs e)
+ void FrontCameraSwitch_Toggled(object? sender, ToggledEventArgs e)
=> cameraView.CameraOptions = e.Value ? CameraOptions.Front : CameraOptions.Back;
// You can also set it to Torch (always on) and Auto
- void FlashSwitch_Toggled(object sender, ToggledEventArgs e)
+ void FlashSwitch_Toggled(object? sender, ToggledEventArgs e)
=> cameraView.FlashMode = e.Value ? CameraFlashMode.On : CameraFlashMode.Off;
- void DoCameraThings_Clicked(object sender, EventArgs e)
+ void DoCameraThings_Clicked(object? sender, EventArgs e)
{
cameraView.Shutter();
doCameraThings.Text = cameraView.CaptureMode == CameraCaptureMode.Video
@@ -51,7 +51,7 @@ void DoCameraThings_Clicked(object sender, EventArgs e)
: "Snap Picture";
}
- void CameraView_OnAvailable(object sender, bool e)
+ void CameraView_OnAvailable(object? sender, bool e)
{
if (e)
{
@@ -67,7 +67,7 @@ void CameraView_OnAvailable(object sender, bool e)
zoomSlider.IsEnabled = e;
}
- void CameraView_MediaCaptured(object sender, MediaCapturedEventArgs e)
+ void CameraView_MediaCaptured(object? sender, MediaCapturedEventArgs e)
{
switch (cameraView.CaptureMode)
{
diff --git a/samples/XCT.Sample/Pages/Views/MediaElementPage.xaml.cs b/samples/XCT.Sample/Pages/Views/MediaElementPage.xaml.cs
index 24fbe5f91..a3fbf7987 100644
--- a/samples/XCT.Sample/Pages/Views/MediaElementPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/MediaElementPage.xaml.cs
@@ -6,14 +6,14 @@ public partial class MediaElementPage
{
public MediaElementPage() => InitializeComponent();
- void OnMediaOpened(object sender, EventArgs e) => Console.WriteLine("Media opened.");
+ void OnMediaOpened(object? sender, EventArgs e) => Console.WriteLine("Media opened.");
- void OnMediaFailed(object sender, EventArgs e) => Console.WriteLine("Media failed.");
+ void OnMediaFailed(object? sender, EventArgs e) => Console.WriteLine("Media failed.");
- void OnMediaEnded(object sender, EventArgs e) => Console.WriteLine("Media ended.");
+ void OnMediaEnded(object? sender, EventArgs e) => Console.WriteLine("Media ended.");
- void OnSeekCompleted(object sender, EventArgs e) => Console.WriteLine("Seek completed.");
+ void OnSeekCompleted(object? sender, EventArgs e) => Console.WriteLine("Seek completed.");
- void OnResetClicked(object sender, EventArgs e) => mediaElement.Source = null;
+ void OnResetClicked(object? sender, EventArgs e) => mediaElement.Source = null;
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/PopupGalleryPage.xaml b/samples/XCT.Sample/Pages/Views/PopupGalleryPage.xaml
new file mode 100644
index 000000000..54b0596e8
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/PopupGalleryPage.xaml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/PopupGalleryPage.xaml.cs b/samples/XCT.Sample/Pages/Views/PopupGalleryPage.xaml.cs
new file mode 100644
index 000000000..63fa5ecaf
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/PopupGalleryPage.xaml.cs
@@ -0,0 +1,7 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views
+{
+ public partial class PopupGalleryPage
+ {
+ public PopupGalleryPage() => InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/ButtonPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/ButtonPopup.xaml
new file mode 100644
index 000000000..257593a98
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/ButtonPopup.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/ButtonPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/ButtonPopup.xaml.cs
new file mode 100644
index 000000000..3a37bcd68
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/ButtonPopup.xaml.cs
@@ -0,0 +1,9 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class ButtonPopup
+ {
+ public ButtonPopup() => InitializeComponent();
+
+ void Button_Clicked(object? sender, System.EventArgs e) => Dismiss(null);
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/CsharpBindingPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/CsharpBindingPopup.xaml
new file mode 100644
index 000000000..d5d7955dd
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/CsharpBindingPopup.xaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/CsharpBindingPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/CsharpBindingPopup.xaml.cs
new file mode 100644
index 000000000..1f4a2ba3a
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/CsharpBindingPopup.xaml.cs
@@ -0,0 +1,13 @@
+using Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class CsharpBindingPopup
+ {
+ public CsharpBindingPopup()
+ {
+ InitializeComponent();
+ BindingContext = new CsharpBindingPopupViewModel();
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/MultipleButtonPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/MultipleButtonPopup.xaml
new file mode 100644
index 000000000..a5eccaaad
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/MultipleButtonPopup.xaml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/MultipleButtonPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/MultipleButtonPopup.xaml.cs
new file mode 100644
index 000000000..ab0bf5d85
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/MultipleButtonPopup.xaml.cs
@@ -0,0 +1,11 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class MultipleButtonPopup
+ {
+ public MultipleButtonPopup() => InitializeComponent();
+
+ void Cancel_Clicked(object? sender, System.EventArgs e) => Dismiss(false);
+
+ void Okay_Clicked(object? sender, System.EventArgs e) => Dismiss(true);
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/NoLightDismissPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/NoLightDismissPopup.xaml
new file mode 100644
index 000000000..8f5dc9523
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/NoLightDismissPopup.xaml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/NoLightDismissPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/NoLightDismissPopup.xaml.cs
new file mode 100644
index 000000000..f254677bf
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/NoLightDismissPopup.xaml.cs
@@ -0,0 +1,9 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class NoLightDismissPopup
+ {
+ public NoLightDismissPopup() => InitializeComponent();
+
+ void Button_Clicked(object? sender, System.EventArgs e) => Dismiss(null);
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/OpenedEventSimplePopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/OpenedEventSimplePopup.xaml
new file mode 100644
index 000000000..ad33e3f6d
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/OpenedEventSimplePopup.xaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/OpenedEventSimplePopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/OpenedEventSimplePopup.xaml.cs
new file mode 100644
index 000000000..1ba820592
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/OpenedEventSimplePopup.xaml.cs
@@ -0,0 +1,21 @@
+using Xamarin.CommunityToolkit.UI.Views;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class OpenedEventSimplePopup
+ {
+ public OpenedEventSimplePopup()
+ {
+ InitializeComponent();
+ Opened += OnOpened;
+ }
+
+ void OnOpened(object? sender, PopupOpenedEventArgs e)
+ {
+ Opened -= OnOpened;
+
+ Title.Text = "Opened Event Popup";
+ Message.Text = "The content of this popup was updated after the popup was rendered";
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/PopupAnchorPage.xaml b/samples/XCT.Sample/Pages/Views/Popups/PopupAnchorPage.xaml
new file mode 100644
index 000000000..978b9abfb
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/PopupAnchorPage.xaml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/PopupAnchorPage.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/PopupAnchorPage.xaml.cs
new file mode 100644
index 000000000..95f1a2005
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/PopupAnchorPage.xaml.cs
@@ -0,0 +1,35 @@
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class PopupAnchorPage
+ {
+ public PopupAnchorPage() => InitializeComponent();
+
+ void OnPanUpdated(object? sender, PanUpdatedEventArgs e)
+ {
+ if (sender is Label label)
+ {
+ if (Device.RuntimePlatform == Device.Android)
+ {
+ label.TranslationX += e.TotalX;
+ label.TranslationY += e.TotalY;
+ }
+ else
+ {
+ switch (e.StatusType)
+ {
+ case GestureStatus.Running:
+ label.TranslationX = e.TotalX;
+ label.TranslationY = e.TotalY;
+ break;
+ case GestureStatus.Completed:
+ label.TranslationX += e.TotalX;
+ label.TranslationY += e.TotalY;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/PopupPositionPage.xaml b/samples/XCT.Sample/Pages/Views/Popups/PopupPositionPage.xaml
new file mode 100644
index 000000000..fdb89a59e
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/PopupPositionPage.xaml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/PopupPositionPage.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/PopupPositionPage.xaml.cs
new file mode 100644
index 000000000..090c7d20b
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/PopupPositionPage.xaml.cs
@@ -0,0 +1,7 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class PopupPositionPage
+ {
+ public PopupPositionPage() => InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/PopupSize.cs b/samples/XCT.Sample/Pages/Views/Popups/PopupSize.cs
new file mode 100644
index 000000000..64a713845
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/PopupSize.cs
@@ -0,0 +1,18 @@
+using Xamarin.Essentials;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ static class PopupSize
+ {
+ // examples for fixed sizes
+ public static Size Tiny => new Size(100, 100);
+
+ public static Size Small => new Size(300, 300);
+
+ // examples for relative to screen sizes
+ public static Size Medium => new Size(0.7 * (DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density), 0.6 * (DeviceDisplay.MainDisplayInfo.Height / DeviceDisplay.MainDisplayInfo.Density));
+
+ public static Size Large => new Size(0.9 * (DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density), 0.8 * (DeviceDisplay.MainDisplayInfo.Height / DeviceDisplay.MainDisplayInfo.Density));
+ }
+}
diff --git a/samples/XCT.Sample/Pages/Views/Popups/ReturnResultPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/ReturnResultPopup.xaml
new file mode 100644
index 000000000..943bd9b37
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/ReturnResultPopup.xaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/ReturnResultPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/ReturnResultPopup.xaml.cs
new file mode 100644
index 000000000..aeaa0f083
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/ReturnResultPopup.xaml.cs
@@ -0,0 +1,12 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class ReturnResultPopup
+ {
+ public ReturnResultPopup() =>
+ InitializeComponent();
+
+ protected override string GetLightDismissResult() => "Light Dismiss";
+
+ void Button_Clicked(object? sender, System.EventArgs e) => Dismiss("Close button tapped");
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/SimplePopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/SimplePopup.xaml
new file mode 100644
index 000000000..d1a8149fc
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/SimplePopup.xaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/SimplePopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/SimplePopup.xaml.cs
new file mode 100644
index 000000000..0adc37d6a
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/SimplePopup.xaml.cs
@@ -0,0 +1,7 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class SimplePopup
+ {
+ public SimplePopup() => InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/ToggleSizePopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/ToggleSizePopup.xaml
new file mode 100644
index 000000000..27e940434
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/ToggleSizePopup.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/ToggleSizePopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/ToggleSizePopup.xaml.cs
new file mode 100644
index 000000000..6592a506f
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/ToggleSizePopup.xaml.cs
@@ -0,0 +1,27 @@
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class ToggleSizePopup
+ {
+ Size originalSize;
+
+ public ToggleSizePopup()
+ {
+ InitializeComponent();
+ originalSize = Size;
+ }
+
+ void Button_Clicked(object? sender, System.EventArgs e)
+ {
+ if (originalSize == Size)
+ {
+ Size = new Size(originalSize.Width * 1.25, originalSize.Height * 1.25);
+ }
+ else
+ {
+ Size = originalSize;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/TransparentPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/TransparentPopup.xaml
new file mode 100644
index 000000000..120e5726c
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/TransparentPopup.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/TransparentPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/TransparentPopup.xaml.cs
new file mode 100644
index 000000000..2cdde83d4
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/TransparentPopup.xaml.cs
@@ -0,0 +1,18 @@
+using Xamarin.Forms.PlatformConfiguration;
+using Xamarin.CommunityToolkit.PlatformConfiguration.iOSSpecific;
+using Xamarin.CommunityToolkit.PlatformConfiguration.WindowsSpecific;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class TransparentPopup
+ {
+ public TransparentPopup() => InitializeComponent();
+
+ protected override void OnBindingContextChanged()
+ {
+ base.OnBindingContextChanged();
+ On().UseArrowDirection(PopoverArrowDirection.Right);
+ On().SetBorderColor(Xamarin.Forms.Color.Red);
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/Popups/XamlBindingPopup.xaml b/samples/XCT.Sample/Pages/Views/Popups/XamlBindingPopup.xaml
new file mode 100644
index 000000000..df8c9f38c
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/XamlBindingPopup.xaml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/Popups/XamlBindingPopup.xaml.cs b/samples/XCT.Sample/Pages/Views/Popups/XamlBindingPopup.xaml.cs
new file mode 100644
index 000000000..16d026950
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/Popups/XamlBindingPopup.xaml.cs
@@ -0,0 +1,7 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
+{
+ public partial class XamlBindingPopup
+ {
+ public XamlBindingPopup() => InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/RangeSliderPage.xaml.cs b/samples/XCT.Sample/Pages/Views/RangeSliderPage.xaml.cs
index 7aea5978a..430263588 100644
--- a/samples/XCT.Sample/Pages/Views/RangeSliderPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/RangeSliderPage.xaml.cs
@@ -8,7 +8,7 @@ public partial class RangeSliderPage
public RangeSliderPage()
=> InitializeComponent();
- void OnThumbSizeSwitchToggled(object sender, ToggledEventArgs e)
+ void OnThumbSizeSwitchToggled(object? sender, ToggledEventArgs e)
{
if (e.Value)
{
@@ -27,7 +27,7 @@ Binding GetSliderValueBinding(object source)
Source = source
};
- void OnThumbRadiusSwitchToggled(object sender, ToggledEventArgs e)
+ void OnThumbRadiusSwitchToggled(object? sender, ToggledEventArgs e)
{
if (sender == LowerUpperThumbRadiusSwitch)
{
@@ -58,7 +58,7 @@ void OnThumbRadiusSwitchToggled(object sender, ToggledEventArgs e)
}
}
- void OnTrackRadiusSwitchToggled(object sender, ToggledEventArgs e)
+ void OnTrackRadiusSwitchToggled(object? sender, ToggledEventArgs e)
{
if (e.Value)
{
diff --git a/samples/XCT.Sample/Pages/Views/ShieldPage.xaml b/samples/XCT.Sample/Pages/Views/ShieldPage.xaml
index 49886f414..a1bfa4d67 100644
--- a/samples/XCT.Sample/Pages/Views/ShieldPage.xaml
+++ b/samples/XCT.Sample/Pages/Views/ShieldPage.xaml
@@ -6,72 +6,90 @@
x:Class="Xamarin.CommunityToolkit.Sample.Pages.Views.ShieldPage"
Title="Shield">
-
+
+
+
-
+
-
+
-
+
-
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
diff --git a/samples/XCT.Sample/Pages/Views/ShieldPage.xaml.cs b/samples/XCT.Sample/Pages/Views/ShieldPage.xaml.cs
index 7339ac4ee..d553bec2c 100644
--- a/samples/XCT.Sample/Pages/Views/ShieldPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/ShieldPage.xaml.cs
@@ -6,6 +6,6 @@ public partial class ShieldPage
{
public ShieldPage() => InitializeComponent();
- async void OnShieldTapped(object sender, EventArgs e) => await DisplayAlert("Shield Event", "C# Shield Tapped", "Ok");
+ async void OnShieldTapped(object? sender, EventArgs e) => await DisplayAlert("Shield Event", "C# Shield Tapped", "Ok");
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml b/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml
index ae62efc38..fc968cdae 100644
--- a/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml
+++ b/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml
@@ -35,6 +35,7 @@
diff --git a/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml.cs b/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml.cs
index 8d319ab2f..7263752ba 100644
--- a/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/SideMenuViewPage.xaml.cs
@@ -8,10 +8,10 @@ public partial class SideMenuViewPage
public SideMenuViewPage()
=> InitializeComponent();
- void OnLeftButtonClicked(object sender, EventArgs e)
+ void OnLeftButtonClicked(object? sender, EventArgs e)
=> SideMenuView.State = SideMenuState.LeftMenuShown;
- void OnRightButtonClicked(object sender, EventArgs e)
+ void OnRightButtonClicked(object? sender, EventArgs e)
=> SideMenuView.State = SideMenuState.RightMenuShown;
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml b/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml
index a4887ffc4..2ca00b5e2 100644
--- a/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml
+++ b/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml
@@ -7,7 +7,8 @@
-
+
+
diff --git a/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs b/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs
index 2845fe2fb..24a10912d 100644
--- a/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/SnackBarPage.xaml.cs
@@ -14,7 +14,7 @@ public partial class SnackBarPage : BasePage
{
public SnackBarPage() => InitializeComponent();
- async void DisplaySnackBarClicked(object sender, EventArgs args)
+ async void DisplaySnackBarClicked(object? sender, EventArgs args)
{
var result = await this.DisplaySnackBarAsync(GenerateLongText(5), "Run action", () =>
{
@@ -24,57 +24,74 @@ async void DisplaySnackBarClicked(object sender, EventArgs args)
StatusText.Text = result ? "SnackBar is closed by user" : "SnackBar is closed by timeout";
}
- async void DisplayToastClicked(object sender, EventArgs args)
+ async void DisplaySnackBarWithPadding(object? sender, EventArgs args)
+ {
+ var options = new SnackBarOptions()
+ {
+ BackgroundColor = Color.FromHex("#CC0000"),
+ MessageOptions = new MessageOptions
+ {
+ Message = "msg",
+ Foreground = Color.White,
+ Font = Font.SystemFontOfSize(16),
+ Padding = new Thickness(10, 20, 30, 40)
+ }
+ };
+
+ await this.DisplaySnackBarAsync(options);
+ }
+
+ async void DisplayToastClicked(object? sender, EventArgs args)
{
await this.DisplayToastAsync(GenerateLongText(5));
StatusText.Text = "Toast is closed by timeout";
}
- async void DisplaySnackBarAdvancedClicked(object sender, EventArgs args)
+ async void DisplaySnackBarAdvancedClicked(object? sender, EventArgs args)
{
const string SmileIcon = "\uf118";
- var messageOptions = new MessageOptions
- {
- Foreground = Color.DeepSkyBlue,
- Font = Font.OfSize("FARegular", 40),
- Message = SmileIcon
- };
-
- var actionOptions = new List
+ var options = new SnackBarOptions
{
- new SnackBarActionOptions
+ MessageOptions = new MessageOptions
{
- ForegroundColor = Color.Red,
- BackgroundColor = Color.Green,
- Font = Font.OfSize("Times New Roman", 15),
- Text = "Action1",
- Action = () =>
- {
- Debug.WriteLine("1");
- return Task.CompletedTask;
- }
+ Foreground = Color.DeepSkyBlue,
+ Font = Font.OfSize("FARegular", 40),
+ Padding = new Thickness(10, 20, 30, 40),
+ Message = SmileIcon
},
- new SnackBarActionOptions
+ Duration = TimeSpan.FromMilliseconds(5000),
+ BackgroundColor = Color.Coral,
+ IsRtl = CultureInfo.CurrentCulture.TextInfo.IsRightToLeft,
+ Actions = new List
{
- ForegroundColor = Color.Green,
- BackgroundColor = Color.Red,
- Font = Font.OfSize("Times New Roman", 20),
- Text = "Action2",
- Action = () =>
+ new SnackBarActionOptions
+ {
+ ForegroundColor = Color.Red,
+ BackgroundColor = Color.Green,
+ Font = Font.OfSize("Times New Roman", 15),
+ Padding = new Thickness(10, 20, 30, 40),
+ Text = "Action1",
+ Action = () =>
+ {
+ Debug.WriteLine("1");
+ return Task.CompletedTask;
+ }
+ },
+ new SnackBarActionOptions
{
- Debug.WriteLine("2");
- return Task.CompletedTask;
+ ForegroundColor = Color.Green,
+ BackgroundColor = Color.Red,
+ Font = Font.OfSize("Times New Roman", 20),
+ Padding = new Thickness(40, 30, 20, 10),
+ Text = "Action2",
+ Action = () =>
+ {
+ Debug.WriteLine("2");
+ return Task.CompletedTask;
+ }
}
}
};
- var options = new SnackBarOptions
- {
- MessageOptions = messageOptions,
- Duration = TimeSpan.FromMilliseconds(5000),
- BackgroundColor = Color.Coral,
- IsRtl = CultureInfo.CurrentCulture.TextInfo.IsRightToLeft,
- Actions = actionOptions
- };
var result = await this.DisplaySnackBarAsync(options);
StatusText.Text = result ? "SnackBar is closed by user" : "SnackBar is closed by timeout";
}
diff --git a/samples/XCT.Sample/Pages/Views/TabView/CustomTabsPage.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/CustomTabsPage.xaml.cs
index b2649bde9..8e8273717 100644
--- a/samples/XCT.Sample/Pages/Views/TabView/CustomTabsPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/TabView/CustomTabsPage.xaml.cs
@@ -6,6 +6,6 @@ public partial class CustomTabsPage : BasePage
{
public CustomTabsPage() => InitializeComponent();
- void OnFabTabTapped(object sender, TabTappedEventArgs e) => DisplayAlert("FabTabGallery", "Tab Tapped.", "Ok");
+ void OnFabTabTapped(object? sender, TabTappedEventArgs e) => DisplayAlert("FabTabGallery", "Tab Tapped.", "Ok");
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml
new file mode 100644
index 000000000..a08c4ca21
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs
new file mode 100644
index 000000000..fe53d1b9c
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs
@@ -0,0 +1,7 @@
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.TabView
+{
+ public partial class LazyTabPage
+ {
+ public LazyTabPage() => InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml
new file mode 100644
index 000000000..68c8ab19a
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs
new file mode 100644
index 000000000..24fb78a44
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs
@@ -0,0 +1,29 @@
+using Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.TabView
+{
+ public partial class LazyTestView : ContentView
+ {
+ public LazyTestView()
+ {
+ InitializeComponent();
+
+ Build();
+ NormalTestViewModel.Current.LoadedViews += "LazyView Loaded \n";
+ }
+
+ void Build()
+ {
+ for (var i = 0; i < 117; i++)
+ {
+ var box = new BoxView
+ {
+ BackgroundColor = i % 2 == 0 ? Color.Blue : Color.Fuchsia
+ };
+
+ uniformGrid.Children.Add(box);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml
new file mode 100644
index 000000000..2026ef55d
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs
new file mode 100644
index 000000000..f792cf33a
--- /dev/null
+++ b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs
@@ -0,0 +1,16 @@
+using Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.Pages.Views.TabView
+{
+ public partial class NormalTestView : ContentView
+ {
+ public NormalTestView()
+ {
+ InitializeComponent();
+ BindingContext = NormalTestViewModel.Current;
+
+ NormalTestViewModel.Current.LoadedViews += "NormalTestLoaded \n";
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Pages/Views/TabView/TabBadgePage.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/TabBadgePage.xaml.cs
index 41dab454f..c5293b6c9 100644
--- a/samples/XCT.Sample/Pages/Views/TabView/TabBadgePage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/TabView/TabBadgePage.xaml.cs
@@ -26,9 +26,9 @@ public int Counter
}
}
- void OnIncreaseClicked(object sender, EventArgs e) => Counter++;
+ void OnIncreaseClicked(object? sender, EventArgs e) => Counter++;
- void OnDecreaseClicked(object sender, EventArgs e)
+ void OnDecreaseClicked(object? sender, EventArgs e)
{
if (Counter == 0)
return;
diff --git a/samples/XCT.Sample/Pages/Views/TabView/TabPlacementPage.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/TabPlacementPage.xaml.cs
index 2a4ec087b..a56f5f52a 100644
--- a/samples/XCT.Sample/Pages/Views/TabView/TabPlacementPage.xaml.cs
+++ b/samples/XCT.Sample/Pages/Views/TabView/TabPlacementPage.xaml.cs
@@ -7,7 +7,7 @@ public partial class TabPlacementPage : BasePage
{
public TabPlacementPage() => InitializeComponent();
- void OnChangeTabStripPlacementClicked(object sender, EventArgs e)
+ void OnChangeTabStripPlacementClicked(object? sender, EventArgs e)
{
if (TabView.TabStripPlacement == TabStripPlacement.Bottom)
TabView.TabStripPlacement = TabStripPlacement.Top;
diff --git a/samples/XCT.Sample/Pages/WelcomePage.xaml.cs b/samples/XCT.Sample/Pages/WelcomePage.xaml.cs
index 7fe36d455..60392f552 100644
--- a/samples/XCT.Sample/Pages/WelcomePage.xaml.cs
+++ b/samples/XCT.Sample/Pages/WelcomePage.xaml.cs
@@ -7,10 +7,10 @@ public partial class WelcomePage : BasePage
public WelcomePage()
=> InitializeComponent();
- async void OnAboutClicked(object sender, EventArgs e)
+ async void OnAboutClicked(object? sender, EventArgs e)
=> await Navigation.PushModalAsync(new BaseNavigationPage(new AboutPage()));
- async void OnSettingsClicked(object sender, EventArgs e)
+ async void OnSettingsClicked(object? sender, EventArgs e)
=> await Navigation.PushModalAsync(new BaseNavigationPage(new SettingPage()));
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/Resx/AppResources.Designer.cs b/samples/XCT.Sample/Resx/AppResources.Designer.cs
index 1fd909ed2..150cb2cf6 100644
--- a/samples/XCT.Sample/Resx/AppResources.Designer.cs
+++ b/samples/XCT.Sample/Resx/AppResources.Designer.cs
@@ -10,35 +10,48 @@
namespace Xamarin.CommunityToolkit.Sample.Resx {
using System;
- using System.Reflection;
- [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class AppResources {
+ ///
+ /// 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()]
+ public class AppResources {
- private static System.Resources.ResourceManager resourceMan;
+ private static global::System.Resources.ResourceManager resourceMan;
- private static System.Globalization.CultureInfo resourceCulture;
+ private static global::System.Globalization.CultureInfo resourceCulture;
- [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AppResources() {
}
- [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static System.Resources.ResourceManager ResourceManager {
+ ///
+ /// 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 {
get {
- if (object.Equals(null, resourceMan)) {
- System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Xamarin.CommunityToolkit.Sample.Resx.AppResources", typeof(AppResources).Assembly);
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xamarin.CommunityToolkit.Sample.Resx.AppResources", typeof(AppResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
- [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static System.Globalization.CultureInfo Culture {
+ ///
+ /// 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 {
get {
return resourceCulture;
}
@@ -47,27 +60,48 @@ internal class AppResources {
}
}
- internal static string ChangeLanguage {
+ ///
+ /// 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);
}
}
- internal static string English {
+ ///
+ /// Looks up a localized string similar to English.
+ ///
+ public static string English {
get {
return ResourceManager.GetString("English", resourceCulture);
}
}
- internal static string Spanish {
+ ///
+ /// Looks up a localized string similar to Save.
+ ///
+ public static string Save {
+ get {
+ return ResourceManager.GetString("Save", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Spanish.
+ ///
+ public static string Spanish {
get {
return ResourceManager.GetString("Spanish", resourceCulture);
}
}
- internal static string Save {
+ ///
+ /// Looks up a localized string similar to App version: {0}.
+ ///
+ public static string Version {
get {
- return ResourceManager.GetString("Save", resourceCulture);
+ return ResourceManager.GetString("Version", resourceCulture);
}
}
}
diff --git a/samples/XCT.Sample/Resx/AppResources.en.resx b/samples/XCT.Sample/Resx/AppResources.en.resx
new file mode 100644
index 000000000..0d86c5b45
--- /dev/null
+++ b/samples/XCT.Sample/Resx/AppResources.en.resx
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 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.
+
+
+ English
+
+
+ Spanish
+
+
+ Save
+
+
+ App version: {0}
+
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/Resx/AppResources.es.Designer.cs b/samples/XCT.Sample/Resx/AppResources.es.Designer.cs
deleted file mode 100644
index 32676c162..000000000
--- a/samples/XCT.Sample/Resx/AppResources.es.Designer.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace Xamarin.CommunityToolkit.Sample.Resx {
- using System;
- using System.Reflection;
-
-
- [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class AppResources_es {
-
- private static System.Resources.ResourceManager resourceMan;
-
- private static System.Globalization.CultureInfo resourceCulture;
-
- [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal AppResources_es() {
- }
-
- [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static System.Resources.ResourceManager ResourceManager {
- get {
- if (object.Equals(null, resourceMan)) {
- System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Xamarin.CommunityToolkit.Sample.Resx.AppResources.es", typeof(AppResources_es).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
-
- internal static string ChangeLanguage {
- get {
- return ResourceManager.GetString("ChangeLanguage", resourceCulture);
- }
- }
-
- internal static string English {
- get {
- return ResourceManager.GetString("English", resourceCulture);
- }
- }
-
- internal static string Spanish {
- get {
- return ResourceManager.GetString("Spanish", resourceCulture);
- }
- }
-
- internal static string Save {
- get {
- return ResourceManager.GetString("Save", resourceCulture);
- }
- }
- }
-}
diff --git a/samples/XCT.Sample/Resx/AppResources.es.resx b/samples/XCT.Sample/Resx/AppResources.es.resx
index 91b4689d0..c9e4c0859 100644
--- a/samples/XCT.Sample/Resx/AppResources.es.resx
+++ b/samples/XCT.Sample/Resx/AppResources.es.resx
@@ -1,4 +1,4 @@
-
+
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
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.
-
+
English
-
+
Spanish
-
+
Save
+
+ App version: {0}
+
\ No newline at end of file
diff --git a/samples/XCT.Sample/ViewModels/AboutViewModel.cs b/samples/XCT.Sample/ViewModels/AboutViewModel.cs
index 816d2627b..b7133e5e9 100644
--- a/samples/XCT.Sample/ViewModels/AboutViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/AboutViewModel.cs
@@ -12,13 +12,24 @@ 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...";
- ICommand selectedContributorCommand;
+ public AboutViewModel()
+ {
+ PageAppearingCommand = CommandFactory.Create(OnAppearing);
+ SelectedContributorCommand = CommandFactory.Create(async () =>
+ {
+ if (SelectedContributor == null)
+ return;
+
+ await Launcher.OpenAsync(SelectedContributor.HtmlUrl);
+ SelectedContributor = null;
+ });
+ }
public RepositoryContributor[] Contributors
{
@@ -26,7 +37,7 @@ public RepositoryContributor[] Contributors
set => SetProperty(ref contributors, value);
}
- public RepositoryContributor SelectedContributor
+ public RepositoryContributor? SelectedContributor
{
get => selectedContributor;
set => SetProperty(ref selectedContributor, value);
@@ -38,14 +49,9 @@ public string EmptyViewText
set => SetProperty(ref emptyViewText, value);
}
- public ICommand SelectedContributorCommand => selectedContributorCommand ??= new AsyncCommand(async () =>
- {
- if (SelectedContributor is null)
- return;
+ public ICommand PageAppearingCommand { get; }
- await Launcher.OpenAsync(SelectedContributor.HtmlUrl);
- SelectedContributor = null;
- });
+ public ICommand SelectedContributorCommand { get; }
public async Task OnAppearing()
{
diff --git a/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs
index dda757747..55e001563 100644
--- a/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Base/BaseGalleryViewModel.cs
@@ -2,28 +2,27 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.CommunityToolkit.Sample.Models;
-using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Sample.ViewModels
{
public abstract class BaseGalleryViewModel : BaseViewModel
{
- ICommand filterCommand;
-
- protected BaseGalleryViewModel()
+ public BaseGalleryViewModel()
{
Items = CreateItems().OrderBy(x => x.Title).ToList();
Filter();
+ FilterCommand = CommandFactory.Create(Filter);
}
- public ICommand FilterCommand => filterCommand ??= new Command(Filter);
-
public IReadOnlyList Items { get; }
- public IEnumerable FilteredItems { get; private set; }
+ public ICommand FilterCommand { get; }
+
+ public string FilterValue { private get; set; } = string.Empty;
- public string FilterValue { private get; set; }
+ public IEnumerable FilteredItems { get; private set; } = Enumerable.Empty();
protected abstract IEnumerable CreateItems();
diff --git a/samples/XCT.Sample/ViewModels/Behaviors/BehaviorsGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/BehaviorsGalleryViewModel.cs
index 75de8c626..9c226149d 100644
--- a/samples/XCT.Sample/ViewModels/Behaviors/BehaviorsGalleryViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Behaviors/BehaviorsGalleryViewModel.cs
@@ -57,6 +57,14 @@ public class BehaviorsGalleryViewModel : BaseGalleryViewModel
typeof(CharactersValidationBehaviorPage),
nameof(CharactersValidationBehavior),
"Changes an Entry's text color when an invalid string is provided."),
+ new SectionModel(
+ typeof(ProgressBarAnimationBehaviorPage),
+ nameof(ProgressBarAnimationBehavior),
+ "Animate the progress for the ProgressBar"),
+ new SectionModel(
+ typeof(SetFocusOnEntryCompletedBehaviorPage),
+ nameof(SetFocusOnEntryCompletedBehavior),
+ "Set focus to another element when an entry is completed"),
};
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/ViewModels/Behaviors/EventToCommandBehaviorViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/EventToCommandBehaviorViewModel.cs
index 57b8672b3..a8973056f 100644
--- a/samples/XCT.Sample/ViewModels/Behaviors/EventToCommandBehaviorViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Behaviors/EventToCommandBehaviorViewModel.cs
@@ -1,20 +1,21 @@
using System.Windows.Input;
-using Xamarin.Forms;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors
{
public class EventToCommandBehaviorViewModel : BaseViewModel
{
- ICommand incrementCommand;
-
int clickCount;
- public ICommand IncrementCommand => incrementCommand ??= new Command(() => ClickCount++);
+ public EventToCommandBehaviorViewModel() =>
+ IncrementCommand = CommandFactory.Create(() => ClickCount++);
public int ClickCount
{
get => clickCount;
set => SetProperty(ref clickCount, value);
}
+
+ public ICommand IncrementCommand { get; }
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs
index 87056411a..af0555810 100644
--- a/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Behaviors/MaxLengthReachedBehaviorViewModel.cs
@@ -1,12 +1,12 @@
using System;
using System.Windows.Input;
-using Xamarin.Forms;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors
{
public class MaxLengthReachedBehaviorViewModel : BaseViewModel
{
- string commandExecutions;
+ string commandExecutions = string.Empty;
public string CommandExecutions
{
@@ -17,7 +17,7 @@ public string CommandExecutions
public ICommand MaxLengthReachedCommand { get; }
public MaxLengthReachedBehaviorViewModel()
- => MaxLengthReachedCommand = new Command(OnCommandExecuted);
+ => MaxLengthReachedCommand = CommandFactory.Create(OnCommandExecuted);
void OnCommandExecuted(string text)
=> CommandExecutions += string.Format("MaxLength reached with value: '{0}'.", text) + Environment.NewLine;
diff --git a/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs b/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs
new file mode 100644
index 000000000..4e950d778
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Behaviors/ProgressBarAnimationBehaviorViewModel.cs
@@ -0,0 +1,31 @@
+using System.Windows.Input;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors
+{
+ public class ProgressBarAnimationBehaviorViewModel : BaseViewModel
+ {
+ double progress;
+
+ public ProgressBarAnimationBehaviorViewModel()
+ {
+ SetTo0Command = new Command(() => SetProgress(0));
+ SetTo50Command = new Command(() => SetProgress(0.5));
+ SetTo100Command = new Command(() => SetProgress(1));
+ }
+
+ public ICommand SetTo0Command { get; }
+
+ public ICommand SetTo50Command { get; }
+
+ public ICommand SetTo100Command { get; }
+
+ public double 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 a80440737..8ce3761d1 100644
--- a/samples/XCT.Sample/ViewModels/Behaviors/UserStoppedTypingBehaviorViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Behaviors/UserStoppedTypingBehaviorViewModel.cs
@@ -1,14 +1,12 @@
using System;
using System.Windows.Input;
-using Xamarin.Forms;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Behaviors
{
public class UserStoppedTypingBehaviorViewModel : BaseViewModel
{
- #region Properties
-
- string performedSearches;
+ string performedSearches = string.Empty;
public string PerformedSearches
{
@@ -18,10 +16,8 @@ public string PerformedSearches
public ICommand SearchCommand { get; }
- #endregion Properties
-
public UserStoppedTypingBehaviorViewModel()
- => SearchCommand = new Command(PerformSearch);
+ => SearchCommand = CommandFactory.Create(PerformSearch);
void PerformSearch(string searchTerms)
=> PerformedSearches += string.Format("Performed search for '{0}'.", searchTerms) + Environment.NewLine;
diff --git a/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs
index 195c042fd..44385785e 100644
--- a/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Converters/ByteArrayToImageSourceViewModel.cs
@@ -1,7 +1,9 @@
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
+using System.Windows.Input;
using Octokit;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
{
@@ -9,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);
@@ -25,6 +27,11 @@ public bool IsBusy
set => SetProperty(ref isBusy, value);
}
+ public ICommand PageAppearingCommand { get; }
+
+ public ByteArrayToImageSourceViewModel() =>
+ PageAppearingCommand = CommandFactory.Create(OnAppearing);
+
public async Task OnAppearing()
{
try
diff --git a/samples/XCT.Sample/ViewModels/Converters/ConvertersGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ConvertersGalleryViewModel.cs
index 7962ce7b6..32941eb8c 100644
--- a/samples/XCT.Sample/ViewModels/Converters/ConvertersGalleryViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Converters/ConvertersGalleryViewModel.cs
@@ -85,6 +85,14 @@ public class ConvertersGalleryViewModel : BaseGalleryViewModel
typeof(ListToStringConverterPage),
nameof(ListToStringConverter),
"A converter that allows users to convert an incoming binding that implements IEnumerable to a single string value. The Separator property is used to join the items in the IEnumerable."),
+ new SectionModel(
+ typeof(EnumToBoolConverterPage),
+ nameof(EnumToBoolConverter),
+ "A converter that allows you to convert an Enum to boolean value"),
+ new SectionModel(
+ typeof(ImageResourceConverterPage),
+ nameof(ImageResourceConverter),
+ "A converter that allows you to convert embeded ressource image id to an ImageSource"),
};
}
}
diff --git a/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs
new file mode 100644
index 000000000..098dcb240
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Converters/EnumToBoolConverterViewModel.cs
@@ -0,0 +1,25 @@
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
+{
+ public class EnumToBoolConverterViewModel : BaseViewModel
+ {
+ private IssueState selectedState = IssueState.None;
+
+ 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
+ }
+}
\ No newline at end of file
diff --git a/samples/XCT.Sample/ViewModels/Converters/ImageResourceConverterViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ImageResourceConverterViewModel.cs
new file mode 100644
index 000000000..a19a3bcaf
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Converters/ImageResourceConverterViewModel.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Windows.Input;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
+{
+ public class ImageResourceConverterViewModel : BaseViewModel
+ {
+ const string img1 = "button.png";
+ const string img2 = "logo.png";
+ const string imagesPath = "Images";
+
+ string defaultNamespace;
+
+ string? imageName;
+
+ public string? ImageName
+ {
+ get => imageName;
+ set => SetProperty(ref imageName, value);
+ }
+
+ ICommand? changeImageCommand;
+
+ public ICommand ChangeImageCommand => changeImageCommand ??= new Command(() =>
+ {
+ ImageName = (ImageName?.Equals(BuildEmbededImagePath(img1)) ?? false) ?
+ BuildEmbededImagePath(img2) :
+ BuildEmbededImagePath(img1);
+ });
+
+ public ImageResourceConverterViewModel()
+ {
+ defaultNamespace = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
+ ImageName = BuildEmbededImagePath(img1);
+ }
+
+ string BuildEmbededImagePath(string imgName)
+ => $"{defaultNamespace}.{imagesPath}.{imgName}";
+ }
+}
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/ItemSelectedEventArgsViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs
index 52affb3d5..101fb04ab 100644
--- a/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Converters/ItemSelectedEventArgsViewModel.cs
@@ -15,7 +15,7 @@ public class ItemSelectedEventArgsViewModel
new Person() { Id = 3, Name = "Person 3" }
};
- public ICommand ItemSelectedCommand { get; private set; } = new AsyncCommand(person
- => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person.Name, "Cancel"));
+ public ICommand ItemSelectedCommand { get; } =
+ 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 7f53249d1..eedfb6995 100644
--- a/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Converters/ItemTappedEventArgsViewModel.cs
@@ -7,22 +7,21 @@ 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; private set; } = new AsyncCommand(person
- => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person.Name, "Cancel"));
+ public ICommand ItemTappedCommand { get; } =
+ CommandFactory.Create(person => Application.Current.MainPage.DisplayAlert("Item Tapped: ", person?.Name, "Cancel"));
}
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/ListIsNullOrEmptyViewModel.cs b/samples/XCT.Sample/ViewModels/Converters/ListIsNullOrEmptyViewModel.cs
index 392a6415a..051593e0a 100644
--- a/samples/XCT.Sample/ViewModels/Converters/ListIsNullOrEmptyViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Converters/ListIsNullOrEmptyViewModel.cs
@@ -1,4 +1,5 @@
-using Xamarin.CommunityToolkit.ObjectModel;
+using Xamarin.CommunityToolkit.Helpers;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
@@ -9,7 +10,7 @@ public class ListIsNullOrEmptyViewModel : BaseViewModel
public ListIsNullOrEmptyViewModel()
{
- AddItemCommand = new Command(() =>
+ AddItemCommand = CommandFactory.Create(() =>
{
Items.Add(new Person
{
@@ -17,7 +18,7 @@ public ListIsNullOrEmptyViewModel()
Name = $"Person {Items.Count}"
});
});
- RemoveItemCommand = new Command(() => Items.RemoveAt(0));
+ RemoveItemCommand = CommandFactory.Create(() => Items.RemoveAt(0));
// ListIsNullOrEmptyConvertor needs to know that Items are updated
Items.CollectionChanged += (sender, e) => OnPropertyChanged(nameof(Items));
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 51b400743..38a70cdb3 100644
--- a/samples/XCT.Sample/ViewModels/Effects/EffectsGalleryViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Effects/EffectsGalleryViewModel.cs
@@ -33,6 +33,16 @@ public class EffectsGalleryViewModel : BaseGalleryViewModel
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."),
+
+ 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."),
+
+ new SectionModel(
+ typeof(ShadowEffectPage),
+ nameof(ShadowEffect),
+ "The ShadowEffect allows all views to display shadow.")
};
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/ViewModels/Extensions/ExtensionsGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Extensions/ExtensionsGalleryViewModel.cs
new file mode 100644
index 000000000..e254ffd77
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Extensions/ExtensionsGalleryViewModel.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using Xamarin.CommunityToolkit.Extensions;
+using Xamarin.CommunityToolkit.Sample.Models;
+using Xamarin.CommunityToolkit.Sample.Pages.Effects;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Effects
+{
+ public class ExtensionsGalleryViewModel : BaseGalleryViewModel
+ {
+ protected override IEnumerable CreateItems() => new[]
+ {
+ new SectionModel(
+ typeof(ImageResourceExtensionPage),
+ nameof(ImageResourceExtension),
+ "A XAML extension that helps to display images from embedded resources"),
+ };
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Markup/SearchViewModel.cs b/samples/XCT.Sample/ViewModels/Markup/SearchViewModel.cs
index e9c21cfed..62e2b24c9 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;
@@ -8,8 +9,6 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Markup
{
public class SearchViewModel : BaseViewModel
{
- ICommand backCommand, likeCommand, openTwitterSearchCommand, openHelpCommand;
-
public string SearchText { get; set; }
public List SearchResults { get; set; }
@@ -54,17 +53,24 @@ public SearchViewModel()
},
}
};
+
+ BackCommand = new RelayCommand(Back);
+ LikeCommand = new RelayCommand(Like);
+ OpenTwitterSearchCommand = new RelayCommandAsync(OpenTwitterSearch);
+ OpenHelpCommand = new RelayCommandAsync(OpenHelp);
}
- public ICommand BackCommand => backCommand ??= new RelayCommand(Back);
+ public ICommand BackCommand { get; }
- public ICommand LikeCommand => likeCommand ??= new RelayCommand(Like);
+ public ICommand LikeCommand { get; }
- public ICommand OpenTwitterSearchCommand => openTwitterSearchCommand ??= new RelayCommandAsync(OpenTwitterSearch);
+ public ICommand OpenTwitterSearchCommand { get; }
- public ICommand OpenHelpCommand => openHelpCommand ??= new RelayCommandAsync(OpenHelp);
+ public ICommand OpenHelpCommand { get; }
- void Back() { }
+ void Back()
+ {
+ }
void Like(Tweet tweet) => tweet.IsLikedByMe = !tweet.IsLikedByMe;
@@ -74,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; } = new List();
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 a9b57200e..82578e00b 100644
--- a/samples/XCT.Sample/ViewModels/SettingViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/SettingViewModel.cs
@@ -1,27 +1,36 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Input;
using Xamarin.CommunityToolkit.Helpers;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.CommunityToolkit.Sample.Models;
using Xamarin.CommunityToolkit.Sample.Resx;
-using Xamarin.Forms;
+using Xamarin.Essentials;
namespace Xamarin.CommunityToolkit.Sample.ViewModels
{
public class SettingViewModel : BaseViewModel
{
- public SettingViewModel() => LoadLanguages();
+ IList supportedLanguages = Enumerable.Empty().ToList();
- IList supportedLanguages;
+ Language selectedLanguage = new Language(AppResources.English, "en");
- public IList SupportedLanguages
+ public SettingViewModel()
{
- get => supportedLanguages;
- private set => SetProperty(ref supportedLanguages, value);
+ LoadLanguages();
+
+ ChangeLanguageCommand = CommandFactory.Create(() =>
+ {
+ LocalizationResourceManager.Current.CurrentCulture = CultureInfo.GetCultureInfo(SelectedLanguage.CI);
+ LoadLanguages();
+ });
}
- Language selectedLanguage;
+ public LocalizedString AppVersion { get; } = new LocalizedString(() => string.Format(AppResources.Version, AppInfo.VersionString));
+
+ public ICommand ChangeLanguageCommand { get; }
public Language SelectedLanguage
{
@@ -29,13 +38,11 @@ public Language SelectedLanguage
set => SetProperty(ref selectedLanguage, value);
}
- ICommand changeLanguageCommand;
-
- public ICommand ChangeLanguageCommand => changeLanguageCommand ??= new Command(() =>
+ public IList SupportedLanguages
{
- LocalizationResourceManager.Current.SetCulture(CultureInfo.GetCultureInfo(SelectedLanguage.CI));
- LoadLanguages();
- });
+ get => supportedLanguages;
+ private set => SetProperty(ref supportedLanguages, value);
+ }
void LoadLanguages()
{
diff --git a/samples/XCT.Sample/ViewModels/Views/BadgeViewViewModel.cs b/samples/XCT.Sample/ViewModels/Views/BadgeViewViewModel.cs
index 0aea46870..c95155981 100644
--- a/samples/XCT.Sample/ViewModels/Views/BadgeViewViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Views/BadgeViewViewModel.cs
@@ -1,5 +1,5 @@
using System.Windows.Input;
-using Xamarin.Forms;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views
{
@@ -7,12 +7,17 @@ public class BadgeViewViewModel : BaseViewModel
{
int counter;
- public BadgeViewViewModel() => Counter = 3;
+ public BadgeViewViewModel()
+ {
+ Counter = 3;
+
+ IncreaseCommand = CommandFactory.Create(Increase);
+ DecreaseCommand = CommandFactory.Create(Decrease);
+ }
public int Counter
{
get => counter;
-
set
{
counter = value;
@@ -20,9 +25,9 @@ public int Counter
}
}
- public ICommand IncreaseCommand => new Command(Increase);
+ public ICommand IncreaseCommand { get; }
- public ICommand DecreaseCommand => new Command(Decrease);
+ public ICommand DecreaseCommand { get; }
void Increase() => Counter++;
diff --git a/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs b/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs
index 98e1d5e2d..9281f689f 100644
--- a/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Views/ExpanderViewModel.cs
@@ -1,21 +1,23 @@
using System.Windows.Input;
-using Xamarin.Forms;
+using Xamarin.CommunityToolkit.ObjectModel;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views
{
public partial class ExpanderViewModel : BaseViewModel
{
- ICommand command;
-
- public ICommand Command => command ??= new Command(p =>
+ public ExpanderViewModel()
{
- var sender = (Item)p;
- if (!sender.IsExpanded)
- return;
+ Command = CommandFactory.Create- (sender =>
+ {
+ if (!sender.IsExpanded)
+ return;
+
+ foreach (var item in Items)
+ item.IsExpanded = sender == item;
+ });
+ }
- foreach (var item in Items)
- item.IsExpanded = sender == item;
- });
+ public ICommand Command { get; }
public Item[] Items { get; } = new Item[]
{
@@ -44,7 +46,7 @@ public partial class ExpanderViewModel : BaseViewModel
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
new file mode 100644
index 000000000..eec92643c
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/PopupControlViewModel.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using Xamarin.CommunityToolkit.Extensions;
+using Xamarin.CommunityToolkit.ObjectModel;
+using Xamarin.CommunityToolkit.Sample.Models;
+using Xamarin.CommunityToolkit.Sample.Pages.Views.Popups;
+using Xamarin.CommunityToolkit.UI.Views;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views
+{
+ public class PopupGalleryViewModel
+ {
+ public PopupGalleryViewModel()
+ {
+ DisplayPopup = CommandFactory.Create(OnDisplayPopup);
+ }
+
+ INavigation Navigation => Application.Current.MainPage.Navigation;
+
+ 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"),
+ new SectionModel(typeof(MultipleButtonPopup), "Popup With Multiple Buttons", Color.Red, "Displays a basic popup with a cancel and confirm button"),
+ new SectionModel(typeof(NoLightDismissPopup), "Simple Popup Without Light Dismiss", Color.Red, "Displays a basic popup but does not allow the user to close it if they tap outside of the popup. In other words the LightDismiss is set to false."),
+ new SectionModel(typeof(ToggleSizePopup), "Toggle Size Popup", Color.Red, "Displays a popup that can have it's size updated by pressing a button"),
+ new SectionModel(typeof(TransparentPopup), "Transparent Popup", Color.Red, "Displays a popup with a transparent background"),
+ new SectionModel(typeof(PopupAnchorPage), "Anchor Popup", Color.Red, "Popups can be anchored to other view's on the screen"),
+ new SectionModel(typeof(OpenedEventSimplePopup), "Opened Event Popup", Color.Red, "Popup with opened event"),
+ new SectionModel(typeof(ReturnResultPopup), "Return Result Popup", Color.Red, "A popup that returns a string message when dismissed"),
+ new SectionModel(typeof(XamlBindingPopup), "Xaml Binding Popup", Color.Red, "A simple popup that uses XAML BindingContext"),
+ new SectionModel(typeof(CsharpBindingPopup), "C# Binding Popup", Color.Red, "A simple popup that uses C# BindingContext")
+ }.OrderBy(x => x.Title);
+
+ public ICommand DisplayPopup { get; }
+
+ async Task OnDisplayPopup(Type? popupType)
+ {
+ var view = (VisualElement)Activator.CreateInstance(popupType);
+
+ if (view is Popup popup)
+ {
+ var result = await Navigation.ShowPopupAsync(popup);
+ await Application.Current.MainPage.DisplayAlert("Popup Result", result, "OKAY");
+ }
+ else if (view is BasePopup basePopup)
+ {
+ Navigation.ShowPopup(basePopup);
+ }
+ else if (view is Page page)
+ {
+ await Navigation.PushAsync(page);
+ }
+ }
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/Popups/CsharpBindingPopupViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Popups/CsharpBindingPopupViewModel.cs
new file mode 100644
index 000000000..ce53e9799
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/Popups/CsharpBindingPopupViewModel.cs
@@ -0,0 +1,9 @@
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups
+{
+ public class CsharpBindingPopupViewModel
+ {
+ public string Title { get; } = "Xaml Binding Popup";
+
+ public string Message { get; } = "This is a native popup with a Xamarin.Forms View being rendered. The behaviors of the popup will confirm to 100% native look and feel, but still allows you to use your Xamarin.Forms controls.";
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/Popups/PopupAnchorViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Popups/PopupAnchorViewModel.cs
new file mode 100644
index 000000000..440bf9c3d
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/Popups/PopupAnchorViewModel.cs
@@ -0,0 +1,26 @@
+using System.Windows.Input;
+using Xamarin.CommunityToolkit.Extensions;
+using Xamarin.CommunityToolkit.Sample.Pages.Views.Popups;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups
+{
+ public class PopupAnchorViewModel
+ {
+ public PopupAnchorViewModel()
+ {
+ ShowPopup = new Command(OnShowPopup);
+ }
+
+ INavigation Navigation => Application.Current.MainPage.Navigation;
+
+ public ICommand ShowPopup { get; }
+
+ void OnShowPopup(View anchor)
+ {
+ var popup = new TransparentPopup();
+ popup.Anchor = anchor;
+ Navigation.ShowPopup(popup);
+ }
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/Popups/PopupPositionViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Popups/PopupPositionViewModel.cs
new file mode 100644
index 000000000..4e12e874d
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/Popups/PopupPositionViewModel.cs
@@ -0,0 +1,79 @@
+using System.Windows.Input;
+using Xamarin.CommunityToolkit.Extensions;
+using Xamarin.CommunityToolkit.Sample.Pages.Views.Popups;
+using Xamarin.Forms;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups
+{
+ public class PopupPositionViewModel
+ {
+ public PopupPositionViewModel()
+ {
+ DisplayPopup = new Command(OnDisplayPopup);
+ }
+
+ INavigation Navigation => Application.Current.MainPage.Navigation;
+
+ public ICommand DisplayPopup { get; }
+
+ void OnDisplayPopup(PopupPosition position)
+ {
+ var popup = new SimplePopup();
+
+ switch (position)
+ {
+ case PopupPosition.TopLeft:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.Start, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.Start, true);
+ break;
+ case PopupPosition.Top:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.Start, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, true);
+ break;
+ case PopupPosition.TopRight:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.Start, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.End, true);
+ break;
+ case PopupPosition.Left:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.Center, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.Start, true);
+ break;
+ case PopupPosition.Center:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.Center, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, true);
+ break;
+ case PopupPosition.Right:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.Center, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.End, true);
+ break;
+ case PopupPosition.BottomLeft:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.End, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.Start, true);
+ break;
+ case PopupPosition.Bottom:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.End, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.Center, true);
+ break;
+ case PopupPosition.BottomRight:
+ popup.VerticalOptions = new LayoutOptions(LayoutAlignment.End, true);
+ popup.HorizontalOptions = new LayoutOptions(LayoutAlignment.End, true);
+ break;
+ }
+
+ Navigation.ShowPopup(popup);
+ }
+
+ public enum PopupPosition
+ {
+ TopLeft = 0,
+ Top = 1,
+ TopRight = 2,
+ Left = 3,
+ Center = 4,
+ Right = 5,
+ BottomLeft = 6,
+ Bottom = 7,
+ BottomRight = 8
+ }
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/Popups/XamlBindingPopupViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Popups/XamlBindingPopupViewModel.cs
new file mode 100644
index 000000000..421f699dc
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/Popups/XamlBindingPopupViewModel.cs
@@ -0,0 +1,9 @@
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups
+{
+ public class XamlBindingPopupViewModel
+ {
+ public string Title { get; } = "Xaml Binding Popup";
+
+ public string Message { get; } = "This is a native popup with a Xamarin.Forms View being rendered. The behaviors of the popup will confirm to 100% native look and feel, but still allows you to use your Xamarin.Forms controls.";
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs b/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs
index 68b673a2c..f856df57d 100644
--- a/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Views/StateLayoutViewModel.cs
@@ -1,15 +1,13 @@
using System.Threading.Tasks;
using System.Windows.Input;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.CommunityToolkit.UI.Views;
-using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views
{
public class StateLayoutViewModel : BaseViewModel
{
- ICommand fullscreenLoadingCommand;
- ICommand cycleStatesCommand;
- string customState;
+ string customState = string.Empty;
LayoutState currentState;
LayoutState mainState;
@@ -31,28 +29,19 @@ public string CustomState
set => SetProperty(ref customState, value);
}
- public ICommand FullscreenLoadingCommand
- {
- get => fullscreenLoadingCommand;
- set => SetProperty(ref fullscreenLoadingCommand, value);
- }
+ public ICommand FullscreenLoadingCommand { get; }
- public ICommand CycleStatesCommand
- {
- get => cycleStatesCommand;
- set => SetProperty(ref cycleStatesCommand, value);
- }
+ public ICommand CycleStatesCommand { get; }
public StateLayoutViewModel()
{
- FullscreenLoadingCommand = new Command(async (x) =>
+ FullscreenLoadingCommand = CommandFactory.Create(async () =>
{
MainState = LayoutState.Loading;
await Task.Delay(2000);
MainState = LayoutState.None;
});
-
- CycleStatesCommand = new Command(async (x) => await CycleStates());
+ CycleStatesCommand = CommandFactory.Create(CycleStates);
}
async Task CycleStates()
diff --git a/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs b/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs
index 8e08baa8c..4d890f101 100644
--- a/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Views/TabItemsSourceViewModel.cs
@@ -1,16 +1,22 @@
using System.Collections.ObjectModel;
using System.Windows.Input;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
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; }
}
@@ -19,114 +25,111 @@ public class TabItemsSourceViewModel : BaseViewModel
public TabItemsSourceViewModel()
{
LoadMonkeys();
+
+ ClearDataCommand = CommandFactory.Create(ClearData);
+ UpdateDataCommand = CommandFactory.Create(UpdateData);
}
- public ObservableCollection Monkeys { get; set; }
+ public ObservableCollection Monkeys { get; } = LoadMonkeys();
- public ICommand ClearDataCommand => new Command(ClearData);
+ public ICommand ClearDataCommand { get; }
- public ICommand UpdateDataCommand => new Command(UpdateData);
+ 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/TabViewViewModel.cs b/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs
index 52d69e160..1bbdf8fb6 100644
--- a/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs
@@ -42,7 +42,10 @@ public class TabViewViewModel : BaseGalleryViewModel
"Using TabViewItem VisualStates"),
new SectionModel(typeof(NoContentPage), "Tab without Content",
- "Only the TabStrip is visible")
+ "Only the TabStrip is visible"),
+
+ new SectionModel(typeof(LazyTabPage), "LazyLoadingTab",
+ "See how you can implement LazyViews that are loaded just when you navigate to them"),
};
}
}
\ No newline at end of file
diff --git a/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs
new file mode 100644
index 000000000..e3f6c5828
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs
@@ -0,0 +1,27 @@
+using Xamarin.CommunityToolkit.ObjectModel;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs
+{
+ sealed class LazyTestViewModel : ObservableObject
+ {
+ public static LazyTestViewModel Current { get; } = new LazyTestViewModel();
+
+ string title = string.Empty;
+
+ public string Title
+ {
+ get => title;
+ set => SetProperty(ref title, value);
+ }
+
+ bool loaded;
+
+ public bool Loaded
+ {
+ get => loaded;
+ set => SetProperty(ref loaded, value);
+ }
+
+ public LazyTestViewModel() => Title = "Lazy Tab Sample";
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs
new file mode 100644
index 000000000..81c51d12d
--- /dev/null
+++ b/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs
@@ -0,0 +1,17 @@
+using Xamarin.CommunityToolkit.ObjectModel;
+
+namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs
+{
+ sealed class NormalTestViewModel : ObservableObject
+ {
+ public static NormalTestViewModel Current { get; } = new NormalTestViewModel();
+
+ string loadedViews = string.Empty;
+
+ public string LoadedViews
+ {
+ get => loadedViews;
+ set => SetProperty(ref loadedViews, value);
+ }
+ }
+}
diff --git a/samples/XCT.Sample/ViewModels/Views/ViewsGalleryViewModel.cs b/samples/XCT.Sample/ViewModels/Views/ViewsGalleryViewModel.cs
index a469bdc9f..72caebe65 100644
--- a/samples/XCT.Sample/ViewModels/Views/ViewsGalleryViewModel.cs
+++ b/samples/XCT.Sample/ViewModels/Views/ViewsGalleryViewModel.cs
@@ -48,7 +48,10 @@ public class ViewsGalleryViewModel : BaseGalleryViewModel
"A control to display a set of tabs and their respective content."),
new SectionModel(typeof(UniformGridPage), "UniformGrid",
- "The UniformGrid is just like the Grid, with all rows and columns will have the same size.")
+ "The UniformGrid is just like the Grid, with all rows and columns will have the same size."),
+
+ new SectionModel(typeof(PopupGalleryPage), "Popup",
+ "The popup control renders native popups from the shared code. This page demonstrates a variety of different techniques for displaying native popups.")
};
}
}
diff --git a/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj b/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj
index af5548634..eb1854e4f 100644
--- a/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj
+++ b/samples/XCT.Sample/Xamarin.CommunityToolkit.Sample.csproj
@@ -12,6 +12,7 @@
+
@@ -19,10 +20,32 @@
-
+
+
+
+ True
+ True
+ AppResources.resx
+
+
+
+
+
+ PublicResXFileCodeGenerator
+ AppResources.resx
+
+
+ PublicResXFileCodeGenerator
+ AppResources.resx
+
+
+ PublicResXFileCodeGenerator
+ AppResources.Designer.cs
+
+
+
-
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/CharactersValidationBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/CharactersValidationBehavior_Tests.cs
index d317a3f6e..f9c9f3a2e 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/CharactersValidationBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/CharactersValidationBehavior_Tests.cs
@@ -1,57 +1,63 @@
-using Xamarin.CommunityToolkit.Behaviors;
+using System.Threading.Tasks;
+using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class CharactersValidationBehavior_Tests
{
- public CharactersValidationBehavior_Tests()
- => Device.PlatformServices = new MockPlatformServices();
+ [SetUp]
+ public void Setup() => Device.PlatformServices = new MockPlatformServices();
- [Theory]
- [InlineData(CharacterType.Any, 1, 2, "A", true)]
- [InlineData(CharacterType.Any, 0, int.MaxValue, "", true)]
- [InlineData(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWaWWWW", true)]
- [InlineData(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaaRRaaaa", true)]
- [InlineData(CharacterType.Letter, 4, int.MaxValue, "aaaaaaRRaaaa", true)]
- [InlineData(CharacterType.Digit, 1, int.MaxValue, "-1d", true)]
- [InlineData(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3r", true)]
- [InlineData(CharacterType.NonAlphanumericSymbol, 10, int.MaxValue, "@-&^%!+()/", true)]
- [InlineData(CharacterType.LowercaseLatinLetter, 2, int.MaxValue, "HHHH a r.", true)]
- [InlineData(CharacterType.UppercaseLatinLetter, 2, int.MaxValue, "aaaaaa....R.R.R.aaaa", true)]
- [InlineData(CharacterType.LatinLetter, 5, int.MaxValue, "12345bBbBb", true)]
- [InlineData(CharacterType.Whitespace, 0, int.MaxValue, ";lkjhgfd@+fasf", true)]
- [InlineData(CharacterType.Any, 2, 2, "A", false)]
- [InlineData(CharacterType.Any, 2, 2, "AaA", false)]
- [InlineData(CharacterType.Any, 1, int.MaxValue, "", false)]
- [InlineData(CharacterType.Any, 1, int.MaxValue, null, false)]
- [InlineData(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWW", false)]
- [InlineData(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaa", false)]
- [InlineData(CharacterType.Letter, 4, int.MaxValue, "wHo", false)]
- [InlineData(CharacterType.Digit, 1, int.MaxValue, "-d", false)]
- [InlineData(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3", false)]
- [InlineData(CharacterType.NonAlphanumericSymbol, 1, int.MaxValue, "WWWWWWWW", false)]
- [InlineData(CharacterType.LowercaseLatinLetter, 1, int.MaxValue, "Кириллица", false)]
- [InlineData(CharacterType.UppercaseLatinLetter, 1, int.MaxValue, "КИРИЛЛИЦА", false)]
- [InlineData(CharacterType.LatinLetter, 1, int.MaxValue, "Это Кириллица!", false)]
- [InlineData(CharacterType.Whitespace, 0, 0, "WWWWWW WWWWW", false)]
- public void IsValid(CharacterType characterType, int minimumCharactersNumber, int maximumCharactersNumber, string value, bool expectedValue)
+ [TestCase(CharacterType.Any, 1, 2, "A", true)]
+ [TestCase(CharacterType.Any, 0, int.MaxValue, "", true)]
+ [TestCase(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWaWWWW", true)]
+ [TestCase(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaaRRaaaa", true)]
+ [TestCase(CharacterType.Letter, 4, int.MaxValue, "aaaaaaRRaaaa", true)]
+ [TestCase(CharacterType.Digit, 1, int.MaxValue, "-1d", true)]
+ [TestCase(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3r", true)]
+ [TestCase(CharacterType.NonAlphanumericSymbol, 10, int.MaxValue, "@-&^%!+()/", true)]
+ [TestCase(CharacterType.LowercaseLatinLetter, 2, int.MaxValue, "HHHH a r.", true)]
+ [TestCase(CharacterType.UppercaseLatinLetter, 2, int.MaxValue, "aaaaaa....R.R.R.aaaa", true)]
+ [TestCase(CharacterType.LatinLetter, 5, int.MaxValue, "12345bBbBb", true)]
+ [TestCase(CharacterType.Whitespace, 0, int.MaxValue, ";lkjhgfd@+fasf", true)]
+ [TestCase(CharacterType.Any, 2, 2, "A", false)]
+ [TestCase(CharacterType.Any, 2, 2, "AaA", false)]
+ [TestCase(CharacterType.Any, 1, int.MaxValue, "", false)]
+ [TestCase(CharacterType.Any, 1, int.MaxValue, null, false)]
+ [TestCase(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWW", false)]
+ [TestCase(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaa", false)]
+ [TestCase(CharacterType.Letter, 4, int.MaxValue, "wHo", false)]
+ [TestCase(CharacterType.Digit, 1, int.MaxValue, "-d", false)]
+ [TestCase(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3", false)]
+ [TestCase(CharacterType.NonAlphanumericSymbol, 1, int.MaxValue, "WWWWWWWW", false)]
+ [TestCase(CharacterType.LowercaseLatinLetter, 1, int.MaxValue, "Кириллица", false)]
+ [TestCase(CharacterType.UppercaseLatinLetter, 1, int.MaxValue, "КИРИЛЛИЦА", false)]
+ [TestCase(CharacterType.LatinLetter, 1, int.MaxValue, "Это Кириллица!", false)]
+ [TestCase(CharacterType.Whitespace, 0, 0, "WWWWWW WWWWW", false)]
+ public async Task IsValid(CharacterType characterType, int minimumCharactersNumber, int maximumCharactersNumber, string value, bool expectedValue)
{
+ // Arrange
var behavior = new CharactersValidationBehavior
{
CharacterType = characterType,
MinimumCharacterCount = minimumCharactersNumber,
MaximumCharacterCount = maximumCharactersNumber
};
+
var entry = new Entry
{
Text = value
};
entry.Behaviors.Add(behavior);
- behavior.ForceValidate();
- Assert.Equal(expectedValue, behavior.IsValid);
+
+ // Act
+ await behavior.ForceValidate();
+
+ // Assert
+ Assert.AreEqual(expectedValue, behavior.IsValid);
}
}
}
\ No newline at end of file
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehaviorGeneric_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehaviorGeneric_Tests.cs
new file mode 100644
index 000000000..8e3df334f
--- /dev/null
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehaviorGeneric_Tests.cs
@@ -0,0 +1,170 @@
+using System;
+using System.Reflection;
+using Xamarin.CommunityToolkit.Behaviors;
+using Xamarin.CommunityToolkit.Converters;
+using Xamarin.CommunityToolkit.UnitTests.Mocks;
+using Xamarin.Forms;
+using NUnit.Framework;
+
+namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
+{
+ public class EventToCommandBehaviorGeneric_Tests
+ {
+ [SetUp]
+ public void Setup() => Device.PlatformServices = new MockPlatformServices();
+
+ [Test]
+ public void ArgumentExceptionIfSpecifiedEventDoesNotExist()
+ {
+ var listView = new ListView();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = "Wrong Event Name"
+ };
+ Assert.Throws(() => listView.Behaviors.Add(behavior));
+ }
+
+ [Test]
+ public void NoExceptionIfSpecifiedEventExists()
+ {
+ var listView = new ListView();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = nameof(ListView.ItemTapped)
+ };
+ listView.Behaviors.Add(behavior);
+ }
+
+ [Test]
+ public void NoExceptionIfAttachedToPage()
+ {
+ var page = new ContentPage();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = nameof(Page.Appearing)
+ };
+ page.Behaviors.Add(behavior);
+ }
+
+ [Test]
+ public void NoExceptionWhenTheEventArgsAreNotNull()
+ {
+ var vm = new ViewModelCoffe();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = nameof(ListView.ItemTapped),
+ EventArgsConverter = new ItemSelectedEventArgsConverter(),
+ Command = vm.SelectedCommand
+ };
+
+ Assert.Null(vm.CoffeeName);
+ var coffe = new Coffee { Id = 1, Name = "Café" };
+ var eventArgs = new SelectedItemChangedEventArgs(coffe, 1);
+
+ var notNullArgs = new object?[] { null, eventArgs };
+
+ TriggerEventToCommandBehavior(behavior, notNullArgs);
+
+ Assert.AreEqual(coffe.Name, vm.CoffeeName);
+ }
+
+ [Test]
+ public void NoExceptionWhenTheEventArgsAreNotNull_InheritedType()
+ {
+ var vm = new ViewModelCoffe();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = nameof(ListView.ItemTapped),
+ EventArgsConverter = new ItemSelectedEventArgsConverter(),
+ Command = vm.SelectedCommand
+ };
+
+ Assert.Null(vm.CoffeeName);
+ var coffe = new Starbucks { Id = 1, Name = "Latte" };
+ var eventArgs = new SelectedItemChangedEventArgs(coffe, 1);
+
+ var notNullArgs = new object?[] { null, eventArgs };
+
+ TriggerEventToCommandBehavior(behavior, notNullArgs);
+
+ Assert.AreEqual(coffe.Name, vm.CoffeeName);
+ }
+
+ [Test]
+ public void ParameterOfTypeInt()
+ {
+ var vm = new ViewModelCoffe();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = nameof(ListView.ItemTapped),
+ Command = vm.SelectedCommand,
+ CommandParameter = 2
+ };
+
+ var nullArgs = new object?[] { null, null };
+
+ TriggerEventToCommandBehavior(behavior, nullArgs);
+ }
+
+ [Test]
+ public void NoExceptionWhenTheSelectedItemIsNull()
+ {
+ var vm = new ViewModelCoffe();
+ var behavior = new EventToCommandBehavior
+ {
+ EventName = nameof(ListView.ItemTapped),
+ EventArgsConverter = new ItemSelectedEventArgsConverter(),
+ Command = vm.SelectedCommand
+ };
+
+ Assert.Null(vm.CoffeeName);
+ var coffeNull = default(Coffee);
+ var notNullArgs = new object?[] { null, new SelectedItemChangedEventArgs(coffeNull, -1) };
+
+ TriggerEventToCommandBehavior(behavior, notNullArgs);
+
+ Assert.Null(vm.CoffeeName);
+ }
+
+ static void TriggerEventToCommandBehavior(EventToCommandBehavior eventToCommand, object?[] args)
+ {
+ var method = eventToCommand.GetType().GetMethod("OnTriggerHandled", BindingFlags.Instance | BindingFlags.NonPublic);
+ method?.Invoke(eventToCommand, args);
+ }
+
+ class Starbucks : Coffee
+ {
+ }
+
+ class Coffee
+ {
+ public int Id { get; set; }
+
+ public string Roaster { get; set; } = string.Empty;
+
+ public string? Name { get; set; }
+
+ public string Image { get; set; } = string.Empty;
+ }
+
+ class ViewModelCoffe
+ {
+ public Command SelectedCommand { get; set; }
+
+ public string? CoffeeName { get; set; }
+
+ public ViewModelCoffe()
+ {
+ SelectedCommand = new Command(Selected);
+ }
+
+ void Selected(Coffee coffee)
+ {
+ if (coffee == null)
+ return;
+
+ CoffeeName = coffee?.Name;
+ }
+ }
+ }
+}
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehavior_Tests.cs
index 91787df9b..6806ed5a1 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/EventToCommandBehavior_Tests.cs
@@ -2,16 +2,16 @@
using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class EventToCommandBehavior_Tests
{
- public EventToCommandBehavior_Tests()
- => Device.PlatformServices = new MockPlatformServices();
+ [SetUp]
+ public void SetUp() => Device.PlatformServices = new MockPlatformServices();
- [Fact]
+ [Test]
public void ArgumentExceptionIfSpecifiedEventDoesNotExist()
{
var listView = new ListView();
@@ -22,7 +22,7 @@ public void ArgumentExceptionIfSpecifiedEventDoesNotExist()
Assert.Throws(() => listView.Behaviors.Add(behavior));
}
- [Fact]
+ [Test]
public void NoExceptionIfSpecifiedEventExists()
{
var listView = new ListView();
@@ -33,7 +33,7 @@ public void NoExceptionIfSpecifiedEventExists()
listView.Behaviors.Add(behavior);
}
- [Fact]
+ [Test]
public void NoExceptionIfAttachedToPage()
{
var page = new ContentPage();
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/ImpliedOrderGridBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/ImpliedOrderGridBehavior_Tests.cs
index e02fb2e88..91ee07778 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/ImpliedOrderGridBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/ImpliedOrderGridBehavior_Tests.cs
@@ -1,13 +1,13 @@
using System;
using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class ImpliedOrderGridBehavior_Tests
{
- [Fact]
+ [Test]
public void CorrectRowColumnAssignment()
{
var grid = new Grid();
@@ -73,7 +73,7 @@ public void CorrectRowColumnAssignment()
AssertExpectedCoordinates(grid, new Label(), 4, 0);
}
- [Fact]
+ [Test]
public void ThrowsOnManualAssignmentToUsedCell()
{
var grid = CreateExceptionTestGrid();
@@ -89,7 +89,7 @@ public void ThrowsOnManualAssignmentToUsedCell()
Assert.Throws(() => grid.Children.Add(throwLabel));
}
- [Fact]
+ [Test]
public void ThrowsOnCellsExceeded()
{
var grid = CreateExceptionTestGrid();
@@ -110,7 +110,7 @@ public void ThrowsOnCellsExceeded()
Assert.Throws(() => grid.Children.Add(new Label()));
}
- [Fact]
+ [Test]
public void ThrowsOnSpanExceedsColumns()
{
var grid = CreateExceptionTestGrid();
@@ -121,7 +121,7 @@ public void ThrowsOnSpanExceedsColumns()
Assert.Throws(() => grid.Children.Add(throwLabel));
}
- [Fact]
+ [Test]
public void ThrowsOnSpanExceedsRows()
{
var grid = CreateExceptionTestGrid();
@@ -149,8 +149,8 @@ Grid CreateExceptionTestGrid()
void AssertExpectedCoordinates(Grid grid, View view, int row, int column)
{
grid.Children.Add(view);
- Assert.Equal(row, Grid.GetRow(view));
- Assert.Equal(column, Grid.GetColumn(view));
+ Assert.AreEqual(row, Grid.GetRow(view));
+ Assert.AreEqual(column, Grid.GetColumn(view));
}
}
}
\ No newline at end of file
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs
index 0760c3011..b6d66d3ff 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MaxLengthReachedBehavior_Tests.cs
@@ -2,13 +2,13 @@
using System.Windows.Input;
using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class MaxLengthReachedBehavior_Tests
{
- [Fact]
+ [Test]
public void ShouldExecuteCommandWhenMaxLengthHasBeenReached()
{
// arrange
@@ -20,10 +20,10 @@ public void ShouldExecuteCommandWhenMaxLengthHasBeenReached()
entry.Text += "2";
// assert
- Assert.True(commandHasBeenExecuted);
+ Assert.IsTrue(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public void ShouldInvokeEventHandlerWhenMaxLengthHasBeenReached()
{
// arrange
@@ -35,10 +35,10 @@ public void ShouldInvokeEventHandlerWhenMaxLengthHasBeenReached()
entry.Text += "2";
// assert
- Assert.True(eventHandlerHasBeenInvoked);
+ Assert.IsTrue(eventHandlerHasBeenInvoked);
}
- [Fact]
+ [Test]
public void ShouldExecuteCommandWithTextValueNoLargerThenMaxLength()
{
// arrange
@@ -51,10 +51,10 @@ public void ShouldExecuteCommandWithTextValueNoLargerThenMaxLength()
entry.Text = "123456789";
// assert
- Assert.Equal(expectedLength, actualLength);
+ Assert.AreEqual(expectedLength, actualLength);
}
- [Fact]
+ [Test]
public void ShouldInvokeEventHandlerWithTextValueNoLargerThenMaxLength()
{
// arrange
@@ -67,10 +67,10 @@ public void ShouldInvokeEventHandlerWithTextValueNoLargerThenMaxLength()
entry.Text = "123456789";
// assert
- Assert.Equal(expectedLength, actualLength);
+ Assert.AreEqual(expectedLength, actualLength);
}
- [Fact]
+ [Test]
public void ShouldNotExecuteCommandBeforeMaxLengthHasBeenReached()
{
// arrange
@@ -84,7 +84,7 @@ public void ShouldNotExecuteCommandBeforeMaxLengthHasBeenReached()
Assert.False(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public void ShouldNotInvokeEventHandlerBeforeMaxLengthHasBeenReached()
{
// arrange
@@ -98,7 +98,7 @@ public void ShouldNotInvokeEventHandlerBeforeMaxLengthHasBeenReached()
Assert.False(eventHandlerHasBeenInvoked);
}
- [Fact]
+ [Test]
public void ShouldDismissKeyboardWhenMaxLengthHasBeenReached()
{
// arrange
@@ -113,7 +113,7 @@ public void ShouldDismissKeyboardWhenMaxLengthHasBeenReached()
Assert.False(entry.IsFocused);
}
- [Fact]
+ [Test]
public void ShouldNotDismissKeyboardBeforeMaxLengthHasBeenReached()
{
// arrange
@@ -124,10 +124,10 @@ public void ShouldNotDismissKeyboardBeforeMaxLengthHasBeenReached()
entry.Text = "1";
// assert
- Assert.True(entry.IsFocused);
+ Assert.IsTrue(entry.IsFocused);
}
- [Fact]
+ [Test]
public void ShouldNotDismissKeyboardWhenOptionSetToFalse()
{
// arrange
@@ -139,13 +139,13 @@ public void ShouldNotDismissKeyboardWhenOptionSetToFalse()
entry.Text += "1";
// assert
- Assert.True(entry.IsFocused);
+ Assert.IsTrue(entry.IsFocused);
}
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/MultiValidationBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MultiValidationBehavior_Tests.cs
index 9318fd93b..bfb8a2648 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MultiValidationBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/MultiValidationBehavior_Tests.cs
@@ -1,59 +1,66 @@
-using Xamarin.CommunityToolkit.Behaviors;
+using System.Threading.Tasks;
+using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class MultiValidationBehavior_Tests
{
- public MultiValidationBehavior_Tests()
- => Device.PlatformServices = new MockPlatformServices();
+ [SetUp]
+ public void Setup() => Device.PlatformServices = new MockPlatformServices();
- [Theory]
- [InlineData(CharacterType.Any, 1, 2, "A", true)]
- [InlineData(CharacterType.Any, 0, int.MaxValue, "", true)]
- [InlineData(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWaWWWW", true)]
- [InlineData(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaaRRaaaa", true)]
- [InlineData(CharacterType.Letter, 4, int.MaxValue, "aaaaaaRRaaaa", true)]
- [InlineData(CharacterType.Digit, 1, int.MaxValue, "-1d", true)]
- [InlineData(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3r", true)]
- [InlineData(CharacterType.NonAlphanumericSymbol, 10, int.MaxValue, "@-&^%!+()/", true)]
- [InlineData(CharacterType.LowercaseLatinLetter, 2, int.MaxValue, "HHHH a r.", true)]
- [InlineData(CharacterType.UppercaseLatinLetter, 2, int.MaxValue, "aaaaaa....R.R.R.aaaa", true)]
- [InlineData(CharacterType.LatinLetter, 5, int.MaxValue, "12345bBbBb", true)]
- [InlineData(CharacterType.Whitespace, 0, int.MaxValue, ";lkjhgfd@+fasf", true)]
- [InlineData(CharacterType.Any, 2, 2, "A", false)]
- [InlineData(CharacterType.Any, 2, 2, "AaA", false)]
- [InlineData(CharacterType.Any, 1, int.MaxValue, "", false)]
- [InlineData(CharacterType.Any, 1, int.MaxValue, null, false)]
- [InlineData(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWW", false)]
- [InlineData(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaa", false)]
- [InlineData(CharacterType.Letter, 4, int.MaxValue, "wHo", false)]
- [InlineData(CharacterType.Digit, 1, int.MaxValue, "-d", false)]
- [InlineData(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3", false)]
- [InlineData(CharacterType.NonAlphanumericSymbol, 1, int.MaxValue, "WWWWWWWW", false)]
- [InlineData(CharacterType.LowercaseLatinLetter, 1, int.MaxValue, "Кириллица", false)]
- [InlineData(CharacterType.UppercaseLatinLetter, 1, int.MaxValue, "КИРИЛЛИЦА", false)]
- [InlineData(CharacterType.LatinLetter, 1, int.MaxValue, "Это Кириллица!", false)]
- [InlineData(CharacterType.Whitespace, 0, 0, "WWWWWW WWWWW", false)]
- public void IsValid(CharacterType characterType, int minimumCharactersNumber, int maximumCharactersNumber, string value, bool expectedValue)
+ [TestCase(CharacterType.Any, 1, 2, "A", true)]
+ [TestCase(CharacterType.Any, 0, int.MaxValue, "", true)]
+ [TestCase(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWaWWWW", true)]
+ [TestCase(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaaRRaaaa", true)]
+ [TestCase(CharacterType.Letter, 4, int.MaxValue, "aaaaaaRRaaaa", true)]
+ [TestCase(CharacterType.Digit, 1, int.MaxValue, "-1d", true)]
+ [TestCase(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3r", true)]
+ [TestCase(CharacterType.NonAlphanumericSymbol, 10, int.MaxValue, "@-&^%!+()/", true)]
+ [TestCase(CharacterType.LowercaseLatinLetter, 2, int.MaxValue, "HHHH a r.", true)]
+ [TestCase(CharacterType.UppercaseLatinLetter, 2, int.MaxValue, "aaaaaa....R.R.R.aaaa", true)]
+ [TestCase(CharacterType.LatinLetter, 5, int.MaxValue, "12345bBbBb", true)]
+ [TestCase(CharacterType.Whitespace, 0, int.MaxValue, ";lkjhgfd@+fasf", true)]
+ [TestCase(CharacterType.Any, 2, 2, "A", false)]
+ [TestCase(CharacterType.Any, 2, 2, "AaA", false)]
+ [TestCase(CharacterType.Any, 1, int.MaxValue, "", false)]
+ [TestCase(CharacterType.Any, 1, int.MaxValue, null, false)]
+ [TestCase(CharacterType.LowercaseLetter, 1, int.MaxValue, "WWWWWW", false)]
+ [TestCase(CharacterType.UppercaseLetter, 1, int.MaxValue, "aaaaaa", false)]
+ [TestCase(CharacterType.Letter, 4, int.MaxValue, "wHo", false)]
+ [TestCase(CharacterType.Digit, 1, int.MaxValue, "-d", false)]
+ [TestCase(CharacterType.Alphanumeric, 2, int.MaxValue, "@-3", false)]
+ [TestCase(CharacterType.NonAlphanumericSymbol, 1, int.MaxValue, "WWWWWWWW", false)]
+ [TestCase(CharacterType.LowercaseLatinLetter, 1, int.MaxValue, "Кириллица", false)]
+ [TestCase(CharacterType.UppercaseLatinLetter, 1, int.MaxValue, "КИРИЛЛИЦА", false)]
+ [TestCase(CharacterType.LatinLetter, 1, int.MaxValue, "Это Кириллица!", false)]
+ [TestCase(CharacterType.Whitespace, 0, 0, "WWWWWW WWWWW", false)]
+ public async Task IsValid(CharacterType characterType, int minimumCharactersNumber, int maximumCharactersNumber, string value, bool expectedValue)
{
- var multiBehavior = new MultiValidationBehavior();
+ // Arrange
var behavior = new CharactersValidationBehavior
{
CharacterType = characterType,
MinimumCharacterCount = minimumCharactersNumber,
MaximumCharacterCount = maximumCharactersNumber
};
+
+ var multiBehavior = new MultiValidationBehavior();
multiBehavior.Children.Add(behavior);
+
var entry = new Entry
{
Text = value
};
entry.Behaviors.Add(multiBehavior);
- multiBehavior.ForceValidate();
- Assert.Equal(expectedValue, multiBehavior.IsValid);
+
+ // Act
+ await multiBehavior.ForceValidate();
+
+ // Assert
+ Assert.AreEqual(expectedValue, multiBehavior.IsValid);
}
}
}
\ No newline at end of file
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/NumericValidationBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/NumericValidationBehavior_Tests.cs
index 5494be7c2..711eea8cb 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/NumericValidationBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/NumericValidationBehavior_Tests.cs
@@ -1,70 +1,76 @@
using System.Globalization;
+using System.Threading.Tasks;
using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class NumericValidationBehavior_Tests
{
- public NumericValidationBehavior_Tests()
- => Device.PlatformServices = new MockPlatformServices();
+ [SetUp]
+ public void Setup() => Device.PlatformServices = new MockPlatformServices();
- [Theory]
- [InlineData("en-US", "15.2", 1.0, 16.0, 0, 16, true)]
- [InlineData("en-US", "15.", 1.0, 16.0, 0, 1, true)]
- [InlineData("en-US", "15.88", 1.0, 16.0, 2, 2, true)]
- [InlineData("en-US", "0.99", 0.9, 2.0, 0, 16, true)]
- [InlineData("en-US", ".99", 0.9, 2.0, 0, 16, true)]
- [InlineData("en-US", "1,115.2", 1.0, 2000.0, 0, 16, true)]
- [InlineData("de-DE", "15,2", 1.0, 16.0, 0, 16, true)]
- [InlineData("de-DE", "15,", 1.0, 16.0, 0, 1, true)]
- [InlineData("de-DE", "15,88", 1.0, 16.0, 2, 2, true)]
- [InlineData("de-DE", "0,99", 0.9, 2.0, 0, 16, true)]
- [InlineData("de-DE", ",99", 0.9, 2.0, 0, 16, true)]
- [InlineData("de-DE", "1.115,2", 1.0, 2000.0, 0, 16, true)]
- [InlineData("en-US", "15.3", 16.0, 20.0, 0, 16, false)]
- [InlineData("en-US", "15.3", 0.0, 15.0, 0, 16, false)]
- [InlineData("en-US", "15.", 1.0, 16.0, 0, 0, false)]
- [InlineData("en-US", ".7", 0.0, 16.0, 0, 0, false)]
- [InlineData("en-US", "15", 1.0, 16.0, 1, 16, false)]
- [InlineData("en-US", "", 0.0, 16.0, 0, 16, false)]
- [InlineData("en-US", " ", 0.0, 16.0, 0, 16, false)]
- [InlineData("en-US", null, 0.0, 16.0, 0, 16, false)]
- [InlineData("en-US", "15,2", 1.0, 16.0, 0, 16, false)]
- [InlineData("en-US", "1.115,2", 1.0, 2000.0, 0, 16, false)]
- [InlineData("de-DE", "15,3", 16.0, 20.0, 0, 16, false)]
- [InlineData("de-DE", "15,3", 0.0, 15.0, 0, 16, false)]
- [InlineData("de-DE", "15,", 1.0, 16.0, 0, 0, false)]
- [InlineData("de-DE", ",7", 0.0, 16.0, 0, 0, false)]
- [InlineData("de-DE", "15", 1.0, 16.0, 1, 16, false)]
- [InlineData("de-DE", "", 0.0, 16.0, 0, 16, false)]
- [InlineData("de-DE", " ", 0.0, 16.0, 0, 16, false)]
- [InlineData("de-DE", null, 0.0, 16.0, 0, 16, false)]
- [InlineData("de-DE", "15.2", 1.0, 16.0, 0, 16, false)]
- [InlineData("de-DE", "1,115.2", 1.0, 2000.0, 0, 16, false)]
- public void IsValid(string culture, string value, double minValue, double maxValue, int minDecimalPlaces, int maxDecimalPlaces, bool expectedValue)
+ [TestCase("en-US", "15.2", 1.0, 16.0, 0, 16, true)]
+ [TestCase("en-US", "15.", 1.0, 16.0, 0, 1, true)]
+ [TestCase("en-US", "15.88", 1.0, 16.0, 2, 2, true)]
+ [TestCase("en-US", "0.99", 0.9, 2.0, 0, 16, true)]
+ [TestCase("en-US", ".99", 0.9, 2.0, 0, 16, true)]
+ [TestCase("en-US", "1,115.2", 1.0, 2000.0, 0, 16, true)]
+ [TestCase("de-DE", "15,2", 1.0, 16.0, 0, 16, true)]
+ [TestCase("de-DE", "15,", 1.0, 16.0, 0, 1, true)]
+ [TestCase("de-DE", "15,88", 1.0, 16.0, 2, 2, true)]
+ [TestCase("de-DE", "0,99", 0.9, 2.0, 0, 16, true)]
+ [TestCase("de-DE", ",99", 0.9, 2.0, 0, 16, true)]
+ [TestCase("de-DE", "1.115,2", 1.0, 2000.0, 0, 16, true)]
+ [TestCase("en-US", "15.3", 16.0, 20.0, 0, 16, false)]
+ [TestCase("en-US", "15.3", 0.0, 15.0, 0, 16, false)]
+ [TestCase("en-US", "15.", 1.0, 16.0, 0, 0, false)]
+ [TestCase("en-US", ".7", 0.0, 16.0, 0, 0, false)]
+ [TestCase("en-US", "15", 1.0, 16.0, 1, 16, false)]
+ [TestCase("en-US", "", 0.0, 16.0, 0, 16, false)]
+ [TestCase("en-US", " ", 0.0, 16.0, 0, 16, false)]
+ [TestCase("en-US", null, 0.0, 16.0, 0, 16, false)]
+ [TestCase("en-US", "15,2", 1.0, 16.0, 0, 16, false)]
+ [TestCase("en-US", "1.115,2", 1.0, 2000.0, 0, 16, false)]
+ [TestCase("de-DE", "15,3", 16.0, 20.0, 0, 16, false)]
+ [TestCase("de-DE", "15,3", 0.0, 15.0, 0, 16, false)]
+ [TestCase("de-DE", "15,", 1.0, 16.0, 0, 0, false)]
+ [TestCase("de-DE", ",7", 0.0, 16.0, 0, 0, false)]
+ [TestCase("de-DE", "15", 1.0, 16.0, 1, 16, false)]
+ [TestCase("de-DE", "", 0.0, 16.0, 0, 16, false)]
+ [TestCase("de-DE", " ", 0.0, 16.0, 0, 16, false)]
+ [TestCase("de-DE", null, 0.0, 16.0, 0, 16, false)]
+ [TestCase("de-DE", "15.2", 1.0, 16.0, 0, 16, false)]
+ [TestCase("de-DE", "1,115.2", 1.0, 2000.0, 0, 16, false)]
+ public async Task IsValid(string culture, string value, double minValue, double maxValue, int minDecimalPlaces, int maxDecimalPlaces, bool expectedValue)
{
+ // Arrange
var origCulture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(culture);
+ var behavior = new NumericValidationBehavior
+ {
+ MinimumValue = minValue,
+ MaximumValue = maxValue,
+ MinimumDecimalPlaces = minDecimalPlaces,
+ MaximumDecimalPlaces = maxDecimalPlaces
+ };
+
+ var entry = new Entry
+ {
+ Text = value
+ };
+ entry.Behaviors.Add(behavior);
+
try
{
- var behavior = new NumericValidationBehavior
- {
- MinimumValue = minValue,
- MaximumValue = maxValue,
- MinimumDecimalPlaces = minDecimalPlaces,
- MaximumDecimalPlaces = maxDecimalPlaces
- };
- var entry = new Entry
- {
- Text = value
- };
- entry.Behaviors.Add(behavior);
- behavior.ForceValidate();
- Assert.Equal(expectedValue, behavior.IsValid);
+ // Act
+ await behavior.ForceValidate();
+
+ // Assert
+ Assert.AreEqual(expectedValue, behavior.IsValid);
}
finally
{
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/RequiredStringValidationBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/RequiredStringValidationBehavior_Tests.cs
index 1aa160def..e0bcd48f7 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/RequiredStringValidationBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/RequiredStringValidationBehavior_Tests.cs
@@ -1,78 +1,87 @@
-using Xamarin.CommunityToolkit.Behaviors;
+using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class RequiredStringValidationBehavior_Tests
{
- public RequiredStringValidationBehavior_Tests()
- => Device.PlatformServices = new MockPlatformServices();
+ [SetUp]
+ public void Setup() => Device.PlatformServices = new MockPlatformServices();
- [Fact]
+ [Test]
public void IsValidTrueWhenBothIsNull_Test()
{
- //arrange
+ // Arrange
var passwordEntry = new Entry();
var confirmPasswordEntry = new Entry();
var confirmPasswordBehavior = new RequiredStringValidationBehavior();
confirmPasswordBehavior.Flags = ValidationFlags.ValidateOnAttaching;
- //act
+
+ // Act
confirmPasswordBehavior.RequiredString = passwordEntry.Text;
confirmPasswordEntry.Behaviors.Add(confirmPasswordBehavior);
- //assert
- Assert.True(confirmPasswordBehavior.IsValid);
+
+ // Assert
+ Assert.IsTrue(confirmPasswordBehavior.IsValid);
}
- [Fact]
+ [Test]
public void IsValidFalseWhenOneIsNull_Test()
{
- //arrange
+ // Arrange
var passwordEntry = new Entry();
var confirmPasswordEntry = new Entry();
var confirmPasswordBehavior = new RequiredStringValidationBehavior();
confirmPasswordBehavior.Flags = ValidationFlags.ValidateOnAttaching;
- //act
+
+ // Act
passwordEntry.Text = "123456";
confirmPasswordBehavior.RequiredString = passwordEntry.Text;
confirmPasswordEntry.Behaviors.Add(confirmPasswordBehavior);
+
confirmPasswordEntry.Text = null;
- //assert
+
+ // Assert
Assert.False(confirmPasswordBehavior.IsValid);
}
- [Fact]
+ [Test]
public void IsValidTrueWhenEnterSameText_Test()
{
- //arrange
+ // Arrange
var passwordEntry = new Entry();
var confirmPasswordEntry = new Entry();
var confirmPasswordBehavior = new RequiredStringValidationBehavior();
confirmPasswordBehavior.Flags = ValidationFlags.ValidateOnValueChanging;
- //act
+
+ // Act
passwordEntry.Text = "123456";
confirmPasswordBehavior.RequiredString = passwordEntry.Text;
confirmPasswordEntry.Behaviors.Add(confirmPasswordBehavior);
confirmPasswordEntry.Text = "123456";
- //assert
- Assert.True(confirmPasswordBehavior.IsValid);
+
+ // Assert
+ Assert.IsTrue(confirmPasswordBehavior.IsValid);
}
- [Fact]
+ [Test]
public void IsValidFalseWhenEnterDifferentText_Test()
{
- //arrange
+ // Arrange
var passwordEntry = new Entry();
var confirmPasswordEntry = new Entry();
var confirmPasswordBehavior = new RequiredStringValidationBehavior();
confirmPasswordBehavior.Flags = ValidationFlags.ValidateOnValueChanging;
- //act
+
+ // Act
passwordEntry.Text = "123456";
confirmPasswordBehavior.RequiredString = passwordEntry.Text;
confirmPasswordEntry.Behaviors.Add(confirmPasswordBehavior);
confirmPasswordEntry.Text = "1234567";
- //assert
+
+ // Assert
Assert.False(confirmPasswordBehavior.IsValid);
}
}
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/SetFocusOnEntryCompleted_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/SetFocusOnEntryCompleted_Tests.cs
new file mode 100644
index 000000000..84a9b7380
--- /dev/null
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/SetFocusOnEntryCompleted_Tests.cs
@@ -0,0 +1,54 @@
+using Xamarin.CommunityToolkit.Behaviors;
+using Xamarin.Forms;
+using NUnit.Framework;
+
+namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
+{
+ public class SetFocusOnEntryCompleted_Tests
+ {
+ [Test]
+ public void DoesNotSetFocusBeforeCompletion()
+ {
+ // arrange
+ var entry2 = CreateEntry();
+ var entry1 = CreateEntry(entry2);
+
+ // act
+ entry1.Focus();
+ entry1.Text = "text";
+
+ // assert
+ Assert.False(entry2.IsFocused);
+ }
+
+ [Test]
+ public void SetsFocusWhenCompleted()
+ {
+ // arrange
+ var entry2 = CreateEntry();
+ var entry1 = CreateEntry(entry2);
+
+ // act
+ entry1.Focus();
+ entry1.SendCompleted();
+
+ // assert
+ Assert.IsTrue(entry2.IsFocused);
+ }
+
+ public Entry CreateEntry(VisualElement? nextElement = null)
+ {
+ var entry = new Entry();
+
+ // We simulate Focus/Unfocus behavior ourselves
+ // because unit tests doesn't have "platform-specific" part
+ // where IsFocused is controlled in the real app
+ entry.FocusChangeRequested += (s, e) => entry.SetValue(VisualElement.IsFocusedPropertyKey, e.Focus);
+
+ if (nextElement != null)
+ SetFocusOnEntryCompletedBehavior.SetNextElement(entry, nextElement);
+
+ return entry;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UriValidationBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UriValidationBehavior_Tests.cs
index b9e9406b5..647b8688f 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UriValidationBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UriValidationBehavior_Tests.cs
@@ -1,29 +1,31 @@
using System;
+using System.Threading.Tasks;
using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
public class UriValidationBehavior_Tests
{
- public UriValidationBehavior_Tests()
- => Device.PlatformServices = new MockPlatformServices();
+ [SetUp]
+ public void Setup() => Device.PlatformServices = new MockPlatformServices();
- [Theory]
- [InlineData(@"http://microsoft.com", UriKind.Absolute, true)]
- [InlineData(@"microsoft/xamarin/news", UriKind.Relative, true)]
- [InlineData(@"http://microsoft.com", UriKind.RelativeOrAbsolute, true)]
- [InlineData(@"microsoftcom", UriKind.Absolute, false)]
- [InlineData(@"microsoft\\\\\xamarin/news", UriKind.Relative, false)]
- [InlineData(@"ht\\\.com", UriKind.RelativeOrAbsolute, false)]
- public void IsValid(string value, UriKind uriKind, bool expectedValue)
+ [TestCase(@"http://microsoft.com", UriKind.Absolute, true)]
+ [TestCase(@"microsoft/xamarin/news", UriKind.Relative, true)]
+ [TestCase(@"http://microsoft.com", UriKind.RelativeOrAbsolute, true)]
+ [TestCase(@"microsoftcom", UriKind.Absolute, false)]
+ [TestCase(@"microsoft\\\\\xamarin/news", UriKind.Relative, false)]
+ [TestCase(@"ht\\\.com", UriKind.RelativeOrAbsolute, false)]
+ public async Task IsValid(string value, UriKind uriKind, bool expectedValue)
{
+ // Arrange
var behavior = new UriValidationBehavior
{
UriKind = uriKind,
};
+
var entry = new Entry
{
Text = value,
@@ -33,8 +35,12 @@ public void IsValid(string value, UriKind uriKind, bool expectedValue)
}
};
entry.Behaviors.Add(behavior);
- behavior.ForceValidate();
- Assert.Equal(expectedValue, behavior.IsValid);
+
+ // Act
+ await behavior.ForceValidate();
+
+ // Assert
+ Assert.AreEqual(expectedValue, behavior.IsValid);
}
}
}
\ No newline at end of file
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs
index b69fdc3eb..b7d91f471 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Behaviors/UserStoppedTypingBehavior_Tests.cs
@@ -2,7 +2,7 @@
using System.Windows.Input;
using Xamarin.CommunityToolkit.Behaviors;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Behaviors
{
@@ -10,44 +10,45 @@ public class UserStoppedTypingBehavior_Tests
{
const int defaultTimeThreshold = 1000;
const int defaultLengthThreshold = 0;
+ const int defaultTimeoutThreshold = defaultTimeThreshold * 2;
- [Fact]
+ [Test]
public async Task ShouldExecuteCommandWhenTimeThresholdHasExpired()
{
// arrange
var commandHasBeenExecuted = false;
- var entry = CreateEntryWithBehavior(command: new Command((s) => commandHasBeenExecuted = true));
+ var entry = CreateEntryWithBehavior(command: new Command(_ => commandHasBeenExecuted = true));
// act
entry.Text = "1";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
- Assert.True(commandHasBeenExecuted);
+ Assert.IsTrue(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public async Task ShouldExecuteCommandWithSpecificParameterWhenSpecified()
{
// arrange
var commandHasBeenExecuted = false;
- var entry = CreateEntryWithBehavior(command: new Command((s) => commandHasBeenExecuted = true),
+ var entry = CreateEntryWithBehavior(command: new Command(_ => commandHasBeenExecuted = true),
commandParameter: true);
// act
entry.Text = "1";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
- Assert.True(commandHasBeenExecuted);
+ Assert.IsTrue(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public async Task ShouldNotExecuteCommandBeforeTimeThresholdHasExpired()
{
// arrange
var commandHasBeenExecuted = false;
- var entry = CreateEntryWithBehavior(command: new Command((s) => commandHasBeenExecuted = true));
+ var entry = CreateEntryWithBehavior(command: new Command(_ => commandHasBeenExecuted = true));
// act
entry.Text = "1";
@@ -57,25 +58,25 @@ public async Task ShouldNotExecuteCommandBeforeTimeThresholdHasExpired()
Assert.False(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public async Task ShouldOnlyExectueCommandOnceWhenTextChangedHasOccurredMultipleTimes()
{
// arrange
var timesExecuted = 0;
- var entry = CreateEntryWithBehavior(command: new Command((s) => timesExecuted++));
+ var entry = CreateEntryWithBehavior(command: new Command(_ => timesExecuted++));
// act
entry.Text = "1";
entry.Text = "12";
entry.Text = "123";
entry.Text = "1234";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
- Assert.Equal(1, timesExecuted);
+ Assert.AreEqual(1, timesExecuted);
}
- [Fact]
+ [Test]
public async Task ShouldDismissKeyboardWhenTimeThresholdHasExpired()
{
// arrange
@@ -85,47 +86,47 @@ public async Task ShouldDismissKeyboardWhenTimeThresholdHasExpired()
entry.Focus();
entry.Text = "1";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
Assert.False(entry.IsFocused);
}
- [Fact]
+ [Test]
public async Task ShouldExecuteCommandWhenMinimumLengthThreholdHasBeenReached()
{
// arrange
var commandHasBeenExecuted = false;
- var entry = CreateEntryWithBehavior(command: new Command((s) => commandHasBeenExecuted = true),
+ var entry = CreateEntryWithBehavior(command: new Command(_ => commandHasBeenExecuted = true),
lengthThreshold: 3);
// act
entry.Text = "1";
entry.Text = "12";
entry.Text = "123";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
- Assert.True(commandHasBeenExecuted);
+ Assert.IsTrue(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public async Task ShouldNotExecuteCommandWhenMinimumLengthThreholdHasNotBeenReached()
{
// arrange
var commandHasBeenExecuted = false;
- var entry = CreateEntryWithBehavior(command: new Command((s) => commandHasBeenExecuted = true),
+ var entry = CreateEntryWithBehavior(command: new Command(_ => commandHasBeenExecuted = true),
lengthThreshold: 2);
// act
entry.Text = "1";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
Assert.False(commandHasBeenExecuted);
}
- [Fact]
+ [Test]
public async Task ShouldNotDismissKeyboardWhenMinimumLengthThreholdHasNotBeenReached()
{
// arrange
@@ -136,32 +137,32 @@ public async Task ShouldNotDismissKeyboardWhenMinimumLengthThreholdHasNotBeenRea
entry.Focus();
entry.Text = "1";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
- Assert.True(entry.IsFocused);
+ Assert.IsTrue(entry.IsFocused);
}
- [Fact]
+ [Test]
public async Task ShouldExecuteCommandImmediatelyWhenMinimumLengthThreholdHasNotBeenSet()
{
// arrange
var commandHasBeenExecuted = false;
- var entry = CreateEntryWithBehavior(command: new Command((s) => commandHasBeenExecuted = true));
+ var entry = CreateEntryWithBehavior(command: new Command(_ => commandHasBeenExecuted = true));
// act
entry.Text = "1";
- await Task.Delay(defaultTimeThreshold + 100);
+ await Task.Delay(defaultTimeoutThreshold);
// assert
- Assert.True(commandHasBeenExecuted);
+ Assert.IsTrue(commandHasBeenExecuted);
}
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/BoolToObjectConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/BoolToObjectConverter_Tests.cs
index 29d952be8..5a3c224e2 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/BoolToObjectConverter_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/BoolToObjectConverter_Tests.cs
@@ -1,7 +1,7 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Converters;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@@ -10,9 +10,8 @@ public class BoolToObjectConverter_Tests
public const string TrueTestObject = nameof(TrueTestObject);
public const string FalseTestObject = nameof(FalseTestObject);
- [Theory]
- [InlineData(true, TrueTestObject, FalseTestObject, TrueTestObject)]
- [InlineData(false, TrueTestObject, FalseTestObject, FalseTestObject)]
+ [TestCase(true, TrueTestObject, FalseTestObject, TrueTestObject)]
+ [TestCase(false, TrueTestObject, FalseTestObject, FalseTestObject)]
public void BoolToObjectConvert(bool value, object trueObject, object falseObject, object expectedResult)
{
var boolObjectConverter = new BoolToObjectConverter();
@@ -21,12 +20,11 @@ public void BoolToObjectConvert(bool value, object trueObject, object falseObjec
var result = boolObjectConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture);
- Assert.Equal(result, expectedResult);
+ Assert.AreEqual(result, expectedResult);
}
- [Theory]
- [InlineData(TrueTestObject, TrueTestObject, FalseTestObject, true)]
- [InlineData(FalseTestObject, TrueTestObject, FalseTestObject, false)]
+ [TestCase(TrueTestObject, TrueTestObject, FalseTestObject, true)]
+ [TestCase(FalseTestObject, TrueTestObject, FalseTestObject, false)]
public void BoolToObjectConvertBack(object value, object trueObject, object falseObject, bool expectedResult)
{
var boolObjectConverter = new BoolToObjectConverter();
@@ -35,11 +33,10 @@ public void BoolToObjectConvertBack(object value, object trueObject, object fals
var result = boolObjectConverter.ConvertBack(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture);
- Assert.Equal(result, expectedResult);
+ Assert.AreEqual(result, expectedResult);
}
- [Theory]
- [InlineData("")]
+ [TestCase("")]
public void BoolToObjectInValidValuesThrowArgumenException(object value)
{
var boolObjectConverter = new BoolToObjectConverter();
diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs
index a30e013ee..e2b3a54d8 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/ByteArrayToImageSourceConverter_Tests.cs
@@ -3,13 +3,13 @@
using System.IO;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
public class ByteArrayToImageSourceConverter_Tests
{
- [Fact]
+ [Test]
public void ByteArrayToImageSourceConverter()
{
var byteArray = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
@@ -22,11 +22,11 @@ public void ByteArrayToImageSourceConverter()
var result = byteArrayToImageSourceConverter.Convert(byteArray, typeof(ByteArrayToImageSourceConverter), null, CultureInfo.CurrentCulture);
- Assert.True(StreamEquals(GetStreamFromImageSource((ImageSource)result), memoryStream));
+ Assert.IsTrue(StreamEquals(GetStreamFromImageSource((ImageSource?)result), memoryStream));
}
- [Theory]
- [InlineData("Random String Value")]
+
+ [TestCase("Random String Value")]
public void InvalidConverterValuesReturnsNull(object value)
{
var byteArrayToImageSourceConverter = new ByteArrayToImageSourceConverter();
@@ -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/Converters/DateTimeOffsetConverter_Tests.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DateTimeOffsetConverter_Tests.cs
index 27df80bd6..7a9ef254b 100644
--- a/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DateTimeOffsetConverter_Tests.cs
+++ b/src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Converters/DateTimeOffsetConverter_Tests.cs
@@ -2,24 +2,25 @@
using System.Collections.Generic;
using System.Globalization;
using Xamarin.CommunityToolkit.Converters;
-using Xunit;
+using NUnit.Framework;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
public class DateTimeOffsetConverter_Tests
{
- static DateTime testDateTimeNow = DateTime.Now;
- static DateTime testDateTimeLocal = new DateTime(2020, 08, 25, 13, 37, 00, DateTimeKind.Local);
- static DateTime testDateTimeUtc = new DateTime(2020, 08, 25, 13, 37, 00, DateTimeKind.Utc);
- static DateTime testDateTimeUnspecified = new DateTime(2020, 08, 25, 13, 37, 00);
- static DateTimeOffset testDateTimeOffsetNow = new DateTimeOffset(testDateTimeNow);
- static DateTimeOffset testDateTimeOffsetLocal = new DateTimeOffset(2020, 08, 25, 13, 37, 00, DateTimeOffset.Now.Offset);
- static DateTimeOffset testDateTimeOffsetUtc = new DateTimeOffset(2020, 08, 25, 13, 37, 00, DateTimeOffset.UtcNow.Offset);
+ static readonly DateTime testDateTimeNow = DateTime.Now;
+ static readonly DateTime testDateTimeLocal = new DateTime(2020, 08, 25, 13, 37, 00, DateTimeKind.Local);
+ static readonly DateTime testDateTimeUtc = new DateTime(2020, 08, 25, 13, 37, 00, DateTimeKind.Utc);
+ static readonly DateTime testDateTimeUnspecified = new DateTime(2020, 08, 25, 13, 37, 00);
+
+ static readonly DateTimeOffset testDateTimeOffsetNow = new DateTimeOffset(testDateTimeNow);
+ static readonly DateTimeOffset testDateTimeOffsetLocal = new DateTimeOffset(2020, 08, 25, 13, 37, 00, DateTimeOffset.Now.Offset);
+ static readonly DateTimeOffset testDateTimeOffsetUtc = new DateTimeOffset(2020, 08, 25, 13, 37, 00, DateTimeOffset.UtcNow.Offset);
public static IEnumerable