Sự kiện khay nhớ tạm C #


90

Có sự kiện cập nhật hoặc thay đổi khay nhớ tạm nào mà tôi có thể truy cập thông qua C # không?


còn lớp Control thì sao? Nó ở đâu vậy?

Nó là một phần của WinForms.
Contango,

Câu trả lời:


73

Tôi nghĩ bạn sẽ phải sử dụng một số p / gọi:

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

Xem bài viết này về cách thiết lập màn hình khay nhớ tạm trong c #

Về cơ bản, bạn đăng ký ứng dụng của mình làm trình xem khay nhớ tạm bằng

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

và sau đó bạn sẽ nhận được WM_DRAWCLIPBOARDthông báo mà bạn có thể xử lý bằng cách ghi đè WndProc:

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

(Còn nhiều việc phải làm; chuyển mọi thứ dọc theo chuỗi khay nhớ tạm và hủy đăng ký chế độ xem của bạn, nhưng bạn có thể lấy điều đó từ bài viết )


Nó chỉ hoạt động trên biểu mẫu được mở đầu tiên ... giả sử nếu tôi có MyForm1 và myForm2, vì vậy tôi mở myForm1, sau đó là MyForm2, sự kiện ClipboardChanged sẽ chỉ được đưa ra trong MyForm1. Ý tôi là, trong một ứng dụng MDI ...
serhio

Liên kết đã chết. Bất kỳ bản sao lưu nào mà bạn biết? Tuy nhiên, +1.
Patrick Hofman,

1
Đối với những người lười biếng: Thiết lập bộ hẹn giờ tích tắc ở mức 1ms. Sau đó, với mỗi lần đánh dấu, hãy kiểm tra xem nội dung khay nhớ tạm của bạn có thay đổi hay không. Những móc nối này đang gây ra cảnh báo vi rút và trojan trên máy tính của tôi.
C4d

1
Nó chuyển mọi cửa sổ MSG đến biểu mẫu và khiến việc gỡ lỗi mã trở nên khó khăn

Tương tự như vậy, SharpClipboard như một thư viện có thể có nhiều lợi ích hơn vì nó đóng gói các tính năng giống nhau vào một thư viện thành phần tốt. Sau đó, bạn có thể truy cập ClipboardChangedsự kiện của nó và phát hiện các định dạng dữ liệu khác nhau khi chúng được cắt / sao chép.
Willy Kimura

78

Để hoàn thiện, đây là kiểm soát tôi đang sử dụng trong mã sản xuất. Chỉ cần kéo từ trình thiết kế và nhấp đúp để tạo trình xử lý sự kiện.

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
Bạn đã làm rất tốt! Tuy nhiên, mã gọi sự kiện của bạn không an toàn. Bạn nên tạo một bản sao cục bộ hoặc init sự kiện bằng một đại biểu trống. Bạn cũng quên từ khóa 'sự kiện' trong định nghĩa của ClipboardChanged :)
Ohad Schneider

1
@ohadsc Cảm ơn bạn đã chỉnh sửa. Theo như tôi biết, WndProc được gọi trên chuỗi giao diện người dùng. Vì lớp bắt nguồn từ Control, nên các máy khách cũng nên gọi nó trên chuỗi giao diện người dùng.
dbkk

Nó chỉ hoạt động trên biểu mẫu được mở đầu tiên ... giả sử nếu tôi có MyForm1 và myForm2, vì vậy tôi mở myForm1, sau đó là MyForm2, sự kiện ClipboardChanged sẽ chỉ được đưa ra trong MyForm1 ... Ý tôi là, trong một ứng dụng MDI ...
serhio

Bằng cách nào đó, cuộc gọi của bạn đến SetClipboardViewer đặt Mã lỗi Win32 1400: "Tay cầm cửa sổ không hợp lệ.". Nhưng nó vẫn hoạt động. Điều này có vẻ hơi lạ đối với tôi.
metacircle

1
SharpClipboard như một thư viện có thể có nhiều lợi ích hơn vì nó đóng gói các tính năng giống nhau vào một thư viện thành phần tốt. Sau đó, bạn có thể truy cập ClipboardChangedsự kiện của nó và phát hiện các định dạng dữ liệu khác nhau khi chúng được cắt / sao chép.
Willy Kimura

26

Tôi đã gặp thử thách này trong WPF và kết thúc bằng cách sử dụng phương pháp được mô tả bên dưới. Đối với các biểu mẫu cửa sổ, có những ví dụ tuyệt vời ở nơi khác trong câu trả lời này, chẳng hạn như điều khiển ClipboardHelper.

Đối với WPF, chúng ta không thể ghi đè WndProc, vì vậy chúng ta phải kết nối nó một cách rõ ràng với lệnh gọi HwndSource AddHook bằng cách sử dụng Nguồn từ một cửa sổ. Trình nghe khay nhớ tạm vẫn sử dụng lệnh gọi tương tác gốc AddClipboardFormatListener.

Phương pháp gốc:

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

Lớp quản lý bảng tạm:

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

Điều này được sử dụng trong cửa sổ WPF bằng cách thêm sự kiện trong OnSourceInitialized trở lên, chẳng hạn như sự kiện Window.Loaded hoặc trong quá trình hoạt động. (khi chúng ta có đủ thông tin để sử dụng các hook gốc):

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

