x:Static 和 StaticResource 标记扩展
2014-02-07 17:50
246 查看
标记扩展(markup extension)是 XAML 语言以及 XAML 服务的 .NET 实现的常规功能。 本文简单论述x:Static 和 StaticResource 标记扩展。
Xaml 示例
当x:static与默认 XAML Schema Context一起运行时,对静态属性的查找操作可以由 .NET Framework XAML Serivces及其 XAML Readers和 XAML Writers执行。如下所示,通过ServiceProvider 得到其Xaml Type,进而用反射来取得值。
StaticResource 标记扩展通过查找对已定义资源的引用,指定的 ResourceKey 应与某个现有资源对应,此现有资源使用页、应用程序、可用控件主题和外部资源或系统资源中某一级别的 x:Key 指令来标识。 资源查找按照该顺序执行。
Xaml 示例
<Window.Resources> <FontFamily x:Key="CustomFont">Verdana</FontFamily> </Window.Resources>
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily},Path=Source}"></TextBlock> <TextBlock Text="{Binding Source={StaticResource CustomFont},Path=Source}"></TextBlock>
当x:static与默认 XAML Schema Context一起运行时,对静态属性的查找操作可以由 .NET Framework XAML Serivces及其 XAML Readers和 XAML Writers执行。如下所示,通过ServiceProvider 得到其Xaml Type,进而用反射来取得值。
using System; using System.ComponentModel; using System.Runtime; using System.Runtime.CompilerServices; namespace System.Windows.Markup { [TypeConverter(typeof(StaticExtensionConverter)),MarkupExtensionReturnType(typeof(object))] public class StaticExtension : MarkupExtension { public StaticExtension(); public StaticExtension(string member); public Type MemberType { get; set; } public override object ProvideValue(IServiceProvider serviceProvider); } }
/// <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. /// <returns> /// The object to set on this property. /// </returns> public override object ProvideValue(IServiceProvider serviceProvider) { if (_member == null) { throw new InvalidOperationException(SR.Get(SRID.MarkupExtensionStaticMember)); } object value = null; Type type = MemberType; string fieldString = null; string memberFullName = null; if (type != null) { fieldString = _member; memberFullName = type.FullName + "." + _member; } else { memberFullName = _member; // Validate the _member int dotIndex = _member.IndexOf('.'); if (dotIndex < 0) { throw new ArgumentException(SR.Get(SRID.MarkupExtensionBadStatic, _member)); } // Pull out the type substring (this will include any XML prefix, e.g. "av:Button") string typeString = _member.Substring(0, dotIndex); if (typeString == string.Empty) { throw new ArgumentException(SR.Get(SRID.MarkupExtensionBadStatic, _member)); } // Get the IXamlTypeResolver from the service provider IXamlTypeResolver xamlTypeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver; if (xamlTypeResolver == null) { throw new ArgumentException(SR.Get(SRID.MarkupExtensionNoContext, GetType().Name, "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 (fieldString == string.Empty) { throw new ArgumentException(SR.Get(SRID.MarkupExtensionBadStatic, _member)); } } // Use the built-in parser for enum types if (type.IsEnum) { return Enum.Parse(type, fieldString); } // For other types, reflect bool found = false; object fieldOrProp = type.GetField(fieldString, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static); if (fieldOrProp == null) { fieldOrProp = type.GetProperty(fieldString, BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static); if (fieldOrProp is PropertyInfo) { value = ((PropertyInfo)fieldOrProp).GetValue(null, null); found = true; } } else if (fieldOrProp is FieldInfo) { value = ((FieldInfo)fieldOrProp).GetValue(null); found = true; } if (found) { return value; } else { throw new ArgumentException(SR.Get(SRID.MarkupExtensionBadStatic, memberFullName)); } }
StaticResource 标记扩展通过查找对已定义资源的引用,指定的 ResourceKey 应与某个现有资源对应,此现有资源使用页、应用程序、可用控件主题和外部资源或系统资源中某一级别的 x:Key 指令来标识。 资源查找按照该顺序执行。
using System; using System.Runtime; using System.Windows.Markup; namespace System.Windows { [MarkupExtensionReturnType(typeof(Object))] [Localizability(LocalizationCategory.NeverLocalize)] public class StaticResourceExtension : MarkupExtension { public StaticResourceExtension(); public StaticResourceExtension(object resourceKey); public object ResourceKey { get; set; } public override object ProvideValue(IServiceProvider serviceProvider); } }
/// <summary>Returns an object that should be set on the property where this extension is applied. For <see cref="T:System.Windows.StaticResourceExtension" />, this is the object found in a resource dictionary, where the object to find is identified by the <see cref="P:System.Windows.StaticResourceExtension.ResourceKey" />.</summary> /// <returns>The object value to set on the property where the markup extension provided value is evaluated.</returns> /// <param name="serviceProvider">Object that can provide services for the markup extension.</param> /// <exception cref="T:System.InvalidOperationException"> /// <paramref name="serviceProvider" /> was null, or failed to implement a required service.</exception> public override object ProvideValue(IServiceProvider serviceProvider) { if (this.ResourceKey is SystemResourceKey) { return (this.ResourceKey as SystemResourceKey).Resource; } return this.ProvideValueInternal(serviceProvider, false); } internal object ProvideValueInternal(IServiceProvider serviceProvider, bool allowDeferredReference) { object obj = this.TryProvideValueInternal(serviceProvider, allowDeferredReference, false); if (obj == DependencyProperty.UnsetValue) { throw new Exception(SR.Get("ParserNoResource", new object[] { this.ResourceKey.ToString() })); } return obj; } internal object TryProvideValueInternal(IServiceProvider serviceProvider, bool allowDeferredReference, bool mustReturnDeferredResourceReference) { DeferredResourceReference prefetchedValue = this.PrefetchedValue; object obj; if (prefetchedValue == null) { obj = this.FindResourceInEnviroment(serviceProvider, allowDeferredReference, mustReturnDeferredResourceReference); } else { obj = this.FindResourceInDeferredContent(serviceProvider, allowDeferredReference, mustReturnDeferredResourceReference); if (obj == DependencyProperty.UnsetValue) { obj = (allowDeferredReference ? prefetchedValue : prefetchedValue.GetValue(BaseValueSourceInternal.Unknown)); } } return obj; }
internal object FindResourceInDeferredContent(IServiceProvider serviceProvider, bool allowDeferredReference, bool mustReturnDeferredResourceReference) { ResourceDictionary resourceDictionary = this.FindTheResourceDictionary(serviceProvider, true); object obj = DependencyProperty.UnsetValue; if (resourceDictionary != null) { obj = resourceDictionary.Lookup(this.ResourceKey, allowDeferredReference, mustReturnDeferredResourceReference, false); } if (mustReturnDeferredResourceReference && obj == DependencyProperty.UnsetValue) { obj = new DeferredResourceReferenceHolder(this.ResourceKey, obj); } return obj; } private object FindResourceInAppOrSystem(IServiceProvider serviceProvider, bool allowDeferredReference, bool mustReturnDeferredResourceReference) { object result; if (!SystemResources.IsSystemResourcesParsing) { object obj; result = FrameworkElement.FindResourceFromAppOrSystem(this.ResourceKey, out obj, false, allowDeferredReference, mustReturnDeferredResourceReference); } else { result = SystemResources.FindResourceInternal(this.ResourceKey, allowDeferredReference, mustReturnDeferredResourceReference); } return result; } private object FindResourceInEnviroment(IServiceProvider serviceProvider, bool allowDeferredReference, bool mustReturnDeferredResourceReference) { ResourceDictionary resourceDictionary = this.FindTheResourceDictionary(serviceProvider, false); if (resourceDictionary != null) { return resourceDictionary.Lookup(this.ResourceKey, allowDeferredReference, mustReturnDeferredResourceReference, false); } object obj = this.FindResourceInAppOrSystem(serviceProvider, allowDeferredReference, mustReturnDeferredResourceReference); if (obj == null) { obj = DependencyProperty.UnsetValue; } if (mustReturnDeferredResourceReference && !(obj is DeferredResourceReference)) { obj = new DeferredResourceReferenceHolder(this.ResourceKey, obj); } return obj; }
private ResourceDictionary FindTheResourceDictionary(IServiceProvider serviceProvider, bool isDeferredContentSearch) { IXamlSchemaContextProvider xamlSchemaContextProvider = serviceProvider.GetService(typeof(IXamlSchemaContextProvider)) as IXamlSchemaContextProvider; if (xamlSchemaContextProvider == null) { throw new InvalidOperationException(SR.Get("MarkupExtensionNoContext", new object[] { base.GetType().Name, "IXamlSchemaContextProvider" })); } IAmbientProvider ambientProvider = serviceProvider.GetService(typeof(IAmbientProvider)) as IAmbientProvider; if (ambientProvider == null) { throw new InvalidOperationException(SR.Get("MarkupExtensionNoContext", new object[] { base.GetType().Name, "IAmbientProvider" })); } XamlSchemaContext schemaContext = xamlSchemaContextProvider.SchemaContext; XamlType xamlType = schemaContext.GetXamlType(typeof(FrameworkElement)); XamlType xamlType2 = schemaContext.GetXamlType(typeof(Style)); XamlType xamlType3 = schemaContext.GetXamlType(typeof(FrameworkTemplate)); XamlType xamlType4 = schemaContext.GetXamlType(typeof(Application)); XamlType xamlType5 = schemaContext.GetXamlType(typeof(FrameworkContentElement)); XamlMember member = xamlType5.GetMember("Resources"); XamlMember member2 = xamlType.GetMember("Resources"); XamlMember member3 = xamlType2.GetMember("Resources"); XamlMember member4 = xamlType2.GetMember("BasedOn"); XamlMember member5 = xamlType3.GetMember("Resources"); XamlMember member6 = xamlType4.GetMember("Resources"); XamlType[] types = new XamlType[] { schemaContext.GetXamlType(typeof(ResourceDictionary)) }; IEnumerable<AmbientPropertyValue> allAmbientValues = ambientProvider.GetAllAmbientValues(null, isDeferredContentSearch, types, new XamlMember[] { member, member2, member3, member4, member5, member6 }); List<AmbientPropertyValue> list = allAmbientValues as List<AmbientPropertyValue>; for (int i = 0; i < list.Count; i++) { AmbientPropertyValue ambientPropertyValue = list[i]; if (ambientPropertyValue.Value is ResourceDictionary) { ResourceDictionary resourceDictionary = (ResourceDictionary)ambientPropertyValue.Value; if (resourceDictionary.Contains(this.ResourceKey)) { return resourceDictionary; } } if (ambientPropertyValue.Value is Style) { Style style = (Style)ambientPropertyValue.Value; ResourceDictionary resourceDictionary2 = style.FindResourceDictionary(this.ResourceKey); if (resourceDictionary2 != null) { return resourceDictionary2; } } } return null; }
相关文章推荐
- WPF中StaticResource 标记扩展和DynamicResource 标记扩展
- x:static 标记扩展用法小结
- 类中找不到main方法请将main方法定义为public static void main. 否则 JavaFX 应用程序类必须扩展javafx.application.Application
- xml即可扩展标记语言
- iOS 扩展 UINavigationController 出栈返回到先前标记的位置
- XML: Extentsible Markup Language 可扩展标记语言
- XML(Extensible Markup Language 可扩展的标记语言)简述及读取
- 可扩展标记语言
- 可扩展标记语言XML()
- WPF中的ComponentResourceKey 标记扩展
- XML可扩展标记语言 -- 学习笔记一
- Firefox - 附加组件 - 扩展 - Firebug - HTML面板 - 标记的显示也会与源代码不同,而是按照Firefox对文档结构的解析显示的
- wpf 扩展标记应用 数据类型转
- XAML实例教程系列 - 标记扩展(Markup Extensions)
- WPF,Silverlight与XAML读书笔记(3) - 标记扩展
- XAML语法及标记扩展、附加属性、特定的字符和空白
- XML可扩展标记语言 -- 学习笔记二
- Loki库读解 STATIC_CHECK扩展:可放在任何地方的STATIC_CHECK,编译期打印出类型的大小
- wpf中xaml的类型转换器与标记扩展
- 标记扩展 Markup Extension