зеркало из https://github.com/DeGsoft/maui-linux.git
105 строки
4.4 KiB
C#
105 строки
4.4 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Xml;
|
|
using System.Linq;
|
|
using System.Maui.Internals;
|
|
using System.Collections.Generic;
|
|
|
|
namespace System.Maui.Xaml
|
|
{
|
|
[ContentProperty(nameof(Key))]
|
|
public sealed class StaticResourceExtension : IMarkupExtension
|
|
{
|
|
public string Key { get; set; }
|
|
public object ProvideValue(IServiceProvider serviceProvider)
|
|
{
|
|
if (serviceProvider == null)
|
|
throw new ArgumentNullException(nameof(serviceProvider));
|
|
if (Key == null)
|
|
throw new XamlParseException("you must specify a key in {StaticResource}", serviceProvider);
|
|
if (!(serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideParentValues valueProvider))
|
|
throw new ArgumentException();
|
|
|
|
var xmlLineInfo = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) is IXmlLineInfoProvider xmlLineInfoProvider ? xmlLineInfoProvider.XmlLineInfo : null;
|
|
|
|
if ( !TryGetResource(Key, valueProvider.ParentObjects, out var resource, out var resourceDictionary)
|
|
&& !TryGetApplicationLevelResource(Key, out resource, out resourceDictionary))
|
|
throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
|
|
|
|
Diagnostics.ResourceDictionaryDiagnostics.OnStaticResourceResolved(resourceDictionary, Key, valueProvider.TargetObject, valueProvider.TargetProperty);
|
|
|
|
return CastTo(resource, valueProvider.TargetProperty);
|
|
}
|
|
|
|
//used by X.HR.F
|
|
internal static object CastTo(object value, object targetProperty)
|
|
{
|
|
var bp = targetProperty as BindableProperty;
|
|
var pi = targetProperty as PropertyInfo;
|
|
var propertyType = bp?.ReturnType ?? pi?.PropertyType;
|
|
if (propertyType == null)
|
|
{
|
|
if (value.GetType().GetTypeInfo().IsGenericType && (value.GetType().GetGenericTypeDefinition() == typeof(OnPlatform<>) || value.GetType().GetGenericTypeDefinition() == typeof(OnIdiom<>)))
|
|
{
|
|
// This is only there to support our backward compat story with pre 2.3.3 compiled Xaml project who was not providing TargetProperty
|
|
var method = value.GetType().GetRuntimeMethod("op_Implicit", new[] { value.GetType() });
|
|
value = method.Invoke(null, new[] { value });
|
|
}
|
|
return value;
|
|
}
|
|
if (propertyType.IsAssignableFrom(value.GetType()))
|
|
return value;
|
|
var implicit_op = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: propertyType)
|
|
?? propertyType.GetImplicitConversionOperator(fromType: value.GetType(), toType: propertyType);
|
|
if (implicit_op != null)
|
|
return implicit_op.Invoke(value, new[] { value });
|
|
|
|
//Special case for https://bugzilla.xamarin.com/show_bug.cgi?id=59818
|
|
//On OnPlatform, check for an opImplicit from the targetType
|
|
if (Device.Flags != null
|
|
&& Device.Flags.Contains("xamlDoubleImplicitOpHack")
|
|
&& value.GetType().GetTypeInfo().IsGenericType
|
|
&& (value.GetType().GetGenericTypeDefinition() == typeof(OnPlatform<>)))
|
|
{
|
|
var tType = value.GetType().GenericTypeArguments[0];
|
|
var opImplicit = tType.GetImplicitConversionOperator(fromType: tType, toType: propertyType)
|
|
?? propertyType.GetImplicitConversionOperator(fromType: tType, toType: propertyType);
|
|
|
|
if (opImplicit != null)
|
|
{
|
|
//convert the OnPlatform<T> to T
|
|
var opPlatformImplicitConversionOperator = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: tType);
|
|
value = opPlatformImplicitConversionOperator.Invoke(null, new[] { value });
|
|
|
|
//and convert to toType
|
|
value = opImplicit.Invoke(null, new[] { value });
|
|
return value;
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
bool TryGetResource(string key, IEnumerable<object> parentObjects, out object resource, out ResourceDictionary resourceDictionary)
|
|
{
|
|
resource = null;
|
|
resourceDictionary = null;
|
|
|
|
foreach (var p in parentObjects) {
|
|
var resDict = p is IResourcesProvider irp && irp.IsResourcesCreated ? irp.Resources : p as ResourceDictionary;
|
|
if (resDict == null)
|
|
continue;
|
|
if (resDict.TryGetValueAndSource(Key, out resource, out resourceDictionary))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool TryGetApplicationLevelResource(string key, out object resource, out ResourceDictionary resourceDictionary)
|
|
{
|
|
resource = null;
|
|
resourceDictionary = null;
|
|
return Application.Current != null && ((IResourcesProvider)Application.Current).IsResourcesCreated && Application.Current.Resources.TryGetValueAndSource (key, out resource, out resourceDictionary);
|
|
}
|
|
}
|
|
} |