Как создать новый DataGridViewRow и указать значения, используя имена столбцов, а не индексы? - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть DataGridView.Я пытаюсь добавить строки к нему путем клонирования строки добавления новой строки.Когда я добавляю строку, я устанавливаю некоторые значения ее ячеек.Я пытаюсь получить доступ к экземплярам DataGridViewCell по имени их столбца.

Перед отображением пользовательского интерфейса я делаю нечто подобное в подклассе DataGridView:

MyDataGridViewRow r = Rows[NewRowIndex].Clone() as MyDataGridViewRow;
Rows.Add(r);
r.Cells[Columns["MyColumnName"].Index].Value = "Example text";

Это неработать, потому что я получаю (в последней строке) это исключение:

System.ArgumentOutOfRangeException: 'Указанный аргумент находится вне диапазона допустимых значений.Имя параметра: rowIndex '

Я предполагаю, что ячейки добавляются в соответствующий столбец, но не в строку.

Если я непосредственно использую оператор DataGridViewRow.Cells[] с именем столбцаTag:

System.ArgumentException: «Столбец с именем Tag не найден.Имя параметра: columnName '

Когда это происходит, я вижу в отладчике, что коллекция Cells содержит все столбцы, и каждый Cell имеет

  • ColumnIndex и RowIndex равно -1, если я пытаюсь использовать оператор [] до Rows.Add, а
  • только RowIndex равно -1, если я вызываю Rows.Add до[] оператор (в этом случае ColumnIndex имеют значения, начинающиеся с 0).

Это происходит до отображения какой-либо формы.

Поэтому я попытался создать небольшой проектэто та же ошибка.Это в классе Form1:

DataGridView dgv;

public Form1()
{
    InitializeComponent();

    dgv = new DataGridView();

    // from DataGridView subclass ctor
    dgv.RowTemplate = new MyRow();

    dgv.Left = 10;
    dgv.Top = 10;
    Controls.Add(dgv);

    // from Initialize method
    dgv.Columns.Clear();
    DataGridViewTextBoxColumn c = new DataGridViewTextBoxColumn()
    {
        HeaderText = "My Header",
        Name = "MyColumn"
    };
    dgv.Columns.Add(c);

    // here the columns and row templates should be ready
    MyRow r = dgv.Rows[dgv.NewRowIndex].Clone() as MyRow;
    r.Cells["MyColumn"].Value = "My Value";
    dgv.Rows.Add(r);
}

internal class MyRow : DataGridViewRow
{
    internal MyRow() : base()
    {
    }
}

Теперь я получаю еще одно исключение в строке dgv.Columns.Add(c):

System.MissingMethodException: 'Для этого объекта не определен конструктор без параметров.'

Сведения об исключении:

System.MissingMethodException
  HResult=0x80131513
  Message=No parameterless constructor defined for this object.
  Source=mscorlib
  StackTrace:
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at System.Windows.Forms.DataGridViewRow.Clone()
   at System.Windows.Forms.DataGridView.get_RowTemplateClone()
   at System.Windows.Forms.DataGridViewRowCollection.AddInternal(Boolean newRow, Object[] values)
   at System.Windows.Forms.DataGridView.AddNewRow(Boolean createdByEditing)
   at System.Windows.Forms.DataGridView.OnColumnCollectionChanged_PostNotification(DataGridViewColumn dataGridViewColumn)
   at System.Windows.Forms.DataGridViewColumnCollection.OnCollectionChanged_PostNotification(CollectionChangeEventArgs ccea, Boolean changeIsInsertion, Point newCurrentCell)
   at System.Windows.Forms.DataGridViewColumnCollection.Add(DataGridViewColumn dataGridViewColumn)
   at project_namespace.Form1..ctor() in {project folder path here}\Form1.cs:line 37
   at project_namespace.Program.Main() in {project folder path here}\Program.cs:line 19

Смежный вопрос здесь .

Я использую .NET Framework 4.6.1.

Обновление 1 :

Если изменить строку dgv.Columns.Add(c); на

dgv.HandleCreated += (s, e) => { dgv.Columns.Add(c); };

, я получу следующее исключениев строке, которая начинается с MyRow r:

System.ArgumentOutOfRangeException: 'Индекс был вне диапазона.Должен быть неотрицательным и меньшим, чем размер коллекции.Имя параметра: index '

Сведения об исключении:

System.ArgumentOutOfRangeException
  HResult=0x80131502
  Message=Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
  Source=mscorlib
  StackTrace:
   at System.Collections.ArrayList.get_Item(Int32 index)
   at System.Windows.Forms.DataGridViewRowCollection.SharedRow(Int32 rowIndex)
   at System.Windows.Forms.DataGridViewRowCollection.get_Item(Int32 index)
   at cs_test_6.Form1..ctor() in .....\Form1.cs:line 45
   at cs_test_6.Program.Main() in .....\Program.cs:line 19

, и если я удаляю последние три строки в конструкторе, я получаю ту же первую ошибку в строке с dgv.Columns.Add(c) теперь внутри однострочной анонимной функции.

Обновление 2 : что я узнал:

  • класс шаблона строки должен иметь открытый конструктор;
  • строки должны быть добавлены после столбцов;
  • Я могу использовать класс шаблона строки с некоторыми свойствами, чтобы установить столбцы по имени, но мне все еще неясно;

Если я загружаю порядок столбцов из файла, и они могут быть переупорядочены, как я могу использовать шаблон строки, чтобы установить значения ячеек по имени?Этот код работает так же, как Rows.Add(val1, val2) (но, вероятно, он менее эффективен):

MyDataGridViewRow r = new MyDataGridViewRow()
{

};
r.CreateCells(this);
r.Cells[0] =
    new DataGridViewTextBoxCell()
    {
        Value = val1
    };
r.Cells[1] =
    new DataGridViewTextBoxCell()
    {
        Value = val2
    };
Rows.Add(r);

Если я пытаюсь использовать r.Cells["MyColumn"], я получаю сообщение об ошибке, показанное в начале вопроса.

Мой вопрос: Как и когда я могу ссылаться на ячейки по имени столбца внутри подкласса DataGridViewRow?Я пытался сделать это в конструкторе, но он не работает, даже с целочисленными индексами.Мне нужно это сделать, потому что я хочу иметь переставляемые столбцы.

...