committed by
Andrey Kunchev
21 changed files with 1105 additions and 231 deletions
@ -0,0 +1,15 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Metadata |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines the property that contains the object's content in markup.
|
||||
|
/// </summary>
|
||||
|
[AttributeUsage(AttributeTargets.Property)] |
||||
|
public class TemplateContentAttribute : Attribute |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,225 +1,11 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
namespace Avalonia.Markup.Xaml |
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.IO; |
|
||||
using System.Reflection; |
|
||||
using System.Text; |
|
||||
using OmniXaml; |
|
||||
using Avalonia.Platform; |
|
||||
using Avalonia.Markup.Xaml.Context; |
|
||||
using Avalonia.Markup.Xaml.Styling; |
|
||||
using OmniXaml.ObjectAssembler; |
|
||||
using Avalonia.Controls; |
|
||||
using Avalonia.Markup.Xaml.Data; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml |
|
||||
{ |
{ |
||||
/// <summary>
|
public class AvaloniaXamlLoader : |
||||
/// Loads XAML for a avalonia application.
|
#if OMNIXAML
|
||||
/// </summary>
|
AvaloniaXamlLoaderOmniXaml |
||||
public class AvaloniaXamlLoader : XmlLoader |
#else
|
||||
|
AvaloniaXamlLoaderPortableXaml |
||||
|
#endif
|
||||
{ |
{ |
||||
private static AvaloniaParserFactory s_parserFactory; |
|
||||
private static IInstanceLifeCycleListener s_lifeCycleListener = new AvaloniaLifeCycleListener(); |
|
||||
private static Stack<Uri> s_uriStack = new Stack<Uri>(); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
|
|
||||
/// </summary>
|
|
||||
public AvaloniaXamlLoader() |
|
||||
: this(GetParserFactory()) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="xamlParserFactory">The parser factory to use.</param>
|
|
||||
public AvaloniaXamlLoader(IParserFactory xamlParserFactory) |
|
||||
: base(xamlParserFactory) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the URI of the XAML file currently being loaded.
|
|
||||
/// </summary>
|
|
||||
/// <remarks>
|
|
||||
/// TODO: Making this internal for now as I'm not sure that this is the correct
|
|
||||
/// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
|
|
||||
/// the currently loading XAML file, as we can't use the OmniXAML parsing context
|
|
||||
/// there. Maybe we need a way to inject OmniXAML context into the objects its
|
|
||||
/// constructing?
|
|
||||
/// </remarks>
|
|
||||
internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Loads the XAML into a Avalonia component.
|
|
||||
/// </summary>
|
|
||||
/// <param name="obj">The object to load the XAML into.</param>
|
|
||||
public static void Load(object obj) |
|
||||
{ |
|
||||
Contract.Requires<ArgumentNullException>(obj != null); |
|
||||
|
|
||||
var loader = new AvaloniaXamlLoader(); |
|
||||
loader.Load(obj.GetType(), obj); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Loads the XAML for a type.
|
|
||||
/// </summary>
|
|
||||
/// <param name="type">The type.</param>
|
|
||||
/// <param name="rootInstance">
|
|
||||
/// The optional instance into which the XAML should be loaded.
|
|
||||
/// </param>
|
|
||||
/// <returns>The loaded object.</returns>
|
|
||||
public object Load(Type type, object rootInstance = null) |
|
||||
{ |
|
||||
Contract.Requires<ArgumentNullException>(type != null); |
|
||||
|
|
||||
// HACK: Currently Visual Studio is forcing us to change the extension of xaml files
|
|
||||
// in certain situations, so we try to load .xaml and if that's not found we try .xaml.
|
|
||||
// Ideally we'd be able to use .xaml everywhere
|
|
||||
var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
|
||||
|
|
||||
if (assetLocator == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException( |
|
||||
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); |
|
||||
} |
|
||||
|
|
||||
foreach (var uri in GetUrisFor(type)) |
|
||||
{ |
|
||||
if (assetLocator.Exists(uri)) |
|
||||
{ |
|
||||
using (var stream = assetLocator.Open(uri)) |
|
||||
{ |
|
||||
var initialize = rootInstance as ISupportInitialize; |
|
||||
initialize?.BeginInit(); |
|
||||
return Load(stream, rootInstance, uri); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
throw new FileNotFoundException("Unable to find view for " + type.FullName); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Loads XAML from a URI.
|
|
||||
/// </summary>
|
|
||||
/// <param name="uri">The URI of the XAML file.</param>
|
|
||||
/// <param name="baseUri">
|
|
||||
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
||||
/// </param>
|
|
||||
/// <param name="rootInstance">
|
|
||||
/// The optional instance into which the XAML should be loaded.
|
|
||||
/// </param>
|
|
||||
/// <returns>The loaded object.</returns>
|
|
||||
public object Load(Uri uri, Uri baseUri = null, object rootInstance = null) |
|
||||
{ |
|
||||
Contract.Requires<ArgumentNullException>(uri != null); |
|
||||
|
|
||||
var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
|
||||
|
|
||||
if (assetLocator == null) |
|
||||
{ |
|
||||
throw new InvalidOperationException( |
|
||||
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); |
|
||||
} |
|
||||
|
|
||||
using (var stream = assetLocator.Open(uri, baseUri)) |
|
||||
{ |
|
||||
return Load(stream, rootInstance, uri); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Loads XAML from a string.
|
|
||||
/// </summary>
|
|
||||
/// <param name="xaml">The string containing the XAML.</param>
|
|
||||
/// <param name="rootInstance">
|
|
||||
/// The optional instance into which the XAML should be loaded.
|
|
||||
/// </param>
|
|
||||
/// <returns>The loaded object.</returns>
|
|
||||
public object Load(string xaml, object rootInstance = null) |
|
||||
{ |
|
||||
Contract.Requires<ArgumentNullException>(xaml != null); |
|
||||
|
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml))) |
|
||||
{ |
|
||||
return Load(stream, rootInstance); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Loads XAML from a stream.
|
|
||||
/// </summary>
|
|
||||
/// <param name="stream">The stream containing the XAML.</param>
|
|
||||
/// <param name="rootInstance">
|
|
||||
/// The optional instance into which the XAML should be loaded.
|
|
||||
/// </param>
|
|
||||
/// <param name="uri">The URI of the XAML</param>
|
|
||||
/// <returns>The loaded object.</returns>
|
|
||||
public object Load(Stream stream, object rootInstance = null, Uri uri = null) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
if (uri != null) |
|
||||
{ |
|
||||
s_uriStack.Push(uri); |
|
||||
} |
|
||||
|
|
||||
var result = base.Load(stream, new Settings |
|
||||
{ |
|
||||
RootInstance = rootInstance, |
|
||||
InstanceLifeCycleListener = s_lifeCycleListener, |
|
||||
ParsingContext = new Dictionary<string, object> |
|
||||
{ |
|
||||
{ "Uri", uri } |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
var topLevel = result as TopLevel; |
|
||||
|
|
||||
if (topLevel != null) |
|
||||
{ |
|
||||
DelayedBinding.ApplyBindings(topLevel); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
finally |
|
||||
{ |
|
||||
if (uri != null) |
|
||||
{ |
|
||||
s_uriStack.Pop(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static AvaloniaParserFactory GetParserFactory() |
|
||||
{ |
|
||||
if (s_parserFactory == null) |
|
||||
{ |
|
||||
s_parserFactory = new AvaloniaParserFactory(); |
|
||||
} |
|
||||
|
|
||||
return s_parserFactory; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the URI for a type.
|
|
||||
/// </summary>
|
|
||||
/// <param name="type">The type.</param>
|
|
||||
/// <returns>The URI.</returns>
|
|
||||
private static IEnumerable<Uri> GetUrisFor(Type type) |
|
||||
{ |
|
||||
var asm = type.GetTypeInfo().Assembly.GetName().Name; |
|
||||
var typeName = type.FullName; |
|
||||
yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); |
|
||||
yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); |
|
||||
|
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,227 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Reflection; |
||||
|
using System.Text; |
||||
|
using OmniXaml; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Markup.Xaml.Context; |
||||
|
using Avalonia.Markup.Xaml.Styling; |
||||
|
using OmniXaml.ObjectAssembler; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Markup.Xaml.Data; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml |
||||
|
{ |
||||
|
#if OMNIXAML
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML for a avalonia application.
|
||||
|
/// </summary>
|
||||
|
public class AvaloniaXamlLoaderOmniXaml : XmlLoader |
||||
|
{ |
||||
|
private static AvaloniaParserFactory s_parserFactory; |
||||
|
private static IInstanceLifeCycleListener s_lifeCycleListener = new AvaloniaLifeCycleListener(); |
||||
|
private static Stack<Uri> s_uriStack = new Stack<Uri>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
|
||||
|
/// </summary>
|
||||
|
public AvaloniaXamlLoaderOmniXaml() |
||||
|
: this(GetParserFactory()) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="xamlParserFactory">The parser factory to use.</param>
|
||||
|
public AvaloniaXamlLoaderOmniXaml(IParserFactory xamlParserFactory) |
||||
|
: base(xamlParserFactory) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the URI of the XAML file currently being loaded.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// TODO: Making this internal for now as I'm not sure that this is the correct
|
||||
|
/// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
|
||||
|
/// the currently loading XAML file, as we can't use the OmniXAML parsing context
|
||||
|
/// there. Maybe we need a way to inject OmniXAML context into the objects its
|
||||
|
/// constructing?
|
||||
|
/// </remarks>
|
||||
|
internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the XAML into a Avalonia component.
|
||||
|
/// </summary>
|
||||
|
/// <param name="obj">The object to load the XAML into.</param>
|
||||
|
public static void Load(object obj) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(obj != null); |
||||
|
|
||||
|
var loader = new AvaloniaXamlLoaderOmniXaml(); |
||||
|
loader.Load(obj.GetType(), obj); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the XAML for a type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type.</param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(Type type, object rootInstance = null) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(type != null); |
||||
|
|
||||
|
// HACK: Currently Visual Studio is forcing us to change the extension of xaml files
|
||||
|
// in certain situations, so we try to load .xaml and if that's not found we try .xaml.
|
||||
|
// Ideally we'd be able to use .xaml everywhere
|
||||
|
var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
||||
|
|
||||
|
if (assetLocator == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException( |
||||
|
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); |
||||
|
} |
||||
|
|
||||
|
foreach (var uri in GetUrisFor(type)) |
||||
|
{ |
||||
|
if (assetLocator.Exists(uri)) |
||||
|
{ |
||||
|
using (var stream = assetLocator.Open(uri)) |
||||
|
{ |
||||
|
var initialize = rootInstance as ISupportInitialize; |
||||
|
initialize?.BeginInit(); |
||||
|
return Load(stream, rootInstance, uri); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
throw new FileNotFoundException("Unable to find view for " + type.FullName); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML from a URI.
|
||||
|
/// </summary>
|
||||
|
/// <param name="uri">The URI of the XAML file.</param>
|
||||
|
/// <param name="baseUri">
|
||||
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
||||
|
/// </param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(Uri uri, Uri baseUri = null, object rootInstance = null) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(uri != null); |
||||
|
|
||||
|
var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
||||
|
|
||||
|
if (assetLocator == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException( |
||||
|
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); |
||||
|
} |
||||
|
|
||||
|
using (var stream = assetLocator.Open(uri, baseUri)) |
||||
|
{ |
||||
|
return Load(stream, rootInstance, uri); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML from a string.
|
||||
|
/// </summary>
|
||||
|
/// <param name="xaml">The string containing the XAML.</param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(string xaml, object rootInstance = null) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(xaml != null); |
||||
|
|
||||
|
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml))) |
||||
|
{ |
||||
|
return Load(stream, rootInstance); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML from a stream.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream containing the XAML.</param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <param name="uri">The URI of the XAML</param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(Stream stream, object rootInstance = null, Uri uri = null) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
if (uri != null) |
||||
|
{ |
||||
|
s_uriStack.Push(uri); |
||||
|
} |
||||
|
|
||||
|
var result = base.Load(stream, new Settings |
||||
|
{ |
||||
|
RootInstance = rootInstance, |
||||
|
InstanceLifeCycleListener = s_lifeCycleListener, |
||||
|
ParsingContext = new Dictionary<string, object> |
||||
|
{ |
||||
|
{ "Uri", uri } |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
var topLevel = result as TopLevel; |
||||
|
|
||||
|
if (topLevel != null) |
||||
|
{ |
||||
|
DelayedBinding.ApplyBindings(topLevel); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
if (uri != null) |
||||
|
{ |
||||
|
s_uriStack.Pop(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static AvaloniaParserFactory GetParserFactory() |
||||
|
{ |
||||
|
if (s_parserFactory == null) |
||||
|
{ |
||||
|
s_parserFactory = new AvaloniaParserFactory(); |
||||
|
} |
||||
|
|
||||
|
return s_parserFactory; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the URI for a type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type.</param>
|
||||
|
/// <returns>The URI.</returns>
|
||||
|
private static IEnumerable<Uri> GetUrisFor(Type type) |
||||
|
{ |
||||
|
var asm = type.GetTypeInfo().Assembly.GetName().Name; |
||||
|
var typeName = type.FullName; |
||||
|
yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); |
||||
|
yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
#endif
|
||||
|
} |
||||
@ -0,0 +1,219 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Reflection; |
||||
|
using System.Text; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Markup.Xaml.Context; |
||||
|
using Avalonia.Markup.Xaml.Data; |
||||
|
using Avalonia.Markup.Xaml.PortableXaml; |
||||
|
using Avalonia.Platform; |
||||
|
using Portable.Xaml; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Loads XAML for a avalonia application.
|
||||
|
/// </summary>
|
||||
|
public class AvaloniaXamlLoaderPortableXaml |
||||
|
{ |
||||
|
internal static readonly AvaloniaXamlSchemaContext _context |
||||
|
= new AvaloniaXamlSchemaContext(new AvaloniaRuntimeTypeProvider()); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
|
||||
|
/// </summary>
|
||||
|
public AvaloniaXamlLoaderPortableXaml() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the URI of the XAML file currently being loaded.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// TODO: Making this internal for now as I'm not sure that this is the correct
|
||||
|
/// thing to do, but its needed by <see cref="StyleInclude"/> to get the URL of
|
||||
|
/// the currently loading XAML file, as we can't use the OmniXAML parsing context
|
||||
|
/// there. Maybe we need a way to inject OmniXAML context into the objects its
|
||||
|
/// constructing?
|
||||
|
/// </remarks>
|
||||
|
[Obsolete] |
||||
|
internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null; |
||||
|
|
||||
|
private static Stack<Uri> s_uriStack = new Stack<Uri>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the XAML into a Avalonia component.
|
||||
|
/// </summary>
|
||||
|
/// <param name="obj">The object to load the XAML into.</param>
|
||||
|
public static void Load(object obj) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(obj != null); |
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
loader.Load(obj.GetType(), obj); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads the XAML for a type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type.</param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(Type type, object rootInstance = null) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(type != null); |
||||
|
|
||||
|
// HACK: Currently Visual Studio is forcing us to change the extension of xaml files
|
||||
|
// in certain situations, so we try to load .xaml and if that's not found we try .xaml.
|
||||
|
// Ideally we'd be able to use .xaml everywhere
|
||||
|
var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
||||
|
|
||||
|
if (assetLocator == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException( |
||||
|
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); |
||||
|
} |
||||
|
|
||||
|
foreach (var uri in GetUrisFor(type)) |
||||
|
{ |
||||
|
if (assetLocator.Exists(uri)) |
||||
|
{ |
||||
|
using (var stream = assetLocator.Open(uri)) |
||||
|
{ |
||||
|
var initialize = rootInstance as ISupportInitialize; |
||||
|
initialize?.BeginInit(); |
||||
|
return Load(stream, type, rootInstance, uri); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
throw new FileNotFoundException("Unable to find view for " + type.FullName); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML from a URI.
|
||||
|
/// </summary>
|
||||
|
/// <param name="uri">The URI of the XAML file.</param>
|
||||
|
/// <param name="baseUri">
|
||||
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
||||
|
/// </param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(Uri uri, Uri baseUri = null, object rootInstance = null) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(uri != null); |
||||
|
|
||||
|
var assetLocator = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
||||
|
|
||||
|
if (assetLocator == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException( |
||||
|
"Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); |
||||
|
} |
||||
|
|
||||
|
using (var stream = assetLocator.Open(uri, baseUri)) |
||||
|
{ |
||||
|
return Load(stream, null, rootInstance, uri); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML from a string.
|
||||
|
/// </summary>
|
||||
|
/// <param name="xaml">The string containing the XAML.</param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(string xaml, Type type = null, object rootInstance = null) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(xaml != null); |
||||
|
|
||||
|
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml))) |
||||
|
{ |
||||
|
return Load(stream, type, rootInstance); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Loads XAML from a stream.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream containing the XAML.</param>
|
||||
|
/// <param name="rootInstance">
|
||||
|
/// The optional instance into which the XAML should be loaded.
|
||||
|
/// </param>
|
||||
|
/// <param name="uri">The URI of the XAML</param>
|
||||
|
/// <returns>The loaded object.</returns>
|
||||
|
public object Load(Stream stream, Type type = null, object rootInstance = null, Uri uri = null) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
if (uri != null) |
||||
|
{ |
||||
|
s_uriStack.Push(uri); |
||||
|
} |
||||
|
|
||||
|
var readerSettings = new XamlXmlReaderSettings(); |
||||
|
|
||||
|
if (rootInstance != null && type == null) |
||||
|
{ |
||||
|
type = rootInstance.GetType(); |
||||
|
} |
||||
|
|
||||
|
if (type != null) |
||||
|
{ |
||||
|
readerSettings.LocalAssembly = type.GetTypeInfo().Assembly; |
||||
|
} |
||||
|
|
||||
|
var reader = new XamlXmlReader(stream, _context, readerSettings); |
||||
|
object result = Load(reader, rootInstance); |
||||
|
|
||||
|
var topLevel = result as TopLevel; |
||||
|
|
||||
|
if (topLevel != null) |
||||
|
{ |
||||
|
DelayedBinding.ApplyBindings(topLevel); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
if (uri != null) |
||||
|
{ |
||||
|
s_uriStack.Pop(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal static object Load(XamlXmlReader reader, object instance) |
||||
|
{ |
||||
|
var writer = AvaloniaXamlObjectWriter.Create(_context, instance); |
||||
|
|
||||
|
XamlServices.Transform(reader, writer); |
||||
|
|
||||
|
return writer.Result; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the URI for a type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type.</param>
|
||||
|
/// <returns>The URI.</returns>
|
||||
|
private static IEnumerable<Uri> GetUrisFor(Type type) |
||||
|
{ |
||||
|
var asm = type.GetTypeInfo().Assembly.GetName().Name; |
||||
|
var typeName = type.FullName; |
||||
|
yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); |
||||
|
yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Avalonia.Markup.Xaml.Templates; |
||||
|
using Portable.Xaml.ComponentModel; |
||||
|
using avm = Avalonia.Metadata; |
||||
|
using pm = Portable.Xaml.Markup; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.PortableXaml |
||||
|
{ |
||||
|
public class AvaloniaMemberAttributeProvider : ICustomAttributeProvider |
||||
|
{ |
||||
|
public AvaloniaMemberAttributeProvider(MemberInfo info) |
||||
|
{ |
||||
|
_info = info; |
||||
|
} |
||||
|
|
||||
|
public object[] GetCustomAttributes(bool inherit) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public object[] GetCustomAttributes(Type attributeType, bool inherit) |
||||
|
{ |
||||
|
object[] result = null; |
||||
|
|
||||
|
if (attributeType == typeof(pm.XamlDeferLoadAttribute)) |
||||
|
{ |
||||
|
var attr = GetXamlDeferLoadAttribute(inherit); |
||||
|
|
||||
|
if (attr != null) |
||||
|
{ |
||||
|
result = new object[] { attr }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (result == null || result.Length == 0) |
||||
|
{ |
||||
|
var attr = _info.GetCustomAttributes(attributeType, inherit); |
||||
|
return (attr as object[]) ?? attr.ToArray(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool IsDefined(Type attributeType, bool inherit) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
private readonly MemberInfo _info; |
||||
|
|
||||
|
private Attribute GetXamlDeferLoadAttribute(bool inherit) |
||||
|
{ |
||||
|
var result = _info.GetCustomAttributes(typeof(avm.TemplateContentAttribute), inherit) |
||||
|
.Cast<avm.TemplateContentAttribute>() |
||||
|
.FirstOrDefault(); |
||||
|
|
||||
|
if (result == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return new pm.XamlDeferLoadAttribute(typeof(TemplateLoader), typeof(TemplateContent)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.PortableXaml |
||||
|
{ |
||||
|
internal class AvaloniaNameScope : Portable.Xaml.Markup.INameScope |
||||
|
{ |
||||
|
public object Instance { get; set; } |
||||
|
|
||||
|
private Dictionary<string, object> _names = new Dictionary<string, object>(); |
||||
|
|
||||
|
public object FindName(string name) |
||||
|
{ |
||||
|
object result; |
||||
|
if (_names.TryGetValue(name, out result)) |
||||
|
return result; |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public void RegisterName(string name, object scopedElement) |
||||
|
{ |
||||
|
if (scopedElement != null) |
||||
|
_names.Add(name, scopedElement); |
||||
|
|
||||
|
//TODO: ???
|
||||
|
//var control = scopedElement as Control;
|
||||
|
|
||||
|
//if (control != null)
|
||||
|
//{
|
||||
|
// var nameScope = (Instance as INameScope) ?? control.FindNameScope();
|
||||
|
|
||||
|
// if (nameScope != null)
|
||||
|
// {
|
||||
|
// nameScope.Register(name, scopedElement);
|
||||
|
// }
|
||||
|
//}
|
||||
|
} |
||||
|
|
||||
|
public void UnregisterName(string name) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void RegisterOnNameScope(object target) |
||||
|
{ |
||||
|
var nameScope = target as INameScope; |
||||
|
|
||||
|
if (nameScope != null) |
||||
|
{ |
||||
|
foreach (var v in _names) |
||||
|
{ |
||||
|
nameScope.Register(v.Key, v.Value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,147 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Markup.Xaml.Templates; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Metadata; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Styling; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.Context |
||||
|
{ |
||||
|
using ClrNamespaceInfo = Tuple<string, Assembly>; |
||||
|
|
||||
|
public interface IRuntimeTypeProvider |
||||
|
{ |
||||
|
Type FindType(string xamlNamespace, string name, Type[] genArgs); |
||||
|
|
||||
|
IEnumerable<Assembly> ReferencedAssemblies { get; } |
||||
|
} |
||||
|
|
||||
|
public class AvaloniaRuntimeTypeProvider : IRuntimeTypeProvider |
||||
|
{ |
||||
|
private const string ClrNamespace = "clr-namespace:"; |
||||
|
// private const string AvaloniaNs = "https://github.com/avaloniaui";
|
||||
|
|
||||
|
private static readonly IEnumerable<Assembly> ForcedAssemblies = new[] |
||||
|
{ |
||||
|
typeof(AvaloniaObject).GetTypeInfo().Assembly, |
||||
|
typeof(Control).GetTypeInfo().Assembly, |
||||
|
typeof(Style).GetTypeInfo().Assembly, |
||||
|
typeof(DataTemplate).GetTypeInfo().Assembly, |
||||
|
typeof(SolidColorBrush).GetTypeInfo().Assembly, |
||||
|
typeof(IValueConverter).GetTypeInfo().Assembly, |
||||
|
}; |
||||
|
|
||||
|
private Dictionary<string, HashSet<ClrNamespaceInfo>> _namespaces = new Dictionary<string, HashSet<ClrNamespaceInfo>>(); |
||||
|
|
||||
|
private List<Assembly> _scanned = new List<Assembly>(); |
||||
|
|
||||
|
public IEnumerable<Assembly> ReferencedAssemblies => _scanned; |
||||
|
|
||||
|
public AvaloniaRuntimeTypeProvider() |
||||
|
{ |
||||
|
ScanAssemblies(ForcedAssemblies); |
||||
|
ScanNewAssemblies(); |
||||
|
} |
||||
|
|
||||
|
private static bool IsClrNamespace(string ns) |
||||
|
{ |
||||
|
return ns.StartsWith(ClrNamespace); |
||||
|
} |
||||
|
|
||||
|
private static Assembly GetAssembly(string assemblyName) |
||||
|
{ |
||||
|
return Assembly.Load(new AssemblyName(assemblyName)); |
||||
|
} |
||||
|
|
||||
|
private void ScanAssemblies(IEnumerable<Assembly> assemblies) |
||||
|
{ |
||||
|
foreach (var assembly in assemblies) |
||||
|
{ |
||||
|
var namespaces = assembly.GetCustomAttributes<XmlnsDefinitionAttribute>() |
||||
|
.Select(x => new { x.XmlNamespace, x.ClrNamespace }) |
||||
|
.GroupBy(x => x.XmlNamespace); |
||||
|
|
||||
|
foreach (var nsa in namespaces) |
||||
|
{ |
||||
|
HashSet<ClrNamespaceInfo> reg; |
||||
|
|
||||
|
if (!_namespaces.TryGetValue(nsa.Key, out reg)) |
||||
|
{ |
||||
|
_namespaces[nsa.Key] = reg = new HashSet<Tuple<string, Assembly>>(); |
||||
|
} |
||||
|
|
||||
|
foreach (var child in nsa) |
||||
|
{ |
||||
|
reg.Add(new ClrNamespaceInfo(child.ClrNamespace, assembly)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
_scanned.Add(assembly); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ScanNewAssemblies() |
||||
|
{ |
||||
|
IEnumerable<Assembly> assemblies = AvaloniaLocator.Current |
||||
|
.GetService<IRuntimePlatform>() |
||||
|
?.GetLoadedAssemblies(); |
||||
|
|
||||
|
if (assemblies != null) |
||||
|
{ |
||||
|
assemblies = assemblies.Except(_scanned); |
||||
|
ScanAssemblies(assemblies); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private Dictionary<string, Type> _typeCache = new Dictionary<string, Type>(); |
||||
|
|
||||
|
public Type FindType(string xamlNamespace, string name, Type[] genArgs) |
||||
|
{ |
||||
|
if (IsClrNamespace(xamlNamespace)) |
||||
|
{ |
||||
|
//we need to handle only xaml url namespaces for avalonia,
|
||||
|
//the other namespaces are handled well in portable.xaml
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
string key = $"{xamlNamespace}:{name}"; |
||||
|
|
||||
|
Type type; |
||||
|
|
||||
|
if (_typeCache.TryGetValue(key, out type)) |
||||
|
{ |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
HashSet<ClrNamespaceInfo> reg; |
||||
|
|
||||
|
if (!_namespaces.TryGetValue(xamlNamespace, out reg)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (genArgs != null) |
||||
|
name += "`" + genArgs.Length; |
||||
|
|
||||
|
foreach (var ns in reg) |
||||
|
{ |
||||
|
var n = ns.Item1 + "." + name; |
||||
|
var t = ns.Item2.GetType(n); |
||||
|
if (t != null) |
||||
|
{ |
||||
|
_typeCache[key] = t; |
||||
|
return t; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,91 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Avalonia.Metadata; |
||||
|
using Portable.Xaml.ComponentModel; |
||||
|
using pm = Portable.Xaml.Markup; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.PortableXaml |
||||
|
{ |
||||
|
internal class AvaloniaTypeAttributeProvider : ICustomAttributeProvider |
||||
|
{ |
||||
|
public AvaloniaTypeAttributeProvider(Type type) |
||||
|
{ |
||||
|
_type = type; |
||||
|
} |
||||
|
|
||||
|
public object[] GetCustomAttributes(bool inherit) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public object[] GetCustomAttributes(Type attributeType, bool inherit) |
||||
|
{ |
||||
|
if (attributeType == typeof(pm.ContentPropertyAttribute)) |
||||
|
{ |
||||
|
var cp = GetContentPropertyAttribute(inherit); |
||||
|
|
||||
|
if (cp != null) |
||||
|
{ |
||||
|
return new object[] { cp }; |
||||
|
} |
||||
|
} |
||||
|
else if (attributeType == typeof(pm.RuntimeNamePropertyAttribute)) |
||||
|
{ |
||||
|
if (_namedType.IsAssignableFrom(_type.GetTypeInfo())) |
||||
|
{ |
||||
|
return new object[] |
||||
|
{ |
||||
|
new pm.RuntimeNamePropertyAttribute(nameof(INamed.Name)) |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var attr = _type.GetTypeInfo().GetCustomAttributes(attributeType, inherit); |
||||
|
return (attr as object[]) ?? attr.ToArray(); |
||||
|
} |
||||
|
|
||||
|
public bool IsDefined(Type attributeType, bool inherit) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
private readonly TypeInfo _namedType = typeof(INamed).GetTypeInfo(); |
||||
|
|
||||
|
private readonly Type _type; |
||||
|
|
||||
|
private Attribute GetContentPropertyAttribute(bool inherit) |
||||
|
{ |
||||
|
var type = _type; |
||||
|
|
||||
|
while (type != null) |
||||
|
{ |
||||
|
var properties = type.GetTypeInfo().DeclaredProperties |
||||
|
.Where(x => x.GetCustomAttribute<ContentAttribute>() != null); |
||||
|
string result = null; |
||||
|
|
||||
|
foreach (var property in properties) |
||||
|
{ |
||||
|
if (result != null) |
||||
|
{ |
||||
|
throw new Exception($"Content property defined more than once on {type}."); |
||||
|
} |
||||
|
|
||||
|
result = property.Name; |
||||
|
} |
||||
|
|
||||
|
if (result != null) |
||||
|
{ |
||||
|
return new pm.ContentPropertyAttribute(result); |
||||
|
} |
||||
|
|
||||
|
type = inherit ? type.GetTypeInfo().BaseType : null; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,101 @@ |
|||||
|
using Portable.Xaml; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.PortableXaml |
||||
|
{ |
||||
|
public class AvaloniaXamlObjectWriter : XamlObjectWriter |
||||
|
{ |
||||
|
public static AvaloniaXamlObjectWriter Create(XamlSchemaContext schemaContext, object instance) |
||||
|
{ |
||||
|
var writerSettings = new XamlObjectWriterSettings(); |
||||
|
var nameScope = new AvaloniaNameScope { Instance = instance }; |
||||
|
writerSettings.ExternalNameScope = nameScope; |
||||
|
writerSettings.RegisterNamesOnExternalNamescope = true; |
||||
|
writerSettings.RootObjectInstance = instance; |
||||
|
|
||||
|
return new AvaloniaXamlObjectWriter(schemaContext, writerSettings, nameScope); |
||||
|
} |
||||
|
|
||||
|
private AvaloniaXamlObjectWriter( |
||||
|
XamlSchemaContext schemaContext, |
||||
|
XamlObjectWriterSettings settings, |
||||
|
AvaloniaNameScope nameScope |
||||
|
) |
||||
|
: base(schemaContext, settings) |
||||
|
{ |
||||
|
_nameScope = nameScope; |
||||
|
} |
||||
|
|
||||
|
protected override void OnAfterBeginInit(object value) |
||||
|
{ |
||||
|
base.OnAfterBeginInit(value); |
||||
|
} |
||||
|
|
||||
|
protected override void OnAfterEndInit(object value) |
||||
|
{ |
||||
|
base.OnAfterEndInit(value); |
||||
|
} |
||||
|
|
||||
|
protected override void OnAfterProperties(object value) |
||||
|
{ |
||||
|
base.OnAfterProperties(value); |
||||
|
|
||||
|
//AfterEndInit is not called as it supports only
|
||||
|
//Portable.Xaml.ComponentModel.ISupportInitialize
|
||||
|
//and we have Avalonia.ISupportInitialize so we need some hacks
|
||||
|
_endEditValue = value; |
||||
|
} |
||||
|
|
||||
|
protected override void OnBeforeProperties(object value) |
||||
|
{ |
||||
|
//OnAfterBeginInit is not called as it supports only
|
||||
|
//Portable.Xaml.ComponentModel.ISupportInitialize
|
||||
|
//and we have Avalonia.ISupportInitialize so we need some hacks
|
||||
|
HandleBeginInit(value); |
||||
|
|
||||
|
base.OnBeforeProperties(value); |
||||
|
} |
||||
|
|
||||
|
public override void WriteEndObject() |
||||
|
{ |
||||
|
base.WriteEndObject(); |
||||
|
|
||||
|
//AfterEndInit is not called as it supports only
|
||||
|
//Portable.Xaml.ComponentModel.ISupportInitialize
|
||||
|
//and we have Avalonia.ISupportInitialize so we need some hacks
|
||||
|
HandleEndEdit(_endEditValue); |
||||
|
_endEditValue = null; |
||||
|
} |
||||
|
|
||||
|
private object _endEditValue; |
||||
|
|
||||
|
private AvaloniaNameScope _nameScope; |
||||
|
|
||||
|
private void HandleBeginInit(object value) |
||||
|
{ |
||||
|
(value as Avalonia.ISupportInitialize)?.BeginInit(); |
||||
|
} |
||||
|
|
||||
|
private void HandleEndEdit(object value) |
||||
|
{ |
||||
|
(value as Avalonia.ISupportInitialize)?.EndInit(); |
||||
|
} |
||||
|
|
||||
|
private void HandleFinished() |
||||
|
{ |
||||
|
if(_nameScope != null && Result != null) |
||||
|
{ |
||||
|
_nameScope.RegisterOnNameScope(Result); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void Dispose(bool disposing) |
||||
|
{ |
||||
|
if (disposing) |
||||
|
{ |
||||
|
HandleFinished(); |
||||
|
} |
||||
|
|
||||
|
base.Dispose(disposing); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Avalonia.Markup.Xaml.Context; |
||||
|
using Portable.Xaml; |
||||
|
using Portable.Xaml.ComponentModel; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.PortableXaml |
||||
|
{ |
||||
|
internal class AvaloniaXamlSchemaContext : XamlSchemaContext |
||||
|
{ |
||||
|
public AvaloniaXamlSchemaContext(IRuntimeTypeProvider typeProvider) |
||||
|
: base(typeProvider.ReferencedAssemblies) |
||||
|
{ |
||||
|
_avaloniaTypeProvider = typeProvider; |
||||
|
} |
||||
|
|
||||
|
private IRuntimeTypeProvider _avaloniaTypeProvider; |
||||
|
|
||||
|
protected override XamlType GetXamlType(string xamlNamespace, string name, params XamlType[] typeArguments) |
||||
|
{ |
||||
|
XamlType type = null; |
||||
|
try |
||||
|
{ |
||||
|
type = ResolveXamlTypeName(xamlNamespace, name, typeArguments, false); |
||||
|
|
||||
|
if (type == null) |
||||
|
{ |
||||
|
type = base.GetXamlType(xamlNamespace, name, typeArguments); |
||||
|
} |
||||
|
} |
||||
|
catch(Exception e) |
||||
|
{ |
||||
|
//TODO: log or wrap exception
|
||||
|
throw e; |
||||
|
} |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
private XamlType ResolveXamlTypeName(string xmlNamespace, string xmlLocalName, XamlType[] typeArguments, bool required) |
||||
|
{ |
||||
|
Type[] genArgs = null; |
||||
|
if (typeArguments != null && typeArguments.Any()) |
||||
|
{ |
||||
|
genArgs = typeArguments.Select(t => t?.UnderlyingType).ToArray(); |
||||
|
|
||||
|
if (genArgs.Any(t => t == null)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
Type type = _avaloniaTypeProvider.FindType(xmlNamespace, xmlLocalName, genArgs); |
||||
|
|
||||
|
if (type == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return GetXamlType(type); |
||||
|
} |
||||
|
|
||||
|
protected override ICustomAttributeProvider GetCustomAttributeProvider(Type type) |
||||
|
=> new AvaloniaTypeAttributeProvider(type); |
||||
|
|
||||
|
protected override ICustomAttributeProvider GetCustomAttributeProvider(MemberInfo member) |
||||
|
=> new AvaloniaMemberAttributeProvider(member); |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,21 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<packages> |
<packages> |
||||
|
<package id="System.Collections" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.ComponentModel" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
<package id="System.ComponentModel.Annotations" version="4.1.0" targetFramework="portable45-net45+win8" /> |
<package id="System.ComponentModel.Annotations" version="4.1.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.ComponentModel.Primitives" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.ComponentModel.TypeConverter" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Globalization" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
<package id="System.Reactive" version="3.0.0" targetFramework="portable45-net45+win8" /> |
<package id="System.Reactive" version="3.0.0" targetFramework="portable45-net45+win8" /> |
||||
<package id="System.Reactive.Core" version="3.0.0" targetFramework="portable45-net45+win8" /> |
<package id="System.Reactive.Core" version="3.0.0" targetFramework="portable45-net45+win8" /> |
||||
<package id="System.Reactive.Interfaces" version="3.0.0" targetFramework="portable45-net45+win8" /> |
<package id="System.Reactive.Interfaces" version="3.0.0" targetFramework="portable45-net45+win8" /> |
||||
<package id="System.Reactive.Linq" version="3.0.0" targetFramework="portable45-net45+win8" /> |
<package id="System.Reactive.Linq" version="3.0.0" targetFramework="portable45-net45+win8" /> |
||||
<package id="System.Reactive.PlatformServices" version="3.0.0" targetFramework="portable45-net45+win8" /> |
<package id="System.Reactive.PlatformServices" version="3.0.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Reflection" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Runtime" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
|
<package id="System.Threading" version="4.3.0" targetFramework="portable45-net45+win8" /> |
||||
</packages> |
</packages> |
||||
Loading…
Reference in new issue