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 Localization Guidance で配布できるこの問題の回避策を書きました。

次のように使用できる 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 に答える