committed by
GitHub
225 changed files with 5750 additions and 3218 deletions
@ -0,0 +1,5 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="System.ValueTuple" Version="4.3.1" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -1,6 +1,6 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="SkiaSharp" Version="1.57.1" /> |
|||
<PackageReference Condition="$(TargetFramework.Trim('.').ToLower().StartsWith('netframework'))" Include="Avalonia.Skia.Linux.Natives" Version="1.57.1.3" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="Avalonia.Skia.Linux.Natives" Version="1.57.1.3" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,5 @@ |
|||
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\ |
|||
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.1\ |
|||
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.1\ |
|||
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\ |
|||
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.1\ |
|||
@ -0,0 +1,7 @@ |
|||
#!/usr/bin/env bash |
|||
|
|||
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp1.0/ |
|||
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard1.1/ |
|||
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard1.1/ |
|||
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia.desktop/$1/lib/netstandard1.3/ |
|||
|
|||
@ -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 ambient class/property
|
|||
/// </summary>
|
|||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, Inherited = true)] |
|||
public class AmbientAttribute : Attribute |
|||
{ |
|||
} |
|||
} |
|||
@ -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 |
|||
{ |
|||
} |
|||
} |
|||
@ -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.Input |
|||
{ |
|||
/// <summary>
|
|||
/// Designates a control as handling its own keyboard navigation.
|
|||
/// </summary>
|
|||
public interface ICustomKeyboardNavigation |
|||
{ |
|||
(bool handled, IInputElement next) GetNext(IInputElement element, NavigationDirection direction); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace Avalonia.Layout |
|||
{ |
|||
/// <summary>
|
|||
/// A special layout root with enforced size for Arrange pass
|
|||
/// </summary>
|
|||
public interface IEmbeddedLayoutRoot : ILayoutRoot |
|||
{ |
|||
Size AllocatedSize { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Styling |
|||
{ |
|||
/// <summary>
|
|||
/// Holds resources for a <see cref="Style"/>.
|
|||
/// </summary>
|
|||
public class StyleResources : IDictionary<string, object>, IDictionary |
|||
{ |
|||
private Dictionary<string, object> _inner = new Dictionary<string, object>(); |
|||
|
|||
public object this[string key] |
|||
{ |
|||
get { return _inner[key]; } |
|||
set { _inner[key] = value; } |
|||
} |
|||
|
|||
public int Count => _inner.Count; |
|||
|
|||
ICollection<string> IDictionary<string, object>.Keys => _inner.Keys; |
|||
|
|||
ICollection<object> IDictionary<string, object>.Values => _inner.Values; |
|||
|
|||
bool ICollection<KeyValuePair<string, object>>.IsReadOnly => false; |
|||
|
|||
object IDictionary.this[object key] |
|||
{ |
|||
get { return ((IDictionary)_inner)[key]; } |
|||
set { ((IDictionary)_inner)[key] = value; } |
|||
} |
|||
|
|||
ICollection IDictionary.Keys => _inner.Keys; |
|||
|
|||
ICollection IDictionary.Values => _inner.Values; |
|||
|
|||
bool ICollection.IsSynchronized => false; |
|||
|
|||
object ICollection.SyncRoot => ((IDictionary)_inner).SyncRoot; |
|||
|
|||
bool IDictionary.IsFixedSize => false; |
|||
|
|||
bool IDictionary.IsReadOnly => false; |
|||
|
|||
public void Add(string key, object value) => _inner.Add(key, value); |
|||
|
|||
public void Clear() => _inner.Clear(); |
|||
|
|||
public bool ContainsKey(string key) => _inner.ContainsKey(key); |
|||
|
|||
public bool Remove(string key) => _inner.Remove(key); |
|||
|
|||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => _inner.GetEnumerator(); |
|||
|
|||
public bool TryGetValue(string key, out object value) => _inner.TryGetValue(key, out value); |
|||
|
|||
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item) |
|||
{ |
|||
return ((IDictionary<string, object>)_inner).Contains(item); |
|||
} |
|||
|
|||
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item) |
|||
{ |
|||
((IDictionary<string, object>)_inner).Add(item); |
|||
} |
|||
|
|||
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) |
|||
{ |
|||
((IDictionary<string, object>)_inner).CopyTo(array, arrayIndex); |
|||
} |
|||
|
|||
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item) |
|||
{ |
|||
return ((IDictionary<string, object>)_inner).Remove(item); |
|||
} |
|||
|
|||
void ICollection.CopyTo(Array array, int index) => ((IDictionary)_inner).CopyTo(array, index); |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator(); |
|||
|
|||
IDictionaryEnumerator IDictionary.GetEnumerator() => ((IDictionary)_inner).GetEnumerator(); |
|||
|
|||
void IDictionary.Add(object key, object value) => ((IDictionary)_inner).Add(key, value); |
|||
|
|||
bool IDictionary.Contains(object key) => ((IDictionary)_inner).Contains(key); |
|||
|
|||
void IDictionary.Remove(object key) => ((IDictionary)_inner).Remove(key); |
|||
} |
|||
} |
|||
@ -1,225 +1,11 @@ |
|||
// 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 |
|||
namespace Avalonia.Markup.Xaml |
|||
{ |
|||
/// <summary>
|
|||
/// Loads XAML for a avalonia application.
|
|||
/// </summary>
|
|||
public class AvaloniaXamlLoader : XmlLoader |
|||
public class AvaloniaXamlLoader : AvaloniaXamlLoaderPortableXaml |
|||
{ |
|||
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); |
|||
public static object Parse(string xaml) |
|||
=> new AvaloniaXamlLoader().Load(xaml); |
|||
|
|||
} |
|||
public static T Parse<T>(string xaml) |
|||
=> (T)Parse(xaml); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,215 @@ |
|||
// 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 Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml.Data; |
|||
using Avalonia.Markup.Xaml.PortableXaml; |
|||
using Avalonia.Platform; |
|||
using Portable.Xaml; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
|
|||
namespace Avalonia.Markup.Xaml |
|||
{ |
|||
/// <summary>
|
|||
/// Loads XAML for a avalonia application.
|
|||
/// </summary>
|
|||
public class AvaloniaXamlLoaderPortableXaml |
|||
{ |
|||
private readonly AvaloniaXamlSchemaContext _context = GetContext(); |
|||
|
|||
private static AvaloniaXamlSchemaContext GetContext() |
|||
{ |
|||
var result = AvaloniaLocator.Current.GetService<AvaloniaXamlSchemaContext>(); |
|||
|
|||
if (result == null) |
|||
{ |
|||
result = AvaloniaXamlSchemaContext.Create(); |
|||
|
|||
AvaloniaLocator.CurrentMutable |
|||
.Bind<AvaloniaXamlSchemaContext>() |
|||
.ToConstant(result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AvaloniaXamlLoader"/> class.
|
|||
/// </summary>
|
|||
public AvaloniaXamlLoaderPortableXaml() |
|||
{ |
|||
} |
|||
|
|||
/// <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(); |
|||
try |
|||
{ |
|||
return Load(stream, rootInstance, uri); |
|||
} |
|||
finally |
|||
{ |
|||
initialize?.EndInit(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
var readerSettings = new XamlXmlReaderSettings() |
|||
{ |
|||
BaseUri = uri, |
|||
LocalAssembly = rootInstance?.GetType().GetTypeInfo().Assembly |
|||
}; |
|||
|
|||
var reader = new XamlXmlReader(stream, _context, readerSettings); |
|||
|
|||
object result = LoadFromReader( |
|||
reader, |
|||
AvaloniaXamlContext.For(readerSettings, rootInstance)); |
|||
|
|||
var topLevel = result as TopLevel; |
|||
|
|||
if (topLevel != null) |
|||
{ |
|||
DelayedBinding.ApplyBindings(topLevel); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
internal static object LoadFromReader(XamlReader reader, AvaloniaXamlContext context = null) |
|||
{ |
|||
var writer = AvaloniaXamlObjectWriter.Create( |
|||
reader.SchemaContext, |
|||
context); |
|||
|
|||
XamlServices.Transform(reader, writer); |
|||
|
|||
return writer.Result; |
|||
} |
|||
|
|||
internal static object LoadFromReader(XamlReader reader) |
|||
{ |
|||
//return XamlServices.Load(reader);
|
|||
return LoadFromReader(reader, null); |
|||
} |
|||
|
|||
/// <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); |
|||
} |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
// 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 Avalonia.Markup.Xaml.Data; |
|||
using OmniXaml; |
|||
using OmniXaml.Typing; |
|||
using System.Reflection; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaAttachableXamlMember : AttachableMember |
|||
{ |
|||
public AvaloniaAttachableXamlMember(string name, |
|||
XamlType owner, |
|||
MethodInfo getter, |
|||
MethodInfo setter, |
|||
ITypeRepository xamlTypeRepository, |
|||
ITypeFeatureProvider featureProvider) |
|||
: base(name, getter, setter, xamlTypeRepository, featureProvider) |
|||
{ |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return "Avalonia Attachable XAML Member " + base.ToString(); |
|||
} |
|||
|
|||
protected override IMemberValuePlugin LookupXamlMemberValueConnector() |
|||
{ |
|||
return new AvaloniaMemberValuePlugin(this); |
|||
} |
|||
} |
|||
} |
|||
@ -1,58 +0,0 @@ |
|||
// 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; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Glass; |
|||
using OmniXaml; |
|||
using OmniXaml.Builder; |
|||
using Avalonia.Metadata; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaContentPropertyProvider : IContentPropertyProvider |
|||
{ |
|||
private readonly Dictionary<Type, string> _values = new Dictionary<Type, string>(); |
|||
|
|||
public string GetContentPropertyName(Type type) |
|||
{ |
|||
string result; |
|||
|
|||
if (!_values.TryGetValue(type, out result)) |
|||
{ |
|||
result = LookupContentProperty(type); |
|||
_values[type] = result; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private string LookupContentProperty(Type type) |
|||
{ |
|||
var result = (from member in type.GetRuntimeProperties() |
|||
let att = member.GetCustomAttribute<ContentAttribute>() |
|||
where att != null |
|||
select member).FirstOrDefault(); |
|||
|
|||
return result?.Name; |
|||
} |
|||
|
|||
void IAdd<ContentPropertyDefinition>.Add(ContentPropertyDefinition item) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
IEnumerator<ContentPropertyDefinition> IEnumerable<ContentPropertyDefinition>.GetEnumerator() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
// 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 OmniXaml; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaLifeCycleListener : IInstanceLifeCycleListener |
|||
{ |
|||
public void OnAfterProperties(object instance) |
|||
{ |
|||
} |
|||
|
|||
public void OnAssociatedToParent(object instance) |
|||
{ |
|||
} |
|||
|
|||
public void OnBegin(object instance) |
|||
{ |
|||
var isi = instance as ISupportInitialize; |
|||
isi?.BeginInit(); |
|||
} |
|||
|
|||
public void OnEnd(object instance) |
|||
{ |
|||
var isi = instance as ISupportInitialize; |
|||
isi?.EndInit(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,25 +0,0 @@ |
|||
// 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 OmniXaml.TypeConversion; |
|||
using OmniXaml.Typing; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaMemberValuePlugin : MemberValuePlugin |
|||
{ |
|||
private readonly MutableMember _xamlMember; |
|||
|
|||
public AvaloniaMemberValuePlugin(MutableMember xamlMember) |
|||
: base(xamlMember) |
|||
{ |
|||
_xamlMember = xamlMember; |
|||
} |
|||
|
|||
public override void SetValue(object instance, object value, IValueContext valueContext) |
|||
{ |
|||
PropertyAccessor.SetValue(instance, _xamlMember, value, valueContext); |
|||
} |
|||
} |
|||
} |
|||
@ -1,181 +0,0 @@ |
|||
// 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 OmniXaml.Builder; |
|||
using OmniXaml.Typing; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml.Templates; |
|||
using Avalonia.Media; |
|||
using Avalonia.Metadata; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Styling; |
|||
using Glass.Core; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaNamespaceRegistry : INamespaceRegistry |
|||
{ |
|||
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 List<ClrNamespace> _clrNamespaces = new List<ClrNamespace>(); |
|||
private List<XamlNamespace> _namespaces = new List<XamlNamespace>(); |
|||
private Dictionary<string, string> _prefixes = new Dictionary<string, string>(); |
|||
private List<Assembly> _scanned = new List<Assembly>(); |
|||
|
|||
public AvaloniaNamespaceRegistry() |
|||
{ |
|||
ScanAssemblies(ForcedAssemblies); |
|||
ScanNewAssemblies(); |
|||
RegisterPrefix(new PrefixRegistration(string.Empty, AvaloniaNs)); |
|||
} |
|||
|
|||
public IEnumerable<PrefixRegistration> RegisteredPrefixes => |
|||
_prefixes.Select(x => new PrefixRegistration(x.Key, x.Value)); |
|||
|
|||
public void AddNamespace(XamlNamespace xamlNamespace) |
|||
{ |
|||
_namespaces.Add(xamlNamespace); |
|||
} |
|||
|
|||
public Namespace GetNamespace(string name) |
|||
{ |
|||
Namespace result; |
|||
|
|||
if (!IsClrNamespace(name)) |
|||
{ |
|||
ScanNewAssemblies(); |
|||
result = _namespaces.FirstOrDefault(x => x.Name == name); |
|||
|
|||
if (result == null) |
|||
{ |
|||
result = _namespaces.FirstOrDefault(x => x.Name == name); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
var nsAndAssembly = ParseClrNameSpace(name); |
|||
|
|||
result = _clrNamespaces.FirstOrDefault(x => |
|||
x.Name == nsAndAssembly.Item1 && |
|||
x.Assembly.GetName().Name == nsAndAssembly.Item2); |
|||
|
|||
if (result == null) |
|||
{ |
|||
var clr = CreateClrNamespace(name); |
|||
_clrNamespaces.Add(clr); |
|||
result = clr; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public Namespace GetNamespaceByPrefix(string prefix) |
|||
{ |
|||
string uri; |
|||
|
|||
if (_prefixes.TryGetValue(prefix, out uri)) |
|||
{ |
|||
return GetNamespace(uri); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public void RegisterPrefix(PrefixRegistration prefixRegistration) |
|||
{ |
|||
_prefixes[prefixRegistration.Prefix] = prefixRegistration.Ns; |
|||
} |
|||
|
|||
private static bool IsClrNamespace(string ns) |
|||
{ |
|||
return ns.StartsWith(ClrNamespace); |
|||
} |
|||
|
|||
private static ClrNamespace CreateClrNamespace(string formattedClrString) |
|||
{ |
|||
var nsAndAssembly = ParseClrNameSpace(formattedClrString); |
|||
var assembly = GetAssembly(nsAndAssembly.Item2); |
|||
|
|||
return new ClrNamespace(assembly, nsAndAssembly.Item1); |
|||
} |
|||
|
|||
private static Tuple<string, string> ParseClrNameSpace(string clrNamespace) |
|||
{ |
|||
var startOfNamespace = clrNamespace.IndexOf(":", StringComparison.Ordinal) + 1; |
|||
var endOfNamespace = clrNamespace.IndexOf(";", startOfNamespace, StringComparison.Ordinal); |
|||
|
|||
if (endOfNamespace < 0) |
|||
{ |
|||
endOfNamespace = clrNamespace.Length - startOfNamespace; |
|||
} |
|||
|
|||
var ns = clrNamespace.Substring(startOfNamespace, endOfNamespace - startOfNamespace); |
|||
|
|||
var remainingPartStart = startOfNamespace + ns.Length + 1; |
|||
var remainingPartLenght = clrNamespace.Length - remainingPartStart; |
|||
var assemblyPart = clrNamespace.Substring(remainingPartStart, remainingPartLenght); |
|||
|
|||
return Tuple.Create(ns, assemblyPart.Dicotomize('=').Item2); |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
var xamlNamespace = _namespaces.FirstOrDefault(x => x.Name == nsa.Key); |
|||
|
|||
if (xamlNamespace == null) |
|||
{ |
|||
xamlNamespace = new XamlNamespace(nsa.Key); |
|||
_namespaces.Add(xamlNamespace); |
|||
} |
|||
|
|||
var clrNamespaces = nsa.Select(x => x.ClrNamespace); |
|||
xamlNamespace.Addresses.Add(new ConfiguredAssemblyWithNamespaces(assembly, clrNamespaces)); |
|||
} |
|||
|
|||
_scanned.Add(assembly); |
|||
} |
|||
} |
|||
|
|||
private void ScanNewAssemblies() |
|||
{ |
|||
IEnumerable<Assembly> assemblies = AvaloniaLocator.Current |
|||
.GetService<IRuntimePlatform>() |
|||
?.GetLoadedAssemblies(); |
|||
|
|||
if (assemblies != null) |
|||
{ |
|||
assemblies = assemblies.Except(_scanned); |
|||
ScanAssemblies(assemblies); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,79 +0,0 @@ |
|||
// 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 OmniXaml; |
|||
using OmniXaml.ObjectAssembler; |
|||
using OmniXaml.ObjectAssembler.Commands; |
|||
using OmniXaml.TypeConversion; |
|||
using Avalonia.Markup.Xaml.Templates; |
|||
using System.Collections.Generic; |
|||
using System.Collections.ObjectModel; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaObjectAssembler : IObjectAssembler |
|||
{ |
|||
private readonly TemplateHostingObjectAssembler objectAssembler; |
|||
private readonly ObjectAssembler assembler; |
|||
|
|||
public AvaloniaObjectAssembler( |
|||
IRuntimeTypeSource typeSource, |
|||
ITopDownValueContext topDownValueContext, |
|||
Settings settings = null) |
|||
{ |
|||
var mapping = new DeferredLoaderMapping(); |
|||
mapping.Map<Template>(x => x.Content, new TemplateLoader()); |
|||
mapping.Map<ControlTemplate>(x => x.Content, new TemplateLoader()); |
|||
mapping.Map<DataTemplate>(x => x.Content, new TemplateLoader()); |
|||
mapping.Map<FocusAdornerTemplate>(x => x.Content, new TemplateLoader()); |
|||
mapping.Map<TreeDataTemplate>(x => x.Content, new TemplateLoader()); |
|||
mapping.Map<ItemsPanelTemplate>(x => x.Content, new TemplateLoader()); |
|||
|
|||
var parsingDictionary = GetDictionary(settings); |
|||
var valueContext = new ValueContext(typeSource, topDownValueContext, parsingDictionary); |
|||
assembler = new ObjectAssembler(typeSource, valueContext, settings); |
|||
objectAssembler = new TemplateHostingObjectAssembler(assembler, mapping); |
|||
} |
|||
|
|||
|
|||
public object Result => objectAssembler.Result; |
|||
|
|||
public EventHandler<XamlSetValueEventArgs> XamlSetValueHandler { get; set; } |
|||
|
|||
public IRuntimeTypeSource TypeSource => assembler.TypeSource; |
|||
|
|||
public ITopDownValueContext TopDownValueContext => assembler.TopDownValueContext; |
|||
|
|||
public IInstanceLifeCycleListener LifecycleListener |
|||
{ |
|||
get { throw new NotImplementedException(); } |
|||
} |
|||
|
|||
public void Process(Instruction node) |
|||
{ |
|||
objectAssembler.Process(node); |
|||
} |
|||
|
|||
public void OverrideInstance(object instance) |
|||
{ |
|||
objectAssembler.OverrideInstance(instance); |
|||
} |
|||
|
|||
private static IReadOnlyDictionary<string, object> GetDictionary(Settings settings) |
|||
{ |
|||
IReadOnlyDictionary<string, object> dict; |
|||
|
|||
if (settings != null) |
|||
{ |
|||
dict = settings.ParsingContext; |
|||
} |
|||
else |
|||
{ |
|||
dict = new ReadOnlyDictionary<string, object>(new Dictionary<string, object>()); |
|||
} |
|||
|
|||
return dict; |
|||
} |
|||
} |
|||
} |
|||
@ -1,41 +0,0 @@ |
|||
// 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 OmniXaml; |
|||
using OmniXaml.ObjectAssembler; |
|||
using OmniXaml.Parsers.Parser; |
|||
using OmniXaml.Parsers.ProtoParser; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaParserFactory : IParserFactory |
|||
{ |
|||
private readonly IRuntimeTypeSource runtimeTypeSource; |
|||
|
|||
public AvaloniaParserFactory() |
|||
: this(new TypeFactory()) |
|||
{ |
|||
} |
|||
|
|||
public AvaloniaParserFactory(ITypeFactory typeFactory) |
|||
{ |
|||
runtimeTypeSource = new AvaloniaRuntimeTypeSource(typeFactory); |
|||
} |
|||
|
|||
public IParser Create(Settings settings) |
|||
{ |
|||
var xamlInstructionParser = new OrderAwareInstructionParser(new InstructionParser(runtimeTypeSource)); |
|||
|
|||
IObjectAssembler objectAssembler = new AvaloniaObjectAssembler( |
|||
runtimeTypeSource, |
|||
new TopDownValueContext(), |
|||
settings); |
|||
var phaseParserKit = new PhaseParserKit( |
|||
new ProtoInstructionParser(runtimeTypeSource), |
|||
xamlInstructionParser, |
|||
objectAssembler); |
|||
|
|||
return new XmlParser(phaseParserKit); |
|||
} |
|||
} |
|||
} |
|||
@ -1,91 +0,0 @@ |
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Collections; |
|||
using Controls; |
|||
using Controls.Primitives; |
|||
using Controls.Templates; |
|||
using Converters; |
|||
using Data; |
|||
using Glass; |
|||
using Input; |
|||
using Media; |
|||
using Media.Imaging; |
|||
using Metadata; |
|||
using OmniXaml; |
|||
using OmniXaml.Builder; |
|||
using OmniXaml.TypeConversion; |
|||
using OmniXaml.Typing; |
|||
using Avalonia.Styling; |
|||
using Platform; |
|||
using Templates; |
|||
|
|||
public class AvaloniaRuntimeTypeSource : IRuntimeTypeSource |
|||
{ |
|||
private readonly RuntimeTypeSource inner; |
|||
|
|||
public AvaloniaRuntimeTypeSource(ITypeFactory typeFactory) |
|||
{ |
|||
var namespaceRegistry = new AvaloniaNamespaceRegistry(); |
|||
var featureProvider = new AvaloniaTypeFeatureProvider(); |
|||
var typeRepository = new AvaloniaTypeRepository(namespaceRegistry, typeFactory, featureProvider); |
|||
|
|||
inner = new RuntimeTypeSource(typeRepository, namespaceRegistry); |
|||
} |
|||
|
|||
public Namespace GetNamespace(string name) |
|||
{ |
|||
return inner.GetNamespace(name); |
|||
} |
|||
|
|||
public Namespace GetNamespaceByPrefix(string prefix) |
|||
{ |
|||
return inner.GetNamespaceByPrefix(prefix); |
|||
} |
|||
|
|||
public void RegisterPrefix(PrefixRegistration prefixRegistration) |
|||
{ |
|||
inner.RegisterPrefix(prefixRegistration); |
|||
} |
|||
|
|||
public void AddNamespace(XamlNamespace xamlNamespace) |
|||
{ |
|||
inner.AddNamespace(xamlNamespace); |
|||
} |
|||
|
|||
public IEnumerable<PrefixRegistration> RegisteredPrefixes => inner.RegisteredPrefixes; |
|||
|
|||
public XamlType GetByType(Type type) |
|||
{ |
|||
return inner.GetByType(type); |
|||
} |
|||
|
|||
public XamlType GetByQualifiedName(string qualifiedName) |
|||
{ |
|||
return inner.GetByQualifiedName(qualifiedName); |
|||
} |
|||
|
|||
public XamlType GetByPrefix(string prefix, string typeName) |
|||
{ |
|||
return inner.GetByPrefix(prefix, typeName); |
|||
} |
|||
|
|||
public XamlType GetByFullAddress(XamlTypeName xamlTypeName) |
|||
{ |
|||
return inner.GetByFullAddress(xamlTypeName); |
|||
} |
|||
|
|||
public Member GetMember(PropertyInfo propertyInfo) |
|||
{ |
|||
return inner.GetMember(propertyInfo); |
|||
} |
|||
|
|||
public AttachableMember GetAttachableMember(string name, MethodInfo getter, MethodInfo setter) |
|||
{ |
|||
return inner.GetAttachableMember(name, getter, setter); |
|||
} |
|||
} |
|||
} |
|||
@ -1,180 +0,0 @@ |
|||
// 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.Collections; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Input; |
|||
using Avalonia.Markup.Xaml.Converters; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Imaging; |
|||
using Avalonia.Metadata; |
|||
using Avalonia.Styling; |
|||
using OmniXaml; |
|||
using OmniXaml.Builder; |
|||
using OmniXaml.TypeConversion; |
|||
using OmniXaml.TypeConversion.BuiltInConverters; |
|||
using OmniXaml.Typing; |
|||
using OmniMetadata = OmniXaml.Typing.Metadata; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaTypeFeatureProvider : ITypeFeatureProvider |
|||
{ |
|||
private Dictionary<Type, OmniMetadata> _metadata = |
|||
new Dictionary<Type, OmniMetadata>(); |
|||
|
|||
private Dictionary<Type, TypeConverterRegistration> _typeConverters = |
|||
new Dictionary<Type, TypeConverterRegistration>(); |
|||
|
|||
public IEnumerable<TypeConverterRegistration> TypeConverters => _typeConverters.Values; |
|||
|
|||
public AvaloniaTypeFeatureProvider() |
|||
{ |
|||
RegisterTypeConverters(); |
|||
} |
|||
|
|||
public string GetContentPropertyName(Type type) |
|||
{ |
|||
return GetMetadata(type)?.ContentProperty; |
|||
} |
|||
|
|||
public OmniMetadata GetMetadata(Type type) |
|||
{ |
|||
OmniMetadata result; |
|||
|
|||
if (!_metadata.TryGetValue(type, out result)) |
|||
{ |
|||
result = LoadMetadata(type); |
|||
_metadata.Add(type, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public ITypeConverter GetTypeConverter(Type type) |
|||
{ |
|||
TypeConverterRegistration result; |
|||
_typeConverters.TryGetValue(type, out result); |
|||
return result?.TypeConverter; |
|||
} |
|||
|
|||
public void RegisterMetadata(Type type, OmniMetadata metadata) |
|||
{ |
|||
_metadata.Add(type, metadata); |
|||
} |
|||
|
|||
public void RegisterTypeConverter(Type type, ITypeConverter converter) |
|||
{ |
|||
_typeConverters.Add(type, new TypeConverterRegistration(type, converter)); |
|||
} |
|||
|
|||
private static OmniMetadata LoadMetadata(Type type) |
|||
{ |
|||
return new OmniMetadata |
|||
{ |
|||
ContentProperty = GetContentProperty(type), |
|||
PropertyDependencies = GetPropertyDependencies(type), |
|||
RuntimePropertyName = type.GetRuntimeProperty("Name")?.Name, |
|||
}; |
|||
} |
|||
|
|||
private static string GetContentProperty(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 result; |
|||
} |
|||
|
|||
type = type.GetTypeInfo().BaseType; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static DependencyRegistrations GetPropertyDependencies(Type type) |
|||
{ |
|||
var result = new List<DependencyRegistration>(); |
|||
|
|||
while (type != null) |
|||
{ |
|||
var registrations = type.GetTypeInfo().DeclaredProperties |
|||
.Select(x => new |
|||
{ |
|||
Property = x.Name, |
|||
Attributes = x.GetCustomAttributes<DependsOnAttribute>(), |
|||
}) |
|||
.Where(x => x.Attributes.Any()) |
|||
.SelectMany(x => x.Attributes.Select(y => new DependencyRegistration(x.Property, y.Name))); |
|||
|
|||
result.AddRange(registrations); |
|||
type = type.GetTypeInfo().BaseType; |
|||
} |
|||
|
|||
return result.Count > 0 ? new DependencyRegistrations(result) : null; |
|||
} |
|||
|
|||
private void RegisterTypeConverters() |
|||
{ |
|||
// HACK: For now these are hard-coded. Hopefully when the .NET Standard Platform
|
|||
// is available we can use the System.ComponentModel.TypeConverters so don't want to
|
|||
// spend time for now inventing a mechanism to register type converters if it's all
|
|||
// going to change.
|
|||
RegisterTypeConverter(typeof(string), new StringTypeConverter()); |
|||
RegisterTypeConverter(typeof(int), new IntTypeConverter()); |
|||
RegisterTypeConverter(typeof(long), new IntTypeConverter()); |
|||
RegisterTypeConverter(typeof(short), new IntTypeConverter()); |
|||
RegisterTypeConverter(typeof(double), new DoubleTypeConverter()); |
|||
RegisterTypeConverter(typeof(float), new IntTypeConverter()); |
|||
RegisterTypeConverter(typeof(bool), new BooleanConverter()); |
|||
RegisterTypeConverter(typeof(Type), new TypeTypeConverter()); |
|||
|
|||
RegisterTypeConverter(typeof(IBitmap), new BitmapTypeConverter()); |
|||
RegisterTypeConverter(typeof(IBrush), new BrushTypeConverter()); |
|||
RegisterTypeConverter(typeof(Color), new ColorTypeConverter()); |
|||
RegisterTypeConverter(typeof(Classes), new ClassesTypeConverter()); |
|||
RegisterTypeConverter(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()); |
|||
RegisterTypeConverter(typeof(DateTime), new DateTimeTypeConverter()); |
|||
RegisterTypeConverter(typeof(Geometry), new GeometryTypeConverter()); |
|||
RegisterTypeConverter(typeof(GridLength), new GridLengthTypeConverter()); |
|||
RegisterTypeConverter(typeof(KeyGesture), new KeyGestureConverter()); |
|||
RegisterTypeConverter(typeof(AvaloniaList<double>), new AvaloniaListTypeConverter<double>()); |
|||
RegisterTypeConverter(typeof(IMemberSelector), new MemberSelectorTypeConverter()); |
|||
RegisterTypeConverter(typeof(Point), new PointTypeConverter()); |
|||
RegisterTypeConverter(typeof(IList<Point>), new PointsListTypeConverter()); |
|||
RegisterTypeConverter(typeof(AvaloniaProperty), new AvaloniaPropertyTypeConverter()); |
|||
RegisterTypeConverter(typeof(RelativePoint), new RelativePointTypeConverter()); |
|||
RegisterTypeConverter(typeof(RelativeRect), new RelativeRectTypeConverter()); |
|||
RegisterTypeConverter(typeof(RowDefinitions), new RowDefinitionsTypeConverter()); |
|||
RegisterTypeConverter(typeof(Size), new SizeTypeConverter()); |
|||
RegisterTypeConverter(typeof(Selector), new SelectorTypeConverter()); |
|||
RegisterTypeConverter(typeof(SolidColorBrush), new BrushTypeConverter()); |
|||
RegisterTypeConverter(typeof(Thickness), new ThicknessTypeConverter()); |
|||
RegisterTypeConverter(typeof(TimeSpan), new TimeSpanTypeConverter()); |
|||
RegisterTypeConverter(typeof(Uri), new UriTypeConverter()); |
|||
RegisterTypeConverter(typeof(Cursor), new CursorTypeConverter()); |
|||
RegisterTypeConverter(typeof(WindowIcon), new IconTypeConverter()); |
|||
RegisterTypeConverter(typeof(FontWeight), new FontWeightConverter()); |
|||
} |
|||
} |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
// 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 OmniXaml; |
|||
using OmniXaml.Typing; |
|||
using Glass.Core; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaTypeRepository : TypeRepository |
|||
{ |
|||
private readonly ITypeFactory _typeFactory; |
|||
|
|||
public AvaloniaTypeRepository(INamespaceRegistry xamlNamespaceRegistry, |
|||
ITypeFactory typeFactory, |
|||
ITypeFeatureProvider featureProvider) : base(xamlNamespaceRegistry, typeFactory, featureProvider) |
|||
{ |
|||
_typeFactory = typeFactory; |
|||
} |
|||
|
|||
public override XamlType GetByType(Type type) |
|||
{ |
|||
Guard.ThrowIfNull(type, nameof(type)); |
|||
return new AvaloniaXamlType(type, this, _typeFactory, FeatureProvider); |
|||
} |
|||
} |
|||
} |
|||
@ -1,126 +0,0 @@ |
|||
// 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.Linq; |
|||
using System.Reflection; |
|||
using Glass; |
|||
using OmniXaml; |
|||
using OmniXaml.Builder; |
|||
using OmniXaml.TypeConversion; |
|||
using OmniXaml.Typing; |
|||
using Avalonia.Collections; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Primitives; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Input; |
|||
using Avalonia.Markup.Xaml.Converters; |
|||
using Avalonia.Markup.Xaml.Data; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Imaging; |
|||
using Avalonia.Metadata; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Styling; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaWiringContext : WiringContext |
|||
{ |
|||
private const string AvaloniaNs = "https://github.com/avaloniaui"; |
|||
|
|||
public AvaloniaWiringContext(ITypeFactory typeFactory) |
|||
: this(typeFactory, new TypeFeatureProvider(GetContentPropertyProvider(), GetConverterProvider())) |
|||
{ |
|||
} |
|||
|
|||
public AvaloniaWiringContext(ITypeFactory typeFactory, TypeFeatureProvider featureProvider) |
|||
: base(CreateTypeContext(typeFactory, featureProvider), featureProvider) |
|||
{ |
|||
} |
|||
|
|||
private static ITypeContext CreateTypeContext(ITypeFactory typeFactory, TypeFeatureProvider featureProvider) |
|||
{ |
|||
var xamlNamespaceRegistry = CreateXamlNamespaceRegistry(); |
|||
var typeRepository = new AvaloniaTypeRepository(xamlNamespaceRegistry, typeFactory, featureProvider); |
|||
|
|||
typeRepository.RegisterMetadata(new GenericMetadata<Visual>().WithRuntimeNameProperty(d => d.Name)); |
|||
typeRepository.RegisterMetadata(new GenericMetadata<Setter>().WithMemberDependency(x => x.Value, x => x.Property)); |
|||
typeRepository.RegisterMetadata( |
|||
new GenericMetadata<SelectingItemsControl>() |
|||
.WithMemberDependency(x => x.SelectedIndex, x => x.Items) |
|||
.WithMemberDependency(x => x.SelectedItem, x => x.Items)); |
|||
|
|||
return new TypeContext(typeRepository, xamlNamespaceRegistry, typeFactory); |
|||
} |
|||
|
|||
private static XamlNamespaceRegistry CreateXamlNamespaceRegistry() |
|||
{ |
|||
var xamlNamespaceRegistry = new XamlNamespaceRegistry(); |
|||
|
|||
var forcedAssemblies = new[] |
|||
{ |
|||
typeof(Binding), |
|||
typeof(Control), |
|||
typeof(IValueConverter), |
|||
typeof(Style), |
|||
}.Select(t => t.GetTypeInfo().Assembly); |
|||
|
|||
foreach (var nsa in |
|||
forcedAssemblies |
|||
.Concat(AvaloniaLocator.Current.GetService<IPclPlatformWrapper>().GetLoadedAssemblies()) |
|||
.Distinct() |
|||
.SelectMany(asm |
|||
=> asm.GetCustomAttributes<XmlnsDefinitionAttribute>().Select(attr => new {asm, attr})) |
|||
.GroupBy(entry => entry.attr.XmlNamespace)) |
|||
{ |
|||
var def = XamlNamespace.Map(nsa.Key) |
|||
.With(nsa.GroupBy(x => x.asm).Select( |
|||
a => Route.Assembly(a.Key) |
|||
.WithNamespaces(a.Select(entry => entry.attr.ClrNamespace).ToList()) |
|||
)); |
|||
xamlNamespaceRegistry.AddNamespace(def); |
|||
} |
|||
xamlNamespaceRegistry.RegisterPrefix(new PrefixRegistration(string.Empty, AvaloniaNs)); |
|||
|
|||
return xamlNamespaceRegistry; |
|||
} |
|||
|
|||
private static ITypeConverterProvider GetConverterProvider() |
|||
{ |
|||
var typeConverterProvider = new TypeConverterProvider(); |
|||
var converters = new[] |
|||
{ |
|||
new TypeConverterRegistration(typeof(IBitmap), new BitmapTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Brush), new BrushTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Color), new ColorTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Classes), new ClassesTypeConverter()), |
|||
new TypeConverterRegistration(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Geometry), new GeometryTypeConverter()), |
|||
new TypeConverterRegistration(typeof(GridLength), new GridLengthTypeConverter()), |
|||
new TypeConverterRegistration(typeof(KeyGesture), new KeyGestureConverter()), |
|||
new TypeConverterRegistration(typeof(AvaloniaList<double>), new AvaloniaListTypeConverter<double>()), |
|||
new TypeConverterRegistration(typeof(IMemberSelector), new MemberSelectorTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Point), new PointTypeConverter()), |
|||
new TypeConverterRegistration(typeof(IList<Point>), new PointsListTypeConverter()), |
|||
new TypeConverterRegistration(typeof(AvaloniaProperty), new AvaloniaPropertyTypeConverter()), |
|||
new TypeConverterRegistration(typeof(RelativePoint), new RelativePointTypeConverter()), |
|||
new TypeConverterRegistration(typeof(RelativeRect), new RelativeRectTypeConverter()), |
|||
new TypeConverterRegistration(typeof(RowDefinitions), new RowDefinitionsTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Selector), new SelectorTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()), |
|||
new TypeConverterRegistration(typeof(TimeSpan), new TimeSpanTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Uri), new UriTypeConverter()), |
|||
new TypeConverterRegistration(typeof(Cursor), new CursorTypeConverter()) |
|||
}; |
|||
|
|||
typeConverterProvider.AddAll(converters); |
|||
return typeConverterProvider; |
|||
} |
|||
|
|||
private static IContentPropertyProvider GetContentPropertyProvider() |
|||
{ |
|||
return new AvaloniaContentPropertyProvider(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
// 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 Avalonia.Markup.Xaml.Data; |
|||
using OmniXaml; |
|||
using OmniXaml.Typing; |
|||
using System; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaXamlMember : Member |
|||
{ |
|||
public AvaloniaXamlMember(string name, |
|||
XamlType owner, |
|||
ITypeRepository xamlTypeRepository, |
|||
ITypeFeatureProvider featureProvider) |
|||
: base(name, owner, xamlTypeRepository, featureProvider) |
|||
{ |
|||
} |
|||
|
|||
protected override IMemberValuePlugin LookupXamlMemberValueConnector() |
|||
{ |
|||
return new AvaloniaMemberValuePlugin(this); |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return "Avalonia XAML Member " + base.ToString(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,61 +0,0 @@ |
|||
// 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.Reflection; |
|||
using OmniXaml; |
|||
using OmniXaml.Typing; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
public class AvaloniaXamlType : XamlType |
|||
{ |
|||
public AvaloniaXamlType(Type type, |
|||
ITypeRepository typeRepository, |
|||
ITypeFactory typeFactory, |
|||
ITypeFeatureProvider featureProvider) : base(type, typeRepository, typeFactory, featureProvider) |
|||
{ |
|||
} |
|||
|
|||
public override OmniXaml.INameScope GetNamescope(object instance) |
|||
{ |
|||
var result = instance as OmniXaml.INameScope; |
|||
|
|||
if (result == null) |
|||
{ |
|||
var control = instance as Control; |
|||
|
|||
if (control != null) |
|||
{ |
|||
var avaloniaNs = (instance as Avalonia.Controls.INameScope) ?? NameScope.GetNameScope(control); |
|||
|
|||
if (avaloniaNs != null) |
|||
{ |
|||
result = new NameScopeWrapper(avaloniaNs); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
protected override Member LookupMember(string name) |
|||
{ |
|||
return new AvaloniaXamlMember(name, this, TypeRepository, FeatureProvider); |
|||
} |
|||
|
|||
protected override AttachableMember LookupAttachableMember(string name) |
|||
{ |
|||
// OmniXAML seems to require a getter and setter even though we don't use them.
|
|||
var getter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Get" + name); |
|||
var setter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Set" + name); |
|||
return new AvaloniaAttachableXamlMember(name, this, getter, setter, TypeRepository, FeatureProvider); |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return "Avalonia XAML Type " + base.ToString(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
// 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.
|
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
internal class NameScopeWrapper : OmniXaml.INameScope |
|||
{ |
|||
private readonly Avalonia.Controls.INameScope _inner; |
|||
|
|||
public NameScopeWrapper(Avalonia.Controls.INameScope inner) |
|||
{ |
|||
_inner = inner; |
|||
} |
|||
|
|||
public object Find(string name) |
|||
{ |
|||
return _inner.Find(name); |
|||
} |
|||
|
|||
public void Register(string name, object scopedElement) |
|||
{ |
|||
_inner.Register(name, scopedElement); |
|||
} |
|||
|
|||
public void Unregister(string name) |
|||
{ |
|||
_inner.Unregister(name); |
|||
} |
|||
} |
|||
} |
|||
@ -1,174 +0,0 @@ |
|||
// 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.Linq; |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using OmniXaml.ObjectAssembler; |
|||
using OmniXaml.TypeConversion; |
|||
using OmniXaml.Typing; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Data; |
|||
using Avalonia.Markup.Xaml.Data; |
|||
using Avalonia.Styling; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
internal static class PropertyAccessor |
|||
{ |
|||
public static void SetValue( |
|||
object instance, |
|||
MutableMember member, |
|||
object value, |
|||
IValueContext context) |
|||
{ |
|||
var avaloniaProperty = FindAvaloniaProperty(instance, member); |
|||
|
|||
if (value is IBinding) |
|||
{ |
|||
SetBinding(instance, member, avaloniaProperty, context, (IBinding)value); |
|||
} |
|||
else if (avaloniaProperty != null) |
|||
{ |
|||
((AvaloniaObject)instance).SetValue(avaloniaProperty, value); |
|||
} |
|||
else if (instance is Setter && member.Name == "Value") |
|||
{ |
|||
// TODO: Make this more generic somehow.
|
|||
var setter = (Setter)instance; |
|||
var targetType = setter.Property.PropertyType; |
|||
var xamlType = member.TypeRepository.GetByType(targetType); |
|||
var convertedValue = default(object); |
|||
|
|||
if (CommonValueConversion.TryConvert(value, xamlType, context, out convertedValue)) |
|||
{ |
|||
SetClrProperty(instance, member, convertedValue); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
SetClrProperty(instance, member, value); |
|||
} |
|||
} |
|||
|
|||
private static AvaloniaProperty FindAvaloniaProperty(object instance, MutableMember member) |
|||
{ |
|||
var registry = AvaloniaPropertyRegistry.Instance; |
|||
var attached = member as AvaloniaAttachableXamlMember; |
|||
var target = instance as AvaloniaObject; |
|||
|
|||
if (target == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
if (attached == null) |
|||
{ |
|||
return registry.FindRegistered(target, member.Name); |
|||
} |
|||
else |
|||
{ |
|||
var ownerType = attached.DeclaringType.UnderlyingType; |
|||
|
|||
RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle); |
|||
|
|||
return registry.GetRegistered(target) |
|||
.Where(x => x.OwnerType == ownerType && x.Name == attached.Name) |
|||
.FirstOrDefault(); |
|||
} |
|||
} |
|||
|
|||
private static void SetBinding( |
|||
object instance, |
|||
MutableMember member, |
|||
AvaloniaProperty property, |
|||
IValueContext context, |
|||
IBinding binding) |
|||
{ |
|||
if (!(AssignBinding(instance, member, binding) || |
|||
ApplyBinding(instance, property, context, binding))) |
|||
{ |
|||
throw new InvalidOperationException( |
|||
$"Cannot assign to '{member.Name}' on '{instance.GetType()}"); |
|||
} |
|||
} |
|||
|
|||
private static void SetClrProperty(object instance, MutableMember member, object value) |
|||
{ |
|||
if (member.IsAttachable) |
|||
{ |
|||
member.Setter.Invoke(null, new[] { instance, value }); |
|||
} |
|||
else |
|||
{ |
|||
member.Setter.Invoke(instance, new[] { value }); |
|||
} |
|||
} |
|||
|
|||
private static bool AssignBinding(object instance, MutableMember member, IBinding binding) |
|||
{ |
|||
var property = instance.GetType() |
|||
.GetRuntimeProperties() |
|||
.FirstOrDefault(x => x.Name == member.Name); |
|||
|
|||
if (property?.GetCustomAttribute<AssignBindingAttribute>() != null) |
|||
{ |
|||
property.SetValue(instance, binding); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private static bool ApplyBinding( |
|||
object instance, |
|||
AvaloniaProperty property, |
|||
IValueContext context, |
|||
IBinding binding) |
|||
{ |
|||
if (property == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
var control = instance as IControl; |
|||
|
|||
if (control != null) |
|||
{ |
|||
if (property != Control.DataContextProperty) |
|||
{ |
|||
DelayedBinding.Add(control, property, binding); |
|||
} |
|||
else |
|||
{ |
|||
control.Bind(property, binding); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// The target is not a control, so we need to find an anchor that will let us look
|
|||
// up named controls and style resources. First look for the closest IControl in
|
|||
// the TopDownValueContext.
|
|||
object anchor = context.TopDownValueContext.StoredInstances |
|||
.Select(x => x.Instance) |
|||
.OfType<IControl>() |
|||
.LastOrDefault(); |
|||
|
|||
// If a control was not found, then try to find the highest-level style as the XAML
|
|||
// file could be a XAML file containing only styles.
|
|||
if (anchor == null) |
|||
{ |
|||
anchor = context.TopDownValueContext.StoredInstances |
|||
.Select(x => x.Instance) |
|||
.OfType<IStyle>() |
|||
.FirstOrDefault(); |
|||
} |
|||
|
|||
((IAvaloniaObject)instance).Bind(property, binding, anchor); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue