Zwischenablage Ereignis C #


88

Gibt es ein geändertes oder aktualisiertes Ereignis in der Zwischenablage, auf das ich über C # zugreifen kann?


Was ist mit der Kontrollklasse? Wo ist es?

Es ist Teil von WinForms.
Contango

Antworten:


72

Ich denke, Sie müssen einige p / invoke verwenden:

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

In diesem Artikel erfahren Sie, wie Sie einen Zwischenablage-Monitor in c # einrichten.

Grundsätzlich registrieren Sie Ihre App als Zwischenablage-Viewer mit

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

und dann erhalten Sie die WM_DRAWCLIPBOARDNachricht, die Sie durch Überschreiben verarbeiten können WndProc:

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

(Es gibt noch mehr zu tun; Dinge entlang der Zwischenablagekette weitergeben und die Registrierung Ihrer Ansicht aufheben, aber das können Sie dem Artikel entnehmen. )


Es funktioniert nur beim ersten geöffneten Formular. Wenn ich MyForm1 und myForm2 habe, also myForm1 öffne, wird MyForm2, das Ereignis ClipboardChanged, nur in MyForm1 ausgelöst. Ich meine, in einer MDI-Anwendung ...
Serhio

Der Link ist tot. Gibt es ein Backup, von dem Sie wissen? +1 trotzdem.
Patrick Hofman

1
Für faule Leute: Stellen Sie einen Timer ein, der bei 1 ms tickt. Überprüfen Sie dann bei jedem Tick, ob sich der Inhalt Ihrer Zwischenablage geändert hat. Diese Hooks lösen auf meinem Computer Viren- und Trojaner-Warnungen aus.
C4d

1
Es fährt alle Fenster MSG auf die Form und machen es so schwer , den Code zu debuggen

Ebenso könnte SharpClipboard als Bibliothek von größerem Nutzen sein, da es dieselben Funktionen in einer feinen Komponentenbibliothek zusammenfasst. Sie können dann auf das ClipboardChangedEreignis zugreifen und verschiedene Datenformate erkennen, wenn sie ausgeschnitten / kopiert werden.
Willy Kimura

77

Der Vollständigkeit halber hier das Steuerelement, das ich im Produktionscode verwende. Ziehen Sie einfach vom Designer und doppelklicken Sie, um den Ereignishandler zu erstellen.

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;
    }
}
}

2
Gut gemacht! Ihr Ereignisaufrufcode ist jedoch nicht threadsicher. Sie sollten entweder eine lokale Kopie erstellen oder das Ereignis mit einem leeren Delegaten initiieren. Sie haben auch das Schlüsselwort 'event' in der Definition von ClipboardChanged vergessen :)
Ohad Schneider

1
@ohadsc Danke für die Korrekturen. Soweit ich weiß, wird WndProc im UI-Thread aufgerufen. Da die Klasse von Control abgeleitet ist, sollten Clients sie auch im UI-Thread aufrufen.
dbkk

Es funktioniert nur mit dem ersten geöffneten Formular ... Wenn ich MyForm1 und myForm2 habe, also myForm1 öffne, wird MyForm2, das Ereignis ClipboardChanged, nur in MyForm1 ausgelöst ... Ich meine, in einer MDI-Anwendung ...
Serhio

Irgendwie setzt Ihr Aufruf von SetClipboardViewer den Win32-Fehlercode 1400: "Ungültiges Fensterhandle". Aber es funktioniert immer noch. Das kommt mir etwas seltsam vor.
Metacircle

1
SharpClipboard als Bibliothek könnte von größerem Nutzen sein, da es dieselben Funktionen in einer feinen Komponentenbibliothek zusammenfasst. Sie können dann auf das ClipboardChangedEreignis zugreifen und verschiedene Datenformate erkennen, wenn sie ausgeschnitten / kopiert werden.
Willy Kimura

26

Ich hatte diese Herausforderung in WPF und habe den unten beschriebenen Ansatz verwendet. Für Windows-Formulare gibt es an anderer Stelle in dieser Antwort hervorragende Beispiele, z. B. das ClipboardHelper-Steuerelement.

Für WPF können wir WndProc nicht überschreiben, daher müssen wir es explizit mit einem HwndSource AddHook-Aufruf unter Verwendung der Quelle aus einem Fenster verknüpfen. Der Listener der Zwischenablage verwendet weiterhin den nativen Interop-Aufruf AddClipboardFormatListener.

Native Methoden:

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);
}

Zwischenablage-Manager-Klasse:

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;
    }
}

Dies wird in einem WPF-Fenster verwendet, indem das Ereignis in OnSourceInitialized oder höher hinzugefügt wird, z. B. das Ereignis Window.Loaded oder während des Betriebs. (wenn wir genug Informationen haben, um die nativen Hooks zu verwenden):

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());
        }
    }
}

Ich verwende diesen Ansatz in einem Path of Exile-Item-Analyzer-Projekt, da das Spiel Item-Informationen über die Zwischenablage anzeigt, wenn Sie Strg-C drücken.

https://github.com/ColinDabritz/PoeItemAnalyzer

