首页 > 解决方案 > 获取已复制到剪贴板的 Excel 单元格属性

问题描述

我正在尝试将多个单元格中的值复制到一个单元格中。如果我只想组合单元格的值,我会使用类似的东西

Dim str as string = My.Computer.ClipBoard.GetText
oxlapp.ActiveCell.Value = str

然而

在这种情况下,我需要包含 html 标记以创建表格,并且我还想包含粗体、斜体和下划线等格式。因此,我需要知道一些单元格属性,而不仅仅是剪贴板中的文本。

我知道它们应该在那里,因为您当然可以复制/粘贴整个单元格。

到目前为止,我尝试通过使用获取 Excel 单元格

My.Computer.Clipboard.GetData(XlClipboardFormat.xlClipboardFormatTable)

My.Computer.Clipboard.GetData(XlClipboardFormat.xlClipboardFormatCSV)

但是在调试时我注意到它们都返回了Nothing

有人知道我如何从剪贴板获取所有单元格属性吗?

为了更清楚,我想要这个

在此处输入图像描述

变成这样:

在此处输入图像描述

如果除了使用剪贴板还有其他方法,我很乐意尝试。

标签: excelvb.net

解决方案


您需要使用剪贴板中的另一种格式 - XML Spreadsheet. 复制的数据包含在具有自己的结构和属性的特殊 XML 中。让我们获取以下工作表的数据:

IMG1

如您所见,每个单元格都有一些格式。此数据的 XML 如下:

<ss:Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
             xmlns:o="urn:schemas-microsoft-com:office:office"
             xmlns:x="urn:schemas-microsoft-com:office:excel"
             xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
             xmlns:html="http://www.w3.org/TR/REC-html40">
    <ss:Styles>
        <ss:Style ss:ID="Default" ss:Name="Normal">
            <ss:Alignment ss:Vertical="Bottom"/>
            <ss:Borders/>
            <ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#000000"/>
            <ss:Interior/>
            <ss:NumberFormat/>
            <ss:Protection/>
        </ss:Style>
        <ss:Style ss:ID="s62">
            <ss:Interior ss:Color="#FFFF00" ss:Pattern="Solid"/>
        </ss:Style>
        <ss:Style ss:ID="s63">
            <ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#000000" ss:Bold="1"/>
        </ss:Style>
        <ss:Style ss:ID="s64">
            <ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#0000FF"/>
        </ss:Style>
        <ss:Style ss:ID="s65">
            <ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#000000" ss:Italic="1"/>
        </ss:Style>
    </ss:Styles>
    <ss:Worksheet ss:Name="Sheet1">
        <ss:Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="2" ss:DefaultRowHeight="15">
            <ss:Row>
                <ss:Cell ss:StyleID="s62">
                    <ss:Data ss:Type="String">A</ss:Data>
                </ss:Cell>
                <ss:Cell ss:StyleID="s63">
                    <ss:Data ss:Type="String">1</ss:Data>
                </ss:Cell>
            </ss:Row>
            <ss:Row>
                <ss:Cell ss:StyleID="s64">
                    <ss:Data ss:Type="String">B</ss:Data>
                </ss:Cell>
                <ss:Cell ss:StyleID="s65">
                    <ss:Data ss:Type="String">2</ss:Data>
                </ss:Cell>
            </ss:Row>
        </ss:Table>
    </ss:Worksheet>
</ss:Workbook>

如您所见,您拥有有关相应样式格式的所有信息。例如,单元格中的值A具有A1样式s62StyleID属性) - 您可以在节点中找到Style具有此编号的适当Styles节点。此 XML 中的行和列的结构是隐含的 - 即您不会看到行和列的索引 - 您需要自己计算它们。例如,第一个节点中的第二个Cell节点Row第一行,第二列

以下代码生成上图中的数据并检索适当的元素进行操作。

注意事项 1.如果仔细观察,该Workbook节点有两个 urn:schemas-microsoft-com:office:spreadsheet命名空间:第一个是 default ,第二个是带有 prefix ss。请记住 - 你总是需要使用ss前缀!

注意事项 2.这种方法有一个缺点- 它不理解隐藏的行(手动或通过自动过滤器)和列!它也包括隐藏的行/列!

Imports <xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
Imports <xmlns:x="urn:schemas-microsoft-com:office:excel">

Sub GetCellsWithFormat()
    '// Create new Excel app
    Dim xlApp = New Excel.Application With {.Visible = True}
    Dim book = xlApp.Workbooks.Add()
    Dim sheet = DirectCast(book.Sheets(1), Excel.Worksheet)
    '// Apply some formatting
    With sheet
        .Range("A1").Interior.Color = Excel.XlRgbColor.rgbYellow
        .Range("B1").Font.Bold = True
        .Range("A2").Font.Color = Excel.XlRgbColor.rgbBlue
        .Range("B2").Font.Italic = True
        '// Add some values
        Dim arr = Array.CreateInstance(GetType(String), {2, 2}, {1, 1})
        arr(1, 1) = "A" : arr(1, 2) = "1"
        arr(2, 1) = "B" : arr(2, 2) = "2"
        With .Range("A1:B2")
            .Value = arr
            .Copy() '//Copy cells to clipboard
        End With
        Dim xml As XElement
        Using xml_stream = DirectCast(Clipboard.GetData("XML Spreadsheet"), Stream)
            '// Get rid of last character (new line) to avoid parsing error
            xml_stream.SetLength(xml_stream.Length - 1)
            xml = XElement.Load(xml_stream)
        End Using
        '// Get any element you need
        Dim styles = xml.<ss:Styles>(0)
        Dim table = xml.<ss:Worksheet>.<ss:Table>(0)
        Dim rows = table.<ss:Row>
        '// Do something with this data
    End With
End Sub

更新

事实上,你不需要使用剪贴板来获取这个 XML - 你只需要使用属性xlRangeValueXMLSpreadsheet的值Value

With sheet
    '// Same code...
    With .Range("A1:B2")
        .Value = arr
        '.Copy() '//No need to copy!
    End With
    Dim xml_string = CStr(.Range("A1:B2").Value(Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet))
    '// Again, exclude last character
    Dim xml = XElement.Parse(xml_string.Substring(0, xml_string.Length - 1))
    '// Get any element you need
    Dim styles = xml.<ss:Styles>(0)
    Dim table = xml.<ss:Worksheet>.<ss:Table>(0)
    Dim rows = table.<ss:Row>
    '// Do something with this data
End With

推荐阅读