我在我的应用程序中实现了一个屏幕截图,用户可以 Select 要捕获的部分,为此,我使用此链接中提供的示例创建了一个控件来覆盖图片框: Creating Custom Picturebox with Draggable and Resizable Selection Window

该控件工作得很好,做了需要做的事情,但我难以实现的是,当用户单击控件外部的按钮时,它将不再移动,将其光标从SizeAll更改为Arrow,但仍然可以调整大小.

我怎么才能完成这样的任务呢?

这是我现在用来创建控件的代码

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

namespace ControlSizable
{
    public partial class FrameControl: UserControl
    {
       public FrameControl()
       {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        DoubleBuffered = true;
        ResizeRedraw = true;
        BackColor = Color.Transparent;
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        using (var p = new Pen(Color.White , 3))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            e.Graphics.DrawRectangle(p, 0, 0, Width - 1, Height - 1);
        }
    }
    const int WM_NCHITTEST = 0x84;
    const int WM_SETCURSOR = 0x20;
    const int WM_NCLBUTTONDBLCLK = 0xA3;
    protected override void WndProc(ref Message m)
    {
        int borderWidth = 10;
        if (m.Msg == WM_SETCURSOR)  /*Setting cursor to SizeAll*/
        {
            if ((m.LParam.ToInt32() & 0xffff) == 0x2 /*Move*/)
            {
                Cursor.Current = Cursors.SizeAll;
                m.Result = (IntPtr)1;
                return;
            }
        
        }
        if ((m.Msg == WM_NCLBUTTONDBLCLK)) /*Disable Mazimiz on Double click*/
        {
            m.Result = (IntPtr)1;
            return;
        }
        base.WndProc(ref m);
        if (m.Msg == WM_NCHITTEST)
        {
            var pos = PointToClient(new Point(m.LParam.ToInt32() & 0xffff,
                m.LParam.ToInt32() >> 16));
            if (pos.X <= ClientRectangle.Left + borderWidth &&
                pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = new IntPtr(13); //TOPLEFT
            else if (pos.X >= ClientRectangle.Right - borderWidth &&
                pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = new IntPtr(14); //TOPRIGHT
            else if (pos.X <= ClientRectangle.Left + borderWidth &&
                pos.Y >= ClientRectangle.Bottom - borderWidth)
                m.Result = new IntPtr(16); //BOTTOMLEFT
            else if (pos.X >= ClientRectangle.Right - borderWidth &&
                pos.Y >= ClientRectangle.Bottom - borderWidth)
                m.Result = new IntPtr(17); //BOTTOMRIGHT
            else if (pos.X <= ClientRectangle.Left + borderWidth)
                m.Result = new IntPtr(10); //LEFT
            else if (pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = new IntPtr(12); //TOP
            else if (pos.X >= ClientRectangle.Right - borderWidth)
                m.Result = new IntPtr(11); //RIGHT
            else if (pos.Y >= ClientRectangle.Bottom - borderWidth)
                m.Result = new IntPtr(15); //Bottom
            else
                m.Result = new IntPtr(2); //Move
        }
    }
}

}

Example of a screenshot using the control: enter image description here

我试图做的是,当用户点击箭头按钮时,控件不再在屏幕上移动,只是根据边缘调整大小,我可以在绘图本身中绘制箭头(这个绘制箭头的过程,我已经可以做到了)

推荐答案

将公共bool属性添加到Custom Control中,此处命名为CanMove,默认为true.

然后,在WndProc覆盖中,当消息为WM_SETCURSOR时,计算CanMove:如果它是缺省值(true),则将光标设置为Cursors.SizeAll,否则设置为Cursors.Arrow(或您认为合适的任何值)

当消息是WM_NCHITTEST时,在最后的if条件下,如果CanMove是true,则返回(IntPtr)2,否则返回IntPtr.Zero.

在FrameControl类文件的顶部添加using System.ComponentModel;.

CanMovefalse时,该控件仍可调整大小.

因此,当您单击该按钮时,只需将Framecontrol的CanMove属性设置为false.

using System.ComponentModel;

public class FrameControl : Control {
    public FrameControl() { // [...]}

    [DefaultValue(true)] 
    public bool CanMove { get; set; } = true;

    // [...]

    protected override void WndProc(ref Message m) {
        if (m.Msg == WM_SETCURSOR)  /*Setting cursor to SizeAll or Arrow */
        {
            if ((m.LParam.ToInt32() & 0xffff) == 0x2 /*Move*/) {
                Cursor.Current = CanMove ? Cursors.SizeAll : Cursors.Arrow;
                m.Result = (IntPtr)1;
                return;
            }
        }
        // [...]
        base.WndProc(ref m);

        if (m.Msg == WM_NCHITTEST) {
            // [...]
            if (pos.X <= ClientRectangle.Left + borderWidth &&
                pos.Y <= ClientRectangle.Top + borderWidth)
                m.Result = (IntPtr)13; //TOPLEFT
            // [...]
            else
                m.Result = CanMove ? (IntPtr)2 : IntPtr.Zero;
        }
    }
}

Csharp相关问答推荐

如何使用PDFSharp将文本添加到现有PDF

为什么在GuardationRule的收件箱函数中,decode.TryParse(valueString,out valueParsed)在给出1.0.1时返回true?

AutoMapper -如何为两个不同的用例设置单个映射?

为什么这个Reflection. Emit代码会导致一个DDL ViolationException?

C#中使用BouncyCastle计算CMac

在C#WinUI中,一个关于System的崩溃."由于未知原因导致执行不例外"

图形API基于appid列表检索多个应用程序

用C#调用由缓冲区指针参数组成的C API

在调整大小的控件上绘制

C#-从基类更新子类

为什么我可以用硬编码的集合而不是变量来设置没有setter的IList属性的值?

同一组件的多个实例触发相同的事件处理程序

在Windows Plesk上发布ASP.NET Core 7 Web API-错误:无法加载文件或程序集';Microsoft.Data.SqlClient';

C#动态设置ServerReport报表参数

基于C#方法的EF核心过滤查询(缓冲与流)

如何使用ODP.NET C#设置Oracle会话时间长度限制

仅在Blazor Web App中覆盖生产的基本路径(.NET8中的_Hosts.cshtml文件功能?)

处理方法内部过滤与外部过滤

外部应用&&的LINQ;左外部连接&类似于PostgreSQL的查询

如何根据分割文本的块数来计算文本的大小?