Événement de presse-papiers C #

90

Y a-t-il un événement de presse-papiers modifié ou mis à jour auquel je peux accéder via C #?

Sevki
la source
qu'en est-il de la classe de contrôle? Où est-ce que c'est?
Cela fait partie de WinForms.
Contango du

Réponses:

73

Je pense que vous devrez utiliser un p / invoke:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

Voir cet article sur la configuration d'un moniteur de presse-papiers en c #

En gros, vous enregistrez votre application en tant que visionneuse de presse-papiers en utilisant

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

puis vous recevrez le WM_DRAWCLIPBOARDmessage, que vous pouvez gérer en remplaçant WndProc:

protected override void WndProc(ref Message m)
{
    switch ((Win32.Msgs)m.Msg)
    {
        case Win32.Msgs.WM_DRAWCLIPBOARD:
        // Handle clipboard changed
        break;
        // ... 
   }
}

(Il y a plus à faire; passer des choses le long de la chaîne du presse-papiers et désenregistrer votre vue, mais vous pouvez l'obtenir à partir de l'article )

Daniel LeCheminant
la source
Cela ne fonctionne que sur le premier formulaire ouvert ... disons si j'ai MyForm1 et myForm2, donc j'ouvre myForm1, puis MyForm2, l'événement ClipboardChanged ne sera déclenché que dans MyForm1. Je veux dire, dans une application MDI ...
serhio
Le lien est mort. Une sauvegarde dont vous avez connaissance? +1 néanmoins.
Patrick Hofman
1
Pour les paresseux: configurez un minuteur qui tourne à 1 ms. Ensuite, à chaque tick, vérifiez si le contenu de votre presse-papiers a changé. Ces hooks déclenchent des alertes de virus et de chevaux de Troie sur mon ordinateur.
C4d
1
Il passe toutes les fenêtres MSG à la forme et la rendent si difficile de déboguer le code
De même, SharpClipboard en tant que bibliothèque pourrait être plus avantageux car il encapsule les mêmes fonctionnalités dans une bibliothèque de composants fins. Vous pouvez alors accéder à son ClipboardChangedévénement et détecter divers formats de données lorsqu'ils sont coupés / copiés.
Willy Kimura
78

Pour être complet, voici le contrôle que j'utilise dans le code de production. Faites simplement glisser depuis le concepteur et double-cliquez pour créer le gestionnaire d'événements.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace ClipboardAssist {

// Must inherit Control, not Component, in order to have Handle
[DefaultEvent("ClipboardChanged")]
public partial class ClipboardMonitor : Control 
{
    IntPtr nextClipboardViewer;

    public ClipboardMonitor()
    {
        this.BackColor = Color.Red;
        this.Visible = false;

        nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
    }

    /// <summary>
    /// Clipboard contents changed.
    /// </summary>
    public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;

    protected override void Dispose(bool disposing)
    {
        ChangeClipboardChain(this.Handle, nextClipboardViewer);
    }

    [DllImport("User32.dll")]
    protected static extern int SetClipboardViewer(int hWndNewViewer);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                OnClipboardChanged();
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            case WM_CHANGECBCHAIN:
                if (m.WParam == nextClipboardViewer)
                    nextClipboardViewer = m.LParam;
                else
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            default:
                base.WndProc(ref m);
                break;
        }
    }

    void OnClipboardChanged()
    {
        try
        {
            IDataObject iData = Clipboard.GetDataObject();
            if (ClipboardChanged != null)
            {
                ClipboardChanged(this, new ClipboardChangedEventArgs(iData));
            }

        }
        catch (Exception e)
        {
            // Swallow or pop-up, not sure
            // Trace.Write(e.ToString());
            MessageBox.Show(e.ToString());
        }
    }
}

public class ClipboardChangedEventArgs : EventArgs
{
    public readonly IDataObject DataObject;

    public ClipboardChangedEventArgs(IDataObject dataObject)
    {
        DataObject = dataObject;
    }
}
}
dbkk
la source
2
Bon travail! Cependant, votre code d'appel d'événement n'est pas thread-safe. Vous devez soit créer une copie locale, soit lancer l'événement avec un délégué vide. Vous avez également oublié le mot-clé 'event' dans la définition de ClipboardChanged :)
Ohad Schneider
1
@ohadsc Merci pour les corrections. Autant que je sache, WndProc est appelé sur le thread d'interface utilisateur. Étant donné que la classe dérive de Control, les clients doivent également l'appeler sur le thread d'interface utilisateur.
dbkk
Cela ne fonctionne que sur le premier formulaire ouvert ... disons si j'ai MyForm1 et myForm2, donc j'ouvre myForm1, puis MyForm2, l'événement ClipboardChanged sera déclenché uniquement dans MyForm1 ... je veux dire, dans une application MDI ...
serhio
En quelque sorte, votre appel à SetClipboardViewer définit le code d'erreur Win32 1400: «poignée de fenêtre non valide». Mais ça marche toujours. Cela me semble un peu étrange.
metacircle
1
SharpClipboard en tant que bibliothèque pourrait être plus avantageux car il encapsule les mêmes fonctionnalités dans une bibliothèque de composants fins. Vous pouvez alors accéder à son ClipboardChangedévénement et détecter divers formats de données lorsqu'ils sont coupés / copiés.
Willy Kimura
26

