0

我正在尝试使用与 StaticExtension 使用的相同命名空间:StaticType.Property 语法在 WPF 标记扩展内进行一些类型解析。该扩展在运行时以及在 Visual Studio 设计器中工作正常,但在 Expression Blend 中失败。经过一些调试后,我发现失败发生在对 IXamlTypeResolver.Resolve() 的调用中。

// Parse Static=properties:Resources.HelloWorld like static resource
int index = this.Static.IndexOf('.');
if (index == -1)
    throw new ArgumentException(Resources.InvalidStaticBindingSyntax + ": " + 
                                this.Static);

// resolve properties:Resources
string typeName = this.Static.Substring(0, index);
IXamlTypeResolver service = _serviceProvider.GetService(typeof(IXamlTypeResolver))
                            as IXamlTypeResolver;

Type memberType = service.Resolve(typeName);

string propName = this.Static.Substring(index + 1);
localized = memberType.GetProperty(propName,
                       BindingFlags.Public | 
                       BindingFlags.Static | 
                       BindingFlags.FlattenHierarchy)
                       .GetValue(memberType, null);

问题是 service.Resolve(typeName) 失败,但仅在 Blend 中。

看看带有 Reflector 的 StaticExtension,MS 使用的代码看起来并没有太大的不同。

它看起来像一个安全问题 - 但我什至尝试签署并 GAC 程序集,但它仍然失败完全一样。

难住了。

4

1 回答 1

0

问题是设计者使用了与 WPF 运行时完全不同的实现。Microsoft Connect 上有一个针对此问题的错误。

我为此问题编写了一个解决方法,可以解决您的特定问题,并且可以与 WPF 本地化指南一起分发。

我创建了一个名为 ExpressionWorkaroundServiceProvider 的包装器,可以这样使用:

// resolve properties:Resources
string typeName = this.Static.Substring(0, index);
string propName = this.Static.Substring(index + 1);

IServiceProvider serviceProvider = new ExpressionWorkaroundServiceProvider(_serviceProvider)
{
    PropertyName = propName
};

IXamlTypeResolver service = serviceProvider.GetService(typeof(IXamlTypeResolver))
                        as IXamlTypeResolver;

Type memberType = service.Resolve(typeName);

this._propertyInfo = memberType.GetProperty(propName,
                BindingFlags.Public |
                BindingFlags.Static |
                BindingFlags.FlattenHierarchy |
                BindingFlags.NonPublic);

ExpressionWorkaroundServiceProvider 的实现:

internal class ExpressionWorkaroundServiceProvider : IServiceProvider, IXamlTypeResolver
{
    private IServiceProvider _originalProvider;

    public string PropertyName { get; set; }

    public ExpressionWorkaroundServiceProvider(IServiceProvider originalProvider)
    {
        if (originalProvider == null)
        {
            throw new ArgumentNullException("originalProvider");
        }

        _originalProvider = originalProvider;
    }

    public object GetService(Type serviceType)
    {
        var servicedObject = _originalProvider.GetService(serviceType);

        if (servicedObject == null && serviceType == typeof(IXamlTypeResolver))
        {
            return this;
        }

        return servicedObject;
    }

    public Type Resolve(string qualifiedTypeName)
    {
        var typeName = qualifiedTypeName.Substring(qualifiedTypeName.IndexOf(':') + 1);

        var types =
            AppDomain.CurrentDomain.GetAssemblies().Aggregate(new List<Type>(),
                (list, asm) =>
                {
                    list.AddRange(asm.GetTypes().Where(p => p.Name.Contains(typeName)));
                    return list;
                });

        if (string.IsNullOrWhiteSpace(PropertyName))
        {
            return types.FirstOrDefault();
        }
        else
        {
            foreach (var type in types)
            {
                if (type.GetProperty(PropertyName,
                        BindingFlags.Public |
                        BindingFlags.Static |
                        BindingFlags.FlattenHierarchy |
                        BindingFlags.NonPublic) != null)
                {
                    return type;
                }
            }

            return null;
        }           
    }
}

这为我解决了这个问题。它不能替代正确的 IXamlTypeResolver 实现,但会在设计器上进行本地化。

于 2011-01-11T12:57:23.553 回答