简体   繁体   English

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

[英]Preserve empty Excel cells when reading data from clipboard into DataTable

I am using the following code to read Excel data from the clipboard into a C# data table. 我正在使用以下代码将Excel数据从剪贴板读取到C#数据表中。 The code is relatively unchanged as found from this answer to this question . 从此问题的 答案可以发现,代码相对不变。 I then add the data table as a data source to a DataGridView control for manipulation. 然后,我将数据表作为数据源添加到DataGridView控件中进行操作。

However, in my Excel data, I have blank/empty cells that I need to preserve, which this code does not do (blank cells are skipped over, effectively compressing each row leaving no empty space; the empty cells are missing from the Excel XML). 但是,在我的Excel数据中,我需要保留空白/空单元格,而此代码不会这样做(跳过了空白单元格,有效地压缩了每一行,不留任何空白空间; Excel XML中缺少了空白单元格)。 How could I preserve empty cells when transferring to the data table? 转移到数据表时如何保存空白单元格?

Method: 方法:

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;
    }

Extension method: 扩展方式:

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

Contrived example to illustrate: (Excel 2015) 有人为举例说明: (Excel 2015)

Range in Excel, copied to clipboard Excel中的范围,复制到剪贴板

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

DataGridView on Winform, with data table as data source Winform上的DataGridView,以数据表作为数据源 VS中的数据表

The cell's xml will have an Index attribute if the previous cell was missing (had an empty value). 如果前一个单元格丢失(具有空值),则该单元格的xml将具有Index属性。 You can update your code to check if the column index has changed before copying it to your data table row. 您可以更新代码以检查列索引是否已更改,然后再将其复制到数据表行中。

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++;
        });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM