Chapter 31. Interacting with the Clipboard

 

I object to doing things that computers can do.

 
 --Olin Shivers

Microsoft has always spearheaded the movement to constantly increase productivity using the Windows operating system. One productivity feature that has allowed people to work smarter and faster is the Windows Clipboard. The Clipboard is a temporary storage area that Windows uses to hold information that is being transferred between documents or applications. Most Windows applications support cutting or copying data to the Clipboard and pasting data from the Clipboard.

The Windows Clipboard can store many types of data, including text, formatted text, images, audio, and binary files. Even though any Clipboard data can be shared by all Windows applications, it is important to note that supported data formats vary between applications. Most applications know how to handle text, but not all applications know how to handle other data formats.

The Clipboard can only hold one data item at a time. When the Clipboard receives new data, the previous data is overwritten with the new contents. Contents can be pasted numerous times, because the contents remain in the Clipboard until cleared, overwritten by newer contents, or when Windows is shut down.

This chapter describes how to use the standard Windows Clipboard API from within your .NET applications.

The Clipboard Class and IDataObject

Accessing the Clipboard and storing data is made possible by the Clipboard class in the System.Windows.Forms namespace, specifically the SetDataObject() and GetDataObject() methods.

SetDataObject() is used to store arbitrary data on the Clipboard, and it defines whether or not the data remains persisted after the application exits. Similarly, GetDataObject() is used to retrieve arbitrary data that is stored on the Clipboard. GetDataObject() can also be used to determine whether data exists on the Clipboard, and what format the data is. Both methods use the IDataObject interface, which is a format-independent mechanism that is used for data transfer and notification of changes in data. The IDataObject interface is used in this situation because arbitrary data can be stored on the Clipboard, and we need an initial way to determine what format the data is before we can work with it.

The SetDataObject() method has two overloaded definitions. The first one (shown in the following line of code) is used to store an object on the Clipboard, releasing the data when the application exits.

public static void SetDataObject(object data);

The following method has a copy parameter that specifies whether the data should be persisted on the Clipboard after the application exits.

public static void SetDataObject(object data, bool copy);

The GetData() method can be used to get the associated data and convert it to the appropriate type.

Storing Built-In Types

Storing built-in types is very simple, especially since .NET automatically handles conversion between similar data formats (ANSI and Unicode text, for example).

The following code shows how to store a built-in type (DataFormats.Text for this example).

string text = "This is a test!";
IDataObject dataObject = new DataObject();
dataObject.SetData(DataFormats.Text, true, text);
Clipboard.SetDataObject(dataObject, true);

The following code shows how to retrieve the text from the Clipboard.

IDataObject dataObject = Clipboard.GetDataObject();
string text = null;
if (dataObject.GetDataPresent(DataFormats.Text))
{
    text = (string)dataObject.GetData(DataFormats.Text);
}

There are many built-in types available, as shown in Table 31.1.

Table 31.1. Available Data Formats

Data Format

Description

Bitmap

Specifies a Windows bitmap format.

CommaSeparatedValue

Specifies a comma-separated value (CSV) format that is a common interchange format for spreadsheet applications.

Dib

Specifies the Windows device-independent bitmap format.

Dif

Specifies the Windows data interchange format.

EnhancedMetafile

Specifies the Windows enhanced metafile format.

FileDrop

Specifies the Windows file drop format.

Html

Specifies text consisting of HTML data.

Locale

Specifies the Windows culture format.

MetafilePict

Specifies the Windows metafile format.

OemText

Specifies the standard Windows original equipment manufacturer (OEM) text format.

Palette

Specifies the Windows palette format.

PenData

Specifies the Windows pen data format, used to store pen strokes for handwriting software.

Riff

Specifies the Resource Interchange File Format (RIFF) audio format.

Rtf

Specifies text consisting of rich text format data.

Serializable

Specifies a format that encapsulates any type of Windows Forms object.

StringFormat

Specifies the Windows Forms string class format, used by Windows Forms to store string objects.

SymbolicLink

Specifies the Windows symbolic link format.

Text

Specifies the standard ANSI text format.

Tiff

Specifies the Tagged Image File format.

UnicodeText

Specifies the standard Windows Unicode text format.

WaveAudio

Specifies the wave audio format.

Storing Custom Data Formats

Situations arise when your application needs to store custom data on the Clipboard, either for use within the same application or so that other related applications can use the data. The .NET framework allows you to store any serializable data type on the Clipboard. To start, we will define a simple custom data object that will be stored on the Clipboard. This object is described with the following code.

[Serializable]
public class CustomData
{
    private static DataFormats.Format dataFormat;
    public static DataFormats.Format DataFormat
    {
        get { return dataFormat; }
    }
    static CustomData()
    {
        dataFormat = DataFormats.GetFormat(typeof(CustomData).FullName);
    }
    private string testString;
    private int testInteger;
    public CustomData()
    {
        testString = string.Empty;
        testInteger = 0;
    }
    public CustomData(string testString, int testInteger)
    {
        this.testString = testString;
        this.testInteger = testInteger;
    }
    public string TestString
    {
        get { return testString; }
        set { testString = value;}
    }
    public int TestInteger
    {
        get { return testInteger; }
        set { testInteger = value; }
    }
    public override string ToString()
    {
        return string.Format("TestString:{0}, TestInteger{1}",
                                         testString,
                                         testInteger);
    }
}