J'ai eu ce défi dans WPF et j'ai fini par utiliser l'approche décrite ci-dessous. Pour les formulaires Windows, il existe d'excellents exemples ailleurs dans cette réponse, tels que le contrôle ClipboardHelper.

Pour WPF, nous ne pouvons pas remplacer WndProc, nous devons donc le raccorder explicitement à un appel HwndSource AddHook à l'aide de la source à partir d'une fenêtre. L'écouteur du presse-papiers utilise toujours l'appel d'interopérabilité natif AddClipboardFormatListener.

Méthodes natives:

internal static class NativeMethods
{
    // See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
    public const int WM_CLIPBOARDUPDATE = 0x031D;
    public static IntPtr HWND_MESSAGE = new IntPtr(-3);

    // See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool AddClipboardFormatListener(IntPtr hwnd);
}

Classe Clipboard Manager:

using System.Windows;
using System.Windows.Interop;

public class ClipboardManager
{
    public event EventHandler ClipboardChanged;

    public ClipboardManager(Window windowSource)
    {
        HwndSource source = PresentationSource.FromVisual(windowSource) as HwndSource;
        if(source == null)
        {
            throw new ArgumentException(
                "Window source MUST be initialized first, such as in the Window's OnSourceInitialized handler."
                , nameof(windowSource));
        }

        source.AddHook(WndProc);

        // get window handle for interop
        IntPtr windowHandle = new WindowInteropHelper(windowSource).Handle;

        // register for clipboard events
        NativeMethods.AddClipboardFormatListener(windowHandle);
    }

    private void OnClipboardChanged()
    {
        ClipboardChanged?.Invoke(this, EventArgs.Empty);
    }

    private static readonly IntPtr WndProcSuccess = IntPtr.Zero;

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == NativeMethods.WM_CLIPBOARDUPDATE)
        {
            OnClipboardChanged();
            handled = true;
        }

        return WndProcSuccess;
    }
}

Cela est utilisé dans une fenêtre WPF en ajoutant l'événement dans OnSourceInitialized ou version ultérieure, comme l'événement Window.Loaded ou pendant l'opération. (lorsque nous avons suffisamment d'informations pour utiliser les hooks natifs):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        // Initialize the clipboard now that we have a window soruce to use
        var windowClipboardManager = new ClipboardManager(this);
        windowClipboardManager.ClipboardChanged += ClipboardChanged;
    }

    private void ClipboardChanged(object sender, EventArgs e)
    {
        // Handle your clipboard update here, debug logging example:
        if (Clipboard.ContainsText())
        {
            Debug.WriteLine(Clipboard.GetText());
        }
    }
}

J'utilise cette approche dans un projet d'analyseur d'éléments Path of Exile, car le jeu expose des informations sur les éléments via le presse-papiers lorsque vous appuyez sur Ctrl-C.

https://github.com/ColinDabritz/PoeItemAnalyzer

J'espère que cela aidera quelqu'un avec la gestion des changements de presse-papiers WPF!

Colin Dabritz
la source
1
Si quelqu'un ne sait pas ce que cela signifie de ClipboardChanged?.Invokevoir Utilisation du nouvel opérateur conditionnel Null en C # 6 , section Autres scénarios
marbel82
11

Ok donc c'est un ancien post mais nous avons trouvé une solution qui semble très simple par rapport à l'ensemble de réponses actuel. Nous utilisons WPF et nous voulions avoir nos propres commandes personnalisées (dans un ContextMenu) activées et désactivées si le Presse-papiers contient du texte. Il existe déjà un ApplicationCommands.Cut, Copy and Paste et ces commandes répondent correctement au changement du presse-papiers. Nous venons donc d'ajouter le EventHandler suivant.

ApplicationCommands.Paste.CanExecuteChanged += new EventHandler(Paste_CanExecuteChanged);

