I have a DataTable which is populated from a CSV file then, using a DataGridView the data is edited in memory. As far as I understand the programmatic editing of the data should be done on the DataTable where the user editing is done via. the DataGridView.
However when I add columns programmatically to the DataTable, it is not reflected automatically in the DataGridView and I suspect the converse is also true.
How do you keep the two concurrent? I thought the idea of data binding was that this was automatic ...
Here is the relevant setup code - WorksheetGridView
subclasses DataGridView
// Can access data directly
public DataTable data = new DataTable();
public WorksheetGridView()
{
InitializeComponent();
// Allow copying from table to clipboard
this.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
// TODO: how to allow both row and column selects?
//this.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
// Load up a blank DataTable to hold user inputted data
int i;
const int numBlankRows = Config.Application.DefaultNumRows;
const int numBlankCols = Config.Application.DefaultNumCols;
// TODO: Figure out how to include this as a config variable
DBNull dfltCellContent = DBNull.Value;
DataRow tmpRow;
// Add columns - i used for naming
for (i = 0; i < numBlankCols; i++)
{
this.AddColumn(i);
}
// Add rows
for (i = 0; i < numBlankRows; i++)
{
tmpRow = this.data.NewRow();
// Fill cells with something (i.e. blank cells)
foreach (DataColumn col in this.data.Columns)
{
tmpRow[col.ColumnName] = DBNull.Value;
}
this.data.Rows.Add(tmpRow);
}
// Link data to the view
this.DataSource = this.data;
}
private void AddColumn(int colIndex)
{
// Adds a column to the data array
DataColumn tmpCol;
tmpCol = new DataColumn();
tmpCol.DataType = Type.GetType(Config.Application.DataType);
tmpCol.ColumnName = "C" + colIndex.ToString();
tmpCol.ReadOnly = false;
tmpCol.Unique = false;
tmpCol.AllowDBNull = true;
this.data.Columns.Add(tmpCol);
}
The bit that doesn't work is later when I call AddColumn
for instance in this code to handle pasting tab-delimited data,
public void PasteToCells(string mode)
{
// TODO: Write paste code
int i;
if (Clipboard.ContainsText())
{
string clipBoardContent = Clipboard.GetText();
using (CsvReader pastedCsvReader = new CsvReader(
new StringReader(clipBoardContent), false, '\t'))
{
// TODO: If more rows/cols than in data table then expand accordingly
int numPastedCols = pastedCsvReader.FieldCount;
int currRowIndex, currColumnIndex;
GetSelectedInsertPoint(out currRowIndex, out currColumnIndex);
// Make space for columns if needed
if (mode == "insertcols")
{
int baseIndex = this.data.Columns.Count;
for (i = 0; i < numPastedCols; i++)
{
//this.Columns.Add
// TODO: Doesn't work yet - do you edit the DataGridView and reflect to DataTable or vise-versa?
this.AddColumn(baseIndex + i);
}
}
while (pastedCsvReader.ReadNextRecord())
{
// Make space for rows (row by row) if needed
if (mode == "insertrows")
{
this.data.NewRow();
// TODO: Add a row
}
// Populate the cells with valid pasted text
for (i = 0; i < numPastedCols; i++)
{
this.data.Rows[currRowIndex][currColumnIndex + i] = ConvertCellContent(pastedCsvReader[i]);
}
currRowIndex = currRowIndex + 1;
}
}
}
else
{
// TODO: Do nothing?
Console.WriteLine("No text on clipboard");
}
}
I tried the example given below and it does work. However when I try and do this the horizontal scroll bar expands and contracts briefly but the table in the subclassed DataGridView
is not updated. The column is however in the DataTable
though - for example I cannot add a column of the same name, the column count reflects the extra columns too. Is there perhaps a designer option that might constrict the updating of the DataGridView
?
Also adding rows works fine.
SOLVED:
The AutoGeneratedColumns
was set to false
in the designer code despite being true
in the properties dialog (and set explicitly in the code). The initial columns were generated programmatically and so should not have appeared however this was not picked up on since the designer code also continued to generate 'designed in' columns that were originally used for debugging.
Moral: Check the autogenerated code!