代码之家  ›  专栏  ›  技术社区  ›  Brendan

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

  •  10
  • Brendan  · 技术社区  · 17 年前

    我在子类中生成所有列 DataGridView 编程。然而,Visual Studio 2008一直在读取我的构造函数类(它填充了一个 DataTable 包含空内容并将其绑定到 控件 )并为中的列生成代码 InitializeComponent 方法-在过程设置中 AutoGenerateColumns false .

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

    我怎样才能阻止它这样做?

    我试过:

    • 使控件“冻结”
    • 设置 控件 实例化的对象 protected (在之前的一篇文章中提到 this site )
    10 回复  |  直到 17 年前
        1
  •  5
  •   Marc Gravell    17 年前

    听起来你好像在构造函数中添加控件。也许稍后再添加列——也许类似于覆盖 OnParentChanged ;然后你就可以检查了 DesignMode 因此,您只需在执行过程中添加列(而不是在设计过程中)。

        2
  •  5
  •   JaredPar    17 年前

    我以前见过带有Items属性的ComboBox的这种行为,这真的很令人沮丧。以下是我使用组合框解决这个问题的方法。您应该能够将此应用于DataGridView。

    我创建了一个名为Items的“新”属性,并将其设置为不可浏览,并且明确地隐藏在序列化之外。在引擎盖下,它只访问真实的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; }
    
        3
  •  1
  •   Brendan    17 年前

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

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

        4
  •  1
  •   Dan Is Fiddling By Firelight Leniency    16 年前

    马克是对的。设计器查看构造函数以了解此自动生成行为。这是我绕过它的方法。

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

    使用 Load 包含表单上的事件-包含多个 DataGridView 我们打电话给 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;
    }
    

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

        5
  •  1
  •   ArildF    15 年前

    JaredPar的建议对我很有效:

    public partial class RefusjonsOppgjorGrid : DataGridView
    {
        public RefusjonsOppgjorGrid()
        {
            InitializeComponent();
        }
    
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new DataGridViewColumnCollection Columns
        {
            get{ return base.Columns;}
        }
    }
    
        6
  •  0
  •   robby valles    17 年前

    我经常在自定义控件中这样做,如果你在DesignMode检查中将不想在设计器中执行的代码包装起来,它应该能解决你的问题。

        if (!DesignMode)
        {
            // Your code here
        }
    
        7
  •  0
  •   kjbartel    12 年前

    这已经是一个老问题了,但在2014年的VS2013中仍然是一个问题。

    我有一个 DataGridView 随着其 DataSource 设置为a BindingSource 这反过来又有了另一个 绑定源 作为其 属性 。要解决我的问题,除了移动DataGridView之外,我不需要更改任何其他内容。将数据源分配到 OnControlCreate 在表格上覆盖。

        8
  •  0
  •   Community Mohan Dere    9 年前

    @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...
    }
    

    这确实意味着设计师不能在├Designer任务中使用“编辑项目”等,也不能根据需要调整列的属性,但根据我的需要,这并不是特别有用,所以没有损失。

    不管怎样,这解决了问题,这仍然意味着柱子在设计师中是可见的,这是我在这里的主要目标。

    我只是想分享一下。

        9
  •  0
  •   Stanley Jointer II    10 年前

    由于这对一些人来说仍然是一个问题,包括我自己,直到几天前,我想我会发布我的解决方案,以及从现在开始我在课堂上教给学生的解决方案:

    首先,我创建了一个 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是一个组合框列。来自绑定的数据 数据表 只能匹配组合框中列出的信息。同样,colState是一个组合框列,但此框的默认值是通过查询包含所有州的另一个表(例如在美国)添加的。

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

    应该注意的是,在这种情况下,DataTable是存储过程的结果,在这种情形下不太可能进行编辑。我尝试使用视图和存储函数;第一个也不允许编辑(至少不容易……我怀疑我需要在触发器之前插入,但这是一个数据库问题),而第二个则不会根据动态表生成的一些问题返回表。

        10
  •  0
  •   DavidWainwright    9 年前

    在设计器中重新打开表单,以便自动生成列,然后单击DataGridView,选择“编辑列”,遍历每个有问题的列,并将其“可见”属性设置为False。重新保存并关闭/重新打开表单,以确保它不再发生。这是唯一真正对我有效的非编码解决方案,我不想添加代码来解决winforms设计器的问题。

    推荐文章