Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Clipboard handling with .NET - Part II

0.00/5 (No votes)
3 Jun 2002 1  
Builds on part 1, showing how to use custom/multiple formats

Screenshot of the demo application

Formats that are available after clicking Copy All

Introduction

At the end of April 2002, Nish and I were trying to figure out some of .NET's clipboard capabilities. When we had finished the conversation we decided on writing a two part article, Nish doing part one on the basics then I would do part two on some more advanced topics. I was going to write it as soon as the screensaver competition was over, needless to say I forgot....until now that is.

In this article I hope to cover multiple data formats, and creating your own custom data formats.

Multiple data formats

Placing multiple data formats on the clipboard is incredibly easy; once you know the trick :-)

The first tric...er step is to figure out what data formats you will be using. Later I'll discuss custom formats so ignore those for now. To help you in your search the DataFormats class has a list of commonly used formats stored as static string fields; refer to MSDN for the specifics on each format listed there.

Now that you know the formats you will use, create a instance of a class that implements IDataObject, the only such class is (appropriately) named DataObject.

IDataObject ido = new DataObject();

With the IDataObject interface in hand we can begin to use it. The purpose of the IDataObject is to "[Provide] a format-independent mechanism for transferring data" (MSDN, IDataObject interface). Those familiar with COM will know this object well. It can store one object of each format that you pass in. Thus if you need to store 3 Text formatted objects, you'll need to wrap them into a custom format which I'll explain later.

ido.SetData(DataFormats.Text, true, myString);

That line of code adds a new Text formatted object with the value of myString to the DataObject, and allows it to be converted to other types as well. This will be a key point that you find in Win32 using the Clipboard. Data is often in multiple formats to allow it to be used in a multitude of programs. Typically data will be stored in a custom format, as text, and possibly a bitmap if it represents something graphical. This allows for pasting into many applications and into itself in a native format.

Adding multiple, additional, formats is as easy as additional calls to SetData with differing formats.

Clipboard.SetDataObject(ido, true);

This line finally places the data on the clipboard where it can be read by any program. The true argument tells the Clipboard to make the data available even after the program quits. Later I'll introduce another important point about the second parameter, which isn't mentioned by MSDN.

With the data copied to the Clipboard you can now paste it as you did before; check for the proper data format then retrieve it if it exists.

IDataObject ido = Clipboard.GetDataObject();

if(ido.GetDataPresent(DataFormats.Text))
{
    // Text data is present on the clipboard

    textBox1.Text = (string) ido.GetData(DataFormats.Text);
}

Custom data formats

A custom data format can be anything; whether a special text formatting such as HTML or XML or it can be an instance of a class. To use a custom format, first you register it with Windows. In the demo application you will find that I register the type with Windows in the static constructor for the custom type class, CustomData.

static CustomData
{
    format = DataFormats.GetFormat(
        typeof(CustomData).FullName
    );
}

The code typeof(CustomData).FullName merely retreives the full name of the type; since I needed to choose a unique name I figured that would do. GetFormat returns an instance of the DataFormats.Format class which I store for use as a static property to access the Name and ID of the format. The name doesn't have to be relevant just unique, Windows registers a Format17 which it uses for screenshots.

The only unique part about creating a custom format that uses a class is that the class must be serializable, that is it needs to have the Serializable attribute applied to it.

[Serializable()]
public class CustomData
.....

To use it on the clipboard you do so as you would any other format.

IDataObject ido = new DataObject();
CustomData cd = new CustomData(myImage, myString);

ido.SetData(CustomData.Format.Name, false, cd);

Retrieving data from it is done the same as before.

IDataObject ido = Clipboard.GetDataObject();

if( ido.GetDataPresent(CustomData.Format.Name) )
{
    // Do something interesting with the data

    CustomData cd = (CustomData) 
        ido.GetData(CustomData.Format.Name);
}

Persisting data on the clipboard, ie the 2nd parameter to SetDataObject

According to MSDN the second parameter tells the Clipboard object whether the data inside should be persisted when the application exits. BUT that isn't the full story. What it actually does is delay the serialization of the data until when the data is actually needed.

To see this in action run the included ClipboardTest2 application, uncheck "Persist Data"; then proceed to Draw, Copy, and Paste, then Draw and Paste. You'll see that even though the data was copied only once the new data is shown.

The reason for this lies in that I continue to operate on the same object that was passed into the IDataObject's SetData method, since we told the Clipboard object NOT to serialize the data until needed, that is what it did. On top of that it will reserialize the data everytime the data is requested. Oddly though it only updates the format specified, none of the auto-converted formats are touched once the initial serialization of the format occurs.

To demonstrate this open up the ClipboardTest2 application, again uncheck "Persist Data"; and then Draw, Copy, and Paste. Proceed to Draw and Paste, then open up your favorite image editing software; MSpaint will do. Now Paste the bitmap there; do some more Draw and Pastes then Paste again in another copy of MSPaint. You'll see the same bitmap was pasted in both MSPaint's.

This seems like a bug, but really it is a bug in my use. Once you place an object on the clipboard the intended result is that object stays the same; not to change it like I did. This means the optimal solution is to create a copy and cache it somewhere until it is needed by the Clipboard object.

If you choose to not persist data to the clipboard, upon exiting the application you should re-place the data on the clipboard and persist it; so that the contents are still there for the user to use.

Conclusion

There you have it folks, the Clipboard in all its glory. Hope I didn't bore you too much. As always leave questions or comments below; and please e-mail me any bugs you find.

For those interested in the Visual Style I used in the screen shots, I got it from themexp.org; you'll also need StyleXP or the free update to uxtheme.dll from the same site.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here