From 42ca62386c9b22dd18f528b64975861bb8de99e5 Mon Sep 17 00:00:00 2001 From: Matt Lacey Date: Tue, 14 Jun 2022 12:22:50 +0100 Subject: [PATCH] Initial conversion to use File scoped namespaces Fixes #148 --- .editorconfig | 2 +- ...oolkitSampleMetadataTests.Documentation.cs | 97 +++-- .../ToolkitSampleMetadataTests.cs | 265 ++++++------ .../Diagnostics/DiagnosticDescriptors.cs | 397 +++++++++--------- .../GeneratorExtensions.cs | 213 +++++----- .../IGeneratedToolkitSampleOptionViewModel.cs | 47 +-- ...tSampleGeneratedOptionPropertyContainer.cs | 25 +- ...oolkitSampleBoolOptionMetadataViewModel.cs | 141 +++---- ...ampleMultiChoiceOptionMetadataViewModel.cs | 105 +++-- .../ToolkitSampleOptionGenerator.cs | 125 +++--- .../CommunityToolkit.Labs.Shared/App.xaml.cs | 95 +++-- .../AppLoadingView.xaml.cs | 141 +++---- .../DocOrSampleTemplateSelector.cs | 25 +- .../NavigationPage.xaml.cs | 159 ++++--- .../GeneratedSampleOptionTemplateSelector.cs | 31 +- .../GeneratedSampleOptionsRenderer.xaml.cs | 67 ++- .../ToolkitDocumentationRenderer.xaml.cs | 255 ++++++----- .../Renderers/ToolkitSampleRenderer.xaml.cs | 333 ++++++++------- .../TabbedPage.xaml.cs | 67 ++- .../SampleOne/SamplePage.xaml.cs | 29 +- .../SampleThree/SamplePage3.xaml.cs | 45 +- .../SampleTwo/SamplePage2.xaml.cs | 13 +- .../SampleTwo/SamplePageOptions.xaml.cs | 71 ++-- .../samples/CanvasLayout.Wasm/Program.cs | 5 +- labs/CanvasLayout/src/CanvasLayout.cs | 167 ++++---- .../ExampleCanvasLayoutTestClass.cs | 15 +- .../samples/SizerBase.Wasm/Program.cs | 17 +- platforms/CommunityToolkit.Labs.Droid/Main.cs | 5 +- .../MainActivity.cs | 5 +- .../CommunityToolkit.Labs.Skia.Gtk/Program.cs | 5 +- .../App.xaml.cs | 5 +- .../MainWindow.xaml.cs | 5 +- .../CommunityToolkit.Labs.Skia.WPF/Program.cs | 4 +- .../CommunityToolkit.Labs.Wasm/Program.cs | 5 +- platforms/CommunityToolkit.Labs.iOS/Main.cs | 7 +- platforms/CommunityToolkit.Labs.macOS/Main.cs | 5 +- .../ProjectTemplateFirstSamplePage.xaml.cs | 33 +- .../samples/ProjectTemplate.Wasm/Program.cs | 17 +- template/lab/src/ProjectTemplate.cs | 7 +- .../ExampleProjectTemplateTestClass.cs | 17 +- 40 files changed, 1516 insertions(+), 1556 deletions(-) diff --git a/.editorconfig b/.editorconfig index 42f1c0c21..e81dd2157 100644 --- a/.editorconfig +++ b/.editorconfig @@ -411,7 +411,7 @@ dotnet_diagnostic.SA1634.severity = none dotnet_diagnostic.SA1652.severity = none csharp_using_directive_placement = outside_namespace:silent csharp_prefer_simple_using_statement = true:suggestion -csharp_style_namespace_declarations = block_scoped:silent +csharp_style_namespace_declarations = file_scoped:warning csharp_style_expression_bodied_local_functions = false:silent csharp_style_prefer_null_check_over_type_check = true:suggestion csharp_style_prefer_local_over_anonymous_function = true:suggestion diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.Documentation.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.Documentation.cs index 5387d5cd7..245509824 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.Documentation.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.Documentation.cs @@ -8,12 +8,12 @@ using System.Collections.Immutable; using System.Linq; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Tests +namespace CommunityToolkit.Labs.Core.SourceGenerators.Tests; + +public partial class ToolkitSampleMetadataTests { - public partial class ToolkitSampleMetadataTests - { - // We currently need at least one sample to test the document registry, so we'll have this for the base cases to share. - private static readonly string SimpleSource = $@" + // We currently need at least one sample to test the document registry, so we'll have this for the base cases to share. + private static readonly string SimpleSource = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -32,26 +32,26 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - [TestMethod] - public void MissingFrontMatterSection() - { - string markdown = @" + [TestMethod] + public void MissingFrontMatterSection() + { + string markdown = @" # This is some test documentation... Without any front matter. "; - VerifyGeneratedDiagnostics(SimpleSource, markdown, DiagnosticDescriptors.MarkdownYAMLFrontMatterException.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } - - [DataRow(1, DisplayName = "Title")] - [DataRow(3, DisplayName = "Description")] - [DataRow(4, DisplayName = "Keywords")] - [DataRow(7, DisplayName = "Category")] - [DataRow(8, DisplayName = "Subcategory")] - [TestMethod] - public void MissingFrontMatterField(int removeline) - { - string markdown = @"--- + VerifyGeneratedDiagnostics(SimpleSource, markdown, DiagnosticDescriptors.MarkdownYAMLFrontMatterException.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } + + [DataRow(1, DisplayName = "Title")] + [DataRow(3, DisplayName = "Description")] + [DataRow(4, DisplayName = "Keywords")] + [DataRow(7, DisplayName = "Category")] + [DataRow(8, DisplayName = "Subcategory")] + [TestMethod] + public void MissingFrontMatterField(int removeline) + { + string markdown = @"--- title: Canvas Layout author: mhawker description: A canvas-like VirtualizingLayout for use in an ItemsRepeater @@ -65,18 +65,18 @@ public void MissingFrontMatterField(int removeline) > [!SAMPLE Sample] Without any front matter."; - // Remove the field we want to test is missing. - var lines = markdown.Split('\n').ToList(); - lines.RemoveAt(removeline); - markdown = String.Join('\n', lines); + // Remove the field we want to test is missing. + var lines = markdown.Split('\n').ToList(); + lines.RemoveAt(removeline); + markdown = String.Join('\n', lines); - VerifyGeneratedDiagnostics(SimpleSource, markdown, DiagnosticDescriptors.MarkdownYAMLFrontMatterMissingField.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); // We won't see the sample reference as we bail out when the front matter fails to be complete... - } + VerifyGeneratedDiagnostics(SimpleSource, markdown, DiagnosticDescriptors.MarkdownYAMLFrontMatterMissingField.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); // We won't see the sample reference as we bail out when the front matter fails to be complete... + } - [TestMethod] - public void MarkdownInvalidSampleReference() - { - string markdown = @"--- + [TestMethod] + public void MarkdownInvalidSampleReference() + { + string markdown = @"--- title: Canvas Layout author: mhawker description: A canvas-like VirtualizingLayout for use in an ItemsRepeater @@ -91,15 +91,15 @@ public void MarkdownInvalidSampleReference() Without any front matter. "; - VerifyGeneratedDiagnostics(SimpleSource, markdown, - DiagnosticDescriptors.MarkdownSampleIdNotFound.Id, - DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(SimpleSource, markdown, + DiagnosticDescriptors.MarkdownSampleIdNotFound.Id, + DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void DocumentationMissingSample() - { - string markdown = @"--- + [TestMethod] + public void DocumentationMissingSample() + { + string markdown = @"--- title: Canvas Layout author: mhawker description: A canvas-like VirtualizingLayout for use in an ItemsRepeater @@ -112,15 +112,15 @@ public void DocumentationMissingSample() # This is some test documentation... Without any front matter."; - VerifyGeneratedDiagnostics(SimpleSource, markdown, - DiagnosticDescriptors.DocumentationHasNoSamples.Id, - DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(SimpleSource, markdown, + DiagnosticDescriptors.DocumentationHasNoSamples.Id, + DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void DocumentationValid() - { - string markdown = @"--- + [TestMethod] + public void DocumentationValid() + { + string markdown = @"--- title: Canvas Layout author: mhawker description: A canvas-like VirtualizingLayout for use in an ItemsRepeater @@ -134,7 +134,6 @@ public void DocumentationValid() Without any front matter. > [!SAMPLE Sample]"; - VerifyGeneratedDiagnostics(SimpleSource, markdown); - } + VerifyGeneratedDiagnostics(SimpleSource, markdown); } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.cs index 75a5c98fd..d9f67bff7 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/ToolkitSampleMetadataTests.cs @@ -12,15 +12,15 @@ using System.Text; using System.Threading; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Tests +namespace CommunityToolkit.Labs.Core.SourceGenerators.Tests; + +[TestClass] +public partial class ToolkitSampleMetadataTests { - [TestClass] - public partial class ToolkitSampleMetadataTests + [TestMethod] + public void PaneOptionOnNonSample() { - [TestMethod] - public void PaneOptionOnNonSample() - { - string source = @" + string source = @" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -37,16 +37,16 @@ namespace Windows.UI.Xaml.Controls public class UserControl { } }"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionAttributeOnNonSample.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionAttributeOnNonSample.Id); + } - [DataRow("", DisplayName = "Empty string"), DataRow(" ", DisplayName = "Only whitespace"), DataRow("Test ", DisplayName = "Text with whitespace")] - [DataRow("_", DisplayName = "Underscore"), DataRow("$", DisplayName = "Dollar sign"), DataRow("%", DisplayName = "Percent symbol")] - [DataRow("class", DisplayName = "Reserved keyword 'class'"), DataRow("string", DisplayName = "Reserved keyword 'string'"), DataRow("sealed", DisplayName = "Reserved keyword 'sealed'"), DataRow("ref", DisplayName = "Reserved keyword 'ref'")] - [TestMethod] - public void PaneOptionWithBadName(string name) - { - var source = $@" + [DataRow("", DisplayName = "Empty string"), DataRow(" ", DisplayName = "Only whitespace"), DataRow("Test ", DisplayName = "Text with whitespace")] + [DataRow("_", DisplayName = "Underscore"), DataRow("$", DisplayName = "Dollar sign"), DataRow("%", DisplayName = "Percent symbol")] + [DataRow("class", DisplayName = "Reserved keyword 'class'"), DataRow("string", DisplayName = "Reserved keyword 'string'"), DataRow("sealed", DisplayName = "Reserved keyword 'sealed'"), DataRow("ref", DisplayName = "Reserved keyword 'ref'")] + [TestMethod] + public void PaneOptionWithBadName(string name) + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -65,13 +65,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithBadName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithBadName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void PaneOptionWithConflictingPropertyName() - { - var source = $@" + [TestMethod] + public void PaneOptionWithConflictingPropertyName() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -91,13 +91,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithConflictingName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithConflictingName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void PaneOptionWithConflictingInheritedPropertyName() - { - var source = $@" + [TestMethod] + public void PaneOptionWithConflictingInheritedPropertyName() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -121,13 +121,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithConflictingName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithConflictingName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void PaneOptionWithDuplicateName() - { - var source = $@" + [TestMethod] + public void PaneOptionWithDuplicateName() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -149,13 +149,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithDuplicateName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneOptionWithDuplicateName.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void PaneOptionWithDuplicateName_AllowedBetweenSamples() - { - var source = $@" + [TestMethod] + public void PaneOptionWithDuplicateName_AllowedBetweenSamples() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -182,13 +182,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void PaneMultipleChoiceOptionWithNoChoices() - { - var source = $@" + [TestMethod] + public void PaneMultipleChoiceOptionWithNoChoices() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -208,13 +208,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneMultiChoiceOptionWithNoChoices.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SamplePaneMultiChoiceOptionWithNoChoices.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void SampleGeneratedOptionAttributeOnUnsupportedType() - { - var source = $@" + [TestMethod] + public void SampleGeneratedOptionAttributeOnUnsupportedType() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -228,13 +228,13 @@ public partial class Sample }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleGeneratedOptionAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SamplePaneOptionAttributeOnNonSample.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleGeneratedOptionAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SamplePaneOptionAttributeOnNonSample.Id); + } - [TestMethod] - public void SampleAttributeOnUnsupportedType() - { - var source = $@" + [TestMethod] + public void SampleAttributeOnUnsupportedType() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -247,13 +247,13 @@ public partial class Sample }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void SampleOptionPaneAttributeOnUnsupportedType() - { - var source = $@" + [TestMethod] + public void SampleOptionPaneAttributeOnUnsupportedType() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -276,13 +276,13 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleOptionPaneAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleOptionPaneAttributeOnUnsupportedType.Id, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - [TestMethod] - public void SampleAttributeValid() - { - var source = $@" + [TestMethod] + public void SampleAttributeValid() + { + var source = $@" using System.ComponentModel; using CommunityToolkit.Labs.Core.SourceGenerators; using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; @@ -301,84 +301,83 @@ namespace Windows.UI.Xaml.Controls public class UserControl {{ }} }}"; - // TODO: We should have this return the references to the registries or something so we can check the generated output? - VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); - } + // TODO: We should have this return the references to the registries or something so we can check the generated output? + VerifyGeneratedDiagnostics(source, string.Empty, DiagnosticDescriptors.SampleNotReferencedInMarkdown.Id); + } - /// - /// Verifies the output of a source generator. - /// - /// The generator type to use. - /// The input source to process. - /// The input documentation info to process. - /// The diagnostic ids to expect for the input source code. - private static void VerifyGeneratedDiagnostics(string source, string markdown, params string[] diagnosticsIds) - where TGenerator : class, IIncrementalGenerator, new() - { - VerifyGeneratedDiagnostics(CSharpSyntaxTree.ParseText(source), markdown, diagnosticsIds); - } + /// + /// Verifies the output of a source generator. + /// + /// The generator type to use. + /// The input source to process. + /// The input documentation info to process. + /// The diagnostic ids to expect for the input source code. + private static void VerifyGeneratedDiagnostics(string source, string markdown, params string[] diagnosticsIds) + where TGenerator : class, IIncrementalGenerator, new() + { + VerifyGeneratedDiagnostics(CSharpSyntaxTree.ParseText(source), markdown, diagnosticsIds); + } - /// - /// Verifies the output of a source generator. - /// - /// The generator type to use. - /// The input source tree to process. - /// The input documentation info to process. - /// The diagnostic ids to expect for the input source code. - private static void VerifyGeneratedDiagnostics(SyntaxTree syntaxTree, string markdown, params string[] diagnosticsIds) - where TGenerator : class, IIncrementalGenerator, new() - { - var sampleAttributeType = typeof(ToolkitSampleAttribute); + /// + /// Verifies the output of a source generator. + /// + /// The generator type to use. + /// The input source tree to process. + /// The input documentation info to process. + /// The diagnostic ids to expect for the input source code. + private static void VerifyGeneratedDiagnostics(SyntaxTree syntaxTree, string markdown, params string[] diagnosticsIds) + where TGenerator : class, IIncrementalGenerator, new() + { + var sampleAttributeType = typeof(ToolkitSampleAttribute); - var references = - from assembly in AppDomain.CurrentDomain.GetAssemblies() - where !assembly.IsDynamic - let reference = MetadataReference.CreateFromFile(assembly.Location) - select reference; + var references = + from assembly in AppDomain.CurrentDomain.GetAssemblies() + where !assembly.IsDynamic + let reference = MetadataReference.CreateFromFile(assembly.Location) + select reference; - var compilation = CSharpCompilation.Create( - "original.Sample", - new[] { syntaxTree }, - references, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + var compilation = CSharpCompilation.Create( + "original.Sample", + new[] { syntaxTree }, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - IIncrementalGenerator generator = new TGenerator(); + IIncrementalGenerator generator = new TGenerator(); - GeneratorDriver driver = - CSharpGeneratorDriver - .Create(generator) - .WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options); + GeneratorDriver driver = + CSharpGeneratorDriver + .Create(generator) + .WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options); - if (!string.IsNullOrWhiteSpace(markdown)) - { - var text = new InMemoryAdditionalText(@"C:\pathtorepo\labs\experiment\samples\experiment.Sample\documentation.md", markdown); + if (!string.IsNullOrWhiteSpace(markdown)) + { + var text = new InMemoryAdditionalText(@"C:\pathtorepo\labs\experiment\samples\experiment.Sample\documentation.md", markdown); - driver = driver.AddAdditionalTexts(ImmutableArray.Create(text)); - } + driver = driver.AddAdditionalTexts(ImmutableArray.Create(text)); + } - _ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray diagnostics); + _ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray diagnostics); - HashSet resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet(); + HashSet resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet(); - Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds), $"Expected one of [{string.Join(", ", diagnosticsIds)}] diagnostic Ids. Got [{string.Join(", ", resultingIds)}]"); + Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds), $"Expected one of [{string.Join(", ", diagnosticsIds)}] diagnostic Ids. Got [{string.Join(", ", resultingIds)}]"); - GC.KeepAlive(sampleAttributeType); - } + GC.KeepAlive(sampleAttributeType); + } - // From: https://github.com/dotnet/roslyn/blob/main/src/Compilers/Test/Core/SourceGeneration/TestGenerators.cs - internal class InMemoryAdditionalText : AdditionalText - { - private readonly SourceText _content; + // From: https://github.com/dotnet/roslyn/blob/main/src/Compilers/Test/Core/SourceGeneration/TestGenerators.cs + internal class InMemoryAdditionalText : AdditionalText + { + private readonly SourceText _content; - public InMemoryAdditionalText(string path, string content) - { - Path = path; - _content = SourceText.From(content, Encoding.UTF8); - } + public InMemoryAdditionalText(string path, string content) + { + Path = path; + _content = SourceText.From(content, Encoding.UTF8); + } - public override string Path { get; } + public override string Path { get; } - public override SourceText GetText(CancellationToken cancellationToken = default) => _content; - } + public override SourceText GetText(CancellationToken cancellationToken = default) => _content; } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs index 01bc3b0a9..dd8cbd3b6 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs @@ -4,206 +4,205 @@ using Microsoft.CodeAnalysis; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Diagnostics +namespace CommunityToolkit.Labs.Core.SourceGenerators.Diagnostics; + +/// +/// A container for all instances for errors reported by analyzers in this project. +/// +public static class DiagnosticDescriptors { /// - /// A container for all instances for errors reported by analyzers in this project. + /// Gets a indicating a derived used on a member that isn't a toolkit sample. + /// + /// Format: "Cannot generate sample pane options for type {0} as it does not use ToolkitSampleAttribute". + /// + /// + public static readonly DiagnosticDescriptor SamplePaneOptionAttributeOnNonSample = new( + id: "TKSMPL0001", + title: $"Invalid sample option delaration", + messageFormat: $"Cannot generate sample pane options for type {{0}} as it does not use {nameof(Attributes.ToolkitSampleAttribute)}", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample pane options for a type which does not use {nameof(Attributes.ToolkitSampleAttribute)}."); + + /// + /// Gets a indicating a derived with an empty or invalid name. + /// + /// Format: "Cannot generate sample pane options for type {0} as it contains an empty or invalid name.". + /// + /// + public static readonly DiagnosticDescriptor SamplePaneOptionWithBadName = new( + id: "TKSMPL0002", + title: $"Invalid sample option delaration", + messageFormat: $"Cannot generate sample pane options for type {{0}} as the provided name is empty or invalid", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample pane options when the provided name is empty or invalid."); + + /// + /// Gets a indicating a with a that doesn't have a corresponding . + /// + /// Format: "Cannot link sample options pane to type {0} as the provided sample ID does not match any known {nameof(Attributes.ToolkitSampleAttribute)}". + /// + /// + public static readonly DiagnosticDescriptor OptionsPaneAttributeWithMissingOrInvalidSampleId = new( + id: "TKSMPL0003", + title: $"Missing or invalid sample Id", + messageFormat: $"Cannot link sample options pane to type {{0}} as the provided sample ID does not match any known {nameof(Attributes.ToolkitSampleAttribute)}", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot link sample options pane to a provided sample ID that does not match any known {nameof(Attributes.ToolkitSampleAttribute)}."); + + /// + /// Gets a indicating a derived that contains a name which is already in use by another sample option. + /// + /// Format: "Cannot generate sample pane options with name {0} as the provided name is already in use by another sample option". + /// + /// + public static readonly DiagnosticDescriptor SamplePaneOptionWithDuplicateName = new( + id: "TKSMPL0004", + title: $"Duplicate sample option name", + messageFormat: $"Cannot generate sample pane option with name {{0}} as the provided name is already in use by another sample option", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample pane option when the provided name is used by another sample option."); + + /// + /// Gets a indicating a derived that contains a name which is already defined as a member in the attached class. + /// + /// Format: "Cannot generate sample pane options with name {0} the provided name is already defined as a member in the attached class". + /// + /// + public static readonly DiagnosticDescriptor SamplePaneOptionWithConflictingName = new( + id: "TKSMPL0005", + title: $"Conflicting sample option name", + messageFormat: $"Cannot generate sample pane option with name {{0}} as the provided name is already defined as a member in the attached class", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample pane option when the provided name is already defined as a member in the attached class."); + + /// + /// Gets a indicating a that has no defined options to present to the user. + /// + /// Format: "Cannot generate multiple choice sample pane option with title {{0}} as no choices were provided". + /// + /// + public static readonly DiagnosticDescriptor SamplePaneMultiChoiceOptionWithNoChoices = new( + id: "TKSMPL0006", + title: $"Missing choices in multi-choice sample option", + messageFormat: $"Cannot generate multiple choice sample pane option with title {{0}} as no choices were provided.", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate multiple choice sample pane option as there are no choices provided."); + + /// + /// Gets a indicating a that was used on an unsupported type. + /// + /// Format: "Cannot generate sample metadata as the attribute was used on an unsupported type.". + /// + /// + public static readonly DiagnosticDescriptor SampleAttributeOnUnsupportedType = new( + id: "TKSMPL0007", + title: $"ToolkitSampleAttribute declared on an invalid type", + messageFormat: $"Cannot generate sample metadata as the attribute was used on an unsupported type", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample metadata as the attribute was used on an unsupported type."); + + /// + /// Gets a indicating a that was used on an unsupported type. + /// + /// Format: "Cannot generate options pane metadata as the attribute was used on an unsupported type.". + /// + /// + public static readonly DiagnosticDescriptor SampleOptionPaneAttributeOnUnsupportedType = new( + id: "TKSMPL0008", + title: $"Toolkit sample options pane declared on an invalid type", + messageFormat: $"Cannot generate options pane metadata as the attribute was used on an unsupported type", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate options pane metadata as the attribute was used on an unsupported type."); + + /// + /// Gets a indicating a derived that was used on an unsupported type. + /// + /// Format: "Cannot generate sample option metadata as the attribute was used on an unsupported type.". + /// + /// + public static readonly DiagnosticDescriptor SampleGeneratedOptionAttributeOnUnsupportedType = new( + id: "TKSMPL0009", + title: $"Toolkit sample option declared on an invalid type", + messageFormat: $"Cannot generate sample option metadata as the attribute was used on an unsupported type", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample option metadata as the attribute was used on an unsupported type."); + + /// + /// Gets a indicating an exception occured while parsing the front matter of a markdown sample file. + /// + public static readonly DiagnosticDescriptor MarkdownYAMLFrontMatterException = new( + id: "TKSMPL0010", + title: $"Invalid YAML Front Matter", + messageFormat: $"Cannot generate sample page info for file {{0}} as an error was encountered parsing its YAML front matter: {{1}}", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample page info due to a YAML Front Matter parsing exception."); + + /// + /// Gets a indicating an expected piece of metadata was missing from the front matter of a markdown sample file. + /// + public static readonly DiagnosticDescriptor MarkdownYAMLFrontMatterMissingField = new( + id: "TKSMPL0011", + title: $"Missing YAML Front Matter", + messageFormat: $"Cannot generate sample page info for file {{0}} as no '{{1}}' field was found in its YAML front matter.", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot generate sample page info due to missing YAML Front Matter."); + + /// + /// Gets a indicating the sample referenced in the Markdown file couldn't be found. + /// + public static readonly DiagnosticDescriptor MarkdownSampleIdNotFound = new( + id: "TKSMPL0012", + title: $"Sample Id Not Found from Markdown Reference", + messageFormat: $"Cannot find the sample page referenced in file {{0}} with sample id '{{1}}'.", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: $"Cannot link sample page info due to invalid/unknown id."); + + /// + /// Gets a indicating the sample is not referenced in any Markdown documentation files. + /// + public static readonly DiagnosticDescriptor SampleNotReferencedInMarkdown = new( + id: "TKSMPL0013", + title: $"Sample Not Referenced In Documentation", + messageFormat: $"The sample with id '{{0}}' is not referenced in any documentation files and will not appear in the full sample app.", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: $"Cannot find reference to the sample within the documentation."); + + /// + /// Gets a indicating the documentation file contains no sample references. /// - public static class DiagnosticDescriptors - { - /// - /// Gets a indicating a derived used on a member that isn't a toolkit sample. - /// - /// Format: "Cannot generate sample pane options for type {0} as it does not use ToolkitSampleAttribute". - /// - /// - public static readonly DiagnosticDescriptor SamplePaneOptionAttributeOnNonSample = new( - id: "TKSMPL0001", - title: $"Invalid sample option delaration", - messageFormat: $"Cannot generate sample pane options for type {{0}} as it does not use {nameof(Attributes.ToolkitSampleAttribute)}", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample pane options for a type which does not use {nameof(Attributes.ToolkitSampleAttribute)}."); - - /// - /// Gets a indicating a derived with an empty or invalid name. - /// - /// Format: "Cannot generate sample pane options for type {0} as it contains an empty or invalid name.". - /// - /// - public static readonly DiagnosticDescriptor SamplePaneOptionWithBadName = new( - id: "TKSMPL0002", - title: $"Invalid sample option delaration", - messageFormat: $"Cannot generate sample pane options for type {{0}} as the provided name is empty or invalid", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample pane options when the provided name is empty or invalid."); - - /// - /// Gets a indicating a with a that doesn't have a corresponding . - /// - /// Format: "Cannot link sample options pane to type {0} as the provided sample ID does not match any known {nameof(Attributes.ToolkitSampleAttribute)}". - /// - /// - public static readonly DiagnosticDescriptor OptionsPaneAttributeWithMissingOrInvalidSampleId = new( - id: "TKSMPL0003", - title: $"Missing or invalid sample Id", - messageFormat: $"Cannot link sample options pane to type {{0}} as the provided sample ID does not match any known {nameof(Attributes.ToolkitSampleAttribute)}", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot link sample options pane to a provided sample ID that does not match any known {nameof(Attributes.ToolkitSampleAttribute)}."); - - /// - /// Gets a indicating a derived that contains a name which is already in use by another sample option. - /// - /// Format: "Cannot generate sample pane options with name {0} as the provided name is already in use by another sample option". - /// - /// - public static readonly DiagnosticDescriptor SamplePaneOptionWithDuplicateName = new( - id: "TKSMPL0004", - title: $"Duplicate sample option name", - messageFormat: $"Cannot generate sample pane option with name {{0}} as the provided name is already in use by another sample option", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample pane option when the provided name is used by another sample option."); - - /// - /// Gets a indicating a derived that contains a name which is already defined as a member in the attached class. - /// - /// Format: "Cannot generate sample pane options with name {0} the provided name is already defined as a member in the attached class". - /// - /// - public static readonly DiagnosticDescriptor SamplePaneOptionWithConflictingName = new( - id: "TKSMPL0005", - title: $"Conflicting sample option name", - messageFormat: $"Cannot generate sample pane option with name {{0}} as the provided name is already defined as a member in the attached class", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample pane option when the provided name is already defined as a member in the attached class."); - - /// - /// Gets a indicating a that has no defined options to present to the user. - /// - /// Format: "Cannot generate multiple choice sample pane option with title {{0}} as no choices were provided". - /// - /// - public static readonly DiagnosticDescriptor SamplePaneMultiChoiceOptionWithNoChoices = new( - id: "TKSMPL0006", - title: $"Missing choices in multi-choice sample option", - messageFormat: $"Cannot generate multiple choice sample pane option with title {{0}} as no choices were provided.", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate multiple choice sample pane option as there are no choices provided."); - - /// - /// Gets a indicating a that was used on an unsupported type. - /// - /// Format: "Cannot generate sample metadata as the attribute was used on an unsupported type.". - /// - /// - public static readonly DiagnosticDescriptor SampleAttributeOnUnsupportedType = new( - id: "TKSMPL0007", - title: $"ToolkitSampleAttribute declared on an invalid type", - messageFormat: $"Cannot generate sample metadata as the attribute was used on an unsupported type", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample metadata as the attribute was used on an unsupported type."); - - /// - /// Gets a indicating a that was used on an unsupported type. - /// - /// Format: "Cannot generate options pane metadata as the attribute was used on an unsupported type.". - /// - /// - public static readonly DiagnosticDescriptor SampleOptionPaneAttributeOnUnsupportedType = new( - id: "TKSMPL0008", - title: $"Toolkit sample options pane declared on an invalid type", - messageFormat: $"Cannot generate options pane metadata as the attribute was used on an unsupported type", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate options pane metadata as the attribute was used on an unsupported type."); - - /// - /// Gets a indicating a derived that was used on an unsupported type. - /// - /// Format: "Cannot generate sample option metadata as the attribute was used on an unsupported type.". - /// - /// - public static readonly DiagnosticDescriptor SampleGeneratedOptionAttributeOnUnsupportedType = new( - id: "TKSMPL0009", - title: $"Toolkit sample option declared on an invalid type", - messageFormat: $"Cannot generate sample option metadata as the attribute was used on an unsupported type", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample option metadata as the attribute was used on an unsupported type."); - - /// - /// Gets a indicating an exception occured while parsing the front matter of a markdown sample file. - /// - public static readonly DiagnosticDescriptor MarkdownYAMLFrontMatterException = new( - id: "TKSMPL0010", - title: $"Invalid YAML Front Matter", - messageFormat: $"Cannot generate sample page info for file {{0}} as an error was encountered parsing its YAML front matter: {{1}}", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample page info due to a YAML Front Matter parsing exception."); - - /// - /// Gets a indicating an expected piece of metadata was missing from the front matter of a markdown sample file. - /// - public static readonly DiagnosticDescriptor MarkdownYAMLFrontMatterMissingField = new( - id: "TKSMPL0011", - title: $"Missing YAML Front Matter", - messageFormat: $"Cannot generate sample page info for file {{0}} as no '{{1}}' field was found in its YAML front matter.", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot generate sample page info due to missing YAML Front Matter."); - - /// - /// Gets a indicating the sample referenced in the Markdown file couldn't be found. - /// - public static readonly DiagnosticDescriptor MarkdownSampleIdNotFound = new( - id: "TKSMPL0012", - title: $"Sample Id Not Found from Markdown Reference", - messageFormat: $"Cannot find the sample page referenced in file {{0}} with sample id '{{1}}'.", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Error, - isEnabledByDefault: true, - description: $"Cannot link sample page info due to invalid/unknown id."); - - /// - /// Gets a indicating the sample is not referenced in any Markdown documentation files. - /// - public static readonly DiagnosticDescriptor SampleNotReferencedInMarkdown = new( - id: "TKSMPL0013", - title: $"Sample Not Referenced In Documentation", - messageFormat: $"The sample with id '{{0}}' is not referenced in any documentation files and will not appear in the full sample app.", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: $"Cannot find reference to the sample within the documentation."); - - /// - /// Gets a indicating the documentation file contains no sample references. - /// - public static readonly DiagnosticDescriptor DocumentationHasNoSamples = new( - id: "TKSMPL0014", - title: $"Documentation Has No Samples", - messageFormat: $"The documentation page '{{0}}' does not reference any sample examples, it is recommended to have at least one code sample per document page.", - category: typeof(ToolkitSampleMetadataGenerator).FullName, - defaultSeverity: DiagnosticSeverity.Warning, - isEnabledByDefault: true, - description: $"Document contains no interactive sample code."); - } + public static readonly DiagnosticDescriptor DocumentationHasNoSamples = new( + id: "TKSMPL0014", + title: $"Documentation Has No Samples", + messageFormat: $"The documentation page '{{0}}' does not reference any sample examples, it is recommended to have at least one code sample per document page.", + category: typeof(ToolkitSampleMetadataGenerator).FullName, + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: $"Document contains no interactive sample code."); } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/GeneratorExtensions.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/GeneratorExtensions.cs index ba647e0f4..8478872db 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/GeneratorExtensions.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/GeneratorExtensions.cs @@ -10,142 +10,141 @@ using System.Linq; using System.Text; -namespace CommunityToolkit.Labs.Core.SourceGenerators +namespace CommunityToolkit.Labs.Core.SourceGenerators; + +public static class GeneratorExtensions { - public static class GeneratorExtensions + /// + /// Crawls a namespace and all child namespaces for all contained types. + /// + /// A flattened enumerable of s. + public static IEnumerable CrawlForAllNamedTypes(this INamespaceSymbol namespaceSymbol) { - /// - /// Crawls a namespace and all child namespaces for all contained types. - /// - /// A flattened enumerable of s. - public static IEnumerable CrawlForAllNamedTypes(this INamespaceSymbol namespaceSymbol) + foreach (var member in namespaceSymbol.GetMembers()) { - foreach (var member in namespaceSymbol.GetMembers()) + if (member is INamespaceSymbol nestedNamespace) { - if (member is INamespaceSymbol nestedNamespace) - { - foreach (var item in CrawlForAllNamedTypes(nestedNamespace)) - yield return item; - } - - if (member is INamedTypeSymbol typeSymbol) - yield return typeSymbol; + foreach (var item in CrawlForAllNamedTypes(nestedNamespace)) + yield return item; } - } - /// - /// Crawls an object tree for nested properties of the same type and returns the first instance that matches the . - /// - /// - /// Does not filter against or return the object. - /// - public static T? CrawlBy(this T? root, Func selectPredicate, Func filterPredicate) - { - crawl: - var current = selectPredicate(root); - - if (filterPredicate(current)) - { - return current; - } + if (member is INamedTypeSymbol typeSymbol) + yield return typeSymbol; + } + } - if (current is null) - { - return default; - } + /// + /// Crawls an object tree for nested properties of the same type and returns the first instance that matches the . + /// + /// + /// Does not filter against or return the object. + /// + public static T? CrawlBy(this T? root, Func selectPredicate, Func filterPredicate) + { + crawl: + var current = selectPredicate(root); - root = current; - goto crawl; + if (filterPredicate(current)) + { + return current; } - /// - /// Reconstructs an attribute instance as the given type. - /// - /// The attribute type to create. - /// The attribute data used to construct the instance of - public static T ReconstructAs(this AttributeData attributeData) + if (current is null) { - // Reconstructing the attribute instance provides some safety against changes to the attribute's constructor signature. - var attributeArgs = attributeData.ConstructorArguments.Select(PrepareParameterTypeForActivator).ToArray(); - return (T)Activator.CreateInstance(typeof(T), attributeArgs); + return default; } + root = current; + goto crawl; + } - /// - /// Attempts to reconstruct an attribute instance as the given type, returning null if and are mismatched. - /// - /// The attribute type to create. - /// The attribute data used to construct the instance of - public static T? TryReconstructAs(this AttributeData attributeData) - where T : Attribute - { - var attributeMatchesType = attributeData.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == $"global::{typeof(T).FullName}"; + /// + /// Reconstructs an attribute instance as the given type. + /// + /// The attribute type to create. + /// The attribute data used to construct the instance of + public static T ReconstructAs(this AttributeData attributeData) + { + // Reconstructing the attribute instance provides some safety against changes to the attribute's constructor signature. + var attributeArgs = attributeData.ConstructorArguments.Select(PrepareParameterTypeForActivator).ToArray(); + return (T)Activator.CreateInstance(typeof(T), attributeArgs); + } - if (attributeMatchesType) - return attributeData.ReconstructAs(); - return null; - } + /// + /// Attempts to reconstruct an attribute instance as the given type, returning null if and are mismatched. + /// + /// The attribute type to create. + /// The attribute data used to construct the instance of + public static T? TryReconstructAs(this AttributeData attributeData) + where T : Attribute + { + var attributeMatchesType = attributeData.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == $"global::{typeof(T).FullName}"; - /// - /// Checks whether or not a given type symbol has a specified full name. - /// - /// The input instance to check. - /// The full name to check. - /// Whether has a full name equals to . - public static bool HasFullyQualifiedName(this ISymbol symbol, string name) - { - return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == name; - } + if (attributeMatchesType) + return attributeData.ReconstructAs(); - /// - /// Performs any data transforms needed for using as a parameter in . - /// - /// The 's was null. - public static object? PrepareParameterTypeForActivator(this TypedConstant parameterTypedConstant) - { - if (parameterTypedConstant.Type is null) - throw new ArgumentNullException(nameof(parameterTypedConstant.Type)); + return null; + } - // Types prefixed with global:: do not work with Type.GetType and must be stripped away. - var assemblyQualifiedName = parameterTypedConstant.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) - .Replace("global::", "") - .Replace("string", "System.String"); + /// + /// Checks whether or not a given type symbol has a specified full name. + /// + /// The input instance to check. + /// The full name to check. + /// Whether has a full name equals to . + public static bool HasFullyQualifiedName(this ISymbol symbol, string name) + { + return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == name; + } - var argType = Type.GetType(assemblyQualifiedName); + /// + /// Performs any data transforms needed for using as a parameter in . + /// + /// The 's was null. + public static object? PrepareParameterTypeForActivator(this TypedConstant parameterTypedConstant) + { + if (parameterTypedConstant.Type is null) + throw new ArgumentNullException(nameof(parameterTypedConstant.Type)); - // Enums arrive as the underlying integer type, which doesn't work as a param for Activator.CreateInstance() - if (argType != null && parameterTypedConstant.Kind == TypedConstantKind.Enum) - return Enum.Parse(argType, parameterTypedConstant.Value?.ToString()); + // Types prefixed with global:: do not work with Type.GetType and must be stripped away. + var assemblyQualifiedName = parameterTypedConstant.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + .Replace("global::", "") + .Replace("string", "System.String"); - if (parameterTypedConstant.Kind == TypedConstantKind.Array) - { - // Cannot use actual value to get item type b/c array can be empty. - var paramAssemblyQualifiedName = parameterTypedConstant.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) - .Replace("[]", "") - .Replace("global::", "") - .Replace("string", "System.String"); + var argType = Type.GetType(assemblyQualifiedName); - var paramArgType = paramAssemblyQualifiedName is null ? null : Type.GetType(paramAssemblyQualifiedName); + // Enums arrive as the underlying integer type, which doesn't work as a param for Activator.CreateInstance() + if (argType != null && parameterTypedConstant.Kind == TypedConstantKind.Enum) + return Enum.Parse(argType, parameterTypedConstant.Value?.ToString()); - // Prepare each value in the array. - var arr = parameterTypedConstant.Values.Select(PrepareParameterTypeForActivator).ToArray(); + if (parameterTypedConstant.Kind == TypedConstantKind.Array) + { + // Cannot use actual value to get item type b/c array can be empty. + var paramAssemblyQualifiedName = parameterTypedConstant.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + .Replace("[]", "") + .Replace("global::", "") + .Replace("string", "System.String"); - // This code path will always return object?[] - if (paramArgType is null) - return arr; + var paramArgType = paramAssemblyQualifiedName is null ? null : Type.GetType(paramAssemblyQualifiedName); - // Prepare the array as the correct type. - var result = Array.CreateInstance(paramArgType, arr.Length); - arr.CopyTo(result, 0); + // Prepare each value in the array. + var arr = parameterTypedConstant.Values.Select(PrepareParameterTypeForActivator).ToArray(); - return result; - } + // This code path will always return object?[] + if (paramArgType is null) + return arr; - if (argType is not null) - return Convert.ChangeType(parameterTypedConstant.Value, argType); + // Prepare the array as the correct type. + var result = Array.CreateInstance(paramArgType, arr.Length); + arr.CopyTo(result, 0); - return parameterTypedConstant.Value; + return result; } + + if (argType is not null) + return Convert.ChangeType(parameterTypedConstant.Value, argType); + + return parameterTypedConstant.Value; } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IGeneratedToolkitSampleOptionViewModel.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IGeneratedToolkitSampleOptionViewModel.cs index 9212f958a..1cbb7cb92 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IGeneratedToolkitSampleOptionViewModel.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IGeneratedToolkitSampleOptionViewModel.cs @@ -4,33 +4,32 @@ using System.ComponentModel; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata +namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata; + +/// +/// A common interface for all generated toolkit sample options. +/// Implementations of this interface are updated from the sample pane UI, and referenced by the generated property. +/// +/// +/// Must implement to notify when the user changes a value in the sample pane UI. +/// +/// However, the must be emitted as the changed property name when updates, so the +/// propogated IPNC event can notify the sample control of the change. +/// +public interface IGeneratedToolkitSampleOptionViewModel : INotifyPropertyChanged { /// - /// A common interface for all generated toolkit sample options. - /// Implementations of this interface are updated from the sample pane UI, and referenced by the generated property. + /// The current value. Can be updated by the user via the sample pane UI. + /// + /// A generated property's getter and setter directly references this value, making it available to bind to. + /// + public object? Value { get; set; } + + /// + /// A unique identifier name for this option. /// /// - /// Must implement to notify when the user changes a value in the sample pane UI. - /// - /// However, the must be emitted as the changed property name when updates, so the - /// propogated IPNC event can notify the sample control of the change. + /// Used by the sample system to match up to the original and the control that declared it. /// - public interface IGeneratedToolkitSampleOptionViewModel : INotifyPropertyChanged - { - /// - /// The current value. Can be updated by the user via the sample pane UI. - /// - /// A generated property's getter and setter directly references this value, making it available to bind to. - /// - public object? Value { get; set; } - - /// - /// A unique identifier name for this option. - /// - /// - /// Used by the sample system to match up to the original and the control that declared it. - /// - public string Name { get; } - } + public string Name { get; } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IToolkitSampleGeneratedOptionPropertyContainer.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IToolkitSampleGeneratedOptionPropertyContainer.cs index ac7c651ff..db030d756 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IToolkitSampleGeneratedOptionPropertyContainer.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/IToolkitSampleGeneratedOptionPropertyContainer.cs @@ -4,20 +4,19 @@ using System.Collections.Generic; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata +namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata; + +/// +/// Implementors of this class contain one or more source-generated properties +/// which are bound to in the XAML of a toolkit sample +/// and manipulated from a data-generated options pane. +/// +public interface IToolkitSampleGeneratedOptionPropertyContainer { /// - /// Implementors of this class contain one or more source-generated properties - /// which are bound to in the XAML of a toolkit sample - /// and manipulated from a data-generated options pane. + /// Holds a reference to all generated ViewModels that act + /// as a proxy between the current actual value and the + /// generated properties which consume them. /// - public interface IToolkitSampleGeneratedOptionPropertyContainer - { - /// - /// Holds a reference to all generated ViewModels that act - /// as a proxy between the current actual value and the - /// generated properties which consume them. - /// - public IEnumerable? GeneratedPropertyMetadata { get; set; } - } + public IEnumerable? GeneratedPropertyMetadata { get; set; } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleBoolOptionMetadataViewModel.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleBoolOptionMetadataViewModel.cs index a2117fe6d..e9ae0de13 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleBoolOptionMetadataViewModel.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleBoolOptionMetadataViewModel.cs @@ -5,94 +5,93 @@ using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; using System.ComponentModel; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata +namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata; + +/// +/// An INPC-enabled metadata container for data defined in an . +/// +/// +/// Instances of these are generated by the and +/// provided to the app alongside the sample registration. +/// +public class ToolkitSampleBoolOptionMetadataViewModel : IGeneratedToolkitSampleOptionViewModel { + private string _label; + private string? _title; + private object _value; + /// - /// An INPC-enabled metadata container for data defined in an . + /// Creates a new instance of . /// - /// - /// Instances of these are generated by the and - /// provided to the app alongside the sample registration. - /// - public class ToolkitSampleBoolOptionMetadataViewModel : IGeneratedToolkitSampleOptionViewModel + public ToolkitSampleBoolOptionMetadataViewModel(string id, string label, bool defaultState, string? title = null) { - private string _label; - private string? _title; - private object _value; - - /// - /// Creates a new instance of . - /// - public ToolkitSampleBoolOptionMetadataViewModel(string id, string label, bool defaultState, string? title = null) - { - Name = id; - _title = title; - _label = label; - _value = defaultState; - } + Name = id; + _title = title; + _label = label; + _value = defaultState; + } - /// - public event PropertyChangedEventHandler? PropertyChanged; + /// + public event PropertyChangedEventHandler? PropertyChanged; - /// - /// A unique identifier for this option. - /// - /// - /// Used by the sample system to match up to the original and the control that declared it. - /// - public string Name { get; } + /// + /// A unique identifier for this option. + /// + /// + /// Used by the sample system to match up to the original and the control that declared it. + /// + public string Name { get; } - /// - /// The current boolean value. - /// - /// - /// Provided to accomodate binding to a property that is a non-nullable . - /// - public bool BoolValue + /// + /// The current boolean value. + /// + /// + /// Provided to accomodate binding to a property that is a non-nullable . + /// + public bool BoolValue + { + get => (bool)_value; + set { - get => (bool)_value; - set - { - _value = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); - } + _value = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); } + } - /// - public object? Value + /// + public object? Value + { + get => BoolValue; + set { - get => BoolValue; - set - { - BoolValue = (bool)(value ?? false); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); - } + BoolValue = (bool)(value ?? false); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); } + } - /// - /// A label to display along the boolean option. - /// - public string Label + /// + /// A label to display along the boolean option. + /// + public string Label + { + get => _label; + set { - get => _label; - set - { - _label = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Label))); - } + _label = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Label))); } + } - /// - /// A title to display on top of the boolean option. - /// - public string? Title + /// + /// A title to display on top of the boolean option. + /// + public string? Title + { + get => _title; + set { - get => _title; - set - { - _title = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title))); - } + _title = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title))); } } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleMultiChoiceOptionMetadataViewModel.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleMultiChoiceOptionMetadataViewModel.cs index fc9f4d1e1..1272a2057 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleMultiChoiceOptionMetadataViewModel.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/Metadata/ToolkitSampleMultiChoiceOptionMetadataViewModel.cs @@ -5,73 +5,72 @@ using CommunityToolkit.Labs.Core.SourceGenerators.Attributes; using System.ComponentModel; -namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata +namespace CommunityToolkit.Labs.Core.SourceGenerators.Metadata; + +/// +/// An INPC-enabled metadata container for data defined in an . +/// +public class ToolkitSampleMultiChoiceOptionMetadataViewModel : IGeneratedToolkitSampleOptionViewModel { + private string? _title; + private object? _value; + /// - /// An INPC-enabled metadata container for data defined in an . + /// Creates a new instance of . /// - public class ToolkitSampleMultiChoiceOptionMetadataViewModel : IGeneratedToolkitSampleOptionViewModel + public ToolkitSampleMultiChoiceOptionMetadataViewModel(string name, MultiChoiceOption[] options, string? title = null) { - private string? _title; - private object? _value; - - /// - /// Creates a new instance of . - /// - public ToolkitSampleMultiChoiceOptionMetadataViewModel(string name, MultiChoiceOption[] options, string? title = null) - { - Name = name; - Options = options; - _title = title; - _value = options[0].Value; - } + Name = name; + Options = options; + _title = title; + _value = options[0].Value; + } - /// - public event PropertyChangedEventHandler? PropertyChanged; + /// + public event PropertyChangedEventHandler? PropertyChanged; - /// - /// A unique identifier for this option. - /// - /// - /// Used by the sample system to match up to the original and the control that declared it. - /// - public string Name { get; } + /// + /// A unique identifier for this option. + /// + /// + /// Used by the sample system to match up to the original and the control that declared it. + /// + public string Name { get; } - /// - /// The available options presented to the user. - /// - public MultiChoiceOption[] Options { get; } + /// + /// The available options presented to the user. + /// + public MultiChoiceOption[] Options { get; } - /// - /// The current boolean value. - /// - public object? Value + /// + /// The current boolean value. + /// + public object? Value + { + get => _value; + set { - get => _value; - set - { - // XAML converting a null value isn't supported for all types. - if (value is null) - return; + // XAML converting a null value isn't supported for all types. + if (value is null) + return; - if (value is MultiChoiceOption op) - _value = op.Value; + if (value is MultiChoiceOption op) + _value = op.Value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); } + } - /// - /// A label to display along the boolean option. - /// - public string? Title + /// + /// A label to display along the boolean option. + /// + public string? Title + { + get => _title; + set { - get => _title; - set - { - _title = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title))); - } + _title = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title))); } } } diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators/ToolkitSampleOptionGenerator.cs b/common/CommunityToolkit.Labs.Core.SourceGenerators/ToolkitSampleOptionGenerator.cs index 9efdcabe3..8c755ede0 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators/ToolkitSampleOptionGenerator.cs +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators/ToolkitSampleOptionGenerator.cs @@ -10,73 +10,73 @@ using System.Collections.Generic; using System.Linq; -namespace CommunityToolkit.Labs.Core.SourceGenerators +namespace CommunityToolkit.Labs.Core.SourceGenerators; + +/// +/// For the generated sample pane options, this generator creates the backing properties needed for binding in the UI, +/// as well as implementing the for relaying data between the options pane and the generated property. +/// +[Generator] +public class ToolkitSampleOptionGenerator : IIncrementalGenerator { - /// - /// For the generated sample pane options, this generator creates the backing properties needed for binding in the UI, - /// as well as implementing the for relaying data between the options pane and the generated property. - /// - [Generator] - public class ToolkitSampleOptionGenerator : IIncrementalGenerator - { - private readonly HashSet _handledPropertyNames = new(); - private readonly HashSet _handledAttributes = new(); - private readonly HashSet _handledContainingClasses = new(SymbolEqualityComparer.Default); + private readonly HashSet _handledPropertyNames = new(); + private readonly HashSet _handledAttributes = new(); + private readonly HashSet _handledContainingClasses = new(SymbolEqualityComparer.Default); - public void Initialize(IncrementalGeneratorInitializationContext context) - { - var classes = context.SyntaxProvider - .CreateSyntaxProvider( - static (s, _) => s is ClassDeclarationSyntax c && c.AttributeLists.Count > 0, - static (ctx, _) => ctx.SemanticModel.GetDeclaredSymbol(ctx.Node)) - .Where(static m => m is not null) - .Select(static (x, _) => x!); - - // Get all attributes + the original type symbol. - var allAttributeData = classes.SelectMany((sym, _) => sym.GetAttributes().Select(x => (sym, x))); - - // Find and reconstruct attributes. - var sampleAttributeOptions = allAttributeData - .Select((x, _) => - { - if (x.Item2.TryReconstructAs() is ToolkitSampleBoolOptionAttribute boolOptionAttribute) - return (Attribute: (ToolkitSampleOptionBaseAttribute)boolOptionAttribute, ContainingClassSymbol: x.Item1, Type: typeof(ToolkitSampleBoolOptionMetadataViewModel)); + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var classes = context.SyntaxProvider + .CreateSyntaxProvider( + static (s, _) => s is ClassDeclarationSyntax c && c.AttributeLists.Count > 0, + static (ctx, _) => ctx.SemanticModel.GetDeclaredSymbol(ctx.Node)) + .Where(static m => m is not null) + .Select(static (x, _) => x!); + + // Get all attributes + the original type symbol. + var allAttributeData = classes.SelectMany((sym, _) => sym.GetAttributes().Select(x => (sym, x))); + + // Find and reconstruct attributes. + var sampleAttributeOptions = allAttributeData + .Select((x, _) => + { + if (x.Item2.TryReconstructAs() is ToolkitSampleBoolOptionAttribute boolOptionAttribute) + return (Attribute: (ToolkitSampleOptionBaseAttribute)boolOptionAttribute, ContainingClassSymbol: x.Item1, Type: typeof(ToolkitSampleBoolOptionMetadataViewModel)); - if (x.Item2.TryReconstructAs() is ToolkitSampleMultiChoiceOptionAttribute multiChoiceOptionAttribute) - return (Attribute: (ToolkitSampleOptionBaseAttribute)multiChoiceOptionAttribute, ContainingClassSymbol: x.Item1, Type: typeof(ToolkitSampleMultiChoiceOptionMetadataViewModel)); + if (x.Item2.TryReconstructAs() is ToolkitSampleMultiChoiceOptionAttribute multiChoiceOptionAttribute) + return (Attribute: (ToolkitSampleOptionBaseAttribute)multiChoiceOptionAttribute, ContainingClassSymbol: x.Item1, Type: typeof(ToolkitSampleMultiChoiceOptionMetadataViewModel)); - return default; - }) - .Where(x => x != default); + return default; + }) + .Where(x => x != default); - context.RegisterSourceOutput(sampleAttributeOptions, (ctx, data) => + context.RegisterSourceOutput(sampleAttributeOptions, (ctx, data) => + { + if (_handledContainingClasses.Add(data.ContainingClassSymbol)) { - if (_handledContainingClasses.Add(data.ContainingClassSymbol)) + if (data.ContainingClassSymbol is ITypeSymbol typeSym && !typeSym.AllInterfaces.Any(x => x.HasFullyQualifiedName("global::System.ComponentModel.INotifyPropertyChanged"))) { - if (data.ContainingClassSymbol is ITypeSymbol typeSym && !typeSym.AllInterfaces.Any(x => x.HasFullyQualifiedName("global::System.ComponentModel.INotifyPropertyChanged"))) - { - var inpcImpl = BuildINotifyPropertyChangedImplementation(data.ContainingClassSymbol); - ctx.AddSource($"{data.ContainingClassSymbol}.NotifyPropertyChanged.g", inpcImpl); - } - - var propertyContainerSource = BuildGeneratedPropertyMetadataContainer(data.ContainingClassSymbol); - ctx.AddSource($"{data.ContainingClassSymbol}.GeneratedPropertyContainer.g", propertyContainerSource); + var inpcImpl = BuildINotifyPropertyChangedImplementation(data.ContainingClassSymbol); + ctx.AddSource($"{data.ContainingClassSymbol}.NotifyPropertyChanged.g", inpcImpl); } - if (!_handledAttributes.Add(data.Attribute)) - return; + var propertyContainerSource = BuildGeneratedPropertyMetadataContainer(data.ContainingClassSymbol); + ctx.AddSource($"{data.ContainingClassSymbol}.GeneratedPropertyContainer.g", propertyContainerSource); + } - var dependencyPropertySource = BuildProperty(data.ContainingClassSymbol, data.Attribute.Name, data.Attribute.TypeName, data.Type); + if (!_handledAttributes.Add(data.Attribute)) + return; - if (_handledPropertyNames.Add(data.Attribute.Name)) - ctx.AddSource($"{data.ContainingClassSymbol}.Property.{data.Attribute.Name}.g", dependencyPropertySource); - }); + var dependencyPropertySource = BuildProperty(data.ContainingClassSymbol, data.Attribute.Name, data.Attribute.TypeName, data.Type); - } + if (_handledPropertyNames.Add(data.Attribute.Name)) + ctx.AddSource($"{data.ContainingClassSymbol}.Property.{data.Attribute.Name}.g", dependencyPropertySource); + }); - private static string BuildINotifyPropertyChangedImplementation(ISymbol containingClassSymbol) - { - return $@"#nullable enable + } + + private static string BuildINotifyPropertyChangedImplementation(ISymbol containingClassSymbol) + { + return $@"#nullable enable using System.ComponentModel; namespace {containingClassSymbol.ContainingNamespace} @@ -87,11 +87,11 @@ public partial class {containingClassSymbol.Name} : {nameof(System.ComponentMode }} }} "; - } + } - private static string BuildGeneratedPropertyMetadataContainer(ISymbol containingClassSymbol) - { - return $@"#nullable enable + private static string BuildGeneratedPropertyMetadataContainer(ISymbol containingClassSymbol) + { + return $@"#nullable enable using System.ComponentModel; using System.Collections.Generic; @@ -127,11 +127,11 @@ public partial class {containingClassSymbol.Name} : {typeof(IToolkitSampleGenera }} }} "; - } + } - private static string BuildProperty(ISymbol containingClassSymbol, string propertyName, string typeName, Type viewModelType) - { - return $@"#nullable enable + private static string BuildProperty(ISymbol containingClassSymbol, string propertyName, string typeName, Type viewModelType) + { + return $@"#nullable enable using System.ComponentModel; using System.Linq; @@ -154,6 +154,5 @@ public partial class {containingClassSymbol.Name} }} }} "; - } } } diff --git a/common/CommunityToolkit.Labs.Shared/App.xaml.cs b/common/CommunityToolkit.Labs.Shared/App.xaml.cs index 1e80ce84c..a5dd983ee 100644 --- a/common/CommunityToolkit.Labs.Shared/App.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/App.xaml.cs @@ -25,68 +25,67 @@ using Microsoft.UI.Xaml.Navigation; #endif -namespace CommunityToolkit.Labs.Shared +namespace CommunityToolkit.Labs.Shared; + +/// +/// Provides application-specific behavior to supplement the default Application class. +/// +public sealed partial class App : Application { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - public sealed partial class App : Application - { - // MacOS and iOS don't know the correct type without a full namespace declaration, confusing it with NSWindow and UIWindow. - // Using static will not work. + // MacOS and iOS don't know the correct type without a full namespace declaration, confusing it with NSWindow and UIWindow. + // Using static will not work. #if WINAPPSDK - private static Microsoft.UI.Xaml.Window currentWindow = Microsoft.UI.Xaml.Window.Current; + private static Microsoft.UI.Xaml.Window currentWindow = Microsoft.UI.Xaml.Window.Current; #else - private static Windows.UI.Xaml.Window currentWindow = Windows.UI.Xaml.Window.Current; + private static Windows.UI.Xaml.Window currentWindow = Windows.UI.Xaml.Window.Current; #endif - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// - public App() - { - this.InitializeComponent(); - } + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + } - /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. - /// - /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs e) - { + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { #if WINAPPSDK - currentWindow = new Window(); + currentWindow = new Window(); #endif - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (currentWindow.Content is not Frame rootFrame) - { - // Create a Frame to act as the navigation context and navigate to the first page - currentWindow.Content = rootFrame = new Frame(); + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (currentWindow.Content is not Frame rootFrame) + { + // Create a Frame to act as the navigation context and navigate to the first page + currentWindow.Content = rootFrame = new Frame(); - rootFrame.NavigationFailed += OnNavigationFailed; - } + rootFrame.NavigationFailed += OnNavigationFailed; + } #if !WINAPPSDK - if (e.PrelaunchActivated == false) + if (e.PrelaunchActivated == false) #endif - rootFrame.Navigate(typeof(AppLoadingView), e.Arguments); + rootFrame.Navigate(typeof(AppLoadingView), e.Arguments); - // Ensure the current window is active - currentWindow.Activate(); - } + // Ensure the current window is active + currentWindow.Activate(); + } - /// - /// Invoked when Navigation to a certain page fails - /// - /// The Frame which failed navigation - /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); } } diff --git a/common/CommunityToolkit.Labs.Shared/AppLoadingView.xaml.cs b/common/CommunityToolkit.Labs.Shared/AppLoadingView.xaml.cs index fd9bd077e..f7d963065 100644 --- a/common/CommunityToolkit.Labs.Shared/AppLoadingView.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/AppLoadingView.xaml.cs @@ -24,98 +24,97 @@ using Microsoft.UI.Xaml.Navigation; #endif -namespace CommunityToolkit.Labs.Shared +namespace CommunityToolkit.Labs.Shared; + +/// +/// Kicks off the loading process and determines whether to display a single-sample or multi-sample view. +/// +public sealed partial class AppLoadingView : Page { /// - /// Kicks off the loading process and determines whether to display a single-sample or multi-sample view. + /// Creates a new instance of . /// - public sealed partial class AppLoadingView : Page + public AppLoadingView() { - /// - /// Creates a new instance of . - /// - public AppLoadingView() - { - this.InitializeComponent(); - } + this.InitializeComponent(); + } - /// - /// Backing dependency property for . - /// - public static readonly DependencyProperty IsLoadingProperty = - DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(AppLoadingView), new PropertyMetadata(false)); - - /// - /// Backing dependency property for . - /// - public static readonly DependencyProperty LoadingMessageProperty = - DependencyProperty.Register(nameof(LoadingMessage), typeof(string), typeof(AppLoadingView), new PropertyMetadata(string.Empty)); - - /// - /// Gets or sets a value indicating whether loading operations are being performed. - /// - public bool IsLoading - { - get { return (bool)GetValue(IsLoadingProperty); } - set { SetValue(IsLoadingProperty, value); } - } + /// + /// Backing dependency property for . + /// + public static readonly DependencyProperty IsLoadingProperty = + DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(AppLoadingView), new PropertyMetadata(false)); - /// - /// Gets or sets the displayed loading message. - /// - public string LoadingMessage - { - get { return (string)GetValue(LoadingMessageProperty); } - set { SetValue(LoadingMessageProperty, value); } - } + /// + /// Backing dependency property for . + /// + public static readonly DependencyProperty LoadingMessageProperty = + DependencyProperty.Register(nameof(LoadingMessage), typeof(string), typeof(AppLoadingView), new PropertyMetadata(string.Empty)); - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(e); + /// + /// Gets or sets a value indicating whether loading operations are being performed. + /// + public bool IsLoading + { + get { return (bool)GetValue(IsLoadingProperty); } + set { SetValue(IsLoadingProperty, value); } + } + + /// + /// Gets or sets the displayed loading message. + /// + public string LoadingMessage + { + get { return (string)GetValue(LoadingMessageProperty); } + set { SetValue(LoadingMessageProperty, value); } + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); - IsLoading = true; - LoadingMessage = "Loading..."; + IsLoading = true; + LoadingMessage = "Loading..."; - var sampleDocs = FindReferencedDocumentPages().ToArray(); + var sampleDocs = FindReferencedDocumentPages().ToArray(); - if (sampleDocs.Length == 0) - { - IsLoading = false; - LoadingMessage = "No sample pages were found :("; - return; - } + if (sampleDocs.Length == 0) + { + IsLoading = false; + LoadingMessage = "No sample pages were found :("; + return; + } #if LABS_ALL_SAMPLES - ScheduleNavigate(typeof(NavigationPage), sampleDocs); + ScheduleNavigate(typeof(NavigationPage), sampleDocs); #else - var samples = FindReferencedSamples().ToArray(); + var samples = FindReferencedSamples().ToArray(); - (IEnumerable Samples, IEnumerable Docs, bool AreDocsFirst) displayInfo = (samples, sampleDocs, false); - ScheduleNavigate(typeof(TabbedPage), displayInfo); + (IEnumerable Samples, IEnumerable Docs, bool AreDocsFirst) displayInfo = (samples, sampleDocs, false); + ScheduleNavigate(typeof(TabbedPage), displayInfo); #endif - } + } - // Needed because Frame.Navigate doesn't work inside of the OnNavigatedTo override. - private void ScheduleNavigate(Type type, object? param = null) + // Needed because Frame.Navigate doesn't work inside of the OnNavigatedTo override. + private void ScheduleNavigate(Type type, object? param = null) + { + DispatcherQueue.GetForCurrentThread().TryEnqueue(() => { - DispatcherQueue.GetForCurrentThread().TryEnqueue(() => - { #if !NETFX_CORE - Frame.Navigate(type, param); + Frame.Navigate(type, param); #else - Frame.NavigateToType(type, param, new FrameNavigationOptions { IsNavigationStackEnabled = false }); + Frame.NavigateToType(type, param, new FrameNavigationOptions { IsNavigationStackEnabled = false }); #endif - }); - } + }); + } - private IEnumerable FindReferencedDocumentPages() - { - return ToolkitDocumentRegistry.Execute(); - } + private IEnumerable FindReferencedDocumentPages() + { + return ToolkitDocumentRegistry.Execute(); + } - private IEnumerable FindReferencedSamples() - { - return ToolkitSampleRegistry.Listing.Values; - } + private IEnumerable FindReferencedSamples() + { + return ToolkitSampleRegistry.Listing.Values; } } diff --git a/common/CommunityToolkit.Labs.Shared/DocOrSampleTemplateSelector.cs b/common/CommunityToolkit.Labs.Shared/DocOrSampleTemplateSelector.cs index aa4f4ff84..e281b1e3d 100644 --- a/common/CommunityToolkit.Labs.Shared/DocOrSampleTemplateSelector.cs +++ b/common/CommunityToolkit.Labs.Shared/DocOrSampleTemplateSelector.cs @@ -12,20 +12,19 @@ using Microsoft.UI.Xaml.Controls; #endif -namespace CommunityToolkit.Labs.Shared +namespace CommunityToolkit.Labs.Shared; + +public class DocOrSampleTemplateSelector : DataTemplateSelector { - public class DocOrSampleTemplateSelector : DataTemplateSelector - { - public DataTemplate? Document { get; set; } - public DataTemplate? Sample { get; set; } + public DataTemplate? Document { get; set; } + public DataTemplate? Sample { get; set; } - protected override DataTemplate SelectTemplateCore(object item) => item switch - { - ToolkitFrontMatter _ => Document!, // Used for concrete type in TabbedPage - ToolkitSampleMetadata _ => Sample!, - _ => Document! // Used for string type in ToolkitDocumentationRenderer - }; + protected override DataTemplate SelectTemplateCore(object item) => item switch + { + ToolkitFrontMatter _ => Document!, // Used for concrete type in TabbedPage + ToolkitSampleMetadata _ => Sample!, + _ => Document! // Used for string type in ToolkitDocumentationRenderer + }; - protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) => SelectTemplateCore(item); - } + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) => SelectTemplateCore(item); } diff --git a/common/CommunityToolkit.Labs.Shared/NavigationPage.xaml.cs b/common/CommunityToolkit.Labs.Shared/NavigationPage.xaml.cs index 0e13286b3..dc442cb04 100644 --- a/common/CommunityToolkit.Labs.Shared/NavigationPage.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/NavigationPage.xaml.cs @@ -32,119 +32,118 @@ using CommunityToolkit.Labs.Shared.Renderers; using CommunityToolkit.Labs.Core.SourceGenerators.Metadata; -namespace CommunityToolkit.Labs.Shared +namespace CommunityToolkit.Labs.Shared; + +/// +/// Used to display all Community Toolkit Labs sample projects in one place. +/// +public sealed partial class NavigationPage : Page { + public NavigationPage() + { + this.InitializeComponent(); + } + /// - /// Used to display all Community Toolkit Labs sample projects in one place. + /// Gets the items used for navigating. /// - public sealed partial class NavigationPage : Page - { - public NavigationPage() - { - this.InitializeComponent(); - } + public ObservableCollection NavigationViewItems { get; } = new ObservableCollection(); - /// - /// Gets the items used for navigating. - /// - public ObservableCollection NavigationViewItems { get; } = new ObservableCollection(); + protected override void OnNavigatedTo(NavigationEventArgs e) + { + var samplePages = e.Parameter as IEnumerable; - protected override void OnNavigatedTo(NavigationEventArgs e) + if (samplePages is not null) { - var samplePages = e.Parameter as IEnumerable; + var categories = GenerateSampleNavItemTree(samplePages); - if (samplePages is not null) - { - var categories = GenerateSampleNavItemTree(samplePages); + foreach (var item in categories) + NavigationViewItems.Add(item); + } - foreach (var item in categories) - NavigationViewItems.Add(item); - } + base.OnNavigatedTo(e); + } - base.OnNavigatedTo(e); - } + private void OnSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs e) + { + var selected = (NavigationViewItem)e.SelectedItem; + var selectedMetadata = selected.Tag as ToolkitFrontMatter; - private void OnSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs e) - { - var selected = (NavigationViewItem)e.SelectedItem; - var selectedMetadata = selected.Tag as ToolkitFrontMatter; + if (selectedMetadata is null) + return; - if (selectedMetadata is null) - return; + NavFrame.Navigate(typeof(ToolkitDocumentationRenderer), selectedMetadata); + } - NavFrame.Navigate(typeof(ToolkitDocumentationRenderer), selectedMetadata); - } + private IEnumerable GenerateSampleNavItemTree(IEnumerable sampleMetadata) + { + // Make categories + var categoryData = GenerateCategoryNavItems(sampleMetadata); - private IEnumerable GenerateSampleNavItemTree(IEnumerable sampleMetadata) + foreach (var navData in categoryData) { - // Make categories - var categoryData = GenerateCategoryNavItems(sampleMetadata); + // Make subcategories + var subcategoryData = GenerateSubcategoryNavItems(navData.SampleMetadata ?? Enumerable.Empty()); - foreach (var navData in categoryData) + foreach (var subcategoryItemData in subcategoryData) { - // Make subcategories - var subcategoryData = GenerateSubcategoryNavItems(navData.SampleMetadata ?? Enumerable.Empty()); + // Make samples + var sampleNavigationItems = GenerateSampleNavItems(subcategoryItemData.SampleMetadata ?? Enumerable.Empty()); - foreach (var subcategoryItemData in subcategoryData) + foreach (var item in sampleNavigationItems) { - // Make samples - var sampleNavigationItems = GenerateSampleNavItems(subcategoryItemData.SampleMetadata ?? Enumerable.Empty()); - - foreach (var item in sampleNavigationItems) - { - // Add sample to subcategory - subcategoryItemData.NavItem.MenuItems.Add(item); - } - - // Add subcategory to category - navData.NavItem.MenuItems.Add(subcategoryItemData.NavItem); + // Add sample to subcategory + subcategoryItemData.NavItem.MenuItems.Add(item); } - // Return category - yield return navData.NavItem; + // Add subcategory to category + navData.NavItem.MenuItems.Add(subcategoryItemData.NavItem); } + + // Return category + yield return navData.NavItem; } + } - private IEnumerable GenerateSampleNavItems(IEnumerable sampleMetadata) + private IEnumerable GenerateSampleNavItems(IEnumerable sampleMetadata) + { + foreach (var metadata in sampleMetadata) { - foreach (var metadata in sampleMetadata) + yield return new NavigationViewItem { - yield return new NavigationViewItem - { - Content = metadata.Title, - Tag = metadata, - }; - } + Content = metadata.Title, + Tag = metadata, + }; } + } - private IEnumerable GenerateSubcategoryNavItems(IEnumerable sampleMetadata) - { - var samplesBySubcategory = sampleMetadata.GroupBy(x => x.Subcategory); + private IEnumerable GenerateSubcategoryNavItems(IEnumerable sampleMetadata) + { + var samplesBySubcategory = sampleMetadata.GroupBy(x => x.Subcategory); - foreach (var subcategoryGroup in samplesBySubcategory) + foreach (var subcategoryGroup in samplesBySubcategory) + { + yield return new GroupNavigationItemData(new NavigationViewItem { - yield return new GroupNavigationItemData(new NavigationViewItem - { - Content = subcategoryGroup.Key, - }, subcategoryGroup.ToArray()); - } + Content = subcategoryGroup.Key, + }, subcategoryGroup.ToArray()); } + } - private IEnumerable GenerateCategoryNavItems(IEnumerable sampleMetadata) - { - var samplesByCategory = sampleMetadata.GroupBy(x => x.Category); + private IEnumerable GenerateCategoryNavItems(IEnumerable sampleMetadata) + { + var samplesByCategory = sampleMetadata.GroupBy(x => x.Category); - foreach (var categoryGroup in samplesByCategory) + foreach (var categoryGroup in samplesByCategory) + { + yield return new GroupNavigationItemData(new NavigationViewItem { - yield return new GroupNavigationItemData(new NavigationViewItem - { - Content = categoryGroup.Key, - }, categoryGroup.ToArray()); - } + Content = categoryGroup.Key, + }, categoryGroup.ToArray()); } - - /// A navigation item to contain items in this group. - /// The samples that belong under . - private record GroupNavigationItemData(NavigationViewItem NavItem, IEnumerable SampleMetadata); } + + /// A navigation item to contain items in this group. + /// The samples that belong under . + private record GroupNavigationItemData(NavigationViewItem NavItem, IEnumerable SampleMetadata); } diff --git a/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionTemplateSelector.cs b/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionTemplateSelector.cs index 7058f0d44..e141b90c6 100644 --- a/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionTemplateSelector.cs +++ b/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionTemplateSelector.cs @@ -11,25 +11,24 @@ using Windows.UI.Xaml.Controls; #endif -namespace CommunityToolkit.Labs.Shared.Renderers +namespace CommunityToolkit.Labs.Shared.Renderers; + +/// +/// Selects a sample option template for the provided . +/// +internal class GeneratedSampleOptionTemplateSelector : DataTemplateSelector { - /// - /// Selects a sample option template for the provided . - /// - internal class GeneratedSampleOptionTemplateSelector : DataTemplateSelector - { - public DataTemplate? BoolOptionTemplate { get; set; } + public DataTemplate? BoolOptionTemplate { get; set; } - public DataTemplate? MultiChoiceOptionTemplate { get; set; } + public DataTemplate? MultiChoiceOptionTemplate { get; set; } - protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + return item switch { - return item switch - { - ToolkitSampleBoolOptionMetadataViewModel => BoolOptionTemplate ?? base.SelectTemplateCore(item, container), - ToolkitSampleMultiChoiceOptionMetadataViewModel => MultiChoiceOptionTemplate ?? base.SelectTemplateCore(item, container), - _ => base.SelectTemplateCore(item, container), - }; - } + ToolkitSampleBoolOptionMetadataViewModel => BoolOptionTemplate ?? base.SelectTemplateCore(item, container), + ToolkitSampleMultiChoiceOptionMetadataViewModel => MultiChoiceOptionTemplate ?? base.SelectTemplateCore(item, container), + _ => base.SelectTemplateCore(item, container), + }; } } diff --git a/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionsRenderer.xaml.cs b/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionsRenderer.xaml.cs index e59a0feef..9b970efa7 100644 --- a/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionsRenderer.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/Renderers/GeneratedSampleOptionsRenderer.xaml.cs @@ -26,43 +26,42 @@ using Windows.UI.Xaml.Navigation; #endif -namespace CommunityToolkit.Labs.Shared.Renderers +namespace CommunityToolkit.Labs.Shared.Renderers; + +/// +/// Displays the provided for manipulation by the user. +/// +/// +/// Sample pages implement via source generators, +/// and are provided a reference to the same given to this control. +/// +/// When the user updates the , +/// a PropertyChanged event with the should be emitted. +/// +/// The sample page sees this property change event via the generated , +/// causing it to re-get the proxied . +/// +public sealed partial class GeneratedSampleOptionsRenderer : UserControl { - /// - /// Displays the provided for manipulation by the user. - /// - /// - /// Sample pages implement via source generators, - /// and are provided a reference to the same given to this control. - /// - /// When the user updates the , - /// a PropertyChanged event with the should be emitted. - /// - /// The sample page sees this property change event via the generated , - /// causing it to re-get the proxied . - /// - public sealed partial class GeneratedSampleOptionsRenderer : UserControl + public GeneratedSampleOptionsRenderer() { - public GeneratedSampleOptionsRenderer() - { - this.InitializeComponent(); - } - - /// - /// The backing for . - /// - public static readonly DependencyProperty SampleOptionsProperty = - DependencyProperty.Register(nameof(SampleOptions), typeof(IEnumerable), typeof(GeneratedSampleOptionsRenderer), new PropertyMetadata(null)); + this.InitializeComponent(); + } - /// - /// The generated sample options that should be displayed to the user. - /// - public IEnumerable? SampleOptions - { - get => (IEnumerable?)GetValue(SampleOptionsProperty); - set => SetValue(SampleOptionsProperty, value); - } + /// + /// The backing for . + /// + public static readonly DependencyProperty SampleOptionsProperty = + DependencyProperty.Register(nameof(SampleOptions), typeof(IEnumerable), typeof(GeneratedSampleOptionsRenderer), new PropertyMetadata(null)); - public static Visibility NullOrWhiteSpaceToVisibility(string? str) => string.IsNullOrWhiteSpace(str) ? Visibility.Collapsed : Visibility.Visible; + /// + /// The generated sample options that should be displayed to the user. + /// + public IEnumerable? SampleOptions + { + get => (IEnumerable?)GetValue(SampleOptionsProperty); + set => SetValue(SampleOptionsProperty, value); } + + public static Visibility NullOrWhiteSpaceToVisibility(string? str) => string.IsNullOrWhiteSpace(str) ? Visibility.Collapsed : Visibility.Visible; } diff --git a/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs b/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs index 1acbd6be4..d40999059 100644 --- a/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitDocumentationRenderer.xaml.cs @@ -30,170 +30,169 @@ using Windows.UI.Xaml.Navigation; #endif -namespace CommunityToolkit.Labs.Shared.Renderers +namespace CommunityToolkit.Labs.Shared.Renderers; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public sealed partial class ToolkitDocumentationRenderer : Page { + private const string MarkdownRegexSampleTagExpression = @"^>\s*\[!SAMPLE\s*(?.*)\s*\]\s*$"; + private static readonly Regex MarkdownRegexSampleTag = new Regex(MarkdownRegexSampleTagExpression, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline); + + public ToolkitDocumentationRenderer() + { + this.InitializeComponent(); + } + /// - /// An empty page that can be used on its own or navigated to within a Frame. + /// List of referenced samples in this page. /// - public sealed partial class ToolkitDocumentationRenderer : Page + public List Samples { - private const string MarkdownRegexSampleTagExpression = @"^>\s*\[!SAMPLE\s*(?.*)\s*\]\s*$"; - private static readonly Regex MarkdownRegexSampleTag = new Regex(MarkdownRegexSampleTagExpression, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline); + get { return (List)GetValue(SamplesProperty); } + set { SetValue(SamplesProperty, value); } + } - public ToolkitDocumentationRenderer() - { - this.InitializeComponent(); - } + /// + /// The backing for the property. + /// + public static readonly DependencyProperty SamplesProperty + = + DependencyProperty.Register(nameof(Samples), typeof(List), typeof(ToolkitDocumentationRenderer), new PropertyMetadata(null)); - /// - /// List of referenced samples in this page. - /// - public List Samples - { - get { return (List)GetValue(SamplesProperty); } - set { SetValue(SamplesProperty, value); } - } + /// + /// Intermixed list of string doc snippets for Markdown and + /// objects for samples. + /// + public ObservableCollection DocsAndSamples = new(); - /// - /// The backing for the property. - /// - public static readonly DependencyProperty SamplesProperty - = - DependencyProperty.Register(nameof(Samples), typeof(List), typeof(ToolkitDocumentationRenderer), new PropertyMetadata(null)); - - /// - /// Intermixed list of string doc snippets for Markdown and - /// objects for samples. - /// - public ObservableCollection DocsAndSamples = new(); - - /// - /// The YAML front matter metadata about this documentation file. - /// - public ToolkitFrontMatter? Metadata - { - get { return (ToolkitFrontMatter?)GetValue(MetadataProperty); } - set { SetValue(MetadataProperty, value); } - } + /// + /// The YAML front matter metadata about this documentation file. + /// + public ToolkitFrontMatter? Metadata + { + get { return (ToolkitFrontMatter?)GetValue(MetadataProperty); } + set { SetValue(MetadataProperty, value); } + } - /// - /// The backing for the property. - /// - public static readonly DependencyProperty MetadataProperty = - DependencyProperty.Register(nameof(Metadata), typeof(ToolkitFrontMatter), typeof(ToolkitDocumentationRenderer), new PropertyMetadata(null, OnMetadataPropertyChanged)); + /// + /// The backing for the property. + /// + public static readonly DependencyProperty MetadataProperty = + DependencyProperty.Register(nameof(Metadata), typeof(ToolkitFrontMatter), typeof(ToolkitDocumentationRenderer), new PropertyMetadata(null, OnMetadataPropertyChanged)); - private static async void OnMetadataPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + private static async void OnMetadataPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + if (dependencyObject is ToolkitDocumentationRenderer renderer && + renderer.Metadata != null && + args.OldValue != args.NewValue) { - if (dependencyObject is ToolkitDocumentationRenderer renderer && - renderer.Metadata != null && - args.OldValue != args.NewValue) - { - await renderer.LoadData(); - } + await renderer.LoadData(); } + } - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(e); + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); - Metadata = (ToolkitFrontMatter)e.Parameter; - } + Metadata = (ToolkitFrontMatter)e.Parameter; + } - private async Task LoadData() + private async Task LoadData() + { + if (Metadata is null) { - if (Metadata is null) - { - return; - } + return; + } - List samples = new(); - if (Metadata.SampleIdReferences != null && Metadata.SampleIdReferences.Length > 0 && - !string.IsNullOrWhiteSpace(Metadata.SampleIdReferences[0])) + List samples = new(); + if (Metadata.SampleIdReferences != null && Metadata.SampleIdReferences.Length > 0 && + !string.IsNullOrWhiteSpace(Metadata.SampleIdReferences[0])) + { + foreach (var sampleid in Metadata.SampleIdReferences) { - foreach (var sampleid in Metadata.SampleIdReferences) - { - // We don't check here for key as we validate with SG. - samples.Add(ToolkitSampleRegistry.Listing[sampleid]); - } + // We don't check here for key as we validate with SG. + samples.Add(ToolkitSampleRegistry.Listing[sampleid]); } - Samples = samples; + } + Samples = samples; - var doctext = await GetDocumentationFileContents(Metadata); + var doctext = await GetDocumentationFileContents(Metadata); - var matches = MarkdownRegexSampleTag.Matches(doctext); + var matches = MarkdownRegexSampleTag.Matches(doctext); - DocsAndSamples.Clear(); - if (matches.Count == 0) - { - DocsAndSamples.Add(doctext); - } - else - { - int index = 0; - foreach (Match match in matches) - { - DocsAndSamples.Add(doctext.Substring(index, match.Index - index - 1)); - DocsAndSamples.Add(ToolkitSampleRegistry.Listing[match.Groups["sampleid"].Value]); - index = match.Index + match.Length; - } - - // Put rest of text at end - DocsAndSamples.Add(doctext.Substring(index)); - } + DocsAndSamples.Clear(); + if (matches.Count == 0) + { + DocsAndSamples.Add(doctext); } - - private void SampleListHyperlink_Click(object sender, RoutedEventArgs e) + else { - if (sender is HyperlinkButton btn && btn.DataContext is ToolkitSampleMetadata metadata) + int index = 0; + foreach (Match match in matches) { - var container = DocItemsControl.ContainerFromItem(metadata) as UIElement; - container?.StartBringIntoView(); + DocsAndSamples.Add(doctext.Substring(index, match.Index - index - 1)); + DocsAndSamples.Add(ToolkitSampleRegistry.Listing[match.Groups["sampleid"].Value]); + index = match.Index + match.Length; } + + // Put rest of text at end + DocsAndSamples.Add(doctext.Substring(index)); } + } - private static async Task GetDocumentationFileContents(ToolkitFrontMatter metadata) + private void SampleListHyperlink_Click(object sender, RoutedEventArgs e) + { + if (sender is HyperlinkButton btn && btn.DataContext is ToolkitSampleMetadata metadata) { - // TODO: https://github.com/CommunityToolkit/Labs-Windows/issues/142 - // MSBuild uses wildcard to find the files, and the wildcards decide where they end up - // Single experiments use relative paths, the allExperiment head uses absolute paths that grab from all experiments - // The wildcard captures decide the paths. This discrepency is accounted for manually. - // Logic here is the exact same that MSBuild uses to find and include the files we need. - var assemblyName = typeof(ToolkitSampleRenderer).Assembly.GetName().Name; - if (string.IsNullOrWhiteSpace(assemblyName)) - throw new InvalidOperationException(); + var container = DocItemsControl.ContainerFromItem(metadata) as UIElement; + container?.StartBringIntoView(); + } + } - var isAllExperimentHead = assemblyName.StartsWith("CommunityToolkit.Labs.", StringComparison.OrdinalIgnoreCase); - var isProjectTemplateHead = assemblyName.StartsWith("ProjectTemplate"); - var isSingleExperimentHead = !isAllExperimentHead && !isProjectTemplateHead; + private static async Task GetDocumentationFileContents(ToolkitFrontMatter metadata) + { + // TODO: https://github.com/CommunityToolkit/Labs-Windows/issues/142 + // MSBuild uses wildcard to find the files, and the wildcards decide where they end up + // Single experiments use relative paths, the allExperiment head uses absolute paths that grab from all experiments + // The wildcard captures decide the paths. This discrepency is accounted for manually. + // Logic here is the exact same that MSBuild uses to find and include the files we need. + var assemblyName = typeof(ToolkitSampleRenderer).Assembly.GetName().Name; + if (string.IsNullOrWhiteSpace(assemblyName)) + throw new InvalidOperationException(); - if (metadata.FilePath is null || string.IsNullOrWhiteSpace(metadata.FilePath)) - throw new InvalidOperationException("Missing or malformed path to markdown file. Unable to continue;"); + var isAllExperimentHead = assemblyName.StartsWith("CommunityToolkit.Labs.", StringComparison.OrdinalIgnoreCase); + var isProjectTemplateHead = assemblyName.StartsWith("ProjectTemplate"); + var isSingleExperimentHead = !isAllExperimentHead && !isProjectTemplateHead; - var path = metadata.FilePath; + if (metadata.FilePath is null || string.IsNullOrWhiteSpace(metadata.FilePath)) + throw new InvalidOperationException("Missing or malformed path to markdown file. Unable to continue;"); - if (isSingleExperimentHead || isProjectTemplateHead) - { - var experimentName = assemblyName.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries)[0]; - path = path.Split(new[] { $"\\{experimentName}.Sample" }, StringSplitOptions.RemoveEmptyEntries)[1]; - path = $"{experimentName}.Sample{path}"; - } + var path = metadata.FilePath; - var fileUri = new Uri($"ms-appx:///SourceAssets/{path}"); + if (isSingleExperimentHead || isProjectTemplateHead) + { + var experimentName = assemblyName.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries)[0]; + path = path.Split(new[] { $"\\{experimentName}.Sample" }, StringSplitOptions.RemoveEmptyEntries)[1]; + path = $"{experimentName}.Sample{path}"; + } - try - { - var file = await StorageFile.GetFileFromApplicationUriAsync(fileUri); - var textContents = await FileIO.ReadTextAsync(file); + var fileUri = new Uri($"ms-appx:///SourceAssets/{path}"); - // Remove YAML - need to use array overload as single string not supported on .NET Standard 2.0 - var blocks = textContents.Split(new[] { "---" }, StringSplitOptions.RemoveEmptyEntries); + try + { + var file = await StorageFile.GetFileFromApplicationUriAsync(fileUri); + var textContents = await FileIO.ReadTextAsync(file); - return blocks.LastOrDefault() ?? "Couldn't find content after YAML Front Matter removal."; - } - catch (Exception e) - { - return $"Exception Encountered Loading file '{fileUri}':\n{e.Message}\n{e.StackTrace}"; - } + // Remove YAML - need to use array overload as single string not supported on .NET Standard 2.0 + var blocks = textContents.Split(new[] { "---" }, StringSplitOptions.RemoveEmptyEntries); + + return blocks.LastOrDefault() ?? "Couldn't find content after YAML Front Matter removal."; + } + catch (Exception e) + { + return $"Exception Encountered Loading file '{fileUri}':\n{e.Message}\n{e.StackTrace}"; } } } diff --git a/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitSampleRenderer.xaml.cs b/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitSampleRenderer.xaml.cs index 47890d869..45b7fdbe5 100644 --- a/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitSampleRenderer.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/Renderers/ToolkitSampleRenderer.xaml.cs @@ -29,212 +29,211 @@ using Windows.UI.Xaml.Navigation; #endif -namespace CommunityToolkit.Labs.Shared.Renderers +namespace CommunityToolkit.Labs.Shared.Renderers; + +/// +/// Handles the display of a single toolkit sample, its source code, and the options that control it. +/// +public sealed partial class ToolkitSampleRenderer : Page { /// - /// Handles the display of a single toolkit sample, its source code, and the options that control it. + /// Creates a new instance of . /// - public sealed partial class ToolkitSampleRenderer : Page + public ToolkitSampleRenderer() { - /// - /// Creates a new instance of . - /// - public ToolkitSampleRenderer() - { - this.InitializeComponent(); - } + this.InitializeComponent(); + } - /// - /// The backing for the property. - /// - public static readonly DependencyProperty MetadataProperty = - DependencyProperty.Register(nameof(Metadata), typeof(ToolkitSampleMetadata), typeof(ToolkitSampleRenderer), new PropertyMetadata(null, OnMetadataPropertyChanged)); - - /// - /// The backing for the property. - /// - public static readonly DependencyProperty SampleControlInstanceProperty = - DependencyProperty.Register(nameof(SampleControlInstance), typeof(UIElement), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); - - /// - /// The backing for the property. - /// - public static readonly DependencyProperty SampleOptionsPaneInstanceProperty = - DependencyProperty.Register(nameof(SampleOptionsPaneInstance), typeof(UIElement), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); - - /// - /// The backing for the property. - /// - public static readonly DependencyProperty XamlCodeProperty = - DependencyProperty.Register(nameof(XamlCode), typeof(string), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); - - /// - /// The backing for the property. - /// - public static readonly DependencyProperty CSharpCodeProperty = - DependencyProperty.Register(nameof(CSharpCode), typeof(string), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); - - public ToolkitSampleMetadata? Metadata - { - get { return (ToolkitSampleMetadata?)GetValue(MetadataProperty); } - set { SetValue(MetadataProperty, value); } - } + /// + /// The backing for the property. + /// + public static readonly DependencyProperty MetadataProperty = + DependencyProperty.Register(nameof(Metadata), typeof(ToolkitSampleMetadata), typeof(ToolkitSampleRenderer), new PropertyMetadata(null, OnMetadataPropertyChanged)); - /// - /// The sample control instance being displayed. - /// - public UIElement? SampleControlInstance - { - get => (UIElement?)GetValue(SampleControlInstanceProperty); - set => SetValue(SampleControlInstanceProperty, value); - } + /// + /// The backing for the property. + /// + public static readonly DependencyProperty SampleControlInstanceProperty = + DependencyProperty.Register(nameof(SampleControlInstance), typeof(UIElement), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty SampleOptionsPaneInstanceProperty = + DependencyProperty.Register(nameof(SampleOptionsPaneInstance), typeof(UIElement), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty XamlCodeProperty = + DependencyProperty.Register(nameof(XamlCode), typeof(string), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty CSharpCodeProperty = + DependencyProperty.Register(nameof(CSharpCode), typeof(string), typeof(ToolkitSampleRenderer), new PropertyMetadata(null)); + + public ToolkitSampleMetadata? Metadata + { + get { return (ToolkitSampleMetadata?)GetValue(MetadataProperty); } + set { SetValue(MetadataProperty, value); } + } + + /// + /// The sample control instance being displayed. + /// + public UIElement? SampleControlInstance + { + get => (UIElement?)GetValue(SampleControlInstanceProperty); + set => SetValue(SampleControlInstanceProperty, value); + } + + /// + /// The options pane for the sample being displayed. + /// + public UIElement? SampleOptionsPaneInstance + { + get => (UIElement?)GetValue(SampleOptionsPaneInstanceProperty); + set => SetValue(SampleOptionsPaneInstanceProperty, value); + } + + /// + /// The XAML code being rendered. + /// + public string? XamlCode + { + get => (string?)GetValue(XamlCodeProperty); + set => SetValue(XamlCodeProperty, value); + } + + /// + /// The backing C# for the being rendered. + /// + public string? CSharpCode + { + get => (string?)GetValue(CSharpCodeProperty); + set => SetValue(CSharpCodeProperty, value); + } - /// - /// The options pane for the sample being displayed. - /// - public UIElement? SampleOptionsPaneInstance + private static async void OnMetadataPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + if (dependencyObject is ToolkitSampleRenderer renderer && + renderer.Metadata != null && + args.OldValue != args.NewValue) { - get => (UIElement?)GetValue(SampleOptionsPaneInstanceProperty); - set => SetValue(SampleOptionsPaneInstanceProperty, value); + await renderer.LoadData(); } + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + + Metadata = (ToolkitSampleMetadata)e.Parameter; + } - /// - /// The XAML code being rendered. - /// - public string? XamlCode + private async Task LoadData() + { + if (Metadata is null) { - get => (string?)GetValue(XamlCodeProperty); - set => SetValue(XamlCodeProperty, value); + return; } - /// - /// The backing C# for the being rendered. - /// - public string? CSharpCode + XamlCode = await GetMetadataFileContents(Metadata, "xaml"); + CSharpCode = await GetMetadataFileContents(Metadata, "xaml.cs"); + + var sampleControlInstance = (UIElement)Metadata.SampleControlFactory(); + + // Custom control-based sample options. + if (Metadata.SampleOptionsPaneType is not null && Metadata.SampleOptionsPaneFactory is not null) { - get => (string?)GetValue(CSharpCodeProperty); - set => SetValue(CSharpCodeProperty, value); + SampleOptionsPaneInstance = (UIElement)Metadata.SampleOptionsPaneFactory(sampleControlInstance); } - private static async void OnMetadataPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + // Source generater-based sample options + else if (sampleControlInstance is IToolkitSampleGeneratedOptionPropertyContainer propertyContainer) { - if (dependencyObject is ToolkitSampleRenderer renderer && - renderer.Metadata != null && - args.OldValue != args.NewValue) + // Pass the generated sample options to the displayed Control instance. + // Generated properties reference these in getters and setters. + propertyContainer.GeneratedPropertyMetadata = Metadata.GeneratedSampleOptions; + + SampleOptionsPaneInstance = new GeneratedSampleOptionsRenderer { - await renderer.LoadData(); - } + SampleOptions = propertyContainer.GeneratedPropertyMetadata + }; } - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(e); + // Generated options must be assigned before attempting to render the control, + // else some platforms will nullref from XAML but not properly ignore the exception when binding to generated properties. + SampleControlInstance = sampleControlInstance; + } - Metadata = (ToolkitSampleMetadata)e.Parameter; - } + public static async Task GetMetadataFileContents(ToolkitSampleMetadata metadata, string fileExtension) + { + var filePath = GetRelativePathToFileWithoutExtension(metadata.SampleControlType); - private async Task LoadData() + try { - if (Metadata is null) + // Workaround for https://github.com/unoplatform/uno/issues/8649 + if (fileExtension.Contains(".cs")) { - return; + fileExtension = fileExtension.Replace(".cs", ".cs.dat"); } - XamlCode = await GetMetadataFileContents(Metadata, "xaml"); - CSharpCode = await GetMetadataFileContents(Metadata, "xaml.cs"); - - var sampleControlInstance = (UIElement)Metadata.SampleControlFactory(); + var finalPath = $"ms-appx:///{filePath}.{fileExtension.Trim('.')}"; - // Custom control-based sample options. - if (Metadata.SampleOptionsPaneType is not null && Metadata.SampleOptionsPaneFactory is not null) - { - SampleOptionsPaneInstance = (UIElement)Metadata.SampleOptionsPaneFactory(sampleControlInstance); - } - - // Source generater-based sample options - else if (sampleControlInstance is IToolkitSampleGeneratedOptionPropertyContainer propertyContainer) - { - // Pass the generated sample options to the displayed Control instance. - // Generated properties reference these in getters and setters. - propertyContainer.GeneratedPropertyMetadata = Metadata.GeneratedSampleOptions; - - SampleOptionsPaneInstance = new GeneratedSampleOptionsRenderer - { - SampleOptions = propertyContainer.GeneratedPropertyMetadata - }; - } + var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///{filePath}.{fileExtension.Trim('.')}")); + var textContents = await FileIO.ReadTextAsync(file); - // Generated options must be assigned before attempting to render the control, - // else some platforms will nullref from XAML but not properly ignore the exception when binding to generated properties. - SampleControlInstance = sampleControlInstance; + return textContents; } - - public static async Task GetMetadataFileContents(ToolkitSampleMetadata metadata, string fileExtension) + catch (Exception e) { - var filePath = GetRelativePathToFileWithoutExtension(metadata.SampleControlType); - - try - { - // Workaround for https://github.com/unoplatform/uno/issues/8649 - if (fileExtension.Contains(".cs")) - { - fileExtension = fileExtension.Replace(".cs", ".cs.dat"); - } - - var finalPath = $"ms-appx:///{filePath}.{fileExtension.Trim('.')}"; - - var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///{filePath}.{fileExtension.Trim('.')}")); - var textContents = await FileIO.ReadTextAsync(file); - - return textContents; - } - catch (Exception e) - { - return $"Exception Encountered Loading file '{filePath}':\n{e.Message}\n{e.StackTrace}"; - } + return $"Exception Encountered Loading file '{filePath}':\n{e.Message}\n{e.StackTrace}"; } + } - /// - /// Compute path to a code file bundled in the app using type information. - /// Assumes path to file within the included assembly folder matches the namespace. - /// - private static string GetRelativePathToFileWithoutExtension(Type type) - { - // TODO: https://github.com/CommunityToolkit/Labs-Windows/issues/142 - // MSBuild uses wildcard to find the files, and the wildcards decide where they end up - // Single experiments use relative paths, the allExperiment head uses absolute paths that grab from all experiments - // The wildcard captures decide the paths. This discrepency is accounted for manually. - // Logic here is the exact same that MSBuild uses to find and include the files we need. - var assemblyName = typeof(ToolkitSampleRenderer).Assembly.GetName().Name; - if (string.IsNullOrWhiteSpace(assemblyName)) - throw new InvalidOperationException(); + /// + /// Compute path to a code file bundled in the app using type information. + /// Assumes path to file within the included assembly folder matches the namespace. + /// + private static string GetRelativePathToFileWithoutExtension(Type type) + { + // TODO: https://github.com/CommunityToolkit/Labs-Windows/issues/142 + // MSBuild uses wildcard to find the files, and the wildcards decide where they end up + // Single experiments use relative paths, the allExperiment head uses absolute paths that grab from all experiments + // The wildcard captures decide the paths. This discrepency is accounted for manually. + // Logic here is the exact same that MSBuild uses to find and include the files we need. + var assemblyName = typeof(ToolkitSampleRenderer).Assembly.GetName().Name; + if (string.IsNullOrWhiteSpace(assemblyName)) + throw new InvalidOperationException(); - var isAllExperimentHead = assemblyName.StartsWith("CommunityToolkit.Labs.", StringComparison.OrdinalIgnoreCase); - var isProjectTemplateHead = assemblyName.StartsWith("ProjectTemplate"); - var isSingleExperimentHead = !isAllExperimentHead && !isProjectTemplateHead; + var isAllExperimentHead = assemblyName.StartsWith("CommunityToolkit.Labs.", StringComparison.OrdinalIgnoreCase); + var isProjectTemplateHead = assemblyName.StartsWith("ProjectTemplate"); + var isSingleExperimentHead = !isAllExperimentHead && !isProjectTemplateHead; - var simpleAssemblyName = type.Assembly.GetName().Name; - var typeNamespace = type.Namespace; + var simpleAssemblyName = type.Assembly.GetName().Name; + var typeNamespace = type.Namespace; - if (string.IsNullOrWhiteSpace(simpleAssemblyName)) - throw new ArgumentException($"Unable to find assembly name for provided type {type}.", nameof(simpleAssemblyName)); + if (string.IsNullOrWhiteSpace(simpleAssemblyName)) + throw new ArgumentException($"Unable to find assembly name for provided type {type}.", nameof(simpleAssemblyName)); - if (string.IsNullOrWhiteSpace(typeNamespace)) - throw new ArgumentException($"Unable to find namespace for provided type {type}.", nameof(typeNamespace)); + if (string.IsNullOrWhiteSpace(typeNamespace)) + throw new ArgumentException($"Unable to find namespace for provided type {type}.", nameof(typeNamespace)); - var sampleName = simpleAssemblyName.Replace(".Sample", ""); + var sampleName = simpleAssemblyName.Replace(".Sample", ""); - var folderPath = typeNamespace.Replace(simpleAssemblyName, "").Trim('.').Replace('.', '/'); - if (folderPath.Length != 0) - folderPath += "/"; + var folderPath = typeNamespace.Replace(simpleAssemblyName, "").Trim('.').Replace('.', '/'); + if (folderPath.Length != 0) + folderPath += "/"; - if (isSingleExperimentHead || isProjectTemplateHead) - return $"SourceAssets/{simpleAssemblyName}/{folderPath}{type.Name}"; - - if (isAllExperimentHead) - return $"SourceAssets/{sampleName}/samples/{simpleAssemblyName}/{folderPath}{type.Name}"; + if (isSingleExperimentHead || isProjectTemplateHead) + return $"SourceAssets/{simpleAssemblyName}/{folderPath}{type.Name}"; + + if (isAllExperimentHead) + return $"SourceAssets/{sampleName}/samples/{simpleAssemblyName}/{folderPath}{type.Name}"; - throw new InvalidOperationException("Unable to determine if running in a single or all experiment solution."); - } + throw new InvalidOperationException("Unable to determine if running in a single or all experiment solution."); } } diff --git a/common/CommunityToolkit.Labs.Shared/TabbedPage.xaml.cs b/common/CommunityToolkit.Labs.Shared/TabbedPage.xaml.cs index a49088779..1d9947eb1 100644 --- a/common/CommunityToolkit.Labs.Shared/TabbedPage.xaml.cs +++ b/common/CommunityToolkit.Labs.Shared/TabbedPage.xaml.cs @@ -24,51 +24,50 @@ using Microsoft.UI.Xaml.Navigation; #endif -namespace CommunityToolkit.Labs.Shared +namespace CommunityToolkit.Labs.Shared; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public sealed partial class TabbedPage : Page { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public sealed partial class TabbedPage : Page + public TabbedPage() { - public TabbedPage() - { - this.InitializeComponent(); - } - - public ObservableCollection Items { get; } = new(); + this.InitializeComponent(); + } - protected override void OnNavigatedTo(NavigationEventArgs e) - { - // Note: Need to use as for tuple, think this is the tracking issue here: https://github.com/dotnet/csharplang/issues/3197 - var info = e.Parameter as (IEnumerable Samples, IEnumerable Docs, bool AreDocsFirst)?; + public ObservableCollection Items { get; } = new(); - if (info is null) - { - return; - } - else if (info.Value.AreDocsFirst) - { - foreach (var item in info.Value.Docs) - { - Items.Add(item); - } - } + protected override void OnNavigatedTo(NavigationEventArgs e) + { + // Note: Need to use as for tuple, think this is the tracking issue here: https://github.com/dotnet/csharplang/issues/3197 + var info = e.Parameter as (IEnumerable Samples, IEnumerable Docs, bool AreDocsFirst)?; - foreach (var item in info.Value.Samples) + if (info is null) + { + return; + } + else if (info.Value.AreDocsFirst) + { + foreach (var item in info.Value.Docs) { Items.Add(item); } + } - if (!info.Value.AreDocsFirst) + foreach (var item in info.Value.Samples) + { + Items.Add(item); + } + + if (!info.Value.AreDocsFirst) + { + foreach (var item in info.Value.Docs) { - foreach (var item in info.Value.Docs) - { - Items.Add(item); - } + Items.Add(item); } - - base.OnNavigatedTo(e); } + + base.OnNavigatedTo(e); } } diff --git a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleOne/SamplePage.xaml.cs b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleOne/SamplePage.xaml.cs index 722b860d6..13e0577f0 100644 --- a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleOne/SamplePage.xaml.cs +++ b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleOne/SamplePage.xaml.cs @@ -30,22 +30,21 @@ using Microsoft.UI.Xaml.Navigation; #endif -namespace CanvasLayout.Sample.SampleOne +namespace CanvasLayout.Sample.SampleOne; + +[ToolkitSampleBoolOption("IsTextVisible", "IsVisible", true)] +[ToolkitSampleMultiChoiceOption("TextSize", title: "Text size", "Small : 12", "Normal : 16", "Big : 32")] +[ToolkitSampleMultiChoiceOption("TextFontFamily", title: "Font family", "Segoe UI", "Arial", "Consolas")] +[ToolkitSampleMultiChoiceOption("TextForeground", title: "Text foreground", + "Teal : #0ddc8c", + "Sand : #e7a676", + "Dull green : #5d7577")] + +[ToolkitSample(id: nameof(SamplePage), "Simple Options", description: "A sample page for showing how to do simple options.")] +public sealed partial class SamplePage : Page { - [ToolkitSampleBoolOption("IsTextVisible", "IsVisible", true)] - [ToolkitSampleMultiChoiceOption("TextSize", title: "Text size", "Small : 12", "Normal : 16", "Big : 32")] - [ToolkitSampleMultiChoiceOption("TextFontFamily", title: "Font family", "Segoe UI", "Arial", "Consolas")] - [ToolkitSampleMultiChoiceOption("TextForeground", title: "Text foreground", - "Teal : #0ddc8c", - "Sand : #e7a676", - "Dull green : #5d7577")] - - [ToolkitSample(id: nameof(SamplePage), "Simple Options", description: "A sample page for showing how to do simple options.")] - public sealed partial class SamplePage : Page + public SamplePage() { - public SamplePage() - { - this.InitializeComponent(); - } + this.InitializeComponent(); } } diff --git a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleThree/SamplePage3.xaml.cs b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleThree/SamplePage3.xaml.cs index bd605e126..f7453155a 100644 --- a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleThree/SamplePage3.xaml.cs +++ b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleThree/SamplePage3.xaml.cs @@ -34,32 +34,31 @@ // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 -namespace CanvasLayout.Sample.SampleThree +namespace CanvasLayout.Sample.SampleThree; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +[ToolkitSample(id: nameof(SamplePage3), "Canvas Layout", description: "A canvas-like VirtualizingLayout for use in an ItemsRepeater")] +public sealed partial class SamplePage3 : Page { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - [ToolkitSample(id: nameof(SamplePage3), "Canvas Layout", description: "A canvas-like VirtualizingLayout for use in an ItemsRepeater")] - public sealed partial class SamplePage3 : Page + public ObservableCollection Items = new() { - public ObservableCollection Items = new() - { - new() { Left = 100, Top = 50, Width = 100, Height = 100, Text = "Item 1" }, - new() { Left = 400, Top = 250, Width = 200, Height = 200, Text = "Item 2" }, - new() { Left = 200, Top = 500, Width = 100, Height = 100, Text = "Item 3" }, - new() { Left = 1200, Top = 2500, Width = 100, Height = 100, Text = "Item 4" }, - new() { Left = 2200, Top = 1500, Width = 100, Height = 100, Text = "Item 5" }, - new() { Left = 1200, Top = 3500, Width = 100, Height = 100, Text = "Item 6" }, - }; - - public SamplePage3() - { - this.InitializeComponent(); - } - } + new() { Left = 100, Top = 50, Width = 100, Height = 100, Text = "Item 1" }, + new() { Left = 400, Top = 250, Width = 200, Height = 200, Text = "Item 2" }, + new() { Left = 200, Top = 500, Width = 100, Height = 100, Text = "Item 3" }, + new() { Left = 1200, Top = 2500, Width = 100, Height = 100, Text = "Item 4" }, + new() { Left = 2200, Top = 1500, Width = 100, Height = 100, Text = "Item 5" }, + new() { Left = 1200, Top = 3500, Width = 100, Height = 100, Text = "Item 6" }, + }; - public class CanvasItem : CanvasLayoutItem + public SamplePage3() { - public string Text { get; set; } = string.Empty; + this.InitializeComponent(); } } + +public class CanvasItem : CanvasLayoutItem +{ + public string Text { get; set; } = string.Empty; +} diff --git a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePage2.xaml.cs b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePage2.xaml.cs index 1cdbbdf53..2f227109d 100644 --- a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePage2.xaml.cs +++ b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePage2.xaml.cs @@ -11,14 +11,13 @@ using Windows.UI.Xaml.Controls; #endif -namespace CanvasLayout.Sample.SampleTwo +namespace CanvasLayout.Sample.SampleTwo; + +[ToolkitSample(id: nameof(SamplePage2), "Custom options", description: "An empty sample used to demonstrate the sample system.")] +public sealed partial class SamplePage2 : UserControl { - [ToolkitSample(id: nameof(SamplePage2), "Custom options", description: "An empty sample used to demonstrate the sample system.")] - public sealed partial class SamplePage2 : UserControl + public SamplePage2() { - public SamplePage2() - { - this.InitializeComponent(); - } + this.InitializeComponent(); } } diff --git a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePageOptions.xaml.cs b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePageOptions.xaml.cs index 89cbcb591..7539d4f93 100644 --- a/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePageOptions.xaml.cs +++ b/labs/CanvasLayout/samples/CanvasLayout.Sample/SampleTwo/SamplePageOptions.xaml.cs @@ -20,54 +20,53 @@ // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 -namespace CanvasLayout.Sample.SampleTwo +namespace CanvasLayout.Sample.SampleTwo; + +[ToolkitSampleOptionsPane(sampleId: nameof(SamplePage2))] +public sealed partial class SamplePageOptions : UserControl { - [ToolkitSampleOptionsPane(sampleId: nameof(SamplePage2))] - public sealed partial class SamplePageOptions : UserControl - { - private readonly SamplePage2 _samplePage; - private SamplePage2.XamlNamedPropertyRelay _xamlProperties; + private readonly SamplePage2 _samplePage; + private SamplePage2.XamlNamedPropertyRelay _xamlProperties; - public SamplePageOptions(SamplePage2 samplePage) - { - Loaded += SamplePageOptions_Loaded; + public SamplePageOptions(SamplePage2 samplePage) + { + Loaded += SamplePageOptions_Loaded; - _samplePage = samplePage; - _xamlProperties = new SamplePage2.XamlNamedPropertyRelay(_samplePage); + _samplePage = samplePage; + _xamlProperties = new SamplePage2.XamlNamedPropertyRelay(_samplePage); - this.InitializeComponent(); - } + this.InitializeComponent(); + } - private void SamplePageOptions_Loaded(object sender, RoutedEventArgs e) - { - Loaded -= SamplePageOptions_Loaded; + private void SamplePageOptions_Loaded(object sender, RoutedEventArgs e) + { + Loaded -= SamplePageOptions_Loaded; - CustomText.Text = _xamlProperties.PrimaryText.Text; - FontSizeSlider.Value = _xamlProperties.PrimaryText.FontSize; - } + CustomText.Text = _xamlProperties.PrimaryText.Text; + FontSizeSlider.Value = _xamlProperties.PrimaryText.FontSize; + } - private void TextBox_TextChanged(object sender, TextChangedEventArgs e) - { - _xamlProperties.PrimaryText.Text = ((TextBox)sender).Text; - } + private void TextBox_TextChanged(object sender, TextChangedEventArgs e) + { + _xamlProperties.PrimaryText.Text = ((TextBox)sender).Text; + } - private void OnRadioButtonSelectionChanged(object sender, SelectionChangedEventArgs e) + private void OnRadioButtonSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is RadioButtons radioButtons) { - if (sender is RadioButtons radioButtons) - { - if (radioButtons.SelectedItem is null) - return; + if (radioButtons.SelectedItem is null) + return; - var selectedColor = (string)radioButtons.SelectedItem; + var selectedColor = (string)radioButtons.SelectedItem; - _xamlProperties.PrimaryText.Foreground = (SolidColorBrush)XamlBindingHelper.ConvertValue(typeof(SolidColorBrush), selectedColor); - } + _xamlProperties.PrimaryText.Foreground = (SolidColorBrush)XamlBindingHelper.ConvertValue(typeof(SolidColorBrush), selectedColor); } + } - private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) - { - if (_xamlProperties.PrimaryText is not null && IsLoaded && _samplePage.IsLoaded) - _xamlProperties.PrimaryText.FontSize = ((Slider)sender).Value; - } + private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) + { + if (_xamlProperties.PrimaryText is not null && IsLoaded && _samplePage.IsLoaded) + _xamlProperties.PrimaryText.FontSize = ((Slider)sender).Value; } } diff --git a/labs/CanvasLayout/samples/CanvasLayout.Wasm/Program.cs b/labs/CanvasLayout/samples/CanvasLayout.Wasm/Program.cs index 8de4e65c7..bf9d8fb02 100644 --- a/labs/CanvasLayout/samples/CanvasLayout.Wasm/Program.cs +++ b/labs/CanvasLayout/samples/CanvasLayout.Wasm/Program.cs @@ -7,8 +7,8 @@ using Windows.UI.Xaml; #endif -namespace CanvasLayout.Wasm -{ +namespace CanvasLayout.Wasm; + public class Program { private static App? _app; @@ -20,4 +20,3 @@ static int Main(string[] args) return 0; } } -} diff --git a/labs/CanvasLayout/src/CanvasLayout.cs b/labs/CanvasLayout/src/CanvasLayout.cs index 007d63e85..ddd517bb0 100644 --- a/labs/CanvasLayout/src/CanvasLayout.cs +++ b/labs/CanvasLayout/src/CanvasLayout.cs @@ -7,117 +7,116 @@ using Microsoft.UI.Xaml.Controls; using Windows.Foundation; -namespace CommunityToolkit.Labs.WinUI +namespace CommunityToolkit.Labs.WinUI; + +public class CanvasLayout : VirtualizingLayout { - public class CanvasLayout : VirtualizingLayout + #region Setup / teardown + protected override void InitializeForContextCore(VirtualizingLayoutContext context) { - #region Setup / teardown - protected override void InitializeForContextCore(VirtualizingLayoutContext context) - { - base.InitializeForContextCore(context); + base.InitializeForContextCore(context); - if (context.LayoutState is not CanvasLayoutState) - { - // Store any state we might need since (in theory) the layout could be in use by multiple - // elements simultaneously - context.LayoutState = new CanvasLayoutState(); - } + if (context.LayoutState is not CanvasLayoutState) + { + // Store any state we might need since (in theory) the layout could be in use by multiple + // elements simultaneously + context.LayoutState = new CanvasLayoutState(); } + } - protected override void UninitializeForContextCore(VirtualizingLayoutContext context) - { - base.UninitializeForContextCore(context); + protected override void UninitializeForContextCore(VirtualizingLayoutContext context) + { + base.UninitializeForContextCore(context); - // clear any state - context.LayoutState = null; - } + // clear any state + context.LayoutState = null; + } - #endregion + #endregion - #region Layout + #region Layout - protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) - { - int maxWidth = 0; - int maxHeight = 0; + protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) + { + int maxWidth = 0; + int maxHeight = 0; - // Get underlying data about positioning of items and determine if in viewport. - for (int i = 0; i < context.ItemCount; i++) + // Get underlying data about positioning of items and determine if in viewport. + for (int i = 0; i < context.ItemCount; i++) + { + if (context.GetItemAt(i) is CanvasLayoutItem item) { - if (context.GetItemAt(i) is CanvasLayoutItem item) + // See if this item pushes our maximum boundary + maxWidth = Math.Max(item.Left + item.Width, maxWidth); + maxHeight = Math.Max(item.Top + item.Height, maxHeight); + + // Calculate if this item is in our current viewport + Rect rect = new(item.Left, item.Top, item.Width, item.Height); + rect.Intersect(context.RealizationRect); + + // Check if we're in view now so we can compare to if we were last time. + bool nowInView = rect.Width > 0 || rect.Height > 0; + + // If it wasn't visible and now is, realize the container + if (nowInView && !item.IsInView) { - // See if this item pushes our maximum boundary - maxWidth = Math.Max(item.Left + item.Width, maxWidth); - maxHeight = Math.Max(item.Top + item.Height, maxHeight); - - // Calculate if this item is in our current viewport - Rect rect = new(item.Left, item.Top, item.Width, item.Height); - rect.Intersect(context.RealizationRect); - - // Check if we're in view now so we can compare to if we were last time. - bool nowInView = rect.Width > 0 || rect.Height > 0; - - // If it wasn't visible and now is, realize the container - if (nowInView && !item.IsInView) - { - var element = context.GetOrCreateElementAt(i); - element.Measure(new Size(item.Width, item.Height)); - } - // If it was visible, but now isn't recycle the container - else if (!nowInView && item.IsInView) - { - var element = context.GetOrCreateElementAt(i); - context.RecycleElement(element); - } - - // Update our current visibility - item.IsInView = rect.Width > 0 || rect.Height > 0; + var element = context.GetOrCreateElementAt(i); + element.Measure(new Size(item.Width, item.Height)); + } + // If it was visible, but now isn't recycle the container + else if (!nowInView && item.IsInView) + { + var element = context.GetOrCreateElementAt(i); + context.RecycleElement(element); } - } - return new Size(maxWidth, maxHeight); + // Update our current visibility + item.IsInView = rect.Width > 0 || rect.Height > 0; + } } - protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) + return new Size(maxWidth, maxHeight); + } + + protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize) + { + for (int i = 0; i < context.ItemCount; i++) { - for (int i = 0; i < context.ItemCount; i++) + if (context.GetItemAt(i) is CanvasLayoutItem item && item.IsInView) { - if (context.GetItemAt(i) is CanvasLayoutItem item && item.IsInView) - { - var container = context.GetOrCreateElementAt(i); - // Is it better to have cached this from above? - container.Arrange(new Rect(item.Left, item.Top, item.Width, item.Height)); - } + var container = context.GetOrCreateElementAt(i); + // Is it better to have cached this from above? + container.Arrange(new Rect(item.Left, item.Top, item.Width, item.Height)); } - - return finalSize; } - #endregion + return finalSize; } - internal class CanvasLayoutState - { - public int FirstRealizedIndex { get; set; } + #endregion +} - /// - /// List of layout bounds for items starting with the - /// FirstRealizedIndex. - /// - public List LayoutRects { get; } = new List(); - } +internal class CanvasLayoutState +{ + public int FirstRealizedIndex { get; set; } - // TODO: Make DP? Can we do this with property mapping instead? - public class CanvasLayoutItem - { - public int Left { get; set; } + /// + /// List of layout bounds for items starting with the + /// FirstRealizedIndex. + /// + public List LayoutRects { get; } = new List(); +} + +// TODO: Make DP? Can we do this with property mapping instead? +public class CanvasLayoutItem +{ + public int Left { get; set; } - public int Top { get; set; } + public int Top { get; set; } - public int Width { get; set; } + public int Width { get; set; } - public int Height { get; set; } + public int Height { get; set; } - public bool IsInView { get; internal set; } - } + public bool IsInView { get; internal set; } } diff --git a/labs/CanvasLayout/tests/CanvasLayout.Tests/ExampleCanvasLayoutTestClass.cs b/labs/CanvasLayout/tests/CanvasLayout.Tests/ExampleCanvasLayoutTestClass.cs index 135ada1e3..a330e06f6 100644 --- a/labs/CanvasLayout/tests/CanvasLayout.Tests/ExampleCanvasLayoutTestClass.cs +++ b/labs/CanvasLayout/tests/CanvasLayout.Tests/ExampleCanvasLayoutTestClass.cs @@ -3,15 +3,14 @@ using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace CanvasLayout.Tests +namespace CanvasLayout.Tests; + +[TestClass] +public class ExampleCanvasLayoutTestClass { - [TestClass] - public class ExampleCanvasLayoutTestClass + [TestMethod] + public void Just_an_example_test() { - [TestMethod] - public void Just_an_example_test() - { - Assert.AreEqual(1, 1); - } + Assert.AreEqual(1, 1); } } diff --git a/labs/SizerBase/samples/SizerBase.Wasm/Program.cs b/labs/SizerBase/samples/SizerBase.Wasm/Program.cs index d1003ca2d..0dc2b567a 100644 --- a/labs/SizerBase/samples/SizerBase.Wasm/Program.cs +++ b/labs/SizerBase/samples/SizerBase.Wasm/Program.cs @@ -11,17 +11,16 @@ using Windows.UI.Xaml; #endif -namespace SizerBase.Wasm +namespace SizerBase.Wasm; + +public class Program { - public class Program - { - private static App? _app; + private static App? _app; - static int Main(string[] args) - { - Application.Start(_ => _app = new App()); + static int Main(string[] args) + { + Application.Start(_ => _app = new App()); - return 0; - } + return 0; } } diff --git a/platforms/CommunityToolkit.Labs.Droid/Main.cs b/platforms/CommunityToolkit.Labs.Droid/Main.cs index 82cf65bcf..eb4887df3 100644 --- a/platforms/CommunityToolkit.Labs.Droid/Main.cs +++ b/platforms/CommunityToolkit.Labs.Droid/Main.cs @@ -18,8 +18,8 @@ using Windows.UI.Xaml.Media; #endif -namespace CommunityToolkit.Labs.Droid -{ +namespace CommunityToolkit.Labs.Droid; + [global::Android.App.ApplicationAttribute( Label = "@string/ApplicationName", Icon = "@mipmap/icon", @@ -47,4 +47,3 @@ private void ConfigureUniversalImageLoader() ImageSource.DefaultImageLoader = ImageLoader.Instance.LoadImageAsync; } } -} diff --git a/platforms/CommunityToolkit.Labs.Droid/MainActivity.cs b/platforms/CommunityToolkit.Labs.Droid/MainActivity.cs index ad3a52a51..931badd35 100644 --- a/platforms/CommunityToolkit.Labs.Droid/MainActivity.cs +++ b/platforms/CommunityToolkit.Labs.Droid/MainActivity.cs @@ -10,8 +10,8 @@ using Windows.UI.Xaml; #endif -namespace CommunityToolkit.Labs.Droid -{ +namespace CommunityToolkit.Labs.Droid; + [Activity( MainLauncher = true, ConfigurationChanges = global::Uno.UI.ActivityHelper.AllConfigChanges, @@ -20,5 +20,4 @@ namespace CommunityToolkit.Labs.Droid public class MainActivity : ApplicationActivity { } -} diff --git a/platforms/CommunityToolkit.Labs.Skia.Gtk/Program.cs b/platforms/CommunityToolkit.Labs.Skia.Gtk/Program.cs index 02e305192..35dda2058 100644 --- a/platforms/CommunityToolkit.Labs.Skia.Gtk/Program.cs +++ b/platforms/CommunityToolkit.Labs.Skia.Gtk/Program.cs @@ -2,8 +2,8 @@ using GLib; using Uno.UI.Runtime.Skia; -namespace CommunityToolkit.Labs.Skia.Gtk -{ +namespace CommunityToolkit.Labs.Skia.Gtk; + class Program { static void Main(string[] args) @@ -19,4 +19,3 @@ static void Main(string[] args) host.Run(); } } -} diff --git a/platforms/CommunityToolkit.Labs.Skia.WPF.Host/App.xaml.cs b/platforms/CommunityToolkit.Labs.Skia.WPF.Host/App.xaml.cs index ff19086c9..5808d97fa 100644 --- a/platforms/CommunityToolkit.Labs.Skia.WPF.Host/App.xaml.cs +++ b/platforms/CommunityToolkit.Labs.Skia.WPF.Host/App.xaml.cs @@ -6,12 +6,11 @@ using System.Threading.Tasks; using System.Windows; -namespace CommunityToolkit.Labs.WPF.Host -{ +namespace CommunityToolkit.Labs.WPF.Host; + /// /// Interaction logic for App.xaml /// public partial class App : Application { } -} diff --git a/platforms/CommunityToolkit.Labs.Skia.WPF.Host/MainWindow.xaml.cs b/platforms/CommunityToolkit.Labs.Skia.WPF.Host/MainWindow.xaml.cs index a21ab81f6..8b37b4418 100644 --- a/platforms/CommunityToolkit.Labs.Skia.WPF.Host/MainWindow.xaml.cs +++ b/platforms/CommunityToolkit.Labs.Skia.WPF.Host/MainWindow.xaml.cs @@ -13,8 +13,8 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace CommunityToolkit.Labs.WPF.Host -{ +namespace CommunityToolkit.Labs.WPF.Host; + /// /// Interaction logic for MainWindow.xaml /// @@ -27,4 +27,3 @@ public MainWindow() root.Content = new global::Uno.UI.Skia.Platform.WpfHost(Dispatcher, () => new Shared.App()); } } -} diff --git a/platforms/CommunityToolkit.Labs.Skia.WPF/Program.cs b/platforms/CommunityToolkit.Labs.Skia.WPF/Program.cs index 098d05703..dcd0b6a34 100644 --- a/platforms/CommunityToolkit.Labs.Skia.WPF/Program.cs +++ b/platforms/CommunityToolkit.Labs.Skia.WPF/Program.cs @@ -1,3 +1 @@ -namespace CommunityToolkit.Labs.Skia.Gtk -{ -} +namespace CommunityToolkit.Labs.Skia.Gtk; diff --git a/platforms/CommunityToolkit.Labs.Wasm/Program.cs b/platforms/CommunityToolkit.Labs.Wasm/Program.cs index 8e0b71456..04a8d186f 100644 --- a/platforms/CommunityToolkit.Labs.Wasm/Program.cs +++ b/platforms/CommunityToolkit.Labs.Wasm/Program.cs @@ -7,8 +7,8 @@ using Windows.UI.Xaml; #endif -namespace CommunityToolkit.Labs.Wasm -{ +namespace CommunityToolkit.Labs.Wasm; + public class Program { private static App? _app; @@ -20,4 +20,3 @@ static int Main(string[] args) return 0; } } -} diff --git a/platforms/CommunityToolkit.Labs.iOS/Main.cs b/platforms/CommunityToolkit.Labs.iOS/Main.cs index d524bdd17..c4d4ad0de 100644 --- a/platforms/CommunityToolkit.Labs.iOS/Main.cs +++ b/platforms/CommunityToolkit.Labs.iOS/Main.cs @@ -1,7 +1,7 @@ using UIKit; -namespace CommunityToolkit.Labs.iOS -{ +namespace CommunityToolkit.Labs.iOS; + public class Application { // This is the main entry point of the application. @@ -11,5 +11,4 @@ static void Main(string[] args) // you can specify it here. UIApplication.Main(args, null, typeof(Shared.App)); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/platforms/CommunityToolkit.Labs.macOS/Main.cs b/platforms/CommunityToolkit.Labs.macOS/Main.cs index d1d1e181d..a64e1498a 100644 --- a/platforms/CommunityToolkit.Labs.macOS/Main.cs +++ b/platforms/CommunityToolkit.Labs.macOS/Main.cs @@ -1,7 +1,7 @@ using AppKit; -namespace CommunityToolkit.Labs.macOS -{ +namespace CommunityToolkit.Labs.macOS; + static class MainClass { static void Main(string[] args) @@ -11,5 +11,4 @@ static void Main(string[] args) NSApplication.Main(args); } } -} diff --git a/template/lab/samples/ProjectTemplate.Sample/ProjectTemplateFirstSamplePage.xaml.cs b/template/lab/samples/ProjectTemplate.Sample/ProjectTemplateFirstSamplePage.xaml.cs index 73ed64500..f5702dd7c 100644 --- a/template/lab/samples/ProjectTemplate.Sample/ProjectTemplateFirstSamplePage.xaml.cs +++ b/template/lab/samples/ProjectTemplate.Sample/ProjectTemplateFirstSamplePage.xaml.cs @@ -28,24 +28,23 @@ //+:cnd:noEmit -namespace ProjectTemplate.Sample +namespace ProjectTemplate.Sample; + +[ToolkitSampleBoolOption("IsTextVisible", "IsVisible", true)] +// Single values without a colon are used for both label and value. +// To provide a different label for the value, separate with a colon surrounded by a single space on both sides ("label : value"). +[ToolkitSampleMultiChoiceOption("TextSize", title: "Text size", "Small : 12", "Normal : 16", "Big : 32")] +[ToolkitSampleMultiChoiceOption("TextFontFamily", title: "Font family", "Segoe UI", "Arial", "Consolas")] +[ToolkitSampleMultiChoiceOption("TextForeground", title: "Text foreground", + "Teal : #0ddc8c", + "Sand : #e7a676", + "Dull green : #5d7577")] + +[ToolkitSample(id: nameof(ProjectTemplateFirstSamplePage), "Simple Options", description: "A sample page for showing how to do simple options.")] +public sealed partial class ProjectTemplateFirstSamplePage : Page { - [ToolkitSampleBoolOption("IsTextVisible", "IsVisible", true)] - // Single values without a colon are used for both label and value. - // To provide a different label for the value, separate with a colon surrounded by a single space on both sides ("label : value"). - [ToolkitSampleMultiChoiceOption("TextSize", title: "Text size", "Small : 12", "Normal : 16", "Big : 32")] - [ToolkitSampleMultiChoiceOption("TextFontFamily", title: "Font family", "Segoe UI", "Arial", "Consolas")] - [ToolkitSampleMultiChoiceOption("TextForeground", title: "Text foreground", - "Teal : #0ddc8c", - "Sand : #e7a676", - "Dull green : #5d7577")] - - [ToolkitSample(id: nameof(ProjectTemplateFirstSamplePage), "Simple Options", description: "A sample page for showing how to do simple options.")] - public sealed partial class ProjectTemplateFirstSamplePage : Page + public ProjectTemplateFirstSamplePage() { - public ProjectTemplateFirstSamplePage() - { - this.InitializeComponent(); - } + this.InitializeComponent(); } } diff --git a/template/lab/samples/ProjectTemplate.Wasm/Program.cs b/template/lab/samples/ProjectTemplate.Wasm/Program.cs index 86f3479d9..781d9c8cb 100644 --- a/template/lab/samples/ProjectTemplate.Wasm/Program.cs +++ b/template/lab/samples/ProjectTemplate.Wasm/Program.cs @@ -13,17 +13,16 @@ #endif //+:cnd:noEmit -namespace ProjectTemplate.Wasm +namespace ProjectTemplate.Wasm; + +public class Program { - public class Program - { - private static App? _app; + private static App? _app; - static int Main(string[] args) - { - Application.Start(_ => _app = new App()); + static int Main(string[] args) + { + Application.Start(_ => _app = new App()); - return 0; - } + return 0; } } diff --git a/template/lab/src/ProjectTemplate.cs b/template/lab/src/ProjectTemplate.cs index be6e7c8cb..6ca321150 100644 --- a/template/lab/src/ProjectTemplate.cs +++ b/template/lab/src/ProjectTemplate.cs @@ -26,9 +26,8 @@ #endif //+:cnd:noEmit -namespace CommunityToolkit.Labs.WinUI +namespace CommunityToolkit.Labs.WinUI; + +public class ProjectTemplate { - public class ProjectTemplate - { - } } diff --git a/template/lab/tests/ProjectTemplate.Tests/ExampleProjectTemplateTestClass.cs b/template/lab/tests/ProjectTemplate.Tests/ExampleProjectTemplateTestClass.cs index 30b397846..a89ad7534 100644 --- a/template/lab/tests/ProjectTemplate.Tests/ExampleProjectTemplateTestClass.cs +++ b/template/lab/tests/ProjectTemplate.Tests/ExampleProjectTemplateTestClass.cs @@ -27,16 +27,15 @@ #endif //+:cnd:noEmit -namespace ProjectTemplate.Tests +namespace ProjectTemplate.Tests; + +[TestClass] +public class ExampleProjectTemplateTestClass { - [TestClass] - public class ExampleProjectTemplateTestClass + [TestMethod] + public void SimpleExampleTest() { - [TestMethod] - public void SimpleExampleTest() - { - var systemUnderTest = new CommunityToolkit.Labs.WinUI.ProjectTemplate(); - Assert.IsNotNull(systemUnderTest); - } + var systemUnderTest = new CommunityToolkit.Labs.WinUI.ProjectTemplate(); + Assert.IsNotNull(systemUnderTest); } }