| File: System\Windows\Markup\StaticExtension.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\System.Xaml\System.Xaml.csproj (System.Xaml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using System.ComponentModel; using System.Reflection; using System.Runtime.CompilerServices; namespace System.Windows.Markup { /// <summary> /// Class for Xaml markup extension for static field and property references. /// </summary> [TypeForwardedFrom("PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")] [TypeConverter(typeof(StaticExtensionConverter))] [MarkupExtensionReturnType(typeof(object))] public class StaticExtension : MarkupExtension { private string _member; private Type _memberType; /// <summary> /// Constructor that takes no parameters /// </summary> public StaticExtension() { } /// <summary> /// Constructor that takes the member that this is a static reference to. /// This string is of the format Prefix:ClassName.FieldOrPropertyName. /// The Prefix is optional, and refers to the XML prefix in a Xaml file. /// </summary> public StaticExtension(string member) { _member = member ?? throw new ArgumentNullException(nameof(member)); } /// <summary> /// Return an object that should be set on the targetObject's targetProperty /// for this markup extension. For a StaticExtension this is a static field /// or property value. /// </summary> /// <param name="serviceProvider">Object that can provide services for the markup extension.</param> /// <returns> The object to set on this property.</returns> public override object ProvideValue(IServiceProvider serviceProvider) { if (_member is null) { throw new InvalidOperationException(SR.MarkupExtensionStaticMember); } Type type = MemberType; string fieldString; string typeNameForError = null; if (type is not null) { fieldString = _member; typeNameForError = type.FullName; } else { // Validate the _member int dotIndex = _member.IndexOf('.'); if (dotIndex < 0) { throw new ArgumentException(SR.Format(SR.MarkupExtensionBadStatic, _member)); } // Pull out the type substring (this will include any XML prefix, e.g. "av:Button") string typeString = _member.Substring(0, dotIndex); if (string.IsNullOrEmpty(typeString)) { throw new ArgumentException(SR.Format(SR.MarkupExtensionBadStatic, _member)); } // Get the IXamlTypeResolver from the service provider ArgumentNullException.ThrowIfNull(serviceProvider); if (serviceProvider.GetService(typeof(IXamlTypeResolver)) is not IXamlTypeResolver xamlTypeResolver) { throw new ArgumentException(SR.Format(SR.MarkupExtensionNoContext, GetType().Name, nameof(IXamlTypeResolver))); } // Use the type resolver to get a Type instance. type = xamlTypeResolver.Resolve(typeString); // Get the member name substring. fieldString = _member.Substring(dotIndex + 1, _member.Length - dotIndex - 1); if (string.IsNullOrEmpty(typeString)) { throw new ArgumentException(SR.Format(SR.MarkupExtensionBadStatic, _member)); } } // Use the built-in parser for enum types. if (type.IsEnum) { return Enum.Parse(type, fieldString); } // For other types, reflect. if (GetFieldOrPropertyValue(type, fieldString, out object value)) { return value; } throw new ArgumentException(SR.Format(SR.MarkupExtensionBadStatic, typeNameForError is not null ? $"{typeNameForError}.{_member}" : _member)); } /// <summary> /// Return false if a public static field or property with the same /// name cannot be found. /// <summary> private bool GetFieldOrPropertyValue(Type type, string name, out object value) { Type currentType = type; do { FieldInfo field = currentType.GetField(name, BindingFlags.Public | BindingFlags.Static); if (field is not null) { value = field.GetValue(null); return true; } currentType = currentType.BaseType; } while (currentType is not null); currentType = type; do { PropertyInfo prop = currentType.GetProperty(name, BindingFlags.Public | BindingFlags.Static); if (prop is not null) { value = prop.GetValue(null, null); return true; } currentType = currentType.BaseType; } while (currentType is not null); value = null; return false; } /// <summary> /// The static field or property represented by a string. This string is /// of the format Prefix:ClassName.FieldOrPropertyName. The Prefix is /// optional, and refers to the XML prefix in a Xaml file. /// </summary> [ConstructorArgument("member")] public string Member { get => _member; set => _member = value ?? throw new ArgumentNullException(nameof(value)); } [DefaultValue(null)] public Type MemberType { get => _memberType; set => _memberType = value ?? throw new ArgumentNullException(nameof(value)); } } }