31 Days of Windows 8 | Day #17: The Clipboard

This article is Day #17 in a series called 31 Days of Windows 8.  Each of the articles in this series will be published for both HTML5/JS and XAML/C#. You can find additional resources, downloads, and source code on our website.

advertisementsample

Today, we’re going to focus on the Windows 8 clipboard exclusively. More specifically, we’re going to look at how we can save and retrieve data from this system-wide and heavily used mechanism.  There are generally four types of data that we are going to see a user want to copy and paste:

  • Text
  • HTML
  • Images
  • Files

We’ll write some code in this article that shows not only how to copy and paste these values, but also how to detect which type of data the clipboard currently contains.

Saving Data to the Clipboard

As we saw briefly in yesterday’s article on context menus, we took a very quick look at saving some text to the clipboard.  This time, we’ll cover that in more depth, and include saving images and files to the clipboard as well.  To get started, we should talk about the DataPackage object.

A DataPackage is what we are going to use to transport our data.  We will create a DataPackage when we save data to the clipboard, and we will use the Clipboard.GetContent() method to retrieve the data when we’re pasting it.

In my sample project (which you can download from GitHub), you will see that I’ve created a button with an event handler for each data type.  We’ll spend the rest of this section looking at how we store these different types of data to the Clipboard.

It is important to note that the clipboard is actually divided into several sections, one for each data type.  You can save data to one or many of these sections, and the target for pasting will make the determination as to what type of data it will display when pasted.  This might sound very similar to how the Share Contract works, and for the most part, it is.

It’s also likely that you’ve encountered this in the past: you copy content from one app, and try to paste it in another, only to have it paste something else.  This is a direct artifact of the “sections” of the clipboard.  Let’s take a look at how to save each data type:

Text

Certainly the simplest example, text can be stored to the Clipboard in three lines of code:

DataPackage d = new DataPackage();
d.SetText(TextBoxValue.Text);
Clipboard.SetContent(d);
 

You will see a pattern form as we move through the other examples, but this is about as basic as they come.  We create a new DataPackage object, call the SetText() method with the text we want to save, and then set the content of the Clipboard to that DataPackage.

HTML

HTML, while similar to text, has its own quirks and formatting, and because of this, requires slightly different treatment when adding it to a DataPackage.  In this example, I am grabbing the HTML source from a WebView control (HTMLSource), and using that as my DataPackage contents.  However, I am also setting the SetText() value of this DataPackage, so that you can see how multiple values can be set at the same time.

DataPackage d = new DataPackage();
            
string s = HtmlFormatHelper.CreateHtmlFormat(HTMLSource.InvokeScript("eval", new string[] { "document.documentElement.outerHTML;" }));
d.SetHtmlFormat(s);
 
string t = HtmlUtilities.ConvertToText(s);
d.SetText(t);
 
Clipboard.SetContent(d);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

As you can see above, we can set multiple values at the same time, and as you get deeper into this example, you’ll start to notice that most of your favorite apps store data in multiple formats “just in case.”

Images

Our next example is images, and I want to be really clear on this one.  We’re not talking about a file that happens to be an image.  We’re talking about copying an image from a website, for example, and then pasting it into a OneNote file or Windows Live Writer.  In my example, I am allowing the user to copy an image from my application to their clipboard.

DataPackage d = new DataPackage();
Uri uri = new Uri("ms-appx:///Assets/WideLogo.png");
StorageFile sf = await StorageFile.GetFileFromApplicationUriAsync(uri);
d.SetBitmap(RandomAccessStreamReference.CreateFromFile(sf));
Clipboard.SetContent(d);
 

In the image example, we are grabbing the image from its location in our project, creating a StorageFile from it, and then setting the SetBitmap() content of the DataPackage with it.  As with all of the examples in this article, we end our code with Clipboard.SetContent() to actually complete the action.

Files

Files are treated very similarly to images, but there’s one major difference: we can copy multiple files to the clipboard at once.  You’ve done this before, highlight and grab some of the files cluttering up your desktop before dragging them as a group to the Recycle Bin.  Instead of throwing them away, you could cut/copy them, and paste them to another location.  Files are always passed as a collection of files, even if there is only one.

DataPackage d = new DataPackage();
Uri uri = new Uri("ms-appx:///Assets/PeriodicTable.xls");
List<StorageFile> files = new List<StorageFile>();
StorageFile sf = await StorageFile.GetFileFromApplicationUriAsync(uri);
files.Add(sf);
d.SetStorageItems(files);
Clipboard.SetContent(d);
 

As you can see, there’s very little difference between the code for images and files.  One important note, as you work through this in your own project, relates to files you might add to your project.  When I added the PeriodicTable.xls file to my project, I initially forgot to set the “Build Action” on that file in my project, and by default, the Build Action is “None.”  If you also forget, using the code above will result in a “FileNotFoundException.”

Simply set the Build Action of your file to “Content” by looking in the Properties pane of Visual Studio 2012.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }17-XAML-BuildAction

So, as far as saving content to the Clipboard, that’s just about it!  Our next step is going to be retrieving it from the Clipboard when the user chooses to paste it.

Detecting the Contents of the Clipboard

When it comes to “getting pasted” as I’ve started saying, I tend to do this all in one method that gets the content, determines which data type is available, and displays the content correctly based on that determination.

I had hoped, when writing this article, that there was going to be some amazing event handler, like OnPastedTo() or something, that would recognize when the user is attempting to paste some content to the app, so that we can take action on it.  (I personally live and die with Ctrl + X, Ctrl + C, and Ctrl + V).  I have not found that event yet, but if/when I do, I will update this page.  For now, I’ve created my own event handler that fires when you click a button.

You’ll see, in the example below, that I call the GetContent() method on the Clipboard, and then use a series of IF statements to act on the content appropriately.

private async void PasteButton_Click(object sender, RoutedEventArgs e)
{
    var DataPackage = Clipboard.GetContent();
 
    if (DataPackage.Contains(StandardDataFormats.Text))
    {
        TextBoxPaste.Text = await DataPackage.GetTextAsync();
    }
 
    if (DataPackage.Contains(StandardDataFormats.Bitmap))
    {
        RandomAccessStreamReference image = await DataPackage.GetBitmapAsync();
        var imageStream = await image.OpenReadAsync();
        BitmapImage bmp = new BitmapImage();
        bmp.SetSource(imageStream);
        ImagePaste.Source = bmp;
    }
 
    if (DataPackage.Contains(StandardDataFormats.StorageItems))
    {
        var storageFiles = await DataPackage.GetStorageItemsAsync();
 
        foreach (var file in storageFiles)
        {
            var currentFile = file as StorageFile;
            await currentFile.CopyAsync(ApplicationData.Current.LocalFolder, currentFile.Name, NameCollisionOption.ReplaceExisting);
            MessageText.Text = currentFile.Name + " has been saved to " + ApplicationData.Current.LocalFolder.Path.ToString() + "/" + currentFile.Name;
        }
    }
 
    if (DataPackage.Contains(StandardDataFormats.Html))
    {
        string html = await DataPackage.GetHtmlFormatAsync();
        HTMLPaste.NavigateToString(html);
    }
}

 

Let me quickly discuss each of the IF statements.  For text, I simply grab the Text data and place it in a TextBlock control on my page.  For an image, I need to convert the Image data to a BitmapImage object before I can set it as the source of an Image control.  For files, I loop through the collection of files, saving each of them as local files in my application, and then write the name of the file and the location of the folder to a TextBlock.  Finally, for HTML, I grab the HTML source, and, using a WebView control, navigate the control to the HTML source that I have received.

In all it’s pretty simple, but I was delighted the first time that I copied content from a webpage directly into my app, and it just worked!  The same is true for images, text, and files.  I highly recommend grabbing the source of this project and playing with it.  It will really help you to understand exactly how the clipboard is being used by your other applications.

Summary

Today, we took a deep look at the Clipboard, and how we can save and retrieve data as needed.  It supports several different file types, and I think you’ll be surprised just how redundant most of your favorite applications are when they save data to the Clipboard.

To download the entire code solution for the project discussed in this article, click the icon below:

downloadXAML

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Tomorrow, we’re going to add another useful tool to our Windows 8 development tool belt: the FilePicker.  We’ll look at retrieving files from the user’s device, and even filtering them so that we only get our preferred file types.  See you then!

downloadTheTools

7 thoughts on “31 Days of Windows 8 | Day #17: The Clipboard

  1. Pingback: 31 Days of Windows 8 | Day #18: File Associations & App Contracts « Blankenblog

  2. Pingback: The Daily Six Pack: November 19, 2012 | Dirk Strauss

  3. Glad to know that you can retrieve data from the clipboard, which wasn’t allowed on Windows Phone 7.x

  4. Pingback: 31 Days of Windows 8 | Day #17: The Clipboard

  5. Pingback: 31 Days of Windows 8 | Day #17: The Clipboard | Answer My Query

  6. So, if you copy text, and then copy something else is that text lost then? Or can it be retrieved on windows 8?

  7. Sorry but I don’t find the keyword Clipboard on windows phone 8.1. What I am wrong thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s