Monitoring the clipboard The following class monitors the clipboard and raises an event whenever the contents change. The monitoring starts when the class is created and ends when Dispose is called.

To achieve this a message-only window (a term that comes from the Win32 API) is created using an instance of HwndSource class (since I am using WPF). The window's handle is then registered via AddClipboardFormatListener to receive a message whenever the clipboard changes. The window's messages are processed by WndProc which raises the event when the WM_CLIPBOARDUPDATE message comes.

In other solutions for monitoring the clipboard I saw this was done on the actual main window of the application, but I wanted to separate the logic of monitoring the clipboard form the View and keep a clean MVVM. In an application I would instantiate the ClipboardMonitor in the ViewModel.

I am interested if there may be any hidden pitfalls where this approach may go wrong.

public sealed class ClipboardMonitor : IDisposable
{
    private static class NativeMethods
    {
        /// &lt;summary&gt;
        /// Places the given window in the system-maintained clipboard format listener list.
        /// &lt;/summary&gt;
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool AddClipboardFormatListener(IntPtr hwnd);

        /// &lt;summary&gt;
        /// Removes the given window from the system-maintained clipboard format listener list.
        /// &lt;/summary&gt;
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RemoveClipboardFormatListener(IntPtr hwnd);

        /// &lt;summary&gt;
        /// Sent when the contents of the clipboard have changed.
        /// &lt;/summary&gt;
        public const int WM_CLIPBOARDUPDATE = 0x031D;

        /// &lt;summary&gt;
        /// To find message-only windows, specify HWND_MESSAGE in the hwndParent parameter of the FindWindowEx function.
        /// &lt;/summary&gt;
        public static IntPtr HWND_MESSAGE = new IntPtr(-3);
    }

    private HwndSource hwndSource = new HwndSource(0, 0, 0, 0, 0, 0, 0, null, NativeMethods.HWND_MESSAGE);

    public ClipboardMonitor()
    {
        hwndSource.AddHook(WndProc);
        NativeMethods.AddClipboardFormatListener(hwndSource.Handle);
    }

    public void Dispose()
    {
        NativeMethods.RemoveClipboardFormatListener(hwndSource.Handle);
        hwndSource.RemoveHook(WndProc);
        hwndSource.Dispose();
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == NativeMethods.WM_CLIPBOARDUPDATE)
        {
            OnClipboardContentChanged?.Invoke(this, EventArgs.Empty);
        }

        return IntPtr.Zero;
    }

    /// &lt;summary&gt;
    /// Occurs when the clipboard content changes.
    /// &lt;/summary&gt;
    public event EventHandler OnClipboardContentChanged;
}
Your code looks fine except for two points:  


a Dispose() method should never throw an exception but yours will likely throw one if it is called twice. This can be avoided by having a private bool disposed variable which is checked by an if condition.  
an event based method OnXXX is usually either private or protected and used to actually raise the event. A simple rename to ClipboardChanged will be sufficient to handle that issue.