зеркало из https://github.com/DeGsoft/maui-linux.git
[X] add callback for previewer on failing ctor (#5101)
Add a callback when object instantiation or creation fails, so the previewer can replace it by an educated guess
This commit is contained in:
Родитель
50d3499670
Коммит
c71149c89b
|
@ -22,6 +22,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
Device.PlatformServices = null;
|
||||
XamlLoader.FallbackTypeResolver = null;
|
||||
XamlLoader.ValueCreatedCallback = null;
|
||||
XamlLoader.InstantiationFailedCallback = null;
|
||||
Xamarin.Forms.Internals.ResourceLoader.ExceptionHandler = null;
|
||||
}
|
||||
|
||||
|
@ -450,5 +451,41 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
|
||||
Assert.That(myButton.BackgroundColor, Is.Not.EqualTo(Color.Blue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanReplaceTypeWhenInstantiationThrows()
|
||||
{
|
||||
var xaml = @"
|
||||
<ContentPage xmlns=""http://xamarin.com/schemas/2014/forms""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
|
||||
xmlns:local=""clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests""
|
||||
xmlns:missing=""clr-namespace:MissingNamespace;assembly=MissingAssembly"">
|
||||
<StackLayout>
|
||||
<local:InstantiateThrows />
|
||||
<local:InstantiateThrows x:FactoryMethod=""CreateInstance"" />
|
||||
<local:InstantiateThrows>
|
||||
<x:Arguments>
|
||||
<x:Int32>1</x:Int32>
|
||||
</x:Arguments>
|
||||
</local:InstantiateThrows>
|
||||
<missing:Test>
|
||||
<x:Arguments>
|
||||
<x:Int32>1</x:Int32>
|
||||
</x:Arguments>
|
||||
</missing:Test>
|
||||
</StackLayout>
|
||||
</ContentPage>";
|
||||
XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(Button);
|
||||
XamlLoader.InstantiationFailedCallback = (type) => new Button();
|
||||
var o = XamlLoader.Create(xaml, true);
|
||||
Assert.DoesNotThrow(() => XamlLoader.Create(xaml, true));
|
||||
}
|
||||
}
|
||||
|
||||
public class InstantiateThrows
|
||||
{
|
||||
public InstantiateThrows() => throw new InvalidOperationException();
|
||||
public static InstantiateThrows CreateInstance() => throw new InvalidOperationException();
|
||||
public InstantiateThrows(int value) => throw new InvalidOperationException();
|
||||
}
|
||||
}
|
|
@ -7,11 +7,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
[XamlCompilation(XamlCompilationOptions.Skip)]
|
||||
public partial class FactoryMethodMissingCtor : MockView
|
||||
{
|
||||
public FactoryMethodMissingCtor()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public FactoryMethodMissingCtor() => InitializeComponent();
|
||||
public FactoryMethodMissingCtor(bool useCompiledXaml)
|
||||
{
|
||||
//this stub will be replaced at compile time
|
||||
|
@ -20,15 +16,11 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
[TestFixture]
|
||||
public class Tests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
Device.PlatformServices = new MockPlatformServices();
|
||||
}
|
||||
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
|
||||
[TearDown] public void TearDown() => Device.PlatformServices = null;
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void Throw(bool useCompiledXaml)
|
||||
[Test]
|
||||
public void Throw([Values(false, true)]bool useCompiledXaml)
|
||||
{
|
||||
if (useCompiledXaml)
|
||||
Assert.Throws(new XamlParseExceptionConstraint(7, 4), () => MockCompiler.Compile(typeof(FactoryMethodMissingCtor)));
|
||||
|
|
|
@ -80,8 +80,14 @@ namespace Xamarin.Forms.Xaml
|
|||
if (converted != null && converted.GetType() == type)
|
||||
value = converted;
|
||||
}
|
||||
if (value == null)
|
||||
value = Activator.CreateInstance(type);
|
||||
if (value == null) {
|
||||
try {
|
||||
value = Activator.CreateInstance(type);
|
||||
}
|
||||
catch (TargetInvocationException tie) {
|
||||
value = XamlLoader.InstantiationFailedCallback?.Invoke(new XamlLoader.CallbackTypeInfo { XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = node.XmlType.Name }) ?? throw tie;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TargetInvocationException e) when (e.InnerException is XamlParseException || e.InnerException is XmlException) {
|
||||
throw e.InnerException;
|
||||
|
@ -181,7 +187,13 @@ namespace Xamarin.Forms.Xaml
|
|||
ci.GetParameters().Length != 0 && ci.IsPublic &&
|
||||
ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof (ParameterAttribute))));
|
||||
object[] arguments = CreateArgumentsArray(node, ctorInfo);
|
||||
return ctorInfo.Invoke(arguments);
|
||||
try {
|
||||
return ctorInfo.Invoke(arguments);
|
||||
}
|
||||
catch (Exception e) when (e is TargetInvocationException || e is MissingMemberException) {
|
||||
return XamlLoader.InstantiationFailedCallback?.Invoke(new XamlLoader.CallbackTypeInfo { XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = node.XmlType.Name }) ?? throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public object CreateFromFactory(Type nodeType, IElementNode node)
|
||||
|
@ -191,7 +203,12 @@ namespace Xamarin.Forms.Xaml
|
|||
if (!node.Properties.ContainsKey(XmlName.xFactoryMethod))
|
||||
{
|
||||
//non-default ctor
|
||||
return Activator.CreateInstance(nodeType, arguments);
|
||||
try {
|
||||
return Activator.CreateInstance(nodeType, arguments);
|
||||
}
|
||||
catch (Exception e) when (e is TargetInvocationException || e is MissingMemberException) {
|
||||
return XamlLoader.InstantiationFailedCallback?.Invoke(new XamlLoader.CallbackTypeInfo { XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = node.XmlType.Name }) ?? throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var factoryMethod = ((string)((ValueNode)node.Properties[XmlName.xFactoryMethod]).Value);
|
||||
|
@ -219,7 +236,12 @@ namespace Xamarin.Forms.Xaml
|
|||
var mi = nodeType.GetRuntimeMethods().FirstOrDefault(isMatch);
|
||||
if (mi == null)
|
||||
throw new MissingMemberException($"No static method found for {nodeType.FullName}::{factoryMethod} ({string.Join(", ", types.Select(t => t.FullName))})");
|
||||
return mi.Invoke(null, arguments);
|
||||
try {
|
||||
return mi.Invoke(null, arguments);
|
||||
}
|
||||
catch (TargetInvocationException tie) {
|
||||
return XamlLoader.InstantiationFailedCallback?.Invoke(new XamlLoader.CallbackTypeInfo { XmlNamespace = node.XmlType.NamespaceUri, XmlTypeName = node.XmlType.Name}) ?? throw tie;
|
||||
}
|
||||
}
|
||||
|
||||
public object[] CreateArgumentsArray(IElementNode enode)
|
||||
|
|
|
@ -317,5 +317,6 @@ namespace Xamarin.Forms.Xaml
|
|||
|
||||
internal static Func<IList<FallbackTypeInfo>, Type, Type> FallbackTypeResolver { get; set; }
|
||||
internal static Action<CallbackTypeInfo, object> ValueCreatedCallback { get; set; }
|
||||
internal static Func<CallbackTypeInfo, object> InstantiationFailedCallback { get; set; }
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче