我编写了一个自定义 xaml 扩展,但在设计时无法获得 IXamlTypeResolver。我做了一些观察,这似乎是由于 dev studio 2010 中引入的一个错误。作为实验,我反编译了 x:Static 并重建为外部扩展,但它也无法获得 IXamlTypeResolver。然而,构建一个在设计时工作。我想一定有一些内在的魔力在发生。我想知道是否有任何解决方法。我不介意做一些额外的工作来获取我需要的信息,比如解析命名空间 xaml 声明,但似乎我需要这样做的服务在设计时也不可用。Microsoft 是否有解决此问题的计划?它严重限制了自定义 xaml 扩展的实用性。这一定会影响到第 3 方库提供者——我想知道他们是如何解决这个问题的。
[MarkupExtensionReturnType(typeof(object))]
[TypeConverter(typeof(MyStaticExtensionConverter))]
public class MyStaticExtension : MarkupExtension
{
private string _member;
private Type _memberType;
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public MyStaticExtension()
{
}
public MyStaticExtension(string member)
{
if (member == null) {
throw new ArgumentNullException("member");
}
this._member = member;
}
private bool GetFieldOrPropertyValue(Type type, string name, out object value)
{
FieldInfo field = null;
Type baseType = type;
do {
field = baseType.GetField(name, BindingFlags.Public | BindingFlags.Static);
if (field != null) {
value = field.GetValue(null);
return true;
}
baseType = baseType.BaseType;
}
while (baseType != null);
PropertyInfo property = null;
baseType = type;
do {
property = baseType.GetProperty(name, BindingFlags.Public | BindingFlags.Static);
if (property != null) {
value = property.GetValue(null, null);
return true;
}
baseType = baseType.BaseType;
}
while (baseType != null);
value = null;
return false;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this._member == null) {
throw new InvalidOperationException("MarkupExtensionStaticMember");
}
Type memberType = this.MemberType;
string str = null;
string str2 = null;
object obj2;
if (memberType != null) {
str = this._member;
str2 = memberType.FullName + "." + this._member;
}
else {
str2 = this._member;
int index = this._member.IndexOf('.');
if (index < 0) {
throw new ArgumentException("MarkupExtensionBadStatic", this._member);
}
string qualifiedTypeName = this._member.Substring(0, index);
if (qualifiedTypeName == string.Empty) {
throw new ArgumentException("MarkupExtensionBadStatic", this._member);
}
if (serviceProvider == null) {
throw new ArgumentNullException("serviceProvider");
}
IXamlTypeResolver service = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
// Exception will thrown here as at design time
if (service == null) {
throw new ArgumentException("MarkupExtensionNoContext", base.GetType().Name);
}
memberType = service.Resolve(qualifiedTypeName);
str = this._member.Substring(index + 1, (this._member.Length - index) - 1);
if (str == string.Empty) {
throw new ArgumentException("MarkupExtensionBadStatic", this._member);
}
}
if (memberType.IsEnum) {
return Enum.Parse(memberType, str);
}
if (!this.GetFieldOrPropertyValue(memberType, str, out obj2)) {
throw new ArgumentException("MarkupExtensionBadStatic", str2);
}
return obj2;
}
[ConstructorArgument("member")]
public string Member
{
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this._member;
}
set
{
if (value == null) {
throw new ArgumentNullException("value");
}
this._member = value;
}
}
[DefaultValue((string)null)]
public Type MemberType
{
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this._memberType;
}
set
{
if (value == null) {
throw new ArgumentNullException("value");
}
this._memberType = value;
}
}
}
internal class MyStaticExtensionConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType));
}
[SecurityCritical, SecurityTreatAsSafe]
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(InstanceDescriptor)) {
return base.ConvertTo(context, culture, value, destinationType);
}
MyStaticExtension extension = value as MyStaticExtension;
if (extension == null) {
throw new ArgumentException("MustBeOfType", "value");
}
return new InstanceDescriptor(typeof(MyStaticExtension).GetConstructor(new Type[] { typeof(string) }), new object[] { extension.Member });
}
}