private void Paste_CanExecuteChanged(object sender, EventArgs e) {
  ourVariable= Clipboard.ContainsText();
}

Nous contrôlons en fait CanExecute sur notre propre commande de cette façon. Fonctionne pour ce dont nous avions besoin et peut-être que cela aidera les autres.

Eric
la source
Excellente solution, car c'est si simple ... Merci!
okieh
1
C'est une solution fantastique au problème spécifique de l'activation ou de la désactivation de la commande coller. Malheureusement, il ne couvre pas le scénario spécifique «le texte a changé» et ne se déclenchera pas lors de la copie de plusieurs lignes de texte par exemple.
Colin Dabritz
11

Il y a plusieurs façons de faire cela, mais c'est mon préféré et cela fonctionne pour moi. J'ai créé une bibliothèque de classes afin que d'autres puissent ajouter le projet et inclure la DLL, puis simplement l'appeler et l'utiliser où ils le souhaitent dans leurs applications.

Cette réponse a été faite à l'aide de celle-ci .

  1. Créez un projet de bibliothèque de classes et nommez-le ClipboardHelper.
  2. Remplacez le nom Class1 par ClipboardMonitor.
  3. Ajoutez-y le code ci-dessous.
  4. Ajoutez une référence System.Windows.Forms.

Plus d'étapes sous code.

using System;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;

namespace ClipboardHelper
{
    public static class ClipboardMonitor
    {
        public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
        public static event OnClipboardChangeEventHandler OnClipboardChange;

        public static void Start()
        {
            ClipboardWatcher.Start();
            ClipboardWatcher.OnClipboardChange += (ClipboardFormat format, object data) =>
            {
                if (OnClipboardChange != null)
                    OnClipboardChange(format, data);
            };
        }

        public static void Stop()
        {
            OnClipboardChange = null;
            ClipboardWatcher.Stop();
        }

        class ClipboardWatcher : Form
        {
            // static instance of this form
            private static ClipboardWatcher mInstance;

            // needed to dispose this form
            static IntPtr nextClipboardViewer;

            public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
            public static event OnClipboardChangeEventHandler OnClipboardChange;

            // start listening
            public static void Start()
            {
                // we can only have one instance if this class
                if (mInstance != null)
                    return;

                var t = new Thread(new ParameterizedThreadStart(x => Application.Run(new ClipboardWatcher())));
                t.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
                t.Start();
            }

            // stop listening (dispose form)
            public static void Stop()
            {
                mInstance.Invoke(new MethodInvoker(() =>
                {
                    ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);
                }));
                mInstance.Invoke(new MethodInvoker(mInstance.Close));

                mInstance.Dispose();

                mInstance = null;
            }

            // on load: (hide this window)
            protected override void SetVisibleCore(bool value)
            {
                CreateHandle();

                mInstance = this;

                nextClipboardViewer = SetClipboardViewer(mInstance.Handle);

                base.SetVisibleCore(false);
            }

            [DllImport("User32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

            [DllImport("User32.dll", CharSet = CharSet.Auto)]
            private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

            // defined in winuser.h
            const int WM_DRAWCLIPBOARD = 0x308;
            const int WM_CHANGECBCHAIN = 0x030D;

            protected override void WndProc(ref Message m)
            {
                switch (m.Msg)
                {
                    case WM_DRAWCLIPBOARD:
                        ClipChanged();
                        SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                        break;

                    case WM_CHANGECBCHAIN:
                        if (m.WParam == nextClipboardViewer)
                            nextClipboardViewer = m.LParam;
                        else
                            SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                        break;

                    default:
                        base.WndProc(ref m);
                        break;
                }
            }

            static readonly string[] formats = Enum.GetNames(typeof(ClipboardFormat));

            private void ClipChanged()
            {
                IDataObject iData = Clipboard.GetDataObject();

                ClipboardFormat? format = null;

                foreach (var f in formats)
                {
                    if (iData.GetDataPresent(f))
                    {
                        format = (ClipboardFormat)Enum.Parse(typeof(ClipboardFormat), f);
                        break;
                    }
                }

                object data = iData.GetData(format.ToString());

                if (data == null || format == null)
                    return;

                if (OnClipboardChange != null)
                    OnClipboardChange((ClipboardFormat)format, data);
            }
        }
    }

    public enum ClipboardFormat : byte
    {
        /// <summary>Specifies the standard ANSI text format. This static field is read-only.
        /// </summary>
        /// <filterpriority>1</filterpriority>
        Text,
        /// <summary>Specifies the standard Windows Unicode text format. This static field
        /// is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        UnicodeText,
        /// <summary>Specifies the Windows device-independent bitmap (DIB) format. This static
        /// field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Dib,
        /// <summary>Specifies a Windows bitmap format. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Bitmap,
        /// <summary>Specifies the Windows enhanced metafile format. This static field is
        /// read-only.</summary>
        /// <filterpriority>1</filterpriority>
        EnhancedMetafile,
        /// <summary>Specifies the Windows metafile format, which Windows Forms does not
        /// directly use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        MetafilePict,
        /// <summary>Specifies the Windows symbolic link format, which Windows Forms does
        /// not directly use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        SymbolicLink,
        /// <summary>Specifies the Windows Data Interchange Format (DIF), which Windows Forms
        /// does not directly use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Dif,
        /// <summary>Specifies the Tagged Image File Format (TIFF), which Windows Forms does
        /// not directly use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Tiff,
        /// <summary>Specifies the standard Windows original equipment manufacturer (OEM)
        /// text format. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        OemText,
        /// <summary>Specifies the Windows palette format. This static field is read-only.
        /// </summary>
        /// <filterpriority>1</filterpriority>
        Palette,
        /// <summary>Specifies the Windows pen data format, which consists of pen strokes
        /// for handwriting software, Windows Forms does not use this format. This static
        /// field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        PenData,
        /// <summary>Specifies the Resource Interchange File Format (RIFF) audio format,
        /// which Windows Forms does not directly use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Riff,
        /// <summary>Specifies the wave audio format, which Windows Forms does not directly
        /// use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        WaveAudio,
        /// <summary>Specifies the Windows file drop format, which Windows Forms does not
        /// directly use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        FileDrop,
        /// <summary>Specifies the Windows culture format, which Windows Forms does not directly
        /// use. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Locale,
        /// <summary>Specifies text consisting of HTML data. This static field is read-only.
        /// </summary>
        /// <filterpriority>1</filterpriority>
        Html,
        /// <summary>Specifies text consisting of Rich Text Format (RTF) data. This static
        /// field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Rtf,
        /// <summary>Specifies a comma-separated value (CSV) format, which is a common interchange
        /// format used by spreadsheets. This format is not used directly by Windows Forms.
        /// This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        CommaSeparatedValue,
        /// <summary>Specifies the Windows Forms string class format, which Windows Forms
        /// uses to store string objects. This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        StringFormat,
        /// <summary>Specifies a format that encapsulates any type of Windows Forms object.
        /// This static field is read-only.</summary>
        /// <filterpriority>1</filterpriority>
        Serializable,
    }
}
  1. Dans vos autres projets, faites un clic droit sur la solution et Ajouter -> Quitter le projet -> ClipboardHelper.csproj
  2. Sur votre projet, allez et cliquez avec le bouton droit sur Références -> Ajouter une référence -> Solution -> Sélectionnez ClipboardHelper.
  3. Dans votre fichier de classe du type de projet à l'aide de ClipboardHelper.
  4. Vous pouvez maintenant taper ClipboardMonitor.Start ou .Stop ou .OnClipboardChanged

    using ClipboardHelper;
    
    namespace Something.Something.DarkSide
    {
        public class MainWindow
        {
    
            public MainWindow()
            {
                InitializeComponent();
    
                Loaded += MainWindow_Loaded;
            }
    
            void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
                ClipboardMonitor.OnClipboardChange += ClipboardMonitor_OnClipboardChange;
                ClipboardMonitor.Start();
            }               
    
            private void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data)
            {
                // Do Something...
            }
    }
AzzamAziz
la source
6

Je pense que l'une des solutions précédentes ne vérifie pas la valeur null sur la méthode dispose:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace ClipboardAssist {

// Must inherit Control, not Component, in order to have Handle
[DefaultEvent("ClipboardChanged")]
public partial class ClipboardMonitor : Control 
{
    IntPtr nextClipboardViewer;

    public ClipboardMonitor()
    {
        this.BackColor = Color.Red;
        this.Visible = false;

        nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
    }

    /// <summary>
    /// Clipboard contents changed.
    /// </summary>
    public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;

    protected override void Dispose(bool disposing)
    {
        if(nextClipboardViewer != null)
            ChangeClipboardChain(this.Handle, nextClipboardViewer);
    }

