Search

'genericTypeExtension'에 해당되는 글 1건

  1. 2011.03.23 GenericTypeExtension works in .NET4.0

GenericTypeExtension works in .NET4.0

프로그래밍 2011.03.23 18:41 Posted by 아일레프

-- I'm sorry for my poor English. --

There are many "GenericTypeExtension" implementations.


http://stackoverflow.com/questions/1706123/how-to-reference-a-generic-type-in-the-datatype-attribute-of-a-hierarchicaldatate

http://blogs.msdn.com/b/mikehillberg/archive/2006/10/06/limitedgenericssupportinxaml.aspx

http://windowsclient.net/blogs/rob_relyea/archive/2009/06/01/xaml-using-generic-types-in-xaml-2009.aspx


All of these don't work in .NET4. Why? These GenericTypeExtensions use IXamlTypeResolver and IXamlTypeResolver.Resolve("generic:List`1") correctly returns "typeof(List<>)" in .NET3.0. However, it can't resolve in .NET 4.0. "IXamlTypeResolver.Resolve("generic:List`1")" just throw an Exception in .NET4.

"Character '`' was unexpected in string 'generic:List`1'.  Invalid XAML type name."

But don't be afraid. There are other useful services NET4.0 provide. If you used IXamlNamespaceResolver and IXamlSchemeaContextProvider, you can get a generic type easily.


xmlns:generic="clr-namespace:System.Collections.Generic;assembly=mscorlib"
XamlNamespaceResolver nameResolver = 
                                serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlNamespaceResolver;
IXamlSchemaContextProvider schemeContextProvider = 
                                serviceProvider.GetService(typeof(IXamlSchemaContextProvider)) as IXamlSchemaContextProvider;
XamlTypeName xamlTypeName = new XamlTypeName(nameResolver.GetNamespace("generic"), "List`1");
Type genericType = schemeContextProvider.SchemaContext.GetXamlType(xamlTypeName).UnderlyingType;

If you explore the ServiceProviderContext through Reflector, you can find other services the ServiceProviderContext implement.

ITypeDescriptorContext, IXamlTypeResolver, IUriContext, IAmbientProvider, 
IXamlSchemaContextProvider, IRootObjectProvider, IXamlNamespaceResolver, 
IProvideValueTarget, IXamlNameResolver, IDestinationTypeProvider

 

I attached a complete GenericTypeExtension, please enjoy it. Thanks~!


[ContentProperty("TypeArguments")]
public class GenericTypeExtension : MarkupExtension
{
        
    private Collection<Type> _typeArguments = new Collection<Type>();
    public Collection<Type> TypeArguments
    {
        get { return _typeArguments; }
    }

    // generic:List`1
    private string baseTypeName;
    public string BaseTypeName
    {
        get { return baseTypeName; }
        set { baseTypeName = value; }
    }
    public GenericTypeExtension() { }
    public GenericTypeExtension(string baseTypeName) { this.baseTypeName = baseTypeName; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (string.IsNullOrEmpty(baseTypeName))
            throw new ArgumentNullException("BaseTypeName");
        string[] baseTypeArray = baseTypeName.Split(':');

        if (baseTypeArray.Length != 2)
            throw new ArgumentException("BaseTypeName");

        if (TypeArguments.Count == 0)
            throw new ArgumentException("TypeArguments");

        IXamlNamespaceResolver nameResolver = 
                                        serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlNamespaceResolver;
        IXamlSchemaContextProvider schemeContextProvider = 
                                        serviceProvider.GetService(typeof(IXamlSchemaContextProvider)) as IXamlSchemaContextProvider;

        if (nameResolver == null || schemeContextProvider == null)
        {
            IRootObjectProvider rootObjectProvider = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
            if (rootObjectProvider as DependencyObject != null &&  
               !DesignerProperties.GetIsInDesignMode(rootObjectProvider as DependencyObject))
                throw new Exception("This Generic markup extension requires these services");
            else
                return null;
        }

        XamlTypeName xamlTypeName = new XamlTypeName(nameResolver.GetNamespace(baseTypeArray[0]), baseTypeArray[1]);
        Type genericType  = schemeContextProvider.SchemaContext.GetXamlType(xamlTypeName).UnderlyingType;
        Type[] typeArguments = TypeArguments.ToArray();

        return genericType.MakeGenericType(typeArguments);
    }
}


        <local:GenericTypeExtension BaseTypeName="generic:List`1">
            <x:Type TypeName="system:String"/>
        </local:GenericTypeExtension>

신고