将数据从剪贴板读入DataTable时,保留空的Excel单元格

我正在使用下面的代码从剪贴板中读取Excel数据到C#数据表中。 从这个问题的答案中发现的代码是相对不变的。 然后,我将数据表作为数据源添加到DataGridView控件进行操作。

然而,在我的Excel数据中,我有空白/空单元格,我需要保留,这段代码不会做(空白单元格跳过,有效地压缩每一行,不留空的空间;空的单元格从Excel XML )。 转移到数据表时,如何保留空单元?

方法:

private DataTable ParseClipboardData(bool blnFirstRowHasHeader) { var clipboard = Clipboard.GetDataObject(); if (!clipboard.GetDataPresent("XML Spreadsheet")) return null; StreamReader streamReader = new StreamReader((MemoryStream)clipboard.GetData("XML Spreadsheet")); streamReader.BaseStream.SetLength(streamReader.BaseStream.Length - 1); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(streamReader.ReadToEnd()); XNamespace ssNs = "urn:schemas-microsoft-com:office:spreadsheet"; DataTable dt = new DataTable(); var linqRows = xmlDocument.fwToXDocument().Descendants(ssNs + "Row").ToList<XElement>(); for (int x = 0; x < linqRows.Max(a => a.Descendants(ssNs + "Cell").Count()); x++) dt.Columns.Add("Column " + x.ToString()); int intCol = 0; DataRow currentRow; linqRows.ForEach(rowElement => { intCol = 0; currentRow = dt.Rows.Add(); rowElement.Descendants(ssNs + "Cell") .ToList<XElement>() .ForEach(cell => currentRow[intCol++] = cell.Value); }); if (blnFirstRowHasHeader) { int x = 0; foreach (DataColumn dcCurrent in dt.Columns) dcCurrent.ColumnName = dt.Rows[0][x++].ToString(); dt.Rows.RemoveAt(0); } return dt; } 

扩展方法:

 public static XDocument fwToXDocument(this XmlDocument xmlDocument) { using (XmlNodeReader xmlNodeReader = new XmlNodeReader(xmlDocument)) { xmlNodeReader.MoveToContent(); var doc = XDocument.Load(xmlNodeReader); return doc; } } 

举例说明: (Excel 2015)

在Excel中的范围,复制到剪贴板

在Excel中的范围,复制到剪贴板

Winform上的DataGridView,数据表作为数据源 数据表在VS

如果以前的单元格丢失(有一个空的值),单元格的xml将有一个Index属性。 您可以更新您的代码,以检查列索引是否已经更改,然后将其复制到您的数据表行。

 linqRows.ForEach(rowElement => { intCol = 0; currentRow = dt.Rows.Add(); rowElement.Descendants(ssNs + "Cell") .ToList<XElement>() .ForEach(cell => { int cellIndex = 0; XAttribute indexAttribute = cell.Attribute(ssNs + "Index"); if (indexAttribute != null) { Int32.TryParse(indexAttribute.Value, out cellIndex); intCol = cellIndex - 1; } currentRow[intCol] = cell.Value; intCol++; }); });