Ich hoffe, dies hilft jemandem bei der Handhabung von Änderungen in der WPF-Zwischenablage!


1
Wenn jemand nicht weiß , was es bedeutet , zu ClipboardChanged?.Invokesehen # 6 Verwenden des New Null Conditional Operator in C , Abschnitt Andere Szenarien
marbel82

11

Ok, das ist ein alter Beitrag, aber wir haben eine Lösung gefunden, die im Vergleich zu den aktuellen Antworten sehr einfach zu sein scheint. Wir verwenden WPF und wollten, dass unsere eigenen benutzerdefinierten Befehle (in einem ContextMenu) aktiviert und deaktiviert werden, wenn die Zwischenablage Text enthält. Es gibt bereits einen ApplicationCommands.Cut, Copy and Paste, und diese Befehle reagieren korrekt auf Änderungen in der Zwischenablage. Also haben wir gerade den folgenden EventHandler hinzugefügt.

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

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

Auf diese Weise steuern wir CanExecute auf eigenen Befehl. Funktioniert für das, was wir brauchten, und vielleicht hilft es anderen da draußen.


Tolle Lösung, weil es so einfach ist ... Danke!
Okieh

1
Dies ist eine fantastische Lösung für das spezifische Problem des Aktivierens oder Deaktivierens des Einfügebefehls. Leider wird das spezifische Szenario "Der Text wurde geändert" nicht behandelt und es wird beispielsweise beim Kopieren von Text mit mehreren verschiedenen Zeilen nicht ausgelöst.
Colin Dabritz

11

Es gibt mehrere Möglichkeiten, dies zu tun, aber dies ist mein Favorit und funktioniert für mich. Ich habe eine Klassenbibliothek erstellt, damit andere das Projekt hinzufügen und die DLL einschließen können. Rufen Sie sie dann einfach auf und verwenden Sie sie, wo immer sie wollen, in ihren Anwendungen.

Diese Antwort wurde mit Hilfe dieser gemacht .

  1. Erstellen Sie ein Klassenbibliotheksprojekt und nennen Sie es ClipboardHelper.
  2. Ersetzen Sie den Namen der Klasse 1 durch ClipboardMonitor.
  3. Fügen Sie den folgenden Code hinzu.
  4. Fügen Sie die System.Windows.Forms-Referenz hinzu.

Weitere Schritte unter 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. Klicken Sie in Ihren anderen Projekten mit der rechten Maustaste auf Lösung und dann auf Hinzufügen -> Projekt beenden -> ZwischenablageHelper.csproj
  2. Gehen Sie in Ihrem Projekt zu und klicken Sie mit der rechten Maustaste auf Referenzen -> Referenz hinzufügen -> Lösung -> Wählen Sie ClipboardHelper.
  3. In Ihrer Klassendatei des Projekttyps mit ClipboardHelper.
  4. Sie können jetzt ClipboardMonitor.Start oder .Stop oder .OnClipboardChanged eingeben

    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...
            }
    }

6

Ich glaube, eine der früheren Lösungen prüft die Entsorgungsmethode nicht auf Null:

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;
        }
    }
}

Es ist niemals null, weil der Konstruktor es festlegt. Das einzige, was ich anders machen würde, ist den Aufruf base.Dispose()der dispose-Methode.
jedmao

Wie auch immer. Für Überprüfungszwecke, wie Sie sie aufgelistet haben, sollten Sie IntPtr.Zero für NULL verwenden (beachten Sie, dass es nicht dem C # null entspricht) stackoverflow.com/questions/1456861/…
walter

1
ChangeClipboardChain wird immer beim Beenden in allen msdn-Beispielen ausgeführt
Walter

Der Zweck ist es, sich aus der Zwischenablage-Viewer-Kette zu entfernen
Walter

5

SharpClipboard als Bibliothek könnte von größerem Nutzen sein, da es dieselben Funktionen in einer feinen Komponentenbibliothek zusammenfasst. Sie können dann auf das ClipboardChangedEreignis zugreifen und verschiedene Datenformate erkennen, wenn sie ausgeschnitten / kopiert werden.

Sie können die verschiedenen Datenformate auswählen, die Sie überwachen möchten:

var clipboard = new SharpClipboard();

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

Hier ist ein Beispiel für das ClipboardChangedEreignis:

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...
    }
}

Sie können auch die Anwendung, in der das Ausschneiden / Kopieren aufgetreten ist, zusammen mit den Details herausfinden:

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);
}

Es gibt auch andere Ereignisse wie das MonitorChanged Ereignis, das abhört, wenn die Überwachung der Zwischenablage deaktiviert wird. Dies bedeutet, dass Sie die Überwachung der Zwischenablage zur Laufzeit aktivieren oder deaktivieren können.

Da es sich um eine Komponente handelt, können Sie sie außerdem in der Designeransicht verwenden, indem Sie sie per Drag & Drop in ein Windows Form ziehen, sodass jeder seine Optionen ganz einfach anpassen und mit den integrierten Ereignissen arbeiten kann.

SharpClipboard scheint die beste Option für Szenarien zur Überwachung der Zwischenablage in .NET zu sein.


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;
            }
        }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.