【问题标题】:WinForms designer properties of different derived types不同派生类型的 WinForms 设计器属性
【发布时间】:2016-10-22 06:08:31
【问题描述】:

假设我有一个特定的类型,我想提供给 Windows 窗体设计器...

public class Style
{
    public CustomBrush Brush { get; set; }
}

CustomBrush 是这样实现的......

public abstract CustomBrush
{
    ...
}

public SolidCustomBrush : CustomBrush
{
    ...
}

public GradientCustomBrush : CustomBrush
{
    ...
}

有没有一种方法可以在设计时从CustomBrush 派生的任何类型中进行选择,实例化所选类型的实例,然后通过设计器对其进行修改?

到目前为止,我认为能够做到这一点的唯一方法是使用enum

enum BrushType
{
    Solid,
    Gradient
}

enum 更改时,Brush 属性下的类型也会更改,但我不喜欢这种方法...它很脏!

【问题讨论】:

标签: c# .net winforms windows-forms-designer propertygrid


【解决方案1】:

作为一个选项,您可以创建一个自定义TypeConverter,它提供一个标准值列表以显示在PropertyGrid 中。

类型转换器可以提供一个类型的值列表 属性窗口控件。当类型转换器提供一组 类型的标准值,属性的值输入字段 属性窗口控件中的关联类型显示向下 显示值列表以设置属性值的箭头 到点击时。

由于您还希望能够在属性网格中编辑CustomBrush 的子属性,因此您应该从ExpandableObjectConverter 派生。

结果

实施

创建一个CustomBrushConverter 类并从ExpandableObjectConverter 派生。然后重写这些方法:

using System;
using System.ComponentModel;
using System.Linq; 
class CustomBrushConverter : ExpandableObjectConverter
{
    CustomBrush[] standardValues = new CustomBrush[] { new SolidCustomBrush(), new GradientCustomBrush() };
    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, System.Globalization.CultureInfo culture, object value)
    {
        var result = standardValues.Where(x => x.ToString() == value).FirstOrDefault();
        if (result != null)
            return result;
        return base.ConvertFrom(context, culture, value);
    }
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }
    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
        return true;
    }
    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        return new StandardValuesCollection(standardValues);
    }
}

然后用TypeConverterAttribute这样装饰Brush属性:

public class Style /*: Component */
{
    [TypeConverter(typeof(CustomBrushConverter))]
    public CustomBrush Brush { get; set; }
}

您可以覆盖CustomBrush 类的ToString 方法,以提供更友好的名称以显示在PropertyGrid 的下拉列表中。例如:

public class GradientCustomBrush : CustomBrush
{
    public Color Color1 { get; set; }
    public Color Color2 { get; set; }
    public override string ToString()
    {
        return "Gradient";
    }
}

【讨论】:

  • 虽然答案完全正确,但投反对票真的很奇怪!
  • 有了这个答案,比如说有人设计了自己的扩展 CustomBrush 的画笔,这个例子可以用来动态查找 CustomBrush 的实现,比如使用反射,并将它们添加到列表中吗?这行得通吗?
  • 该解决方案依赖于 standardValues 数组及其包含的 CustomBrush 实例。所以答案是肯定的。在一个实现中,我使用ITypeDiscoveryService 来查找所需的类型并将它们添加到标准值集合中。
  • 好的,所以我已经实现了这个,但是有一些障碍......下拉列表肯定是正确的,但是比如说每个 CustomBrush 实现都有我也有的属性想通过设计器进行操作(即 SolidCustomBrush 有一个 Color 属性,我想设置它的颜色)...这也可以实现吗?
  • @deveton 关于 UiTypeEditor,它控制编辑部分(如显示模态对话框)。序列化是序列化相关属性和类型转换器的责任。
猜你喜欢
  • 1970-01-01
  • 2014-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多