WPF–Copy UIElement to Clipboard as Multiple Formats
So about a week ago I wrote a post showing how to Copy a WPF UIElement as an Image to the Clipboard. In reply to that post Rob Relyea made a comment regarding supporting multiple formats on the Clipboard. What do I mean by formats? Well, when copying items to the Clipboard, you an specify different formats in which to copy the data, such as Text, Bitmap, HTML, XAML, and many others.
The idea behind it is that when you copy data to the Clipboard, depending on what application you are pasting into, you can support the different application supported formats. For instance, I may copy some data from my application to the clipboard in two formats; a Bitmap and Text. When that data is pasted into Paint, an image will be pasted. When I paste the same data into Notepad, text will be pasted instead. So let?s go ahead and modify the code snippet from my previously mentioned post to support two formats, an image format and a text format.
To support the Image format, I will keep the majority of the code the same. In order to support the text format, I need to make some assumptions. First, I need to ask myself, ?Where will the text representation of the UIElement being copied come from??. The simplest approach I came up with is to use the DataContext of the UIElement. I will assume that the object that is set as the DataContext of the UIElement being copied will be the text representation and will override the ToString() method to provide the text. So let?s take a look at the new snippet.
Well, lets see this is action. Rob mentioned the idea of a scenario of a ListBoxItem with a rich DataTemplate perhaps a tweet in a Twitter client. So, I am imagining a list of Tweets; a user selects a tweet in the list, copies it (ctrl+c), and then pastes it into various applications. If it is an image application like Paint, the image of the selected ItemTemplate should be pasted. If it is pasted in Notepad then the tweet message should be pasted.
The first thing I want to do is create a very simple DataTempate for my ListBox containing the tweets.
This DataTemplate will display an Image of the Poster and the tweet message next to it. When the item is selected I simply turn the message text red.
Next, I want to create a ListBox and bind a collection to the ItemsSource property. In this case, I have an ObservableCollection<Tweet> used as the ItemsSource of the ListBox. The Tweet is a simple object with two properties, Image and Message, and implements the INotifyPropertyChanged interface.
As you can see I have set the ItemTemplate to our DataTemplate we created earlier, and I have also added a CommandBinding to the ListBox for the Copy command. Anytime the ListBox has focus, and the user hits ctrl+c, the corresponding command will execute. now of course I don?t want the command to execute unless the is actually an item selected, so lets handle the CanExecute methods accordingly.
Now the next part can be a little tricky. Basically what we want to do is get the selected ListBoxItem from the ListBox, then grab the first UIElement in the visual tree of that item. Once we have the first UIElement in the visual tree of the selected item, we can pass that element to our copy method.
Lets see this thing in action.
Here is what the application looks like when it is running. It is a simple list of messages with my image next to it. Lets go ahead and select an item, hit ctrl+c to copy it to the clip board and paste it into Paint.
Now lets not copy anything new to the clipboard. I just want to take what is currently there and paste it into a different program that doesn?t support images, such as Notepad.
As you can see, the text representation is pasted instead of the image representation. Of course, this was a very simple implementation and is labeled with the ?Demo Code? use policy. Feel free to download the Source and start playing around. Try adding new formats, or improving on the code that is there. What ever you do, have fun with it.