2009-04-20 3 views
4

У меня возникла проблема при назначении DataSource элемента управления DataGridView. Мой DataSource является DataTableDefaultView и, как и ожидалось, столбцы автоматически создаются в DataGridView, чтобы соответствовать тем, которые указаны в DataTable, когда я его назначил.DataGridView многократно воссоздает столбцы

Что происходит дальше, так это то, что столбцы, как представляется, автоматически удаляются и воссоздаются еще 2 раза с помощью DataGridView. Почему это произойдет?

В конструктору форме в:

//A DataTable is created with 5 columns 
//The DataTable is populated with some rows. 

myDgv.AutoGenerateColumns = true; 
myDgv.DataSource = myDataTable.DefaultView; 
// myDgv.ColumnAdded event is fired 5 times. 
// WHY: myDgv.ColumnRemoved event is fired 5 times. 
// WHY: myDgv.ColumnAdded event is fired 5 times. 
// WHY: myDgv.ColumnRemoved event is fired 5 times. 
// WHY: myDgv.ColumnAdded event is fired 5 times. 

Edit: Добавлен (надеюсь) самодостаточный пример. Если я установил контрольные точки в обработчиках событий, я нажимаю «Добавлено» один раз 6 раз, а «Удалено» один раз 4 раза. DataTable содержит 2 столбца, и я никогда не прошу удалить какие-либо столбцы в моем коде.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace asdasdgf 
{ 
    public class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 

      DataTable dt = new DataTable(); 
      dt.Columns.Add("Col1", typeof(int)); 
      dt.Columns.Add("Col2", typeof(string)); 

      foreach (int i in Enumerable.Range(0, 10)) 
      { 
       var row = dt.NewRow(); 
       row["Col1"] = i; 
       row["Col2"] = "stackoverflow"; 
       dt.Rows.Add(row); 
      } 

      dataGridView1.ColumnAdded += new DataGridViewColumnEventHandler(dataGridView1_ColumnAdded); 
      dataGridView1.ColumnRemoved += new DataGridViewColumnEventHandler(dataGridView1_ColumnRemoved); 

      dataGridView1.DataSource = dt.DefaultView; 
     } 

     void dataGridView1_ColumnRemoved(object sender, DataGridViewColumnEventArgs e) 
     { 
      // Break here 
     } 

     void dataGridView1_ColumnAdded(object sender, DataGridViewColumnEventArgs e) 
     { 
      // Break here 
     } 

     // Form1.Designer.cs contents: 
     #region Windows Form Designer generated code 
     private System.ComponentModel.IContainer components = null; 
     private System.Windows.Forms.DataGridView dataGridView1; 

     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 



     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.dataGridView1 = new System.Windows.Forms.DataGridView(); 
      ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); 
      this.SuspendLayout(); 
      // 
      // dataGridView1 
      // 
      this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; 
      this.dataGridView1.Location = new System.Drawing.Point(12, 41); 
      this.dataGridView1.Name = "dataGridView1"; 
      this.dataGridView1.Size = new System.Drawing.Size(240, 150); 
      this.dataGridView1.TabIndex = 0; 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(284, 264); 
      this.Controls.Add(this.dataGridView1); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); 
      this.ResumeLayout(false); 

     } 

     #endregion 
    } 
} 
+1

Что происходит, если вместо этого вы используете BindingSource? –

+0

