12

I am trying to copy an object onto the windows clipboard and off again. My code is like this:

Copy on to clipboard:

Clipboard.Clear();
DataObject newObject = new DataObject(prompts);
newObject.SetData(myString);
Clipboard.SetDataObject(newObject);

Where prompts is a List<Data.Sources.PromptResult> collection.

Copy off clipboard:

IDataObject dataObject = System.Windows.Forms.Clipboard.GetDataObject();
if (dataObject.GetDataPresent(typeof(List<Data.Sources.PromptResult>)))
{
  Type type = typeof(List<Data.Sources.PromptResult>);
  Object obj = dataObject.GetData(type);
  return (List<Data.Sources.PromptResult>)dataObject.GetData(type);
}

The GetFormats() shows the format as being in the list and the GetDataPresent(List<Data.Sources.PromptResult>) returns true but if I try to get the object out of the Clipboard class with GetData(List<Data.Sources.PromptResult>) I get a return of null.

Does anyone have any idea what might be wrong?

bluish
  • 26,356
  • 27
  • 122
  • 180
James
  • 2,812
  • 3
  • 22
  • 33
  • 2
    I ran into the same problems but I solved it differently. All I had to do was to make sure **every part of my object** (subobjects) was of a serializable type. Less code by far. Try the [IsSerializable method](http://www.codeproject.com/Articles/8102/Saving-and-obtaining-custom-objects-to-from-Window)! If your class is not serializable the exception describes the problem pretty good. – Bitterblue Jan 07 '15 at 14:19
  • I tried something very similar to this. As @Bitterblue notes, there's an easy way to test if the class in question (the one you just confirmed has a "[Serializeable]" annotation) is truely serializeable. You need to do this. I'm not sure I've seen it spelled out elsewhere as clearly as his reference makes it: "the first and the only clipboard requirement for your class. Your class has to be serializable" – msr Oct 07 '21 at 17:25

5 Answers5

17

OK I tried to add list of my user type to clipboard and get it back... Here is what I tried:

My User Class:

public class User
{
   public int Age { get; set; }
   public string Name { get; set; }
}

Rest of Code:

// Create User list and add some users
List<User> users = new List<User>();
users.Add(new User { age = 15, name = "Peter" });
users.Add(new User { age = 14, name = "John" });

// Lets say its my data format
string format = "MyUserList";
Clipboard.Clear();

// Set data to clipboard
Clipboard.SetData(format, users);

// Get data from clipboard
List<User> result = null;
if (Clipboard.ContainsData(format))
    result = (List<User>)Clipboard.GetData(format);

...and result was null :) ...until I marked User class as Serializable

[Serializable]
public class User
{ 
    //...   
}

After that my code worked. Ok its not the answer but maybe it helps you some how.

ˈvɔlə
  • 9,204
  • 10
  • 63
  • 89
Renatas M.
  • 11,694
  • 1
  • 43
  • 62
  • Are yes, serializable to serialize the class. I use the XML serialization normally but I guess the Clipboard class uses the binary serialization. – James Jan 27 '12 at 14:16
  • 1
    Yes it uses binary serialization. – Renatas M. Jan 27 '12 at 14:20
  • I have had a play around with this and it does seem to work except that I am trying to provide a text output too. I think I may have to implement the IDataObject on my own class. I think this because if I set the DataObject with both my serialized object and a text string then my object is lost when trying to get the data back. I think it may be a bug in the SetData method of the DataObject. - Or prehaps the DataObject class is not serializable. – James Jan 30 '12 at 13:36
  • You also need to make any child property objects serializable too or the copy will fail. Thanks for the tip! my copies work now. – Kezzla Jun 29 '21 at 04:42
4

@Reniuz thanks for your help it has helped me to work out the answer.

In order to get the text and custom object data out of the Clipboard with multiple formats I have implemented the IDataObject interface in my own class. The code to set the data object must have the copy flag set like this:

Clipboard.Clear();
Clipboard.SetDataObject(myClassThatImplementsIDataObject, true);

To get the data out again the standard text can be retrieved using:

Clipboard.GetText();

The data can be retrieved using the data method:

Clipboard.GetData("name of my class");

The other point that was helpful was to test that the object I was putting into the clipboard could be serialized by using the BinaryFormatter class to perform this test... If an exception is thrown that copying to the clipboard would also fail, but silently.

So my class has:

[Serializable]
public class ClipboardPromptsHolder : IDataObject
{
    ...
}
James
  • 2,812
  • 3
  • 22
  • 33
3

I had a similar scenario and after marking my class as serializable I got it to work.

So try putting the Serializable attribute on your class Data.Sources.PromptResult.

granaker
  • 1,318
  • 8
  • 13
0

I found out that, if your class is derived from a different class, the base class also needs to be made [Serializable], otherwise that recipe does not work. In my case, it was something like

public abstract class MyAbstractUser
{
...
}

[Serializable]
public class MyUser : MyAbstractUser
{
...
}

When I tried to exchange values of MyUser over the clipboard, it did not work, but when I added [Serializable] to MyAbstractUser, it did work.

Alex Konnen
  • 717
  • 6
  • 20
0

I came across this while trying to send a list of items to my clipboard. What I needed was the string representation of those items, not the entire object. I tried a few of the suggestions here, to no avail. However, I did come up with my own solution and I wanted to share it. See below.

public static void CopyToClipboard<T>(this IEnumerable<T> items)
{
    StringBuilder stringBuilder = new StringBuilder();

    foreach (T item in items)
        stringBuilder.Append(item.ToString()).AppendLine();

    Clipboard.SetText(stringBuilder.ToString());
}

Add this as an extension method and be sure to override your custom Type's ToString() method.

JasonG
  • 127
  • 1
  • 8