DevExpress WPF PropertyGridControl:在绑定对象的另一部分引用对象

DevExpress WPF PropertyGridControl: Referencing objects in another part of the bound object

我有一个复杂的对象,我试图在 DevExpress WPF PropertyGridControl 中显示它。该对象中嵌套了其他对象。一些嵌套对象引用其他嵌套对象,我想维护它们之间的引用 link(即我不想求助于字符串或 ids 到 link 对象)。这是我正在处理的对象层次结构的人为示例:

public class OrderSystem
{
    public List<Customer> Customers { get; set; }
    public List<Order> Orders { get; set; }
}

public class Customer
{
    public string Name { get; set; }

    public override string ToString() => Name;
}

public class Order
{
    public Customer Buyer { get; set; }
}

我解决这个问题的方法是用自定义类型转换器装饰订单的 Buyer 属性,该转换器决定对象的其他部分的可用客户:

public class Order
{
    [TypeConverter(typeof(AvailableCustomersTypeConverter))]
    public Customer Buyer { get; set; }
}

自定义类型转换器代码如下所示:

    public class AvailableCustomersTypeConverter : TypeConverter
    {
        public static List<Customer> AvailableCustomers { get; set; }

        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            var customers = AvailableCustomers ?? new List<Customer>();
            var availableNames = AvailableCustomers.Select(c => c.Name).ToList();
            return new StandardValuesCollection(availableNames);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) => DoConvert(value);

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) => DoConvert(value);

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => destinationType == typeof(string) || destinationType == typeof(Customer);

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(string) || sourceType == typeof(Customer);

        private object DoConvert(object value)
        {
            if (value is string name)
            {
                if (AvailableCustomers != null)
                {
                    return AvailableCustomers.FirstOrDefault(c => c.Name == name);
                }
                else
                {
                    return string.Empty;
                }
            }
            else if (value is Customer customer)
            {
                return customer.Name;
            }
            else
            {
                throw new NotSupportedException($"{value.GetType().FullName}");
            }
        }
    }

静态 List<Customer> AvailableCustomers 属性 在加载新的 OrderSystem 时设置,或者在 OrderSystem 的 Customers 集合更改时设置。我必须将其设为静态,以便 AvailableCustomersTypeConverter 可以访问它,因为它包含在一个属性中。

这很好用,因为它确实将客户限制为对象其他部分可用的客户。

但是,一旦内容失去焦点,选择就会变成空白:

请注意,我已确认实际对象引用仍然存在。引用没有损坏,它只是停止在 UI.

中正常显示

我想弄清楚如何让选定的客户在内容单元格失去焦点后正确显示。有人有什么想法吗?

我发现了这个问题,这源于我的错误想法,即客户对象需要从字符串(它们的名称)来回转换,因为我认为这就是下拉框将显示的内容。但是,由于我在 Customer 对象(显示名称)上创建了 ToString() 覆盖,因此没有必要这样做。

当我(或者说我的 co-worker)将 AvailableCustomersTypeConverter 中的 GetStandardValues 方法更改为 return 实际客户对象的列表而不仅仅是它们的名称时,事情突然开始起作用了。

此外,因为我直接 return 访问 Customer 对象,所以我不需要所有这些转换方法。更新后的 AvailableCustomersTypeConverter 代码如下所示:

public class AvailableCustomersTypeConverter : TypeConverter
{
    public static List<Customer> AvailableCustomers { get; set; }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true;

    public override bool GetStandardValuesSupported(ITypeDescriptorContext context) => true;

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) => true;

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        return new StandardValuesCollection(AvailableCustomers ?? new List<Customer>());
    }
}