Skip to content


System.OutOfMemoryException Gotcha Using Clipboard.GetData in WPF

Introduction

Consider the following simple class for managing storage and retrieval of custom classes in the Windows Clipboard using WPF:

using System;
using System.Windows;

namespace ClipboardTest.Services
{
    public class ClipboardService : IClipboardService
    {
        public bool ContainsData<T>() where T:class
        {
            return Clipboard.ContainsData(typeof(T).ToString());
        }

        public void SetData<T>(T data) where T:class
        {
            Clipboard.SetData(typeof(T).ToString(), data);
        }

        public T GetData<T>() where T : class
        {
            return Clipboard.GetData(typeof(T).ToString()) as T;
        }
    }
}

Simple stuff, but it lets me abstract the clipboard away and remove the usual “magic string” approach for clipboard types.

Now consider the following basic tests:

using ClipboardTest.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ClipboardTest.Test.Services
{
    public class TestPayload
    {
        public string Data { get; set; }
    }

    [TestClass]
    public class ClipboardServiceTests
    {
        [TestMethod]
        public void SetData_CustomClass_ClipboardContainsInstanceOfClass()
        {
            string data = @"More Cowbell";
            var clipboardService = new ClipboardService();

            clipboardService.SetData<TestPayload>(new TestPayload() { Data = data });

            Assert.IsTrue(clipboardService.ContainsData<TestPayload>());
        }

        [TestMethod]
        public void SetDataGetData_CustomClass_ReturnsEquivilantClass()
        {
            string data = @"More Cowbell";
            var clipboardService = new ClipboardService();

            clipboardService.SetData<TestPayload>(new TestPayload() { Data = data });
            var output = clipboardService.GetData<TestPayload>();

            Assert.IsNotNull(output);
            Assert.AreEqual(data, output.Data);
        }
    }
}

Again, all very simple. The first test checks to make sure that the class gets stored onto the clipboard, and the second checks to see if the class we get back off the clipboard is the same as the one we put in.

The more astute among you have probably spotted the problem in the test code already, but the resultant symptoms are a little confusing.

System.OutOfMemoryException?

When we run the tests the first test runs absolutely fine, but the second test crashes out with a System.OutOfMemoryException. A bit more digging showed that storing and retrieving standard types such as strings, ints etc all worked fine, but my own class was throwing an exception.

Checking good old MSDN threw up the following statement:

An object must be serializable for it to be put on the Clipboard.

Seeing as I had stupidly forgotten to add the SerializableAttribute to the TestPayload class that definitely explained why things weren’t working as I expected; but it didn’t really explain the actual behaviour I was seeing. Another quote from MSDN, but from the WinForms documentation, stated:

If you pass a non-serializable object to a Clipboard method, the method will fail without throwing an exception.

So from that I would expect SetData to silently fail, and for nothing to be on the clipboard. However the first test above clearly shows that the clipboard at least thinks that something of our specified type has been added to the clipboard – it just throws an exception when we try and retrieve it again. Marking the payload class as serializable did fix the issue, but the behaviour I was seeing certainly didn’t make that obvious!

Just out of interest I tested the same code using the WinForms Clipboard class, which looks to all intents and purposes exactly the same as the WPF one, and that did fail silently and returned null from GetData.

Conclusion

So, after all that rambling, the conclusion is that if you are working with the Clipboard in WPF and you are getting System.OutOfMemoryExceptions that don’t seem to make any sense, then you’ve probably forgotten to add the SerializableAttribute to whatever class you placed on the Clipboard.

Share:
  • Twitter
  • DotNetKicks
  • DotNetShoutout
  • Google Bookmarks
  • Digg
  • del.icio.us
  • Live
  • Technorati
  • StumbleUpon
  • email
  • Netvibes
  • Ping.fm
  • Print
  • Reddit

Technorati Tags: , , ,

Posted in Rambling, WPF.

Tagged with , , , .