草庐IT

wpf - 剪贴板更改通知?

coder 2023-11-09 原文

我知道如何将内容放入剪贴板和从剪贴板检索内容。

但是,在这两个操作之间,另一个操作可能会更改剪贴板的内容。

有没有办法在任何应用程序修改剪贴板时得到通知?

最佳答案

您需要添加的唯一引用是您的 wpf 应用程序中的 Windows 窗体。我为在 Internet 上找到的功能创建了一个包装器。

大多数示例所做的比我需要的要多,所以我决定创建自己的类。我喜欢隔离问题,因此此类仅在剪贴板更改时监听并告诉您剪贴板上的数据类型。例如它是文本吗?一个图像?或者什么?

无论如何,这是我的包装器:

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

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;

            Thread 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)]
        public static extern IntPtr SetClipboardViewer(IntPtr 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);

        // 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,
}

我知道它可能太多了,但包装后它应该看起来像:

然后您将类用作:

    static void Main(string[] args)
    {

        ClipboardMonitor.Start();

        ClipboardMonitor.OnClipboardChange += new ClipboardMonitor.OnClipboardChangeEventHandler(ClipboardMonitor_OnClipboardChange);

        Console.Read();

        ClipboardMonitor.Stop(); // do not forget to stop


        
    }

    static void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data)
    {
        Console.WriteLine("Clipboard changed and it has the format: "+format.ToString());
    }

关于wpf - 剪贴板更改通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6458030/

有关wpf - 剪贴板更改通知?的更多相关文章

  1. ruby-on-rails - Ruby on Rails 迁移,将表更改为 MyISAM - 2

    如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设

  2. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  3. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  4. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  5. ruby - 更改 ActiveRecord 中对象的类 - 2

    假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。

  6. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  7. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  8. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

  9. ruby - 是否可以将 IRB 提示配置为动态更改? - 2

    我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO

  10. ruby - Watir 更改 Mozilla Firefox 首选项 - 2

    我正在使用Watir运行一个Ruby脚本来为我自动化一些事情。我试图自动将一些文件保存到某个目录。因此,在我的Mozilla设置中,我将默认下载目录设置为桌面并选择自动保存文件。但是,当我开始运行我的脚本时,这些更改并没有反射(reflect)出来。似乎首选项恢复为默认值。我已经包括以下内容require"rubygems"#Optional.require"watir-webdriver"#Forwebautomation.require"win32ole"#Forfilesavedialog.并打开一个新的firefox实例:browser=Watir::Browser.new(:

随机推荐