    [DllImport("User32.dll")]
    protected static extern int SetClipboardViewer(int hWndNewViewer);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                OnClipboardChanged();
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            case WM_CHANGECBCHAIN:
                if (m.WParam == nextClipboardViewer)
                    nextClipboardViewer = m.LParam;
                else
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            default:
                base.WndProc(ref m);
                break;
        }
    }

    void OnClipboardChanged()
    {
        try
        {
            IDataObject iData = Clipboard.GetDataObject();
            if (ClipboardChanged != null)
            {
                ClipboardChanged(this, new ClipboardChangedEventArgs(iData));
            }

        }
        catch (Exception e)
        {
            // Swallow or pop-up, not sure
            // Trace.Write(e.ToString());
            MessageBox.Show(e.ToString());
        }
    }
}

    public class ClipboardChangedEventArgs : EventArgs
    {
        public readonly IDataObject DataObject;

        public ClipboardChangedEventArgs(IDataObject dataObject)
        {
            DataObject = dataObject;
        }
    }
}
SamFisher83
la source
Ce n'est jamais nul car le constructeur le définit. La seule chose que je ferais différemment est d'appeler base.Dispose()la méthode dispose.
jedmao
En tous cas. À des fins de vérification comme vous l'avez répertorié, vous devez utiliser IntPtr.Zero pour NULL (notez que ce n'est pas équivalent à C # null) stackoverflow.com/questions/1456861/…
walter
1
ChangeClipboardChain est exécuté toujours à la sortie dans tous les échantillons msdn
walter
Le but est de se retirer de la chaîne de visionnage du presse-papiers
Walter
5

SharpClipboard en tant que bibliothèque pourrait être plus avantageux car il encapsule les mêmes fonctionnalités dans une bibliothèque de composants fins. Vous pouvez alors accéder à sonClipboardChanged événement et détecter divers formats de données lorsqu'ils sont coupés / copiés.

Vous pouvez choisir les différents formats de données que vous souhaitez surveiller:

var clipboard = new SharpClipboard();

clipboard.ObservableFormats.Texts = true;
clipboard.ObservableFormats.Files = true;
clipboard.ObservableFormats.Images = true;
clipboard.ObservableFormats.Others = true;

Voici un exemple utilisant son ClipboardChangedévénement:

private void ClipboardChanged(Object sender, ClipboardChangedEventArgs e)
{
    // Is the content copied of text type?
    if (e.ContentType == SharpClipboard.ContentTypes.Text)
    {
        // Get the cut/copied text.
        Debug.WriteLine(clipboard.ClipboardText);
    }

    // Is the content copied of image type?
    else if (e.ContentType == SharpClipboard.ContentTypes.Image)
    {
        // Get the cut/copied image.
        Image img = clipboard.ClipboardImage;
    }

    // Is the content copied of file type?
    else if (e.ContentType == SharpClipboard.ContentTypes.Files)
    {
        // Get the cut/copied file/files.
        Debug.WriteLine(clipboard.ClipboardFiles.ToArray());

        // ...or use 'ClipboardFile' to get a single copied file.
        Debug.WriteLine(clipboard.ClipboardFile);
    }

    // If the cut/copied content is complex, use 'Other'.
    else if (e.ContentType == SharpClipboard.ContentTypes.Other)
    {
        // Do something with 'e.Content' here...
    }
}

Vous pouvez également découvrir l'application sur laquelle l'événement de coupe / copie s'est produit avec ses détails:

private void ClipboardChanged(Object sender, SharpClipboard.ClipboardChangedEventArgs e)
{
    // Gets the application's executable name.
    Debug.WriteLine(e.SourceApplication.Name);
    // Gets the application's window title.
    Debug.WriteLine(e.SourceApplication.Title);
    // Gets the application's process ID.
    Debug.WriteLine(e.SourceApplication.ID.ToString());
    // Gets the application's executable path.
    Debug.WriteLine(e.SourceApplication.Path);
}

Il y a aussi d'autres événements tels que le MonitorChanged événement qui écoute chaque fois que la surveillance du presse-papiers est désactivée, ce qui signifie que vous pouvez activer ou désactiver la surveillance du presse-papiers au moment de l'exécution.

En plus de tout cela, puisqu'il s'agit d'un composant, vous pouvez l'utiliser dans Designer View en le faisant glisser et en le déposant dans un formulaire Windows, ce qui permet à quiconque de personnaliser ses options et de travailler avec ses événements intégrés.

SharpClipboard semble être la meilleure option pour les scénarios de surveillance du presse-papiers dans .NET.

Willy Kimura
la source
0
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
        private IntPtr _ClipboardViewerNext;

        private void Form1_Load(object sender, EventArgs e)
        {
            _ClipboardViewerNext = SetClipboardViewer(this.Handle);
        }

        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_DRAWCLIPBOARD = 0x308;

            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    //Clipboard is Change 
                    //your code..............
                    break; 
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
Hossein Hajizadeh
la source