我将根据这篇文章中的答案创建一个示例:PropertyGrid - 动态加载下拉值.
基本思想是拥有自定义类型转换器和重写获取标准值返回编辑属性支持的值的列表。
这里的要点是使用上下文实例获取正在编辑的对象的实例,并尝试根据编辑对象的其他属性过滤列表。
在下面的示例中,我将编辑Product
其中有一个Category
and a SubCategory
属性,并且类别和子类别之间存在关系。例如,如果您选择类别 1,则子类别列表应显示类别 1 的子类别,但如果您选择类别 2,则列表应显示另一组子类别,如下所示:
这是示例的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
private Category category;
[TypeConverter(typeof(CategoryConverter))]
public Category Category
{
get { return category; }
set
{
if (category?.Id != value?.Id)
{
category = value;
SubCategory = null;
}
}
}
[TypeConverter(typeof(SubCategoryConverter))]
public SubCategory SubCategory { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return $"{Id} - {Name}";
}
}
public class SubCategory
{
public int Id { get; set; }
public int CategoryId { get; set; }
public string Name { get; set; }
public override string ToString()
{
return $"{Id} - {Name}";
}
}
public class CategoryService
{
List<Category> categories = new List<Category> {
new Category() { Id = 1, Name = "Category 1" },
new Category() { Id = 2, Name = "Category 2" },
};
List<SubCategory> subCategories = new List<SubCategory> {
new SubCategory() { Id = 11, Name = "Sub Category 1-1", CategoryId= 1 },
new SubCategory() { Id = 12, Name = "Sub Category 1-2", CategoryId= 1 },
new SubCategory() { Id = 13, Name = "Sub Category 1-3", CategoryId= 1 },
new SubCategory() { Id = 21, Name = "Sub Category 2-1", CategoryId= 2 },
new SubCategory() { Id = 22, Name = "Sub Category 2-2", CategoryId= 2 },
};
public IEnumerable<Category> GetCategories()
{
return categories;
}
public IEnumerable<SubCategory> GetSubCategories()
{
return subCategories.ToList();
}
}
public class CategoryConverter : TypeConverter
{
public override StandardValuesCollection GetStandardValues(
ITypeDescriptorContext context)
{
var svc = new CategoryService();
return new StandardValuesCollection(svc.GetCategories().ToList());
}
public override bool GetStandardValuesSupported(
ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(
ITypeDescriptorContext context)
{
return true;
}
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{
if (value != null && value.GetType() == typeof(string))
{
var v = $"{value}";
var id = int.Parse(v.Split('-')[0].Trim());
var svc = new CategoryService();
return svc.GetCategories()
.Where(x => x.Id == id).FirstOrDefault();
}
return base.ConvertFrom(context, culture, value);
}
}
public class SubCategoryConverter : TypeConverter
{
public override StandardValuesCollection GetStandardValues(
ITypeDescriptorContext context)
{
var svc = new CategoryService();
var categoryId = ((Product)context.Instance).Category.Id;
return new StandardValuesCollection(svc.GetSubCategories()
.Where(x => x.CategoryId == categoryId).ToList());
}
public override bool GetStandardValuesSupported(
ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(
ITypeDescriptorContext context)
{
return true;
}
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{
if (value != null && value.GetType() == typeof(string))
{
var v = $"{value}";
var id = int.Parse(v.Split('-')[0].Trim());
var svc = new CategoryService();
return svc.GetSubCategories()
.Where(x => x.Id == id).FirstOrDefault();
}
return base.ConvertFrom(context, culture, value);
}
}