【问题标题】:How do you prevent the Visual Studio designer auto-generating columns in a DataGridView?如何防止 Visual Studio 设计器在 DataGridView 中自动生成列?
【发布时间】:2009-02-09 21:55:03
【问题描述】:

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

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

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

我试过了:

  • 使控件“冻结”
  • 设置DataGridView 实例化对象protected(在之前的帖子中推荐过this site

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我以前在 ComboBox 的 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; }
      

      【讨论】:

      • 我知道您正在尝试什么,但是当我尝试将其调整为子类 DataGridView 时,它失败了。那里应该有“覆盖”吗?
      • 您必须为 DataGridView 的列自定义它。这只是我拥有的 ComboBox 示例的剪切/粘贴。绝对不想覆盖,因为这里没有任何东西是虚拟的
      • 这是我第一次看到属性“DesignerSerializationVisibility”。非常好的功能......我会将它集成到我的几个框架组件中。谢谢 JaredPar。
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

        在包含表单上使用 Load 事件 - 包含多个 DataGridViews 在每个实例上调用 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;
        }
        

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

        【讨论】:

        • 小心这一点,调试器中的 x64 应用程序会吞下从 form_Load 方法抛出的异常
        【解决方案5】:

        JaredPar 的建议对我有用:

        public partial class RefusjonsOppgjorGrid : DataGridView
        {
            public RefusjonsOppgjorGrid()
            {
                InitializeComponent();
            }
        
            [Browsable(false)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
            public new DataGridViewColumnCollection Columns
            {
                get{ return base.Columns;}
            }
        }
        

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

          • 我在上面包装了填充 DataTable 并将其绑定到 DataGridView 的代码,但不幸的是它不起作用
          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

            @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 任务中使用“编辑项目”等,并且他们无法根据需要调整列的属性,但对于我的需要,这并不是特别有用所以没有损失。

            无论如何,这解决了问题,它仍然意味着这些列在设计器中是可见的,这是我在这里的主要目标。

            只是想我会分享。

            【讨论】:

              【解决方案9】:

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

              首先,我创建一个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 是存储过程的结果,在这种情况下不太可能进行编辑。我尝试使用视图以及存储函数;第一个也不允许编辑(至少,不容易......我怀疑我需要在某个地方触发之前插入,但这是一个数据库问题),而第二个不会根据一些动态问题返回表表生成。

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                  猜你喜欢
                  • 2014-03-10
                  • 2018-04-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-10-13
                  • 2021-10-27
                  相关资源
                  最近更新 更多