I have a DataGridView. I try to add rows to it by cloning the add-new-row row. When I add a row, I set some of the values of its cells. I try to access the DataGridViewCell instances by the Name of their column.
Before the UI is shown, I do something similar to this in a subclass of DataGridView:
MyDataGridViewRow r = Rows[NewRowIndex].Clone() as MyDataGridViewRow;
Rows.Add(r);
r.Cells[Columns["MyColumnName"].Index].Value = "Example text";
This does not work because I get (on the last line) this exception:
System.ArgumentOutOfRangeException: 'Specified argument was out of the range of valid values. Parameter name: rowIndex'
I guess that the cells are added to the corresponding column, but not to the row.
If I directly use DataGridViewRow.Cells[]
operator with the column name Tag
:
System.ArgumentException: 'Column named Tag cannot be found. Parameter name: columnName'
When this happens, I see in the debugger that the Cells collection contains all the columns, and each Cell
has
ColumnIndex
and RowIndex
equal to -1
if I try the []
operator before Rows.Add
, andRowIndex
is equal to -1
, if I call Rows.Add
before the []
operator (in this case the ColumnIndex have values starting from 0
).This happens before any form is shown.
So I tried to make a small project that has the same bug. This is in the Form1 class:
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()
{
}
}
Now I get another exception on the line dgv.Columns.Add(c)
:
System.MissingMethodException: 'No parameterless constructor defined for this object.'
Detalis of the exception:
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
Related question here.
I am using .NET Framework 4.6.1.
Update 1:
If I change the dgv.Columns.Add(c);
line to
dgv.HandleCreated += (s, e) => { dgv.Columns.Add(c); };
I get the following exception on the line that starts with MyRow r
:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index'
Exception details:
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
and if I remove the last three lines in the constructor, I get the same first error on the line with dgv.Columns.Add(c)
now inside the one-line anonymous function.
Update 2: What I have learned:
If I load the order of the columns from a file, and they can be reordered, how can I use the row template to set the values of the cells by name? This code works just like Rows.Add(val1, val2)
(but probably it is less efficient):
MyDataGridViewRow r = new MyDataGridViewRow()
{
};
r.CreateCells(this);
r.Cells[0] =
new DataGridViewTextBoxCell()
{
Value = val1
};
r.Cells[1] =
new DataGridViewTextBoxCell()
{
Value = val2
};
Rows.Add(r);
If I try to use r.Cells["MyColumn"]
I get the error shown at the beginning of the question.
My question is: How and when can I reference the cells by column name inside a subclass of DataGridViewRow? I tried to do this in the constructor, but it does not work, not even with integer indices. I need to do this because I want to have reorderable columns.
User contributions licensed under CC BY-SA 3.0