WM_NCLBUTTONUP消息在拖动表单结尾时没有发送,怎么办?

时间:2014-06-30 15:03:40

标签: c# winforms wndproc

编辑: tl; dr转到第一条评论。

这个问题源于我的另一个问题Get MouseDown event when mouse goes down on Form border?

在那个问题中,当用户在表单边框上按下鼠标左键(准备拖动)时,我需要有一个表单触发事件,这非常有效。问题是当用户完成此操作时,通过放开鼠标左键,我还想要触发一个事件。

为此,我将此代码生成为“基本表单”类,其他表单将从中派生。我已经删除了FireMouseButton...()简洁方法;他们解雇自定义事件。

const int WM_NCLBUTTONUP = 0xA2;
const int WM_NCLBUTTONDWN = 0xA1;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_NCLBUTTONUP)
        FireMouseButtonUp();
    if (m.Msg == WM_NCLBUTTONDWN)
        FireMouseButtonDown();
    base.WndProc(ref m);
}

问题在于WM_NCLBUTTONUP消息未按我的预期发送。在查看WM_NCLBUTTONUP的说明后,我可以看到原因,

  当用户在光标处释放鼠标左键时,

[WM_NCLBUTTONUP]被发布   在窗口的非客户区域内。此消息已发布到   包含光标的窗口。如果一个窗口捕获了   鼠标,此消息未发布。

由于表单在拖动时捕获了鼠标,因此不会收到WM_NCLBUTTONUP消息。 (如果形式最大化的话会这样)。这个问题解释得更好The curious problem of the missing WM_NCLBUTTONUP message when a window isn't maximised

这个问题的答案有点帮助,但对我来说却引起很多困惑。在下面的代码中我有一个小的SSCCE,它实现了从上面的答案的解决方案给出的一些代码,检查WMNCHITTEST消息以查看鼠标是否已被释放;

这个想法是当鼠标在表单中移动时应该发送WM_NCHITTEST。因此,一旦拖动停止,此消息应在WndProc消息参数中以鼠标位置DragStartPoint发送;收到DragStartPoint消息时记录WM_NCLBUTTONDOWN的位置。

这个问题的一个问题是WM_NCHITTEST并不总是在拖动开始后发送,只有在顶部边框的远端开始拖动时才会发送(见下图)。单击顶部边框时始终发送WM_NCLBUTTONDOWN消息(从不对侧或底部)。这样很好,但是WM_NCHITTEST和指出的WM_NCLBUTTONUP被发送,但有时只发送。

enter image description here

如何让WM_NCHITTEST“test”在下面的代码中工作,以便在用户停止拖动表单后收到通知? (“test”正在检查DragStartPoint)的if语句中的WM_NCHITTEST

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MouseEventTest
{
    public partial class Form1 : Form
    {
        Random rand = new Random();

        public Form1()
        {
            InitializeComponent();
        }

        const int WM_NCHITTEST = 0x84;
        const int WM_NCLBUTTONUP = 0xA2;
        const int WM_NCLBUTTONDWN = 0xA1;

        public Point DragStartPoint { get; set; }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_NCLBUTTONUP)
            {
                label1.Text = "Mouse Up On Border";
            }
            if (m.Msg == WM_NCLBUTTONDWN)
            {
                label1.Text = "Mouse Down On Border";

                Point pos = lParamToPoint(m.LParam);
                DragStartPoint = this.PointToClient(pos);

                Console.Out.WriteLine("DragStartPoint: " + DragStartPoint);
            }

            if(m.Msg == WM_NCHITTEST)
            {
                Point pos = lParamToPoint(m.LParam);
                Console.Out.WriteLine("HtTestPnt: " + this.PointToClient(pos));

                if (DragStartPoint == this.PointToClient(pos))
                {
                    label1.Text = "Mouse Up HitTest";
                }
            }

            base.WndProc(ref m);
        }

        private Point lParamToPoint(IntPtr lParamIn)
        {
            int x = lParamIn.ToInt32() & 0x0000FFFF;
            int y = (int)((lParamIn.ToInt32() & 0xFFFF0000) >> 16);
            return new Point(x, y);
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(42, 30);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(91, 13);
            this.label1.TabIndex = 0;
            this.label1.Text = "99999999999999";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(185, 75);
            this.Controls.Add(this.label1);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Label label1;
    }
}

0 个答案:

没有答案