diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 50834ed294..45280020c4 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -94,6 +94,8 @@ + + diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs new file mode 100644 index 0000000000..fd99892699 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs @@ -0,0 +1,86 @@ +// 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 OmniXaml; +using Glass.Core; + +namespace Avalonia.Markup.Xaml.MarkupExtensions.Standard +{ + public class StaticExtension : MarkupExtension + { + public StaticExtension() + { + } + + public StaticExtension(string identifier) + { + Identifier = identifier; + } + + public string Identifier { get; set; } + + public override object ProvideValue(MarkupExtensionContext markupExtensionContext) + { + var typeRepository = markupExtensionContext.ValueContext.TypeRepository; + var typeAndMember = GetTypeAndMember(Identifier); + var prefixAndType = GetPrefixAndType(typeAndMember.Item1); + var xamlType = typeRepository.GetByPrefix(prefixAndType.Item1, prefixAndType.Item2); + return GetValue(xamlType.UnderlyingType, typeAndMember.Item2); + } + + private static Tuple GetTypeAndMember(string s) + { + var parts = s.Split('.'); + + if (parts.Length != 2) + { + throw new ArgumentException("Static member must be in the form Type.Member."); + } + + return Tuple.Create(parts[0], parts[1]); + } + + private static Tuple GetPrefixAndType(string s) + { + if (s.Contains(":")) + { + return s.Dicotomize(':'); + } + else + { + return new Tuple(string.Empty, s); + } + } + + private object GetValue(Type type, string name) + { + var t = type; + + while (t != null) + { + var result = t.GetTypeInfo().DeclaredMembers.FirstOrDefault(x => x.Name == name); + + if (result is PropertyInfo) + { + var property = ((PropertyInfo)result); + + if (property.GetMethod.IsStatic) + { + return ((PropertyInfo)result).GetValue(null); + } + } + else if (result is FieldInfo) + { + return ((FieldInfo)result).GetValue(null); + } + + t = t.GetTypeInfo().BaseType; + } + + throw new ArgumentException($"Static member '{type}.{name}' not found."); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs new file mode 100644 index 0000000000..11b390365c --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs @@ -0,0 +1,49 @@ +// 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.Attributes; +using OmniXaml.Typing; +using Glass.Core; + +namespace Avalonia.Markup.Xaml.MarkupExtensions.Standard +{ + [ContentProperty("TargetType")] + public class TypeExtension : MarkupExtension + { + public Type Type { get; set; } + + public TypeExtension() + { + } + + public TypeExtension(Type type) + { + Type = type; + } + + public string TypeName { get; set; } + + private Type ResolveFromString(string type, ITypeRepository typeRepository) + { + Guard.ThrowIfNull(type, nameof(type)); + + var split = type.Split(':'); + var prefix = split.Length == 1 ? split[0] : null; + var typeName = split.Length == 1 ? split[1] : split[0]; + var xamlType = typeRepository.GetByPrefix(prefix, typeName); + return xamlType.UnderlyingType; + } + + public override object ProvideValue(MarkupExtensionContext markupExtensionContext) + { + if (Type != null) + { + return Type; + } + + return ResolveFromString(TypeName, markupExtensionContext.ValueContext.TypeRepository); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs index d14f5d82b6..0b42bedfa8 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs @@ -10,5 +10,6 @@ using System.Runtime.CompilerServices; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Templates")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml", "Avalonia.Markup.Xaml.MarkupExtensions.Standard")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]