如何防止Visual Studio设计器在DataGridView中自动生成列?

时间:2009-02-09 21:55:03

标签: c# .net winforms visual-studio-2008 datagridview

我以编程方式生成子类DataGridView中的所有列。但是Visual Studio 2008会继续读取我的构造函数类(使用空内容填充DataTable并将其绑定到DataGridView)并为InitializeComponent方法中的列生成代码 - 在此过程中将AutoGenerateColumns设置为false

这会导致设计时编译中的错误,这些错误只能通过手动进入设计代码并删除对这些自动生成列的所有引用来解决。

我怎么能阻止它呢?

我尝试过:

  • 使控件'冻结'
  • 设置DataGridView实例化对象protected(在前一篇文章中提到this site

10 个答案:

答案 0 :(得分:5)

听起来你在构造函数中添加了控件。也许稍后添加列 - 可能类似于覆盖OnParentChanged;然后,您就可以检查DesignMode,这样您只需在执行期间添加列(而不是在设计期间)。

答案 1 :(得分:5)

我之前在使用Items属性的ComboBox中看到过这种行为,这真的令人沮丧。以下是我用ComboBox解决这个问题的方法。您应该能够将其应用于DataGridView。

我创建了一个名为Items的“new”属性,并将其设置为不可浏览,并明确地从序列化中隐藏。它只是访问真实的Items属性。

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new ObjectCollection Items
{
    get { return ((ComboBox)this).Items; }
}

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new object DataSource
{
    get { return ((ComboBox)this).DataSource; }

答案 2 :(得分:1)

马克是对的。 Designer会查看此自动生成行为的构造函数。以下是我如何解决它。

从构造函数中获取构造/绑定DataTable到DataGridView的代码,并将其放在方法中。

在包含表单上使用Load事件 - 包含多个DataGridView s,在每个实例上调用BindData()方法,


List<Control> childControls = Misc.Misc.GetAllChildControls(this);
foreach (Control ctrl in childControls) {
    if (ctrl is WorksheetGridView) {
         WorksheetGridView wsgv = ctrl as WorksheetGridView;
         wsgv.BindData();
    }
}

其中GetAllChildControls是帮助程序类中的方法


internal static List<Control> GetAllChildControls(Control topControl)
{
    List<Control> ctrlStore = new List<Control>();
    ctrlStore.Add(topControl);
    if (topControl.HasChildren)
    {
        foreach (Control ctrl in topControl.Controls)
        {
            ctrlStore.AddRange(GetAllChildControls(ctrl));                }
        }
    }
    return ctrlStore;
}

很抱歉,如果这是明确的,但我永远不想忘记如何做到这一点!

答案 3 :(得分:1)

我遇到了类似的问题,我在这里发布我的解决方案,因为当我写下我的问题时,这是最重要的建议问题。每次编译代码时,设计人员都会自动添加数据源中的每一列(下次我构建我的代码时,它们会出现在正在运行的应用程序中),尽管自动生成的列设置为false。

最终,我设法通过为我的一个列提供与自动生成的列相同的名称来阻止它(我的列最初是在数据源可用之前手动创建的)。

答案 4 :(得分:1)

JaredPar的建议对我有用:

public partial class RefusjonsOppgjorGrid : DataGridView
{
    public RefusjonsOppgjorGrid()
    {
        InitializeComponent();
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new DataGridViewColumnCollection Columns
    {
        get{ return base.Columns;}
    }
}

答案 5 :(得分:0)

我经常在自定义控件中执行此操作,如果在DesignMode检查中包装不想在设计器中执行的代码,它应该可以解决您的问题。

    if (!DesignMode)
    {
        // Your code here
    }

答案 6 :(得分:0)

这是一个古老的问题,但在2014年VS2013仍然存在问题。

我有一个DataGridView,其DataSource设置为BindingSource,而BindingSource又为DataSource OnControlCreate。为了解决我的问题,除了将DataGridView.DataSource赋值移动到表单上的{{1}}覆盖之外,我不需要更改任何其他内容。

答案 7 :(得分:0)

@JaredPar's answer让我解决了这个问题,但是任何包含我的DataGridView子类的控件都会在设计器中的任何内容发生更改时添加列。

我想在构造函数中保留列,以便在可视化设计器中看到它们,因此我必须禁用我的子类从其基类继承的标准DataGridViewDesigner,即。我更改了班级的Designer属性......

using System.Windows.Forms.Design;

[Designer(typeof(ControlDesigner))]
public class SpecificDataGridView : DataGridView
{
    [Browsable(false),
     DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new DataGridViewColumnCollection Columns
    {
        get { return base.Columns; }
    }

    ...etc...
}

这确实意味着设计人员无法在DataGridViewDesigner任务中使用“编辑项目”等,他们无法根据需要调整列的属性,但根据我的需要,这不是特别有用所以没有损失。

无论如何,这解决了问题,它仍然意味着设计师可以看到列,这是我的主要目标。

想到我会分享。

答案 8 :(得分:0)

因为这对某些人来说似乎仍然是一个问题,包括我在几天前,我想我会发布我的解决方案,以及从这一点开始向我班级的学生教授的解决方案正向:

首先,我创建一个DataGridView(DGV)对象并在设计视图中创建列,记下特定列的对象名称。

现在,当我想从我的数据库绑定数据时(SQL Server,对于此代码)。我更改了列对象,并将每个列直接绑定到DataTable

中的数据
private void FillAddresses()
    {
        // erase any old data
        if (AddrTable != null)
            AddrTable.Clear();
        else
            AddrTable = new DataTable();

        // switch-case for panel types that need an address
        switch(PanelType)
        {
            case "Customer":
            case "Customers":
            case "Location":
            case "Locations":
            case "Employee":
            case "Employees":
                BuildStateColumnChoices();
                SqlCommand sqlAddrCmd = new SqlCommand();
                sqlAddrCmd.CommandText = "exec SecSchema.sp_GetAddress " + PanelType +
                    "," + ObjectID.ToString(); // Fill the DataTable with a stored procedure
                sqlAddrCmd.Connection = DBConnection;
                sqlAddrCmd.CommandType = CommandType.Text;
                SqlDataAdapter sqlDA = new SqlDataAdapter(sqlAddrCmd);

                try
                {
                    sqlDA.Fill(AddrTable);

                    dgvAddresses.AutoGenerateColumns = false;
                    // Actually, you set both the DataSource and DataPropertyName properties to bind the data
                    dgvAddresses.DataSource = AddrTable;

                    // Note that the column parameters are using the name of the object from the designer.
                    // This differs from the column names.
                    // The DataProperty name is set to the column name returned from the Stored Procedure
                    dgvAddresses.Columns["colAddrType"].DataPropertyName = "Type";
                    dgvAddresses.Columns["collAddress"].DataPropertyName = "Address";
                    dgvAddresses.Columns["colAptNum"].DataPropertyName = "Apt#";
                    dgvAddresses.Columns["colCity"].DataPropertyName = "city";
                    dgvAddresses.Columns["colState"].DataPropertyName = "State";
                    dgvAddresses.Columns["colZIP"].DataPropertyName = "ZIP Code";

                }
                catch(Exception errUnk)
                {
                    MessageBox.Show("Failed to load address data for panel type " +
                        PanelType + "..." + errUnk.Message, "Address error",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                break;
        }
    }

对于上面的代码,DBConnection是我从中获取此代码的对象的公共属性,它存储了SqlConnection对象。此外,colAddressType是ComboBox列。绑定DataTable中的数据只能匹配ComboBox中列出的信息。类似地,colState是一个ComboBox列,但是通过查询包含所有状态的另一个表(在本例中为美国)来添加此框的默认值。

这里的要点是,您可以通过在设计时创建列来绑定要包含在DGV中的数据,然后将数据从DataTable直接绑定到列。这允许您拥有所需的任何类型的列,而不仅仅是默认绑定机制为您提供的默认TextColumn。

应该注意,在这种情况下,DataTable是存储过程的结果,并且在这种情况下不可能进行编辑。我试图使用View以及存储的函数;第一个也没有允许编辑(至少,不容易......我怀疑我需要在触发器之前插入一个插件,但这是一个数据库问题),而第二个不会在此基础上返回表格动态表生成的一些问题。

答案 9 :(得分:0)

在设计器中重新打开表单以便自动生成列,然后单击DataGridView,选择Edit Columns,浏览每个违规列并将其'Visible'属性设置为False。重新保存并关闭/重新打开表单以确保它不再发生。这是唯一真正为我工作的非编码解决方案,我不想添加代码来解决winforms设计师问题。