Как предотвратить автоматическое создание столбцов конструктора Visual Studio в DataGridView?

я генерирую все мои столбцы в подклассе DataGridView программно. Однако Visual Studio 2008 продолжает читать мой класс конструктора (который заполняет DataTable С пустым содержимым и привязывает его к DataGridView) и генерирует код для столбцов InitializeComponent метод-в настройке процесса AutoGenerateColumns до false.

это вызывает ошибки в компиляции времени разработки, которые решаются только вручную, входя в код разработки и удаляя все ссылки на них столбцы автоматически.

как я могу остановить это?

я пробовал:

  • сделать контроль "замороженным"
  • задание DataGridView объект protected (предложено в предыдущем посте, который ссылался на этот сайт)

10 ответов


похоже, что вы добавляете элементы управления в конструктор. Возможно, добавьте столбцы немного позже - возможно, что-то вроде переопределения OnParentChanged; затем вы сможете проверить DesignMode таким образом, вы добавляете столбцы только во время выполнения (не во время проектирования).


Я видел это поведение раньше для ComboBox с свойством Items, и это действительно расстраивает. Вот как я обошел это с ComboBox. Вы должны иметь возможность применить это к DataGridView.

Я создал" новое " свойство под названием 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; }

Марк был прав. Дизайнер смотрит на конструктора такого поведения автогенераторный. Вот как я обошел это.

взял код, который создает / связывает 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 метод в хелпер класс!--7-->


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;
}

Извините, если это явное, но я никогда не хочу забывать, как это сделать!


Я столкнулся с проблемой, подобной этой, и размещаю свое решение здесь, так как, когда я написал свой вопрос, это был верхний предложенный вопрос. Каждый раз, когда я компилировал свой код, дизайнер автоматически добавлял каждый из столбцов в источник данных (и в следующий раз, когда я создавал свой код, они появлялись в запущенном приложении), несмотря на то, что автогенеративные столбцы были установлены в false.

В конце концов мне удалось остановить его, дав одному из моих столбцов то же имя, что и автоматически сгенерированный столбец (мои столбцы изначально были созданы вручную до того, как источник данных был доступен).


JaredPar работал для меня:

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

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

Я часто делаю это в моих пользовательских элементах управления, если вы оберните код, который вы не хотите выполнять в конструкторе в проверке DesignMode, он должен устранить ваши проблемы.

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

это старые вопросы сейчас, но это все еще проблема в 2014 году с VS2013.

Я DataGridView с DataSource установлен BindingSource который в свою очередь имел другой BindingSource как его DataSource. Чтобы решить мою проблему, мне не нужно было ничего менять, кроме перемещения DataGridView.Назначение источника данных в OnControlCreate переопределить форму.


@JaredPar это!--5--> получил меня большую часть пути к решению этого, но любые элементы управления, которые содержали мой 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, и они не могут настроить свойства столбцов, если захотят, но для моих нужд это не было особенно полезно, поэтому это не было потерей.

В любом случае, это исправило проблему, и это все еще означало, что столбцы были видны в дизайнере, который был моей основной целью здесь.

просто подумал, что поделюсь.


поскольку это все еще кажется вопросом для некоторых, включая меня до нескольких дней назад, я думал, что опубликую свое решение, и тот, который я преподаю студентам в своих классах с этого момента:

во-первых, я создаю DataGridView (DGV) объект и создайте столбцы в представлении конструктора, принимая во внимание Имя объекта для конкретного столбца.

теперь, когда я хочу связать данные из моей базы данных (SQL Server, для этого кода). Я изменяю объекты column и связываю каждый столбец непосредственно к данным из 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. Данные из bound DataTable может совпадать только с информацией, указанной в поле со списком. Аналогично colState является столбцом ComboBox, но значения по умолчанию для этого поля добавляются путем запроса другой таблицы, содержащей все состояния (в США, например).

дело здесь в том, что вы можете связать данные, которые вы хотите включить в DGV, создав столбцы во время разработки, а затем привязать свои данные из DataTable к столбцам напрямую. Это позволяет иметь любой тип столбца, а не только TextColumn по умолчанию, который предоставляется механизмом привязки по умолчанию.

следует отметить, что в этом случае DataTable является результатом хранимой процедуры и такое редактирование в данном случае маловероятно. Я попытался использовать представление, а также сохраненную функцию; первый также не позволял редактировать (по крайней мере, нелегко...Я подозреваю, что мне нужна вставка перед триггером где-то, но это вопрос базы данных), в то время как второй не вернет таблицу на основе какой-то проблемы с динамическим созданием таблицы.


повторно откройте форму в конструкторе, чтобы столбцы были автоматически сгенерированы, затем нажмите на DataGridView, выберите Редактировать столбцы, пройдите через каждый оскорбительный столбец и установите для свойства "Visible" значение False. Повторно сохраните и закройте/повторно откройте форму, чтобы убедиться, что этого больше не происходит. Это было единственное некодирующее решение, которое действительно работало для меня, и я не хотел добавлять код для решения проблемы WinForms designer.