如何像这样在 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>
最佳答案
你有两种方法:
- 创建一个类型,其基类是您需要的泛型,例如:
- 创建您自己的处理泛型的标记扩展
第一个解决方案(非常快):只需编写类似的内容
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/