2005-08-20

Copying an HTML-fragment to the Clipboard

Last year, I wrote an article for RealDevs, that showed how to Copy an HTML-fragment to the Clipboard in C#. However, when I recently tried to update the article (fixed a bug in the code), I got no response. I wrote several e-mails to the webmaster, but the article didn't get updated. So I decided to publish it here, on my blog.

Introduction

Applications like Word and Excel let you copy some text or tabular data to the clipboard in HTML-format, so that the formatting and visual style doesn't change when pasted. At work, I had to do something similar: our application uses a lot of grid-controls to display data, and we wanted the users to be able to select data from a grid, and copy it to the clipboard, in a format that would keep the tabular structure of the data. After some research, I found out that you can copy data to the clipboard in HTML-format, and I thought: this is it. Piece of cake. But it wasn't. Apparently, you have to pass a bit more information than just the HTML-code. Googling around gave me some hints how it should be done, but nothing really specific. So I started experimenting, until it worked correctly.
Tip: use a StringBuilder to build the HTML-code, instead of concatenating strings. StringBuilders are very efficient for building long strings (hence the name StringBuilder): they are a lot faster than strings, and allocate much less memory.

Possible applications

There are a lot of situations where you could use this:
  • Copying tabular data (and pasting it in Excel, Word or Outlook).
  • Copying formatted, visually styled data.
  • ...

The Code

using System;
using System.Text;
using System.Windows.Forms;

class Test {
public static void CopyHtmlToClipBoard(string html) {
   Encoding enc = Encoding.UTF8;

   string begin = "Version:0.9\r\nStartHTML:{0:000000}\r\nEndHTML:{1:000000}"
      + "\r\nStartFragment:{2:000000}\r\nEndFragment:{3:000000}\r\n";

   string html_begin = "<html>\r\n<head>\r\n"
      + "<meta http-equiv=\"Content-Type\""
      + " content=\"text/html; charset=" + enc.WebName + "\">\r\n"
      + "<title>HTML clipboard</title>\r\n</head>\r\n<body>\r\n"
      + "<!--StartFragment-->";

   string html_end = "<!--EndFragment-->\r\n</body>\r\n</html>\r\n";

   string begin_sample = String.Format(begin, 0, 0, 0, 0);

   int count_begin = enc.GetByteCount(begin_sample);
   int count_html_begin = enc.GetByteCount(html_begin);
   int count_html = enc.GetByteCount(html);
   int count_html_end = enc.GetByteCount(html_end);

   string html_total = String.Format(
      begin
      , count_begin
      , count_begin + count_html_begin + count_html + count_html_end
      , count_begin + count_html_begin
      , count_begin + count_html_begin + count_html
      ) + html_begin + html + html_end;

   DataObject obj = new DataObject();
   obj.SetData(DataFormats.Html, new System.IO.MemoryStream(
      enc.GetBytes(html_total)));
   Clipboard.SetDataObject(obj, true);
}
}

Example: copying a DataTable

StringBuilder html = new StringBuilder();
html.Append("<table>");
foreach ( DataRow row in table.Rows ) {
   html.Append("<tr>");
   foreach ( object o in row )
      html.AppendFormat("<td>{0}</td>", o);
   html.Append("</tr>");
}
html.Append("</table>");
Test.CopyHtmlToClipboard(html.ToString());

15 comments:

Anonymous said...

very useful !!!

bye

xrado

Anonymous said...

Worked a treat!

Thx

Tony Joselin said...

Perfect! Just what I was looking for. I am amazed that more people haven't come across this problem and posted their own solutions.

Anonymous said...

Brilliant! Just what I was looking for.

Thanks!

Anonymous said...

Thanks dude - just what I needed.

Anonymous said...

Very good. Give us more

Thanks

Anonymous said...

definitely useful!!!
msdn documentation sucks in this!

Anonymous said...

I was able to use Clipboard.setText( str, TextDataFormats.Html ) to paste html fragments into Outlook express, but not outlook. This method did the trick though! Good work Tommy!

Anonymous said...

Ditto on the last comment with respect to Outlook. Thanks very much!

Luke said...

Absolutely brilliant.

Anonymous said...

thx, it's the very thing that I need.

Manh Le said...

Thank you
Absolutely useful

Anonymous said...

Thanks, I used your code in my project.

Anonymous said...

You saved me on this one. From one techie to another thanks!

This is very similar to code in msdn
http://msdn.microsoft.com/en-us/library/ms649015(v=vs.85).aspx
...but your actually works!

Anonymous said...

This works great in Windows 7, though when trying to run on Windows 2008 R2 the clipboard remains empty.

I've tried using a Clipboard Inspector (On Win7), but nothing appears when doing this in code, although I can still paste into Outlook.

Any Ideas?