То же самое происходит :-( – xyz

+0

Я добавил (надеюсь) самодостаточный пример. Если бы я установил точки останова в обработчиках событий, я ударил «Добавлено» один раз 6 раз, а «Удалено» один раз 4 раза. В DataTable содержится 2 столбцы, и я никогда не прошу удалить какие-либо столбцы в моем коде. – xyz

ответ

1

После многих пустяков, похоже, это путь.

В обработчике Load событий вашей формы:

dgv.AutoGenerateColumns = false; 
dgv.DataSource = myDataSource; 

В обработчике Shown событий вашей формы:

dgv.AutoGenerateColumns = true; 

Предоставление желаемого результата ColumnAdded событий увольняет один раз для каждого столбца, а ColumnRemoved Событие не уволено вообще. (Если в обработчике событий Load установлен параметр AutoGenerateColumns = true, он сделает этот раздражающий танец Add-Remove-Add.)

1

Если myDgv.DataSource будет alreadys установлен на то, что бы объяснить, по крайней мере, некоторые из Add/Remove действия. Dito, когда столбцы уже представляют дизайн-время.

Итак, убедитесь, что сетка пуста, и свойство DataSource очищено в конструкторе.

Дополнительно:

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

Но тогда все еще есть 2 Add и 1 Remove actions per column, я боюсь, что нам придется подписаться на неэффективность DataGrid. (Где-то в DataSource.set())

Дополнительно 2:

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

dataGridView1.AutoGenerateColumns = true; 
dataGridView1.DataSource = dt.DefaultView; 

только дает два Добавляйте событие.

+0

Это касается обоих случаев, насколько мне известно. Пожалуйста, попробуйте код, который я опубликовал, если у вас есть время :-) – xyz

+0

Спасибо, что помогли мне , Я не понимаю твое второе дополнение. Итак, по умолчанию .AutoGenerateColumns - это «истина», а .DataSource - «null» - не те ли ценности, которые я желаю в качестве отправной точки, так или иначе? Что устанавливает AGC в true (когда это уже так) и вручную добавляет/удаляет DataSource в конструкторе? – xyz

+0

А, я получил его, работая по порядку: AGC = false, назначить DataSource, AGC = true :-) – xyz

2

У меня есть приложение, которое использует DataGridView для отображения содержимого DataTable, но связать их как это:

dataGridView.DataSource = dataTable; 

Можете ли вы попробовать это?

EDIT:

Я также следующее авто сгенерированный код:

this.dataGridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; 

Не уверен, почему это будет иметь значение, хотя.

+0

То же самое происходит. Либо я делаю что-то принципиально неправильное, либо здесь что-то странное происходит - вряд ли есть какой-либо код в примере в вопросе, и это все равно происходит – xyz

1

Несколько месяцев назад на работе мы строили элемент управления сеткой, который бы имел встроенные возможности фильтрации (аналогично excel). Первоначально мы использовали datagridview и строили вокруг этого. Этот вопрос, который вы сейчас поднимаете, был самым большим шипом на нашей стороне! Поскольку мы использовали DGV под ним и подключались к его событиям, чтобы инициировать различные вещи, которые нам нужно было сделать, это был абсолютный кошмар. DGV - отличный контроль, но под обложками он делает несколько неуклюжих sh ** !! Лучшим обходным решением в конце дня было автоматическое создание столбцов. Да, это была боль, но, по крайней мере, у нас был полный контроль.

В нашей окончательной версии мы закончили тем, что все это царапали, и пошли с маршрутом наследования. Мы унаследовали от DGV, и это облегчило нашу жизнь. Теперь я не уверен, что вы пытаетесь сделать здесь, но если вы создаете свою собственную сетку, сначала попробуйте наследование! Что касается ответа на ваш вопрос, вы не делаете ничего плохого. Datagridview просто такой кокетливый. Если вы не создаете контроль над DGV и просто нуждаетесь в этих событиях, я говорю, старайтесь держаться подальше от колонки, добавленной/удаленной. Посмотрите, можете ли вы вместо этого использовать bindcompleted.

+0

Спасибо за совет. Я думаю, что он был уговорен к работе (см. Выше), но я буду иметь в виду, что это может быть немного haywire! – xyz

1

У меня есть решение! Выберите форму или пользовательский элемент управления и измените значение свойства Localizable на true. Отредактируйте файл resx и заблокируйте записи UserAddedColumn. Затем выберите ваш datagrid и выберите «изменить столбцы». Запретить все столбцы, которые были добавлены автоматически. Сбросьте значение Localizable на false. Таким образом, автоматически добавленные столбцы никогда не возвращались в мою сетку.

Возможно, вам нужно сохранить форму/пользовательский контроль и закрыть вкладку дизайна между каждой операцией.

Смежные вопросы