【问题标题】:How to set HTML to clipboard in C#?如何在 C# 中将 HTML 设置为剪贴板?
【发布时间】:2012-11-11 15:08:20
【问题描述】:

我想将 HTML 格式的富文本放在剪贴板上,这样当用户粘贴到 Word 时,它将包含源 HTML 格式。

使用the Clipboard.SetText method 不起作用。

另外,我希望如果用户粘贴到 Word 等富编辑器中,它将粘贴格式化文本,如果他们粘贴到记事本等普通编辑器中,它将粘贴纯文本。

【问题讨论】:

    标签: c# .net html clipboard


    【解决方案1】:

    在设置 HTML 文本时,您需要提供一个标题,其中包含您实际要粘贴的 html 片段的附加信息,同时能够围绕它提供附加样式:

    Version:0.9
    StartHTML:000125
    EndHTML:000260
    StartFragment:000209
    EndFragment:000222
    <HTML>
    <head>
    <title>HTML clipboard</title>
    </head>
    <body>
    <!–StartFragment–><b>Hello!</b><!–EndFragment–>
    </body>
    </html>
    

    使用标头(和正确的索引),用TextDataFormat.Html 调用Clipboard.SetText 就可以了。

    要处理 HTML 和纯文本粘贴,您不能使用 Clipboard.SetText 方法,因为每次调用它都会清除剪贴板;您需要创建一个DataObject 实例,使用HTML 调用其SetData 方法一次,然后使用纯文本调用一次,然后使用Clipboard.SetDataObject 将对象设置为剪贴板。

    更新

    请参阅“Setting HTML/Text to Clipboard revisited”了解更多详细信息和 ClipboardHelper 实现。

    【讨论】:

    • 阅读链接的帖子,值得!
    • 很棒的东西,但是它和我发现的其他几个解决方案似乎没有将任何内容放入 HTML 格式的剪贴板。它只是保持为空,即使数据对象的 html 格式似乎正确。
    • 标题中的实际数字似乎完全错误。我完全不清楚这些数字是如何计算的,我发现的每一篇文章,包括这篇文章,都未能解释这一点。我能找到的最好的就是神秘的代码,也无济于事。
    • @ygoe -- The Page Linked Chris Thornton 似乎回答了如何设置这些标头编号的问题。
    • @ygoe -- 事实上,我自己也尝试过使用这种技术,数字只是文本开头的字节偏移量。建议在左侧填充数字,以便在设置值时偏移保持正确。也就是说,使用 012345 之类的占位符,然后在评估最终偏移量后替换这些占位符,例如使用 IndexOf() 或类似函数,但请确保对值使用相同数量的字符,因此用零填充。
    【解决方案2】:

    我找到了一些代码:https://www.experts-exchange.com/questions/21966855/Create-a-hyperlink-in-VB-net-copy-to-clipboard-Should-be-able-to-paste-hyperlink-in-Microsoft-Word-Excel.html

    此代码处理更新开始和结束索引的问题。

    转换成c#:

    public void AddHyperlinkToClipboard(string link, string description)
    {
        const string sContextStart = "<HTML><BODY><!--StartFragment -->";
        const string sContextEnd = "<!--EndFragment --></BODY></HTML>";
        const string m_sDescription = "Version:1.0" + Constants.vbCrLf + "StartHTML:aaaaaaaaaa" + Constants.vbCrLf + "EndHTML:bbbbbbbbbb" + Constants.vbCrLf + "StartFragment:cccccccccc" + Constants.vbCrLf + "EndFragment:dddddddddd" + Constants.vbCrLf;
    
        string sHtmlFragment = "<A HREF=" + Strings.Chr(34) + link + Strings.Chr(34) + ">" + description + "</A>";
    
        string sData = m_sDescription + sContextStart + sHtmlFragment + sContextEnd;
        sData = sData.Replace("aaaaaaaaaa", m_sDescription.Length.ToString().PadLeft(10, '0'));
        sData = sData.Replace("bbbbbbbbbb", sData.Length.ToString().PadLeft(10, '0'));
        sData = sData.Replace("cccccccccc", (m_sDescription + sContextStart).Length.ToString().PadLeft(10, '0'));
        sData = sData.Replace("dddddddddd", (m_sDescription + sContextStart + sHtmlFragment).Length.ToString().PadLeft(10, '0'));
        sData.Dump();
        Clipboard.SetDataObject(new DataObject(DataFormats.Html, sData), true );
    }
    

    【讨论】:

    • 我还在 SetDataObject 中添加了“true”,以便在线程退出后将内容保留在剪贴板上。
    • 计算适用于基本的 ASCII 字符集,但它必须是:Encoding.UTF8.GetByteCount(sData).ToString().PadLeft(10, '0') 而不是 sData.Length。 ToString().PadLeft(10, '0') 以便在使用更宽的字符时不会损坏。
    【解决方案3】:

    让我分享一个将剪贴板数据设置为 HTML 的助手,这是我刚刚为我的小项目 #DevComrade 提出的:

    
    var dataObject = new DataObject();
    dataObject.SetData(DataFormats.Html, ClipboardFormats.ConvertHtmlToClipboardData(html);
    Host.SetClipboardDataObject(dataObject);
    
    internal static class ClipboardFormats
    {
        static readonly string HEADER = 
            "Version:0.9\r\n" +
            "StartHTML:{0:0000000000}\r\n" +
            "EndHTML:{1:0000000000}\r\n" +
            "StartFragment:{2:0000000000}\r\n" +
            "EndFragment:{3:0000000000}\r\n";
    
        static readonly string HTML_START =
            "<html>\r\n" +
            "<body>\r\n" +
            "<!--StartFragment-->";
    
        static readonly string HTML_END =
            "<!--EndFragment-->\r\n" +
            "</body>\r\n" +
            "</html>";
    
        public static string ConvertHtmlToClipboardData(string html)
        {
            var encoding = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
            var data = Array.Empty<byte>();
    
            var header = encoding.GetBytes(String.Format(HEADER, 0, 1, 2, 3));
            data = data.Concat(header).ToArray();
    
            var startHtml = data.Length;
            data = data.Concat(encoding.GetBytes(HTML_START)).ToArray();
    
            var startFragment = data.Length;
            data = data.Concat(encoding.GetBytes(html)).ToArray();
    
            var endFragment = data.Length;
            data = data.Concat(encoding.GetBytes(HTML_END)).ToArray();
    
            var endHtml = data.Length;
    
            var newHeader = encoding.GetBytes(
                String.Format(HEADER, startHtml, endHtml, startFragment, endFragment));
            if (newHeader.Length != startHtml)
            {
                throw new InvalidOperationException(nameof(ConvertHtmlToClipboardData));
            }
    
            Array.Copy(newHeader, data, length: startHtml);
            return encoding.GetString(data);
        } 
    }
    
    

    我使用了 thisthis 引用。另外,感谢@DaveyBoy 发现了一个错误。

    【讨论】:

    • 我相信这行有一个错误: var newHeader = encoding.GetBytes( String.Format(HEADER, startHtml, startFragment, endFragment, endHtml));很确定这应该是: var newHeader = encoding.GetBytes(string.Format(cbHeader, startHtml, endHtml, startFragment, endFragment));如果没有该修复,我无法将其粘贴到 Outlook 或 Word 中(但由于某种原因,MSTeams 很好地接受了它)。当我查看我们构建的实际字符串时,我意识到 endHtml 的值太小了。
    • 回到这个.. 哦,是的,我现在明白你的意思了 - 已修复! ?
    【解决方案4】:

    Arthur 关于标题是正确的,但这里要注意的重要一点是数据不会以纯文本形式出现在剪贴板上。您必须使用 CF_HTML。您可以在 MSDN 上阅读相关内容:http://msdn.microsoft.com/en-us/library/aa767917(v=vs.85).aspx 正确地说,您将有一个 CF_TEXT 简单地显示:“Hello!”,然后是带有 HTML 标题和数据的 CF_HTML,如 Arthur 的示例所示。

    【讨论】:

      【解决方案5】:

      正如亚瑟所说,我使用了Setting HTML/Text to Clipboard revisited的代码

      我必须在 Header 中添加换行符才能使其工作(在本例中为 VB)

      Private Const Header As String = "Version:0.9" & vbCrLf & "StartHTML:<<<<<<<<1" & vbCrLf & "EndHTML:<<<<<<<<2" & vbCrLf & "StartFragment:<<<<<<<<3" & vbCrLf & "EndFragment:<<<<<<<<4" & vbCrLf & "StartSelection:<<<<<<<<3" & vbCrLf & "EndSelection:<<<<<<<<4"
      

      希望对你有帮助

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多