2

На форме есть пустая DataGridView. Создаю для неё DataTable.

private void новыйToolStripMenuItem_Click(object sender, EventArgs e)
{
    DataTable dt = new DataTable();
    dt.Columns.Add(new DataColumn("Product"));
    dt.Columns.Add(new DataColumn("Prize"));
    dt.Columns.Add(new DataColumn("Count"));
    dataGridView1.DataSource = dt;
}

Ввожу в строку DataGridView данные и пытаюсь сохранить их в XML.

private void сохранитьToolStripMenuItem_Click(object sender, EventArgs e)
{
    DataTable dT = GetDataTableFromDGV(dataGridView1);
    DataSet dS = new DataSet();
    dS.Tables.Add(dT);
    SaveFileDialog save = new SaveFileDialog();
    save.Filter = "XML|*.xml";
    if (save.ShowDialog(this) == DialogResult.OK)
    {
        try
        {
            dS.WriteXml(save.FileName);
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
}

Метод GetDataTableFromDGV

private DataTable GetDataTableFromDGV(DataGridView dgv)
{
    DataTable dt = new DataTable();
    foreach (DataGridViewColumn column in dgv.Columns)
    {
        if (column.Visible)
        {
            dt.Columns.Add();
        }
    }
    object[] cellValues = new object[dgv.Columns.Count];
    foreach (DataGridViewRow row in dgv.Rows)
    {
        for (int i = 0; i < row.Cells.Count; i++)
        {
            cellValues[i] = row.Cells[i].Value;
        }
        dt.Rows.Add(cellValues);
    }
    return dt;
}

При попытке открыть сохраненный XML

private void открытьToolStripMenuItem_Click(object sender, EventArgs e)
{
    OpenFileDialog open = new OpenFileDialog();
    if (open.ShowDialog(this) == DialogResult.OK)
    {
        string path = open.FileName;
        ds = new DataSet();
        ds.ReadXml(path);
        dataGridView1.DataSource = ds.Tables[0].DefaultView;
    }
}

Всегда получается, что нет последней Column. В методе GetDataTableFromDGV() указывает на ошибку NullReferenceException в строке:

cellValues[i] = row.Cells[i].Value;

Прочитал, что надо изначально задавать column в DataTable чтобы её избежать, но они уже заданы при создании. В чем может быть ошибка?

  • Уважаемый, серьезно, сидел и "гуглил", что же такое "dgv". Сразу расшифровано написать нельзя? – EvgeniyZ May 12 '18 at 17:40
  • 1
    @EvgeniyZ Исправлено. Все, чтобы вы улыбались) – Hedgehog May 12 '18 at 17:49
  • Ваша ошибка в... object[] cellValues = new object[dgv.Columns.Count]; . Чему будет равен cellValues[0]? Я отвечу - NULL, ибо вы просто задали пустой массив объектов. А инициализировать? Ну а вообще, я бы закрыл как дубликат. – EvgeniyZ May 12 '18 at 18:01
  • @EvgeniyZ Задал массив, далее прошелся в цикле и записал значения. С чего бы ему быть null? Проблема в том что последний row.Cell[i].value возвращает null хотя в начале у него было задано конкретное value – Hedgehog May 12 '18 at 18:14

1 Answers1

1

Выкиньте полностью метод GetDataTableFromDGV.

У вас привязан DataTable к DataGridView, вот его и берите:

var dt = (DataTable)dataGridView1.DataSource;

Ещё лучше - сделайте его полем класса (формы).

DataSet тоже можно полностью выкинуть. Я понимаю, почему вы его используете: не получалось читать данные иначе.

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

Запись:

dt.WriteXml(path, XmlWriteMode.WriteSchema);

Чтение:

dt.ReadXml(path);
dataGridView1.DataSource = dt;

Обратите внимание: создавать локальные DataTable не нужно! Мы его сделали полем.

Напомню, что DataSet тоже не нужен.

Осталось исправить ещё одну строку кода, чтобы всё заработало - дать имя дататейблу при его создании:

dt = new DataTable("Products");

Это необходимо в отсутствие датасета.