質問

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>
役に立ちましたか?

解決

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>

他のヒント

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top