【问题标题】:hook on default "Paste" event of WinForms TextBox control挂钩 WinForms TextBox 控件的默认“粘贴”事件
【发布时间】:2011-03-27 15:36:36
【问题描述】:

我需要“修改”所有粘贴到 TextBox 中的文本,以便以某种结构化的方式显示。我可以使用拖放、ctrl-v 来完成,但如何使用默认上下文的菜单“粘贴”来完成?

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    虽然我通常不建议使用低级别的 Windows API,而且这可能不是这样做的唯一方法,但它确实可以解决问题:

    using System;
    using System.Windows.Forms;
    
    public class ClipboardEventArgs : EventArgs
    {
        public string ClipboardText { get; set; }
        public ClipboardEventArgs(string clipboardText)
        {
            ClipboardText = clipboardText;
        }
    }
    
    class MyTextBox : TextBox
    {
        public event EventHandler<ClipboardEventArgs> Pasted;
    
        private const int WM_PASTE = 0x0302;
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_PASTE)
            {
                var evt = Pasted;
                if (evt != null)
                {
                    evt(this, new ClipboardEventArgs(Clipboard.GetText()));
                    // don't let the base control handle the event again
                    return;
                }
            }
    
            base.WndProc(ref m);
        }
    }
    
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
    
            var tb = new MyTextBox();
            tb.Pasted += (sender, args) => MessageBox.Show("Pasted: " + args.ClipboardText);
    
            var form = new Form();
            form.Controls.Add(tb);
    
            Application.Run(form);
        }
    }
    

    最终,WinForms 工具包不是很好。它是 Win32 和 Common Controls 的精简包装器。它公开了 80% 的最有用的 API。另外 20% 经常丢失或没有以明显的方式暴露。如果可能的话,我建议从 WinForms 转移到 WPF,因为 WPF 似乎是一个更好的 .NET GUI 架构框架。

    【讨论】:

    • 谢谢,我刚刚学到了一些新东西(不仅仅是如何捕捉“粘贴”,还有一种新的做事方式)
    • 粘贴字段声明中缺少事件关键字,为什么要使用局部变量 evt ?
    • 您在if 语句中缺少return,这会导致基本控件重新处理此事件。我在粘贴时格式化 XML 并且没有 return,格式化和未格式化的 XML 都会显示为基本控件再次处理粘贴。
    • @Maxence 局部变量是为了避免在检查 Pasted == null 和调用处理程序之间可能发生的竞争条件。如果单独的订阅者在检查和调用之间取消订阅另一个线程上的事件,您最终可能会遇到空引用异常。 C# 6 允许 Pasted?.Invoke() 作为替代的安全解决方案。
    • @itsme86 即使在 C#6 中,捕获变量也很重要,因为我们不仅要防止竞争条件,而且如果Pasted 事件在第一名。因此,即使我们进入 C#10,这个实现仍然是相关的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 2011-05-16
    • 2013-04-01
    相关资源
    最近更新 更多