using System;
namespace Xamarin.Forms
{
public abstract class RouteFactory
{
public abstract Element GetOrCreate();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Xamarin.Forms
{
public static class Routing
{
static int s_routeCount = 0;
static Dictionary<string, RouteFactory> s_routes = new Dictionary<string, RouteFactory>();
static Dictionary<string, Page> s_implicitPageRoutes = new Dictionary<string, Page>();
const string ImplicitPrefix = "IMPL_";
const string DefaultPrefix = "D_FAULT_";
internal const string PathSeparator = "/";
// We only need these while a navigation is happening
internal static void ClearImplicitPageRoutes()
{
s_implicitPageRoutes.Clear();
}
internal static void RegisterImplicitPageRoute(Page page)
{
var route = GetRoute(page);
if (!IsUserDefined(route))
s_implicitPageRoutes[route] = page;
}
// Shell works much better if the entire nav stack can be represented by a string
// If the users pushes pages without using routes we want these page keys tracked
internal static void RegisterImplicitPageRoutes(Shell shell)
{
foreach (var item in shell.Items)
{
foreach (var section in item.Items)
{
var navigationStackCount = section.Navigation.NavigationStack.Count;
for (int i = 1; i < navigationStackCount; i++)
{
RegisterImplicitPageRoute(section.Navigation.NavigationStack[i]);
}
var navigationModalStackCount = section.Navigation.ModalStack.Count;
for (int i = 0; i < navigationModalStackCount; i++)
{
var page = section.Navigation.ModalStack[i];
RegisterImplicitPageRoute(page);
if (page is NavigationPage np)
{
foreach (var npPages in np.Pages)
{
RegisterImplicitPageRoute(npPages);
}
}
}
}
}
}
internal static string GenerateImplicitRoute(string source)
{
if (IsImplicit(source))
return source;
return String.Concat(ImplicitPrefix, source);
}
internal static bool IsImplicit(string source)
{
return source.StartsWith(ImplicitPrefix, StringComparison.Ordinal);
}
internal static bool IsImplicit(BindableObject source)
{
return IsImplicit(GetRoute(source));
}
internal static bool IsDefault(string source)
{
return source.StartsWith(DefaultPrefix, StringComparison.Ordinal);
}
internal static bool IsDefault(BindableObject source)
{
return IsDefault(GetRoute(source));
}
internal static bool IsUserDefined(BindableObject source)
{
if (source == null)
return false;
return IsUserDefined(GetRoute(source));
}
internal static bool IsUserDefined(string route)
{
if (route == null)
return false;
return !(IsDefault(route) || IsImplicit(route));
}
internal static void Clear()
{
s_implicitPageRoutes.Clear();
s_routes.Clear();
}
public static readonly BindableProperty RouteProperty =
BindableProperty.CreateAttached("Route", typeof(string), typeof(Routing), null,
defaultValueCreator: CreateDefaultRoute);
static object CreateDefaultRoute(BindableObject bindable)
{
return $"{DefaultPrefix}{bindable.GetType().Name}{++s_routeCount}";
}
internal static string[] GetRouteKeys()
{
string[] keys = new string[s_routes.Count + s_implicitPageRoutes.Count];
s_routes.Keys.CopyTo(keys, 0);
s_implicitPageRoutes.Keys.CopyTo(keys, s_routes.Count);
return keys;
}
public static Element GetOrCreateContent(string route)
{
Element result = null;
if (s_implicitPageRoutes.TryGetValue(route, out var page))
{
return page;
}
if (s_routes.TryGetValue(route, out var content))
result = content.GetOrCreate();
if (result == null)
{
// okay maybe its a type, we'll try that just to be nice to the user
var type = Type.GetType(route);
if (type != null)
result = Activator.CreateInstance(type) as Element;
}
if (result != null)
SetRoute(result, route);
return result;
}
public static string GetRoute(BindableObject obj)
{
return (string)obj.GetValue(RouteProperty);
}
internal static string GetRoutePathIfNotImplicit(Element obj)
{
var source = GetRoute(obj);
if (IsImplicit(source))
return String.Empty;
return $"{source}/";
}
public static string FormatRoute(List<string> segments)
{
var route = FormatRoute(String.Join(PathSeparator, segments));
return route;
}
public static string FormatRoute(string route)
{
return route;
}
public static void RegisterRoute(string route, RouteFactory factory)
{
if (!String.IsNullOrWhiteSpace(route))
route = FormatRoute(route);
ValidateRoute(route, factory);
s_routes[route] = factory;
}
public static void UnRegisterRoute(string route)
{
if (s_routes.TryGetValue(route, out _))
s_routes.Remove(route);
}
public static void RegisterRoute(string route, Type type)
{
RegisterRoute(route, new TypeRouteFactory(type));
}
public static void SetRoute(Element obj, string value)
{
obj.SetValue(RouteProperty, value);
}
static void ValidateRoute(string route, RouteFactory routeFactory)
{
if (string.IsNullOrWhiteSpace(route))
throw new ArgumentNullException(nameof(route), "Route cannot be an empty string");
routeFactory = routeFactory ?? throw new ArgumentNullException(nameof(routeFactory), "Route Factory cannot be null");
var uri = new Uri(route, UriKind.RelativeOrAbsolute);
var parts = uri.OriginalString.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var part in parts)
{
if (IsImplicit(part))
throw new ArgumentException($"Route contains invalid characters in \"{part}\"");
}
RouteFactory existingRegistration = null;
if (s_routes.TryGetValue(route, out existingRegistration) && !existingRegistration.Equals(routeFactory))
throw new ArgumentException($"Duplicated Route: \"{route}\"");
}
class TypeRouteFactory : RouteFactory
{
readonly Type _type;
public TypeRouteFactory(Type type)
{
_type = type;
}
public override Element GetOrCreate()
{
return (Element)Activator.CreateInstance(_type);
}
public override bool Equals(object obj)
{
if ((obj is TypeRouteFactory typeRouteFactory))
return typeRouteFactory._type == _type;
return false;
}
public override int GetHashCode()
{
return _type.GetHashCode();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
public static class DependencyService
{
static bool s_initialized;
static readonly object s_dependencyLock = new object();
static readonly object s_initializeLock = new object();
static readonly List<Type> DependencyTypes = new List<Type>();
static readonly Dictionary<Type, DependencyData> DependencyImplementations = new Dictionary<Type, DependencyData>();
public static T Resolve<T>(DependencyFetchTarget fallbackFetchTarget = DependencyFetchTarget.GlobalInstance) where T : class
{
var result = DependencyResolver.Resolve(typeof(T)) as T;
return result ?? Get<T>(fallbackFetchTarget);
}
public static T Get<T>(DependencyFetchTarget fetchTarget = DependencyFetchTarget.GlobalInstance) where T : class
{
Initialize();
DependencyData dependencyImplementation;
lock (s_dependencyLock)
{
Type targetType = typeof(T);
if (!DependencyImplementations.TryGetValue(targetType, out dependencyImplementation))
{
Type implementor = FindImplementor(targetType);
DependencyImplementations[targetType] = (dependencyImplementation = implementor != null ? new DependencyData { ImplementorType = implementor } : null);
}
}
if (dependencyImplementation == null)
return null;
if (fetchTarget == DependencyFetchTarget.GlobalInstance)
{
if (dependencyImplementation.GlobalInstance == null)
{
lock (dependencyImplementation)
{
if (dependencyImplementation.GlobalInstance == null)
{
dependencyImplementation.GlobalInstance = Activator.CreateInstance(dependencyImplementation.ImplementorType);
}
}
}
return (T)dependencyImplementation.GlobalInstance;
}
return (T)Activator.CreateInstance(dependencyImplementation.ImplementorType);
}
public static void Register<T>() where T : class
{
Type type = typeof(T);
if (!DependencyTypes.Contains(type))
DependencyTypes.Add(type);
}
public static void Register<T, TImpl>() where T : class where TImpl : class, T
{
Type targetType = typeof(T);
Type implementorType = typeof(TImpl);
if (!DependencyTypes.Contains(targetType))
DependencyTypes.Add(targetType);
lock (s_dependencyLock)
DependencyImplementations[targetType] = new DependencyData { ImplementorType = implementorType };
}
public static void RegisterSingleton<T>(T instance) where T : class
{
Type targetType = typeof(T);
Type implementorType = typeof(T);
if (!DependencyTypes.Contains(targetType))
DependencyTypes.Add(targetType);
lock (s_dependencyLock)
DependencyImplementations[targetType] = new DependencyData { ImplementorType = implementorType, GlobalInstance = instance };
}
static Type FindImplementor(Type target) =>
DependencyTypes.FirstOrDefault(t => target.IsAssignableFrom(t));
static void Initialize()
{
if (s_initialized)
return;
lock (s_initializeLock)
{
if (s_initialized)
return;
Assembly[] assemblies = Device.GetAssemblies();
if (Internals.Registrar.ExtraAssemblies != null)
{
assemblies = assemblies.Union(Internals.Registrar.ExtraAssemblies).ToArray();
}
Initialize(assemblies);
}
}
internal static void Initialize(Assembly[] assemblies)
{
if (s_initialized)
return;
lock (s_initializeLock)
{
if (s_initialized)
return;
// Don't use LINQ for performance reasons
// Naive implementation can easily take over a second to run
foreach (Assembly assembly in assemblies)
{
object[] attributes = assembly.GetCustomAttributesSafe(typeof(DependencyAttribute));
if (attributes == null)
continue;
for (int i = 0; i < attributes.Length; i++)
{
DependencyAttribute attribute = (DependencyAttribute)attributes[i];
if (!DependencyTypes.Contains(attribute.Implementor))
{
DependencyTypes.Add(attribute.Implementor);
}
}
}
s_initialized = true;
}
}
class DependencyData
{
public object GlobalInstance { get; set; }
public Type ImplementorType { get; set; }
}
}
}
using System;
namespace Xamarin.Forms
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class DependencyAttribute : Attribute
{
public DependencyAttribute(Type implementorType)
{
Implementor = implementorType;
}
internal Type Implementor { get; private set; }
}
}
public Assembly[] GetAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies();
}
public Uri Location
{
get;
private set;
}
internal class RequestDefinition
{
public RequestDefinition(RouteRequestBuilder theWinningRoute, Shell shell)
{
Item = theWinningRoute.Item;
Section = theWinningRoute.Section ?? Item?.CurrentItem;
Content = theWinningRoute.Content ?? Section?.CurrentItem;
GlobalRoutes = theWinningRoute.GlobalRouteMatches;
List<String> builder = new List<string>();
if (Item?.Route != null)
builder.Add(Item.Route);
if (Section?.Route != null)
builder.Add(Section?.Route);
if (Content?.Route != null)
builder.Add(Content?.Route);
if (GlobalRoutes != null)
builder.AddRange(GlobalRoutes);
var uriPath = MakeUriString(builder);
var uri = ShellUriHandler.CreateUri(uriPath);
FullUri = ShellUriHandler.ConvertToStandardFormat(shell, uri);
}
string MakeUriString(List<string> segments)
{
if (segments[0].StartsWith("/", StringComparison.Ordinal) || segments[0].StartsWith("\\", StringComparison.Ordinal))
return String.Join("/", segments);
return $"//{String.Join("/", segments)}";
}
public Uri FullUri { get; }
public ShellItem Item { get; }
public ShellSection Section { get; }
public ShellContent Content { get; }
public List<string> GlobalRoutes { get; }
}
IDictionary<string, string> MergeData(Element shellElement, IDictionary<string, string> data, bool isPopping)
{
if (!isPopping)
return data;
var returnValue = new Dictionary<string, string>(data);
var existing = (IDictionary<string, string>)shellElement.GetValue(ShellContent.QueryAttributesProperty);
if (existing == null)
return data;
foreach (var datum in existing)
{
if (!returnValue.ContainsKey(datum.Key))
returnValue[datum.Key] = datum.Value;
}
return returnValue;
}
codecd
最新推荐文章于 2024-03-26 17:00:41 发布
这篇博客深入探讨了Xamarin.Forms中的路由注册与管理,包括RouteFactory和Routing静态类的功能,以及如何创建和查找页面内容。同时,文章也介绍了DependencyService,它是Xamarin.Forms中实现依赖注入的机制,用于跨平台获取服务实例。内容涵盖了注册、解析和初始化过程。
摘要由CSDN通过智能技术生成