Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shell routing and Service registration automation #13402

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/Controls/src/Core/MauiServiceAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.Maui.Controls
{
[AttributeUsage(AttributeTargets.Class)]
public class MauiServiceAttribute : Attribute
{
/// <summary>
/// Type gets registered in the DI container, defaults to Singleton
/// </summary>
public MauiServiceAttribute(ServiceLifetime lifetime = ServiceLifetime.Singleton) => Lifetime = lifetime;

/// <summary>
/// Lifetime of the Service type on which this attribute is defined.
/// </summary>
public ServiceLifetime Lifetime { get; }

/// <summary>
/// The type for which this service would be resolved for.
/// <code>builder.Services.AddSingleton&lt;INavigationService, NavigationService&gt;();</code>
/// </summary>
public Type? RegisterFor { get; set; }

/// <summary>
/// If set to true, makes use of the TryAdd method construct while registering the service.
/// </summary>
public bool UseTryAdd { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
#nullable enable
*REMOVED*override Microsoft.Maui.Controls.RefreshView.MeasureOverride(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
Microsoft.Maui.Controls.LayoutOptions.Equals(Microsoft.Maui.Controls.LayoutOptions other) -> bool
Microsoft.Maui.Controls.MauiServiceAttribute
Microsoft.Maui.Controls.MauiServiceAttribute.MauiServiceAttribute(Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime = Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton) -> void
Microsoft.Maui.Controls.MauiServiceAttribute.RegisterFor.get -> System.Type?
Microsoft.Maui.Controls.MauiServiceAttribute.RegisterFor.set -> void
Microsoft.Maui.Controls.MauiServiceAttribute.Lifetime.get -> Microsoft.Extensions.DependencyInjection.ServiceLifetime
Microsoft.Maui.Controls.MauiServiceAttribute.UseTryAdd.get -> bool
Microsoft.Maui.Controls.MauiServiceAttribute.UseTryAdd.set -> void
Microsoft.Maui.Controls.Region.Equals(Microsoft.Maui.Controls.Region other) -> bool
Microsoft.Maui.Controls.RouteAttribute
Microsoft.Maui.Controls.RouteAttribute.ImplicitViewModel.get -> bool
Microsoft.Maui.Controls.RouteAttribute.ImplicitViewModel.set -> void
Microsoft.Maui.Controls.RouteAttribute.Route.get -> string?
Microsoft.Maui.Controls.RouteAttribute.RouteAttribute() -> void
Microsoft.Maui.Controls.RouteAttribute.RouteAttribute(string! route, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime = Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton) -> void
Microsoft.Maui.Controls.RouteAttribute.Routes.get -> string![]?
Microsoft.Maui.Controls.RouteAttribute.Routes.set -> void
Microsoft.Maui.Controls.RouteAttribute.Lifetime.get -> Microsoft.Extensions.DependencyInjection.ServiceLifetime
Microsoft.Maui.Controls.RouteAttribute.Lifetime.set -> void
Microsoft.Maui.Controls.RouteAttribute.ViewModelType.get -> System.Type?
Microsoft.Maui.Controls.RouteAttribute.ViewModelType.set -> void
Microsoft.Maui.Controls.Shapes.Matrix.Equals(Microsoft.Maui.Controls.Shapes.Matrix other) -> bool
Microsoft.Maui.Controls.VisualElement.~VisualElement() -> void
override Microsoft.Maui.Controls.LayoutOptions.GetHashCode() -> int
Expand Down
38 changes: 38 additions & 0 deletions src/Controls/src/Core/RouteAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.Maui.Controls
{
[AttributeUsage(AttributeTargets.Class)]
public class RouteAttribute : Attribute
{
public RouteAttribute() { }

public RouteAttribute(string route, ServiceLifetime lifetime = ServiceLifetime.Singleton)
=> (Route, Lifetime) = (route, lifetime);

public string? Route { get; }

/// <summary>
/// Routes of the View (page) type on which this attribute is defined.
/// When both Routes and Route properties are defined, Routes takes precedence.
/// </summary>
public string[]? Routes { get; set; }

/// <summary>
/// Lifetime of the View (page) / ViewModel type on which this attribute is defined.
/// </summary>
public ServiceLifetime Lifetime { get; set; }

/// <summary>
/// Indicates whether the ViewModel should be associated automatically.
/// </summary>
public bool ImplicitViewModel { get; set; }

/// <summary>
/// Type of the ViewModel associated with the View (page) on which this attribute is defined.
/// When both ImplicitViewModel and ViewModelType properties are defined, ViewModelType takes precedence.
/// </summary>
public Type? ViewModelType { get; set; }
}
}
52 changes: 52 additions & 0 deletions src/Controls/src/SourceGen/Helper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Microsoft.Maui.Controls.SourceGen
{
internal static class Helper
{
internal const string Singleton = nameof(Singleton);
internal const string Scoped = nameof(Scoped);
internal const string Transient = nameof(Transient);

// Determine the namespace the class/enum/struct/record is declared in, if any
internal static string GetNamespace(BaseTypeDeclarationSyntax syntax)
{
// If we don't have a namespace at all we'll return an empty string
// This accounts for the "default namespace" case
string @namespace = string.Empty;

// Get the containing syntax node for the type declaration
// (could be a nested type, for example)
SyntaxNode? potentialNamespaceParent = syntax.Parent;

// Keep moving "out" of nested classes etc until we get to a namespace
// or until we run out of parents
while (potentialNamespaceParent is not null
&& potentialNamespaceParent is not NamespaceDeclarationSyntax
&& potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax)
{
potentialNamespaceParent = potentialNamespaceParent.Parent;
}

// Build up the final namespace by looping until we no longer have a namespace declaration
if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent)
{
// We have a namespace. Use that as the type
@namespace = namespaceParent.Name.ToString();

// Keep moving "out" of the namespace declarations until we
// run out of nested namespace declarations
while (namespaceParent.Parent is NamespaceDeclarationSyntax parent)
{
// Add the outer namespace as a prefix to the final namespace
@namespace = $"{parent.Name}.{@namespace}";
namespaceParent = parent;
}
}

// return the final namespace
return @namespace;
}
}
}
Loading