如何在WPF xaml中使用{x:Type generic:List <sys:string>}?

时间:2018-07-28 15:17:09

标签: wpf xaml generics

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

dataObsevable.pipe(withLatestFrom(scrollEvents)).subscribe(([list, e]) => {
  this.data = list;
  if (e.position) {
    viewPort.scrollToPosition(e.position);
  } else {
    viewPort.scrollToPosition([0, 0]);
  }
});

1 个答案:

答案 0 :(得分:1)

您有两种方法:

  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的文章提供了有关如何使用它的信息。 希望它能对您有所帮助。