wpf - 我如何使用 {x :Type generic:List<sys:String>} in WPF xaml?

标签 wpf xaml generics

如何像这样在 xaml 中使用泛型?

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:dxprg="http://schemas.devexpress.com/winfx/2008/xaml/propertygrid"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             xmlns:generic="clr-namespace:System.Collections.Generic;assembly=mscorlib">
    <dxprg:PropertyGridControl SelectedObject="{Binding Argument}">
        <dxprg:PropertyDefinition Type="<b>{x:Type generic:List<sys:String>}</b>"/>
    </dxprg:PropertyGridControl> 
</UserControl>

最佳答案

你有两种方法:

  1. 创建一个类型,其基类是您需要的泛型,例如:
  2. 创建您自己的处理泛型的标记扩展

第一个解决方案(非常快):只需编写类似的内容

public class ListOfStrings : List<String>
{
}

然后

<dxprg:PropertyGridControl SelectedObject="{Binding Argument}">
    <dxprg:PropertyDefinition Type="{x:Type local:ListOfStrings}" />
</dxprg:PropertyGridControl>

第二种解决方案可能稍微复杂一些,但并非不可能。你可以找到很好的Markup Extension for Generic Classes on CodeProject .

我只是根据您的方便复制代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Markup;
using System.Xaml;
using System.Xaml.Schema;

namespace XamlGenericTypeExtension
{
    [ContentProperty("TypeArguments")]
    [MarkupExtensionReturnType(typeof(Type))]
    public class GenericTypeExtension : MarkupExtension
    {
        private readonly List<Type> _typeArguments = new List<Type>();
        private string _typeName;
        private Type _type;

        public GenericTypeExtension(string typeName)
        {
            if (string.IsNullOrEmpty(typeName)) throw new ArgumentNullException("typeName");
            _typeName = typeName;
        }

        public GenericTypeExtension(string typeName, Type typeArgument)
            : this(typeName)
        {
            if (typeArgument != null)
            {
                _typeArguments.Add(typeArgument);
            }
        }

        public GenericTypeExtension(string typeName, Type typeArgument1, Type typeArgument2)
            : this(typeName, typeArgument1)
        {
            if (typeArgument2 != null)
            {
                _typeArguments.Add(typeArgument2);
            }
        }

        public GenericTypeExtension(string typeName, Type typeArgument1, Type typeArgument2, Type typeArgument3)
            : this(typeName, typeArgument1, typeArgument2)
        {
            if (typeArgument3 != null)
            {
                _typeArguments.Add(typeArgument3);
            }
        }

        public GenericTypeExtension(string typeName, Type typeArgument1, Type typeArgument2, Type typeArgument3, Type typeArgument4)
            : this(typeName, typeArgument1, typeArgument2, typeArgument3)
        {
            if (typeArgument4 != null)
            {
                _typeArguments.Add(typeArgument4);
            }
        }

        public GenericTypeExtension()
        {
        }

        public string BaseTypeName
        {
            get
            {
                return _typeName;
            }
            set
            {
                if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");
                _typeName = value;
                _type = null;
            }
        }

        [TypeConverter(typeof(TypeArgumentsConverter))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public IList TypeArguments
        {
            get
            {
                return _typeArguments;
            }
            set
            {
                _typeArguments.Clear();
                if (null != value && 0 != value.Count)
                {
                    _typeArguments.AddRange(value.OfType<Type>());
                }
            }
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null) throw new ArgumentNullException("serviceProvider");

            if (_type == null)
            {
                if (string.IsNullOrEmpty(_typeName))
                {
                    throw new InvalidOperationException("No base type name was specified.");
                }

                if (_typeArguments.Count == 0)
                {
                    _type = ResolveNonGenericType(serviceProvider, _typeName);
                }
                else
                {
                    _type = ResolveGenericType(serviceProvider, _typeName, _typeArguments.ToArray());
                }
            }

            return _type;
        }

        private static Type ResolveNonGenericType(IServiceProvider serviceProvider, string typeName)
        {
            var resolver = GetRequiredService<IXamlTypeResolver>(serviceProvider);
            Type type = resolver.Resolve(typeName);

            if (type == null)
            {
                throw new InvalidOperationException(string.Format("Unable to resolve type '{0}'.", typeName));
            }

            return type;
        }

        private static Type ResolveGenericType(IServiceProvider serviceProvider, string typeName, Type[] typeArguments)
        {
            string namespaceName;
            string[] splitTypeName = typeName.Split(':');
            if (2 == splitTypeName.Length)
            {
                namespaceName = splitTypeName[0];
                typeName = splitTypeName[1];
            }
            else
            {
                namespaceName = string.Empty;
            }

            var resolver = GetRequiredService<IXamlNamespaceResolver>(serviceProvider);
            var schema = GetRequiredService<IXamlSchemaContextProvider>(serviceProvider);

            var xamlNs = resolver.GetNamespace(namespaceName);
            string genericTypeName = string.Format(CultureInfo.InvariantCulture, "{0}`{1:D}", typeName, typeArguments.Length);

            var xamlTypeName = new XamlTypeName(xamlNs, genericTypeName);
            var xamlType = schema.SchemaContext.GetXamlType(xamlTypeName);
            if (xamlType == null)
            {
                throw new InvalidOperationException(string.Format("Unable to resolve type '{0}'.", xamlTypeName));
            }

            Type genericType = xamlType.UnderlyingType;
            if (genericType == null)
            {
                throw new InvalidOperationException(string.Format("Unable to resolve type '{0}'.", xamlTypeName));
            }

            return genericType.MakeGenericType(typeArguments);
        }

        private static T GetRequiredService<T>(IServiceProvider serviceProvider) where T : class
        {
            var result = serviceProvider.GetService(typeof(T)) as T;
            if (null != result) return result;

            throw new InvalidOperationException(string.Format(
                "Markup extension '{0}' requires '{1}' be implemented in the IServiceProvider for ProvideValue.",
                typeof(GenericTypeExtension).Name,
                typeof(T).Name));
        }
    }
}

还有

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Markup;

namespace XamlGenericTypeExtension
{
    public class TypeArgumentsConverter : TypeConverter
    {
        public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(Type)) return true;
            if (context == null) return false;

            var resolver = context.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
            return resolver != null;
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value == null || value is IList<Type>) return value;

            Type valueType = value as Type;
            if (valueType != null)
            {
                return new List<Type> { valueType };
            }

            string valueString = value as string;
            if (valueString != null && context != null)
            {
                var resolver = context.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
                if (resolver != null)
                {
                    var list = valueString.Split(',').Select(s => resolver.Resolve(s.Trim())).ToList();
                    if (list.All(t => t != null)) return list;
                }
            }

            throw GetConvertFromException(value);
        }
    }
}

CodeProject 上的文章提供了有关如何使用它的信息。 希望对您有帮助。

关于wpf - 我如何使用 {x :Type generic:List<sys:String>} in WPF xaml?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51572676/

相关文章:

c# - 压缩图像大小或减小捕获图像的尺寸

java - List<Dog> 是 List<Animal> 的子类吗?为什么 Java 泛型不是隐式多态的?

Java泛型.class

c# - WPF - ConverterParameter 中的动态值

wpf - 调整 WPF 窗口的大小,但保持比例?

c# - 如何让我的程序读取屏幕边缘以便窗口捕捉

c# - 在 WPF 中应用程序启动时应默认选择 ListView 项

c# - 从字符串转换为 <T>

wpf - 在不同的行上跨越不同数量的列

wpf - WPF 中自动剪辑 TextBlock