【问题标题】:C# Add excel text-formatted data to clipboardC#将excel文本格式的数据添加到剪贴板
【发布时间】:2013-03-23 18:57:11
【问题描述】:

在 C# 中,我需要将数据网格行复制到 Excel。因为一行中的某些值是双精度值,所以“-Infinity”值是可能的。

我尝试将行复制为 DataFormats.UnicodeTextDataFormats.Text 但这给了我输出“#NAME?”,我应该看到“-Infinity”(因为 excel 会自动插入一个“=”由于标准单元格格式,在“-Infinity”中的减号之前)。

当我在粘贴之前将单元格格式化为“Text”时,Excel 不会在“-Infinity”之前自动插入“=”。顺便说一句,我不需要在 excel 中对 double 值进行任何计算,所以文本格式对我来说就可以了。

所以我的问题是如何将数据复制到剪贴板并将其粘贴到excel中,同时将单元格格式设置为“文本”。

【问题讨论】:

  • 尝试粘贴 1 tab 2 tab '-Infinity
  • 我知道这个解决方案,但我不想在单元格中使用撇号。不是有剪贴板数据格式,excel 会自动假定数据必须被解释为文本?

标签: c# excel format cell clipboard


【解决方案1】:

从原始剪贴板查看器开始,您可以看到复制

到剪贴板会导致 Excel 向剪贴板抛出大量不同的格式。

其中大部分没有帮助,但其中一些是 excel 内部的,这意味着它将(几乎)保证数据与复制的数据相同。如果我是你,我可能会以 XML SpreadSheet 为目标,或者如果你感觉勇敢 Biff12 这也是 xml(但已压缩)。与普通文本相比,这将使您对粘贴有更多的控制。

作为一个例子,上面的剪辑结果

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<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">
 <Styles>
  <Style ss:ID="Default" ss:Name="Normal">
   <Alignment ss:Vertical="Bottom"/>
   <Borders/>
   <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11" ss:Color="#000000"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID="s63">
   <NumberFormat ss:Format="@"/>
  </Style>
 </Styles>
 <Worksheet ss:Name="Sheet1">
  <Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="2"
   ss:DefaultRowHeight="15">
   <Row>
    <Cell><Data ss:Type="Number">1</Data></Cell>
    <Cell><Data ss:Type="Number">2</Data></Cell>
   </Row>
   <Row>
    <Cell><Data ss:Type="String">Test</Data></Cell>
    <Cell ss:StyleID="s63"><Data ss:Type="String" x:Ticked="1">-Infinity</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>

所以看起来更深一点...当我尝试使用 Clipboard.SetData 将 xml 写入剪贴板时,.Net Clipboard 类似乎做了一些奇怪而不那么美妙的事情

剪贴板从一堆谷壳开始。这当然会导致 Excel 拒绝剪贴板内容。

为了解决这个问题,我使用 Windows API (user32) 调用来处理剪贴板

    [DllImport("user32.dll", SetLastError = true)]
    static extern uint RegisterClipboardFormat(string lpszFormat);
    [DllImport("user32.dll")]
    static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool CloseClipboard();
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool OpenClipboard(IntPtr hWndNewOwner);

    private static void XMLSpreadSheetToClipboard(String S)
    {
        var HGlob = Marshal.StringToHGlobalAnsi(S);
        uint Format = RegisterClipboardFormat("XML SpreadSheet");
        OpenClipboard(IntPtr.Zero);
        SetClipboardData(Format, HGlob);
        CloseClipboard();
        Marshal.FreeHGlobal(HGlob);
    }

【讨论】:

  • 这似乎很有趣。你如何将它复制到剪贴板?您使用 DataFormats.Html 还是“XML SpreadSheet”?我都试过了,但 Excel 拒绝粘贴字符串...
  • @iop 我同意,这比本来应该的要难!我已经包含了一个对我有用的代码示例。
  • 这很棒。伟大代码的一个可爱的起点。通过一篇文章,您为我节省了很多时间来想知道为什么我的剪贴板功能不起作用。 sigh 现在从应用程序内部创建正确的 XML。
  • BIFF12 不幸的是混合了一些 bin 部分。这是.xlsb 文件格式。
【解决方案2】:

感谢您的信息。经过一番搜索,我发现您可以使用 .Net 剪贴板类,但不能将字符串传递给 SetData()。这对我有用:

System::Text::UTF8Encoding^ enc = gcnew System::Text::UTF8Encoding();
System::Windows::Forms::Clipboard::SetData("XML Spreadsheet", gcnew MemoryStream(enc->GetBytes(data)));

【讨论】:

    【解决方案3】:

    win32 api 解决方案对我不起作用。我有随机崩溃。 以下代码可以正常工作,也可以使用 unicode 字符。

    var xml = File.ReadAllText(@"..\..\SampleData\Clipboard-Example3.xml");
    
    var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
    var dataObject = new DataObject();
    dataObject.SetData("XML SpreadSheet", stream);
    
    Clipboard.Clear();
    Clipboard.SetDataObject(dataObject);
    

    【讨论】:

    • 嗨,欢迎来到 SO。检查您正在回答的问题的日期是个好主意。您的答案可能仍然相关,因为这里的问题一直出现在搜索结果中,但您回答的问题大约有 7 年的历史,而且在编程中已经很长时间了 :)
    • 嘿,谢谢。我从来没有想过。也许你可以引导我到一个更好的地方来发布这个解决方案。我一直在寻找类似的东西但没有成功,并将我的发现(经过数小时的研究)放在一个具有匹配上下文的地方。
    • 抱歉,.net 和 c# 不是我的领域,所以我不知道如何提供帮助。
    • @SoftwareEngineer 为现有的旧问题添加新答案很重要,因为新的方法已经到来或被发现/创建。所以不想问两次问题,所以唯一的机会是更新现有的,即使它来自遥远的过去。这个问题很久以前就发布了,但问题仍然存在。 Excel 还在,xml 还在,剪贴板也被广泛使用。甚至谷歌也认为它很重要(这个页面是第一个结果)。所以请停止告诉人们不要将他们的发现发布到“老”问题上,因为它可能会帮助其他人并提高 SO 的质量。 ;)
    • @FrankM - 谢谢,我知道 SO 是如何工作的,我来这里的时间几乎和你一样长。我也知道新用户通常没有意识到他们的答案是针对旧问题的。我没有告诉 Steffan 不要在这里发布答案,只是他们应该知道日期。事实上,我明确表示,这个答案可能仍然是相关的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多