diff --git a/components/Loading/OpenSolution.bat b/components/Loading/OpenSolution.bat new file mode 100644 index 00000000..814a56d4 --- /dev/null +++ b/components/Loading/OpenSolution.bat @@ -0,0 +1,3 @@ +@ECHO OFF + +powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %* \ No newline at end of file diff --git a/components/Loading/samples/Assets/Loading.png b/components/Loading/samples/Assets/Loading.png new file mode 100644 index 00000000..59790fce Binary files /dev/null and b/components/Loading/samples/Assets/Loading.png differ diff --git a/components/Loading/samples/Dependencies.props b/components/Loading/samples/Dependencies.props new file mode 100644 index 00000000..e622e1df --- /dev/null +++ b/components/Loading/samples/Dependencies.props @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/Loading/samples/Loading.Samples.csproj b/components/Loading/samples/Loading.Samples.csproj new file mode 100644 index 00000000..b4decfde --- /dev/null +++ b/components/Loading/samples/Loading.Samples.csproj @@ -0,0 +1,16 @@ + + + Loading + + + + + + + PreserveNewest + + + + + + diff --git a/components/Loading/samples/Loading.md b/components/Loading/samples/Loading.md new file mode 100644 index 00000000..c49f12b6 --- /dev/null +++ b/components/Loading/samples/Loading.md @@ -0,0 +1,17 @@ +--- +title: Loading +author: nmetulev +description: The Loading control helps to show content with animation to the user while the app is doing some calculation.. +keywords: Loading, Control, loader, progress +dev_langs: + - csharp +category: Controls +subcategory: StatusAndInfo +discussion-id: 0 +issue-id: 0 +icon: Assets/Loading.png +--- + +The [Loading](/dotnet/api/microsoft.toolkit.uwp.ui.controls.loading) control is for showing an animation with some content when the user should wait in some tasks of the app. + +> [!Sample LoadingSample] diff --git a/components/Loading/samples/LoadingSample.xaml b/components/Loading/samples/LoadingSample.xaml new file mode 100644 index 00000000..2c50204e --- /dev/null +++ b/components/Loading/samples/LoadingSample.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/components/Loading/samples/LoadingSample.xaml.cs b/components/Loading/samples/LoadingSample.xaml.cs new file mode 100644 index 00000000..945d7264 --- /dev/null +++ b/components/Loading/samples/LoadingSample.xaml.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace LoadingExperiment.Samples; + +[ToolkitSampleTextOption("LoadingContent", "Loading content..", Title = "Content")] +[ToolkitSampleBoolOption("LoadingState", true, Title = "IsLoading")] + +[ToolkitSample(id: nameof(LoadingSample), "Loading", description: $"A sample for showing how to create and use a {nameof(CommunityToolkit.WinUI.Controls.Loading)} control.")] +public sealed partial class LoadingSample : Page +{ + public LoadingSample() + { + this.InitializeComponent(); + } +} diff --git a/components/Loading/src/CommunityToolkit.WinUI.Controls.Loading.csproj b/components/Loading/src/CommunityToolkit.WinUI.Controls.Loading.csproj new file mode 100644 index 00000000..6b886970 --- /dev/null +++ b/components/Loading/src/CommunityToolkit.WinUI.Controls.Loading.csproj @@ -0,0 +1,12 @@ + + + Loading + This package contains Loading. + + + CommunityToolkit.WinUI.Controls.LoadingRns + + + + + diff --git a/components/Loading/src/Dependencies.props b/components/Loading/src/Dependencies.props new file mode 100644 index 00000000..e622e1df --- /dev/null +++ b/components/Loading/src/Dependencies.props @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/Loading/src/Loading.Properties.cs b/components/Loading/src/Loading.Properties.cs new file mode 100644 index 00000000..bf1c244b --- /dev/null +++ b/components/Loading/src/Loading.Properties.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace CommunityToolkit.WinUI.Controls; + +/// +/// Loading control allows to show an loading animation with some xaml in it. +/// +public partial class Loading +{ + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register( + nameof(IsLoading), typeof(bool), typeof(Loading), new PropertyMetadata(default(bool), IsLoadingPropertyChanged)); + + /// + /// Gets or sets a value indicating whether the control is in the loading state. + /// + /// Set this to true to show the Loading control, false to hide the control. + public bool IsLoading + { + get { return (bool)GetValue(IsLoadingProperty); } + set { SetValue(IsLoadingProperty, value); } + } + + private static void IsLoadingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is Loading control) + { + if (control._presenter == null) + { + if (control.GetTemplateChild("ContentGrid") is FrameworkElement content) + { + control._presenter = content; + } + } + + control?.Update(); + } + } +} diff --git a/components/Loading/src/Loading.cs b/components/Loading/src/Loading.cs new file mode 100644 index 00000000..8ed7b1c6 --- /dev/null +++ b/components/Loading/src/Loading.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace CommunityToolkit.WinUI.Controls; + +/// +/// Loading control allows to show an loading animation with some xaml in it. +/// +[TemplateVisualState(Name = "LoadingIn", GroupName = "CommonStates")] +[TemplateVisualState(Name = "LoadingOut", GroupName = "CommonStates")] +public partial class Loading : ContentControl +{ + private FrameworkElement? _presenter; + + /// + /// Initializes a new instance of the class. + /// + public Loading() + { + DefaultStyleKey = typeof(Loading); + } + + /// + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + Update(); + } + + private void Update() + { + VisualStateManager.GoToState(this, IsLoading ? "LoadingIn" : "LoadingOut", true); + } +} diff --git a/components/Loading/src/Loading.xaml b/components/Loading/src/Loading.xaml new file mode 100644 index 00000000..4bf8b58f --- /dev/null +++ b/components/Loading/src/Loading.xaml @@ -0,0 +1,122 @@ + + + + + diff --git a/components/Loading/src/MultiTarget.props b/components/Loading/src/MultiTarget.props new file mode 100644 index 00000000..b11c1942 --- /dev/null +++ b/components/Loading/src/MultiTarget.props @@ -0,0 +1,9 @@ + + + + uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + + \ No newline at end of file diff --git a/components/Loading/src/Themes/Generic.xaml b/components/Loading/src/Themes/Generic.xaml new file mode 100644 index 00000000..488457c7 --- /dev/null +++ b/components/Loading/src/Themes/Generic.xaml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/components/Loading/tests/ExampleLoadingTestClass.cs b/components/Loading/tests/ExampleLoadingTestClass.cs new file mode 100644 index 00000000..65ab605b --- /dev/null +++ b/components/Loading/tests/ExampleLoadingTestClass.cs @@ -0,0 +1,134 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.Tooling.TestGen; +using CommunityToolkit.Tests; +using CommunityToolkit.WinUI.Controls; + +namespace LoadingExperiment.Tests; + +[TestClass] +public partial class ExampleLoadingTestClass : VisualUITestBase +{ + // If you don't need access to UI objects directly or async code, use this pattern. + [TestMethod] + public void SimpleSynchronousExampleTest() + { + var assembly = typeof(Loading).Assembly; + var type = assembly.GetType(typeof(Loading).FullName ?? string.Empty); + + Assert.IsNotNull(type, "Could not find Loading type."); + Assert.AreEqual(typeof(Loading), type, "Type of Loading does not match expected type."); + } + + // If you don't need access to UI objects directly, use this pattern. + [TestMethod] + public async Task SimpleAsyncExampleTest() + { + await Task.Delay(250); + + Assert.IsTrue(true); + } + + // Example that shows how to check for exception throwing. + [TestMethod] + public void SimpleExceptionCheckTest() + { + // If you need to check exceptions occur for invalid inputs, etc... + // Use Assert.ThrowsException to limit the scope to where you expect the error to occur. + // Otherwise, using the ExpectedException attribute could swallow or + // catch other issues in setup code. + Assert.ThrowsException(() => throw new NotImplementedException()); + } + + // The UIThreadTestMethod automatically dispatches to the UI for us to work with UI objects. + [UIThreadTestMethod] + public void SimpleUIAttributeExampleTest() + { + var component = new Loading(); + Assert.IsNotNull(component); + } + + // The UIThreadTestMethod can also easily grab a XAML Page for us by passing its type as a parameter. + // This lets us actually test a control as it would behave within an actual application. + // The page will already be loaded by the time your test is called. + [UIThreadTestMethod] + public void SimpleUIExamplePageTest(ExampleLoadingTestPage page) + { + // You can use the Toolkit Visual Tree helpers here to find the component by type or name: + var component = page.FindDescendant(); + + Assert.IsNotNull(component); + + var componentByName = page.FindDescendant("LoadingControl"); + + Assert.IsNotNull(componentByName); + } + + // You can still do async work with a UIThreadTestMethod as well. + [UIThreadTestMethod] + public async Task SimpleAsyncUIExamplePageTest(ExampleLoadingTestPage page) + { + // This helper can be used to wait for a rendering pass to complete. + // Note, this is already done by loading a Page with the [UIThreadTestMethod] helper. + await CompositionTargetHelper.ExecuteAfterCompositionRenderingAsync(() => { }); + + var component = page.FindDescendant(); + + Assert.IsNotNull(component); + } + + //// ----------------------------- ADVANCED TEST SCENARIOS ----------------------------- + + // If you need to use DataRow, you can use this pattern with the UI dispatch still. + // Otherwise, checkout the UIThreadTestMethod attribute above. + // See https://github.com/CommunityToolkit/Labs-Windows/issues/186 + [TestMethod] + public async Task ComplexAsyncUIExampleTest() + { + await EnqueueAsync(() => + { + var component = new Loading(); + Assert.IsNotNull(component); + }); + } + + // If you want to load other content not within a XAML page using the UIThreadTestMethod above. + // Then you can do that using the Load/UnloadTestContentAsync methods. + [TestMethod] + public async Task ComplexAsyncLoadUIExampleTest() + { + await EnqueueAsync(async () => + { + var component = new Loading(); + Assert.IsNotNull(component); + Assert.IsFalse(component.IsLoaded); + + await LoadTestContentAsync(component); + + Assert.IsTrue(component.IsLoaded); + + await UnloadTestContentAsync(component); + + Assert.IsFalse(component.IsLoaded); + }); + } + + // You can still use the UIThreadTestMethod to remove the extra layer for the dispatcher as well: + [UIThreadTestMethod] + public async Task ComplexAsyncLoadUIExampleWithoutDispatcherTest() + { + var component = new Loading(); + Assert.IsNotNull(component); + Assert.IsFalse(component.IsLoaded); + + await LoadTestContentAsync(component); + + Assert.IsTrue(component.IsLoaded); + + await UnloadTestContentAsync(component); + + Assert.IsFalse(component.IsLoaded); + } +} diff --git a/components/Loading/tests/ExampleLoadingTestPage.xaml b/components/Loading/tests/ExampleLoadingTestPage.xaml new file mode 100644 index 00000000..7513ee79 --- /dev/null +++ b/components/Loading/tests/ExampleLoadingTestPage.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/components/Loading/tests/ExampleLoadingTestPage.xaml.cs b/components/Loading/tests/ExampleLoadingTestPage.xaml.cs new file mode 100644 index 00000000..e8d964a3 --- /dev/null +++ b/components/Loading/tests/ExampleLoadingTestPage.xaml.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace LoadingExperiment.Tests; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public sealed partial class ExampleLoadingTestPage : Page +{ + public ExampleLoadingTestPage() + { + this.InitializeComponent(); + } +} diff --git a/components/Loading/tests/Loading.Tests.projitems b/components/Loading/tests/Loading.Tests.projitems new file mode 100644 index 00000000..dc2dc043 --- /dev/null +++ b/components/Loading/tests/Loading.Tests.projitems @@ -0,0 +1,23 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 339D88E6-64F0-4AB0-B97F-403E3846766F + + + LoadingExperiment.Tests + + + + + ExampleLoadingTestPage.xaml + + + + + Designer + MSBuild:Compile + + + \ No newline at end of file diff --git a/components/Loading/tests/Loading.Tests.shproj b/components/Loading/tests/Loading.Tests.shproj new file mode 100644 index 00000000..80870f40 --- /dev/null +++ b/components/Loading/tests/Loading.Tests.shproj @@ -0,0 +1,13 @@ + + + + 339D88E6-64F0-4AB0-B97F-403E3846766F + 14.0 + + + + + + + +