Tôi đang sử dụng phương pháp này trong một dự án phân tích vật phẩm Path of Exile, vì trò chơi hiển thị thông tin vật phẩm qua khay nhớ tạm khi bạn nhấn Ctrl-C.

https://github.com/ColinDabritz/PoeItemAnalyzer

Tôi hy vọng điều này sẽ giúp ai đó xử lý thay đổi khay nhớ tạm WPF!


1
Nếu ai đó không biết ý nghĩa của việc ClipboardChanged?.Invokenhìn thấy Sử dụng New Null Conditional Operator trong C # 6 , phần kịch bản khác
marbel82

11

Ok, đây là một bài cũ nhưng chúng tôi đã tìm ra một giải pháp có vẻ rất đơn giản so với bộ đáp án hiện tại. Chúng tôi đang sử dụng WPF và chúng tôi muốn bật và tắt các Lệnh tùy chỉnh của riêng mình (trong ContextMenu) nếu Clipboard chứa văn bản. Đã có một ApplicationCommands.Cut, Copy và Paste và các lệnh này phản hồi chính xác với việc thay đổi khay nhớ tạm. Vì vậy, chúng tôi vừa thêm EventHandler sau.

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

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

Chúng tôi thực sự đang điều khiển CanExecute trên Command của riêng mình theo cách này. Làm việc cho những gì chúng tôi cần và có thể nó sẽ giúp ích cho những người khác.


Giải pháp tuyệt vời, bởi vì nó rất đơn giản ... Cảm ơn!
okieh

1
Đây là một giải pháp tuyệt vời cho vấn đề cụ thể khi bật hoặc tắt lệnh dán. Thật không may, nó không bao gồm kịch bản "văn bản đã thay đổi" cụ thể và sẽ không kích hoạt khi sao chép văn bản nhiều dòng khác nhau chẳng hạn.
Colin Dabritz

11

Có nhiều cách để làm điều này nhưng đây là cách tôi yêu thích và phù hợp với tôi. Tôi đã tạo một thư viện lớp để những người khác có thể thêm dự án và bao gồm DLL, sau đó chỉ cần gọi nó và sử dụng nó ở bất cứ đâu họ muốn trong ứng dụng của họ.

Câu trả lời này đã được thực hiện với sự trợ giúp của cái này .

  1. Tạo dự án Thư viện lớp và đặt tên là ClipboardHelper.
  2. Thay thế tên Class1 bằng ClipboardMonitor.
  3. Thêm mã dưới đây vào nó.
  4. Thêm tham chiếu System.Windows.Forms.

Các bước khác dưới mã.

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. Trong các dự án khác của bạn, nhấp chuột phải vào giải pháp và Thêm -> Thoát Dự án -> ClipboardHelper.csproj
  2. Trên dự án của bạn, đi tới và nhấp chuột phải vào Tham chiếu -> Thêm tài liệu tham khảo -> Giải pháp -> Chọn ClipboardHelper.
  3. Trong tệp lớp của bạn thuộc loại dự án sử dụng ClipboardHelper.
  4. Bây giờ bạn có thể nhập ClipboardMonitor.Start hoặc .Stop hoặc .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...
            }
    }

6

Tôi tin rằng một trong những giải pháp trước đó không kiểm tra giá trị rỗng trên phương pháp xử lý:

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

Nó không bao giờ rỗng bởi vì hàm tạo đặt nó. Điều duy nhất tôi sẽ làm khác đi là gọi base.Dispose()trong phương thức vứt bỏ.
jedmao

Dù sao. Vì mục đích xác minh như bạn đã liệt kê, bạn nên sử dụng IntPtr.Zero cho NULL (lưu ý rằng nó không tương đương với C # null) stackoverflow.com/questions/1456861/…
walter

1
ChangeClipboardChain được thực hiện luôn trên lối ra trong tất cả các mẫu MSDN
walter

Mục đích là để xóa chính nó khỏi chuỗi trình xem clipboard
walter

5

SharpClipboard như một thư viện có thể có nhiều lợi ích hơn vì nó đóng gói các tính năng giống nhau vào một thư viện thành phần tốt. Sau đó, bạn có thể truy cập ClipboardChangedsự kiện của nó và phát hiện các định dạng dữ liệu khác nhau khi chúng được cắt / sao chép.

Bạn có thể chọn các định dạng dữ liệu khác nhau mà bạn muốn theo dõi:

var clipboard = new SharpClipboard();

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

Đây là một ví dụ sử dụng ClipboardChangedsự kiện của nó :

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

Bạn cũng có thể tìm hiểu ứng dụng đã xảy ra sự kiện cắt / sao chép cùng với các chi tiết của nó:

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

Ngoài ra còn có các sự kiện khác như MonitorChanged sự kiện sẽ lắng nghe bất cứ khi nào tính năng giám sát khay nhớ tạm bị tắt, có nghĩa là bạn có thể bật hoặc tắt giám sát khay nhớ tạm trong thời gian chạy.

Ngoài tất cả những điều này, vì nó là một thành phần, bạn có thể sử dụng nó trong Chế độ xem nhà thiết kế bằng cách kéo và thả nó vào Biểu mẫu Windows, giúp mọi người cực kỳ dễ dàng tùy chỉnh các tùy chọn của nó và làm việc với các sự kiện có sẵn của nó.

SharpClipboard dường như là lựa chọn tốt nhất cho các tình huống giám sát clipboard trong .NET.


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;
            }
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.