Custom data requires a unique format descriptor, which is created with the following line of code.

dataFormat = DataFormats.GetFormat(typeof(CustomData).FullName);

The simple data object has a static constructor that sets the static dataFormat property so that the format can easily be plugged into the storage operation of the Clipboard.

The following code shows how to copy the CustomData object to the Clipboard.

CustomData data = new CustomData();
data.TestString = "This is a test";
data.TestInteger = 12345;
IDataObject dataObject = new DataObject();
dataObject.SetData(format, true, data);
Clipboard.SetDataObject(dataObject, true);

Similarly, the following code shows how to retrieve the CustomData object from the Clipboard.

IDataObject dataObject = Clipboard.GetDataObject();
CustomData data = null;
if (dataObject.GetDataPresent(CustomData.DataFormat.Name))
{
    data = (CustomData)dataObject.GetData(CustomData.DataFormat.Name);
}

Querying Available Data Formats

You already know that only a single chunk of data can be stored on the Clipboard at any one time, but it is also important to point out that some data types can be easily converted to a variety of different formats. .NET supports both implicit and explicit conversions between multiple data formats, but you generally need to be aware of the formats that a certain type format can convert to; attempting to convert data to an unsupported format will cause exceptions.

IDataObject has a useful method called GetFormats() that can be used to query the formats that the stored data can be converted to, provided that auto conversion was true when the data was stored on the Clipboard.

There are two overloaded definitions for GetFormats() shown in the following. The first definition retrieves all the formats that the stored data can be converted to.

public string[] IDataObject.GetFormats();

The next definition allows you to specify whether or not to include all convertible formats, or only list native types.

public string[] IDataObject.GetFormats(bool autoConvert);

Note

Call GetFormats() to get the supported formats before calling GetData().

Complete Solution

The code snippets in this chapter have been consolidated into a helper class that makes it easier to work with the Clipboard. .NET 2.0 has introduced several wrapper methods around SetDataObject() and GetDataObject() that are specific to certain data types. The intent of this chapter is to show how the low-level API for the Clipboard works, because all the wrapper methods do is encapsulate the SetDataObject() approach.

The complete source code for the helper class is shown below.

internal static class ClipboardHelper
{
    internal static string[] GetCurrentFormats()
    {
        IDataObject dataObject = Clipboard.GetDataObject();
        string[] formats = dataObject.GetFormats(true);
       return formats;
    }
    internal static void CopyText(string text)
    {
        CopyArbitraryData(DataFormats.Text, (object)text);
    }
    internal static void CopyImage(Image image)
    {
        CopyArbitraryData(DataFormats.Bitmap, (object)image);
    }
    internal static void CopyCustomData(CustomData data)
    {
        CopyArbitraryData(CustomData.DataFormat.Name, (object)data);
    }
    internal static string PasteText()
    {
        object rawData = PasteArbitraryData(DataFormats.Text, true);
        string text = null;
        if (rawData != null && rawData is string)
        {
            text = (string)rawData;
        }
        return text;
    }
    internal static Image PasteImage()
    {
        object rawData = PasteArbitraryData(DataFormats.Bitmap, true);
        Image image = null;
        if (rawData != null && rawData is Image)
        {
            image = (Image)rawData;
        }
       return image;
    }
    internal static CustomData PasteCustomData()
    {
        object rawData = PasteArbitraryData(CustomData.DataFormat.Name,
                                            false);
        CustomData data = null;
        if (rawData != null && rawData is CustomData)
        {
            data = (CustomData)rawData;
        }
        return data;
    }
    private static void CopyArbitraryData(string format, object data)
    {
        IDataObject dataObject = new DataObject();
        dataObject.SetData(format, true, data);
        Clipboard.SetDataObject(dataObject, true);
    }
    private static object PasteArbitraryData(string format, bool autoConvert)
    {
        object data = null;
        IDataObject dataObject = Clipboard.GetDataObject();
        if (dataObject.GetDataPresent(format))
        {
            if (autoConvert)
            {
                data = dataObject.GetData(format, true);
            }
            else
            {
                data = dataObject.GetData(format);
            }
        }

        return data;
    }
}

Conclusion

This chapter described what the Windows Clipboard is used for and how to store and retrieve arbitrary data on it. The Clipboard is a standard Windows feature that users expect to work in all applications, so it is advisable that you implement Clipboard functionality where appropriate in order to promote comfortable user interfaces.

Additionally, Clipboard functionality in terms of availability in the user interface is only meaningful in certain contexts. The Cut and Copy commands should only be enabled when data is selected. The Paste command should only be enabled when appropriate data is on the Clipboard. Be sure to design user interfaces that are easy for users to intuit and understand.

The Companion Web site includes the complete source code shown in this chapter, including a simple WinForms application that uses the Clipboard helper class. This demo application is shown in Figure 31.1.

Screenshot of the demo application on the Companion Web site.

Figure 31.1. Screenshot of the demo application on the Companion Web site.

The Clipboard is fairly simple to understand, though it is important to properly implement its functionality because users are so accustomed to its existence.

 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.120.187