【问题标题】:Generic Type in Xaml ResourcesXaml 资源中的泛型类型
【发布时间】:2014-05-08 06:50:33
【问题描述】:

我有一个像这样的通用类:

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

我希望这个类作为资源保存在 Window 或 UserControl 中。然后我需要一个像 https://stackoverflow.com/a/5403397/376086 这样的 Xaml 的 GenericTypeExtension,我复制了它:

[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));
    }
}

但是为什么我这样做时会收到 XamlParseException:

<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>

例外在这里:

内部异常的文本是:

我做错了什么?

更新: 它也不适用于:

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

【问题讨论】:

  • 您是否尝试过使用 Type 实例化您的类型,就像您引用的示例中一样?也许类型是关键?
  • 感谢您的回答,您认为我可以使用 List'1 吗?不,它没有用。

标签: c# wpf xaml c#-4.0 generics


【解决方案1】:

发生的情况是 WPF 尝试将标记扩展的值分配给 Resources 属性,而不是向字典中添加项目。这可以通过以下方式轻松解决:

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

【讨论】:

    【解决方案2】:

    您的 MarkupExtension 提供了类型的实例,但没有为此实例设置 x:Key。

    UPD 我有主意!您可以尝试创建这样的容器:

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

    然后像这样声明资源:

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

    它对资源的使用设置了一些限制,但我想它会有所帮助。

    PS 您可以像StringGenericClass:GenericClass&lt;string&gt; 一样继承以在xaml 中使用它。

    【讨论】:

    • 你的意思是返回 genericType.MakeGenericType(typeArguments); return Activator.CreateInstance(genericType.MakeGenericType(typeArguments)); 会更好吗? ??
    • @Tobias 我的意思是 Activator.CreateInstance(genericType.MakeGenericType(typeArguments));对 x:Key 一无所知。但我不知道如何告诉它关于密钥。
    猜你喜欢
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 2011-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    相关资源
    最近更新 更多