Domanda

I have a generic class like this:

public class GenericClass<T>  where T : class
{
    public GenericClass()
    {
    }
}

And I want this class to hold as a resource in a Window or UserControl. Then I need a GenericTypeExtension for Xaml like this https://stackoverflow.com/a/5403397/376086 which I copied so:

[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 Activator.CreateInstance(genericType.MakeGenericType(typeArguments));
    }
}

But why do I get a XamlParseException when I do this:

<Window x:Class="GenericXaml.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:genericXaml="clr-namespace:GenericXaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow"
    Width="525"
    Height="350">
    <Window.Resources>
        <genericXaml:GenericTypeExtension BaseTypeName="genericXaml:GenericClass`1" x:Key="hanswurst">
            <x:Type TypeName="system:String" />
        </genericXaml:GenericTypeExtension>
    </Window.Resources>
    <Grid />
</Window>

The Exception is here: Exception

The Text of the Inner Exception is: enter image description here

What am I doing wrong?

Update: It also doesn't work with:

        <genericXaml:GenericTypeExtension BaseTypeName="generic:List`1" x:Key="kdid">
        <x:Type TypeName="system:String"/>
    </genericXaml:GenericTypeExtension>
È stato utile?

Soluzione

What's happening is that WPF attempts to assign your markup extension's value to the Resources property, instead of adding an item to the dictionary. This can be easily solved by:

<Window.Resources>
    <ResourceDictionary>
        <genericXaml:GenericTypeExtension BaseTypeName="genericXaml:GenericClass`1" x:Key="hanswurst">
            <x:Type TypeName="system:String" />
        </genericXaml:GenericTypeExtension>
    </ResourceDictionary>
</Window.Resources>

Altri suggerimenti

Your MarkupExtension provides instance of type, but x:Key is not set for this instance.

UPD I have idea! You can try to create container like that:

[ContentProperty("Value")]
public class GenericContainer
{
    public object Value { get; set; }
}

and than declare Resource like that:

<Window.Resources>
    <ns:GenericContainer x:Key="hanswurst">
        <genericXaml:GenericTypeExtension BaseTypeName="genericXaml:GenericClass`1">
            <x:Type TypeName="system:String" />
        </genericXaml:GenericTypeExtension>
    </ns:GenericContainer>
</Window.Resources>

It puts some limitations on usage of resource, but I guess it can help.

PS You can inheritance like StringGenericClass:GenericClass<string> to use it in xaml.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top