自定义DataGridView列在Designer

时间:2016-04-08 14:10:23

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

我制作了一个自定义的DataGridView组件,里面有一个标准的DataGridViewImageColumn。当我不需要在特定表中输入时,新属性会更改列的可见性。我在构造函数中添加列并在CellFormatting事件上更新它。这就是按预期工作的部分。

当我将控件放到新表单上时,它会显示新列。运行程序会在网格中生成两个图像列。

Screenshot in designer

新表单刚刚添加了组件并设置了Dock.Fill

Screenshot from application running

当我开始它而不改变任何东西时它会显示两列。第一个工作就像它应该工作,第二个总是显示丢失的x图像(没有数据,因此它们显示x)。

在表单的设计者中,会自动添加一个ne image列。

private CustomDataGridView customDataGridView1;
private System.Windows.Forms.DataGridViewImageColumn dataGridViewImageColumn1;

当我继续在表单中进行编辑时,有时会发生VS创建更多相同列的副本。要解决这个问题,我必须时不时地清除DGV.Columns列表。

如何阻止VS复制我的字段?

以下代码是重现问题的最小部分。

public class CustomDataGridView : DataGridView
{
    private DataGridViewImageColumn EditStatusIcons;

    private bool hasIcons = true;
    public bool HasIcons
    {
        get { return this.hasIcons; }
        set
        {
            if (this.Columns["EditIcons"] == null) return;

            this.Columns["EditIcons"].Visible = value;
            this.hasIcons = value;
        }
    }

    public CustomDataGridView()
    {
        this.EditStatusIcons = new System.Windows.Forms.DataGridViewImageColumn();

        this.EditStatusIcons.HeaderText = "";
        this.EditStatusIcons.Name = "EditStatusIcons";

        this.Columns.Add(this.EditStatusIcons);
    }
}

修改:我还试图像Custom DataGridView adds columns everytime I build中所说的那样使用this.AutoGenerateColumns = false;。什么都没有改变。

清除表单上的列列表会删除工作列并留下一列dataGridViewImageColumn1,它只是一个名称错误的完整空列。

2 个答案:

答案 0 :(得分:3)

控件按预期运行。

<强>原因

您在构造函数中添加了一列,然后设计器序列化该列。然后运行应用程序,它在构造函数中添加一列。所以你有2列。这种方式继续这样,并不限于2列。即使您不需要构建和运行,也足以打开包含网格的表单并对表单进行小的更改并保存。新专栏诞生了!

<强>解决方案

根据您的要求,要解决问题,您可以考虑以下选项:

  1. 检查控件是否处于设计模式,然后不要添加该列并仅在运行时添加该列。

  2. 您可以检查控件是否包含现有的此类图像列,然后再添加另一个图像列。您可以通过它的某些属性类型使列唯一。

  3. 您可以为控件创建自定义设计器,并在控件初始化中添加添加列的代码。这样,代码仅在第一次将控件添加到表单时运行。

  4. 关于解决方案的一些注意事项

    在解决方案之间进行选择完全基于您的要求,并且所有选项均可用。但请考虑以下有关解决方案的说明:

    1. 关于第一个解决方案,请不要使用DesignMode属性,因为它在构造函数中不起作用。而是以这种方式执行检查:

      if (System.ComponentModel.LicenseManager.UsageMode != LicenseUsageMode.Designtime)
      {
          //The control is not in design mode, add the column here.
      }
      
    2. 关于第二个解决方案,例如,它足以添加新的MyCustomImageColumn类型,并且只检查MyCustomImageColumn类型列的存在,如果存在,请&# 39;添加另一个,因为其中一个就足够了。

    3. 关于第3个解决方案。至少目前您可以使用以前的两种简单解决方案,但我不建议您遵循它。因为DataGridView有自己的设计师名称DataGridViewDesigner是内部的,你不能继承它,如果你只是因为这个要求而创建一个设计师,你将会错过原始设计师的一些功能。可能你可以解决这个问题,甚至可以创建ToolBoxItem而不是设计师,但你不需要它。这个选项可以使答案对于此类案例的未来读者更加完整和有用。

答案 1 :(得分:1)

人们多年来一直反对这个问题,但正如 Reza 所说,这是预期的行为 - 因此它从未被“修复”过。有一个冗长的MSDN forum thread正在讨论这个问题。在众多失败的解决方案提案中,Reza提供的大多数成功建议都在某种程度上被提及。

在上面提到的主题中,用户 CoolDadTx 首先提出的第四个建议是将DataGridView包装在UserControl中,然后以这种方式添加列。进一步推理:

  

使用继承来设置属性是一种不好的做法,   继承应该用于添加功能或覆盖   当前的行为。

     

如果您想进行此类定制,则应使用   usercontrol代替或使用配置你的共享功能   gridviewproperty on runtime。

     

- Marco Guignard,2014年7月17日

优点是UserControl只会向您明确公开的设计器添加属性。因此,您添加的列不会重复。虽然它不像DesignTime if语句那样简洁,但用法可能如下所示:

public class CustomControl : UserControl
{
    private DataGridViewImageColumn EditStatusIcons;
    public DataGridView DGV;

    private bool hasIcons = true;
    public bool HasIcons
    {
        get { return this.hasIcons; }
        set
        {
            if (this.DGV.Columns["EditStatusIcons"] == null) return;

            this.dataGridView1.Columns["EditStatusIcons"].Visible = value;
            this.hasIcons = value;
        }
    }

    public CustomDataGridView()
    {
        this.EditStatusIcons = new System.Windows.Forms.DataGridViewImageColumn();

        this.EditStatusIcons.HeaderText = "";
        this.EditStatusIcons.Name = "EditStatusIcons";

        this.DGV= new DataGridView();
        this.DGV.Dock = DockStyle.Fill;
        this.DGV.Columns.Add(this.EditStatusIcons);

        this.Controls.Add(this.DGV);
    }
}