调用:
ClipboardHelper.CopyToClipboard("<h1>hello world</h1>", "");
/// <summary>
/// Helper to encode and set HTML fragment to clipboard.<br/>
/// See http://theartofdev.com/2014/06/12/setting-htmltext-to-clipboard-revisited/.<br/>
/// <seealso cref="CreateDataObject"/>.
/// </summary>
/// <remarks>
/// The MIT License (MIT) Copyright (c) 2014 Arthur Teplitzki.
/// </remarks>
public static class ClipboardHelper
{
#region Fields and Consts /// <summary>
/// The string contains index references to other spots in the string, so we need placeholders so we can compute the offsets. <br/>
/// The <![CDATA[<<<<<<<]]>_ strings are just placeholders. We'll back-patch them actual values afterwards. <br/>
/// The string layout (<![CDATA[<<<]]>) also ensures that it can't appear in the body of the html because the <![CDATA[<]]> <br/>
/// character must be escaped. <br/>
/// </summary>
private const string Header = @"Version:0.9
StartHTML:<<<<<<<<1
EndHTML:<<<<<<<<2
StartFragment:<<<<<<<<3
EndFragment:<<<<<<<<4
StartSelection:<<<<<<<<3
EndSelection:<<<<<<<<4"; /// <summary>
/// html comment to point the beginning of html fragment
/// </summary>
public const string StartFragment = "<!--StartFragment-->"; /// <summary>
/// html comment to point the end of html fragment
/// </summary>
public const string EndFragment = @"<!--EndFragment-->"; /// <summary>
/// Used to calculate characters byte count in UTF-8
/// </summary>
private static readonly char[] _byteCount = new char[]; #endregion /// <summary>
/// Create <see cref="DataObject"/> with given html and plain-text ready to be used for clipboard or drag and drop.<br/>
/// Handle missing <![CDATA[<html>]]> tags, specified start\end segments and Unicode characters.
/// </summary>
/// <remarks>
/// <para>
/// Windows Clipboard works with UTF-8 Unicode encoding while .NET strings use with UTF-16 so for clipboard to correctly
/// decode Unicode string added to it from .NET we needs to be re-encoded it using UTF-8 encoding.
/// </para>
/// <para>
/// Builds the CF_HTML header correctly for all possible HTMLs<br/>
/// If given html contains start/end fragments then it will use them in the header:
/// <code><![CDATA[<html><body><!--StartFragment-->hello <b>world</b><!--EndFragment--></body></html>]]></code>
/// If given html contains html/body tags then it will inject start/end fragments to exclude html/body tags:
/// <code><![CDATA[<html><body>hello <b>world</b></body></html>]]></code>
/// If given html doesn't contain html/body tags then it will inject the tags and start/end fragments properly:
/// <code><![CDATA[hello <b>world</b>]]></code>
/// In all cases creating a proper CF_HTML header:<br/>
/// <code>
/// <![CDATA[
/// Version:1.0
/// StartHTML:000000177
/// EndHTML:000000329
/// StartFragment:000000277
/// EndFragment:000000295
/// StartSelection:000000277
/// EndSelection:000000277
/// <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
/// <html><body><!--StartFragment-->hello <b>world</b><!--EndFragment--></body></html>
/// ]]>
/// </code>
/// See format specification here: http://msdn.microsoft.com/library/default.asp?url=/workshop/networking/clipboard/htmlclipboard.asp
/// </para>
/// </remarks>
/// <param name="html">a html fragment</param>
/// <param name="plainText">the plain text</param>
public static DataObject CreateDataObject(string html, string plainText)
{
html = html ?? String.Empty;
var htmlFragment = GetHtmlDataString(html); // re-encode the string so it will work correctly (fixed in CLR 4.0)
if (Environment.Version.Major < && html.Length != Encoding.UTF8.GetByteCount(html))
htmlFragment = Encoding.Default.GetString(Encoding.UTF8.GetBytes(htmlFragment)); var dataObject = new DataObject();
dataObject.SetData(DataFormats.Html, htmlFragment);
dataObject.SetData(DataFormats.Text, plainText);
dataObject.SetData(DataFormats.UnicodeText, plainText);
return dataObject;
} /// <summary>
/// Clears clipboard and sets the given HTML and plain text fragment to the clipboard, providing additional meta-information for HTML.<br/>
/// See <see cref="CreateDataObject"/> for HTML fragment details.<br/>
/// </summary>
/// <example>
/// ClipboardHelper.CopyToClipboard("Hello <b>World</b>", "Hello World");
/// </example>
/// <param name="html">a html fragment</param>
/// <param name="plainText">the plain text</param>
public static void CopyToClipboard(string html, string plainText)
{
var dataObject = CreateDataObject(html, plainText);
Clipboard.SetDataObject(dataObject, true);
} /// <summary>
/// Generate HTML fragment data string with header that is required for the clipboard.
/// </summary>
/// <param name="html">the html to generate for</param>
/// <returns>the resulted string</returns>
private static string GetHtmlDataString(string html)
{
var sb = new StringBuilder();
sb.AppendLine(Header);
sb.AppendLine(@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">"); // if given html already provided the fragments we won't add them
int fragmentStart, fragmentEnd;
int fragmentStartIdx = html.IndexOf(StartFragment, StringComparison.OrdinalIgnoreCase);
int fragmentEndIdx = html.LastIndexOf(EndFragment, StringComparison.OrdinalIgnoreCase); // if html tag is missing add it surrounding the given html (critical)
int htmlOpenIdx = html.IndexOf("<html", StringComparison.OrdinalIgnoreCase);
int htmlOpenEndIdx = htmlOpenIdx > - ? html.IndexOf('>', htmlOpenIdx) + : -;
int htmlCloseIdx = html.LastIndexOf("</html", StringComparison.OrdinalIgnoreCase); if (fragmentStartIdx < && fragmentEndIdx < )
{
int bodyOpenIdx = html.IndexOf("<body", StringComparison.OrdinalIgnoreCase);
int bodyOpenEndIdx = bodyOpenIdx > - ? html.IndexOf('>', bodyOpenIdx) + : -; if (htmlOpenEndIdx < && bodyOpenEndIdx < )
{
// the given html doesn't contain html or body tags so we need to add them and place start/end fragments around the given html only
sb.Append("<html><body>");
sb.Append(StartFragment);
fragmentStart = GetByteCount(sb);
sb.Append(html);
fragmentEnd = GetByteCount(sb);
sb.Append(EndFragment);
sb.Append("</body></html>");
}
else
{
// insert start/end fragments in the proper place (related to html/body tags if exists) so the paste will work correctly
int bodyCloseIdx = html.LastIndexOf("</body", StringComparison.OrdinalIgnoreCase); if (htmlOpenEndIdx < )
sb.Append("<html>");
else
sb.Append(html, , htmlOpenEndIdx); if (bodyOpenEndIdx > -)
sb.Append(html, htmlOpenEndIdx > - ? htmlOpenEndIdx : , bodyOpenEndIdx - (htmlOpenEndIdx > - ? htmlOpenEndIdx : )); sb.Append(StartFragment);
fragmentStart = GetByteCount(sb); var innerHtmlStart = bodyOpenEndIdx > - ? bodyOpenEndIdx : (htmlOpenEndIdx > - ? htmlOpenEndIdx : );
var innerHtmlEnd = bodyCloseIdx > - ? bodyCloseIdx : (htmlCloseIdx > - ? htmlCloseIdx : html.Length);
sb.Append(html, innerHtmlStart, innerHtmlEnd - innerHtmlStart); fragmentEnd = GetByteCount(sb);
sb.Append(EndFragment); if (innerHtmlEnd < html.Length)
sb.Append(html, innerHtmlEnd, html.Length - innerHtmlEnd); if (htmlCloseIdx < )
sb.Append("</html>");
}
}
else
{
// handle html with existing start\end fragments just need to calculate the correct bytes offset (surround with html tag if missing)
if (htmlOpenEndIdx < )
sb.Append("<html>");
int start = GetByteCount(sb);
sb.Append(html);
fragmentStart = start + GetByteCount(sb, start, start + fragmentStartIdx) + StartFragment.Length;
fragmentEnd = start + GetByteCount(sb, start, start + fragmentEndIdx);
if (htmlCloseIdx < )
sb.Append("</html>");
} // Back-patch offsets (scan only the header part for performance)
sb.Replace("<<<<<<<<1", Header.Length.ToString("D9"), , Header.Length);
sb.Replace("<<<<<<<<2", GetByteCount(sb).ToString("D9"), , Header.Length);
sb.Replace("<<<<<<<<3", fragmentStart.ToString("D9"), , Header.Length);
sb.Replace("<<<<<<<<4", fragmentEnd.ToString("D9"), , Header.Length); return sb.ToString();
} /// <summary>
/// Calculates the number of bytes produced by encoding the string in the string builder in UTF-8 and not .NET default string encoding.
/// </summary>
/// <param name="sb">the string builder to count its string</param>
/// <param name="start">optional: the start index to calculate from (default - start of string)</param>
/// <param name="end">optional: the end index to calculate to (default - end of string)</param>
/// <returns>the number of bytes required to encode the string in UTF-8</returns>
private static int GetByteCount(StringBuilder sb, int start = , int end = -)
{
int count = ;
end = end > - ? end : sb.Length;
for (int i = start; i < end; i++)
{
_byteCount[] = sb[i];
count += Encoding.UTF8.GetByteCount(_byteCount);
}
return count;
}
}

c# 将html添加进剪贴板(带格式)的更多相关文章

  1. CentOS自带mysql配置(密码更改、端口开放访问、添加进系统启动项)

    前些天虚拟机安装好了CentOS6.1,但是自己想远程连接自带的mysql发现不知道如何改密码,于是谷歌一下,把结果记录下来,方便后期自己使用: 方法一: # /etc/init.d/mysql st ...

  2. ArcGIS中添加进自定义的ttf字符标记符号

    原文:ArcGIS中添加进自定义的ttf字符标记符号 ArcGIS系统中的样式可能不能满足实际生产需要,为了实现快速制图,可自定义一些样式,以便重复利用. 1.   制作的符号库 使用 FontCre ...

  3. ubuntu 应用添加进环境变量

    BG:公司同事使用的电脑系统大多为windows ,有部分mac和Ubuntu(我就是那个部分Ubuntu),某些情况为了统一格式,便下载了一些解压即可使用的软件,但是每次点开文件夹然后点开程序很繁琐 ...

  4. eclipse中添加进新的java项目中文乱码

    eclipse中添加进新的java项目中文乱码 添加学习的一些项目进eclipse中,结果其中的中文注释都变成了乱码 右击项目,点最下面的属性,出来新得弹框 在文本文件编码部分可以发现是GBK格式,选 ...

  5. JS019. 原生JS使用new Blob()实现带格式导出Word、Excel(提供无编程基础将页面上表格导出到本地的方法)

    导出效果 代码实现 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  6. Java导出带格式的Excel数据到Word表格

    前言 在Word中创建报告时,我们经常会遇到这样的情况:我们需要将数据从Excel中复制和粘贴到Word中,这样读者就可以直接在Word中浏览数据,而不用打开Excel文档.在本文中,您将学习如何使用 ...

  7. 如何通过Java导出带格式的 Excel 数据到 Word 表格

    在Word中制作报表时,我们经常需要将Excel中的数据复制粘贴到Word中,这样则可以直接在Word文档中查看数据而无需打开另一个Excel文件.但是如果表格比较长,内容就会存在一定程度的丢失,无法 ...

  8. (转)sscanf() - 从一个字符串中读进与指定格式相符的数据

    (转)sscanf() - 从一个字符串中读进与指定格式相符的数据 sscanf() - 从一个字符串中读进与指定格式相符的数据. 函数原型: Int sscanf( string str, stri ...

  9. linux 给用户添加进新的组

    给用户user1添加一个新的组group1 usermod -G group1 #给当前登录用户所在组设置为 group1 注意:上面的命令有个问题需要知道,这个操作是重置用户所在组,也就是会让当前用 ...

随机推荐

  1. OpenJudge.poj CR2(Enclosure-ceil向上取整)

    0:Enclosure 查看 提交 统计 提问 总时间限制:  1000ms  内存限制:  131072kB 描述 为了防止爆零而加入了一道热身题.大家轻虐- Picks在参加NOI(网上同步赛)时 ...

  2. RGB和HSL色彩的相互转换

    转自: http://blog.csdn.net/aniven/article/details/2205851 RGB和HSL(也叫HSB/HSV)是两种色彩空间,即:红,绿,蓝(Red,Green, ...

  3. Android之Handler用法总结/安卓中只有主线程可以修改UI

    Handler传递消息的方式可以实现实时刷新以及长按连续响应事件. 按钮响应 btnadd_fcl.setOnTouchListener(new View.OnTouchListener() { pr ...

  4. 15个极好的Linux find命令示例

    基于访问/修改/更改时间查找文件 你可以找到基于以下三个文件的时间属性的文件. 访问时间的文件.文件访问时,访问时间得到更新. 的文件的修改时间.文件内容修改时,修改时间得到更新. 更改文件的时间.更 ...

  5. C#指南,重温基础,展望远方!(5)C#语句

    程序操作使用语句进行表示. C# 支持几种不同的语句,其中许多语句是从嵌入语句的角度来定义的. 使用代码块,可以在允许编写一个语句的上下文中编写多个语句. 代码块是由一系列在分隔符 { 和 } 内编写 ...

  6. 转在Python中实现PageFactory模式

    转自: http://www.cnblogs.com/fnng/p/5092383.html 关于 PageFactory 的概念主要是Java中内置了PageFactory类. import org ...

  7. memcache stats命令详解

    参数不算多,我们来启动一个Memcache的服务器端:  /usr/local/bin/memcached -d-m 10 -u root-l 192.168.0.200-p 12000-c 256- ...

  8. 点滴积累【C#】---对上传文件的路径进行加密,以免将路径暴露在浏览器上,避免一些安全隐患!

    效果: 描述: 本事例是为解决在上传或下载文件时避免将路径暴露在外.在上传时将路径进行加密保存到DataTable或数据库中,在下载是再读取DataTable中加密数据进行解密下载. 代码: [前台代 ...

  9. 多线程-ThreadPoolExecutor

    线程池 线程池是可以控制线程创建.释放.并通过某种策略尝试复用线程去执行任务的一种管理框架,从而实现线程资源与任务之间的一种平衡. 类图 Executor Executor是最基本的执行接口:“执行者 ...

  10. Atiti. Php Laravel 5.1 环境搭建以及  error 排除

    Atiti. Php Laravel 5.1 环境搭建以及  error 排除 1. php_5.6.11_apache2.41 1.1. Httpd.Conf增加以下配置,添加php支持1 1.2. ...