1

I have a winform window. When I change the size of the screen, the screen immediately increases or decreases.

I would prefer the Resize behavior of the window will be like Split Container, as long as I drag the mouse I see only line that marks what will be the window size, and only in leaving the Resize operation will be made.

I saw several examples that show that by hiding the frame of the window, and then by clicking on the window itself paint frame.

I want that by clicking on the frame of the window(I don't want to hide the frame) and not on the window.

Is there any way to do this? (May override the behavior of the Resize in any way).

4

1 回答 1

5

我很确定您在 Internet 上找不到任何解决方案。但是我已经为此尝试了一个演示,并且效果很好

winforms和许多其他 UI 技术中,您不能在窗口本身之外呈现某些内容。为了获得我们想要的效果,我们必须根据用户如何调整窗口大小来在窗口外部或内部渲染一些指示性边框。所以看起来我们被困住了?

但是有一种技术可以做到这一点(我称之为层技术)。我们需要一个透明的非聚焦层来渲染指示性边框。该层将与主窗口的andSize同步Location(只有一点偏移)。默认情况下,该图层也将显示,并且仅在用户调整大小时显示并在结束调整大小时隐藏。SizeLocationinvisible

这对我提到的技术来说还不错。但是,当用户调整窗口大小时,如何防止/放弃默认调整大小?幸运的是,它Win32支持 2 条消息,以便轻松完成:

  • WM_RESIZING:当用户启动并不断调整大小时发送到窗口。LParam调整大小时保存当前窗口的结构RECT。我们阅读此信息以正确呈现指示性边框。然后我们需要把它修改RECT为当前Bounds窗口,以丢弃默认的调整大小效果(大小和位置立即改变)。
  • WM_EXITSIZEMOVE:在调整大小或移动结束时发送到窗口。我们需要捕获此消息以根据透明层的和分配窗口的和,当然然后隐藏该层SizeLocationSizeLocation

现在问题完全可以解决了。这是我制作的演示代码。请注意,这里有一个非常讨厌的无法解决和难以理解的错误,它发生在您调整Top-Left角的大小时,Size释放鼠标后正确更新但Location设置了偏移量。我已经调试但没有运气。在某些时候,Topand会无缘无故Left地跳到意想不到的值。但是,调整所有边(左、上、右、下)和其他角的大小是可以的。事实上,用户很难调整大小,所以我认为这个解决方案是可以接受的。Top-Left corner

//Must add using System.Runtime.InteropServices;
public partial class Form1 : Form
{        
    public Form1()
    {
        InitializeComponent();
        //Sizing border initialization
        SizingBorderWidth = 3;
        SizingBorderStyle = DashStyle.Custom;
        SizingBorderColor = Color.Orange;
        //layer initialization
        layer.Owner = this;//especially this one.
        layer.Width = Width + SizingBorderWidth * 2;
        layer.Height = Height + SizingBorderWidth * 2;                         
        //Paint the border when sizing
        layer.Paint += (s, e) => {
            using (Pen p = new Pen(SizingBorderColor) { Width = SizingBorderWidth }) {
                if (Use3DSizingBorder) {
                    ControlPaint.DrawBorder3D(e.Graphics, sizingRect.Left, sizingRect.Top, sizingRect.Width, sizingRect.Height, Border3DStyle.Bump, Border3DSide.All);
                }
                else {
                    p.DashStyle = SizingBorderStyle;
                    p.LineJoin = LineJoin.Round;
                    if(p.DashStyle == DashStyle.Custom)
                       p.DashPattern = new float[] { 8f, 1f, 1f, 1f };//length of each dash from right to left
                    e.Graphics.DrawRectangle(p, sizingRect);
                }
            }
        };
        //Bind the Location of the main form and the layer form together
        LocationChanged += (s, e) => {
            Point p = Location;
            p.Offset(-SizingBorderWidth, -SizingBorderWidth);
            layer.Location = p;
        };
        //Set the intial Location of layer
        Load += (s, e) =>{                
            Point p = Location;
            p.Offset(-SizingBorderWidth, -SizingBorderWidth);
            layer.Location = p;
        };            
    }
    //Set this to true to use 3D indicative/preview border
    public bool Use3DSizingBorder { get; set; }
    //Change the indicative/preview border thickness
    public int SizingBorderWidth { get; set; }
    //Change the indicative/preview border style
    public DashStyle SizingBorderStyle { get; set; }
    //Change the indicative/preview border color
    public Color SizingBorderColor { get; set; }
    //hold the current sizing Rectangle
    Rectangle sizingRect;
    bool startSizing;
    bool suppressSizing;
    //This is a Win32 RECT struct (don't use Rectangle)
    public struct RECT
    {
        public int left, top, right, bottom;
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x214&&!suppressSizing)//WM_SIZING = 0x214
        {                
            RECT rect = (RECT) m.GetLParam(typeof(RECT));
            int w = rect.right - rect.left;
            int h = rect.bottom - rect.top;
            sizingRect = new Rectangle() {X = SizingBorderWidth/2, Y = SizingBorderWidth/2, 
                                          Width = w, Height = h};
            layer.Left = rect.left-SizingBorderWidth;
            layer.Top = rect.top-SizingBorderWidth;
            layer.Width = w+2*SizingBorderWidth;
            layer.Height = h+2*SizingBorderWidth;
            if (!startSizing)
            {
                layer.Show();
                startSizing = true;
            }
            layer.Invalidate();
            //Keep the current position and size fixed
            rect.right = Right;
            rect.bottom = Bottom;
            rect.top = Top;
            rect.left = Left;
            //---------------------------
            Marshal.StructureToPtr(rect, m.LParam, true);
        }
        if (m.Msg == 0x232)//WM_EXITSIZEMOVE = 0x232
        {
            layer.Visible = false;
            BeginInvoke((Action)(() => {
                suppressSizing = true;
                Left = layer.Left + SizingBorderWidth;
                Top = layer.Top + SizingBorderWidth;
                Width = layer.Width - 2 * SizingBorderWidth;
                Height = layer.Height - SizingBorderWidth * 2;
                suppressSizing = false;
            }));
            startSizing = false;
        }
        base.WndProc(ref m);            
    }
    //Here is the layer I mentioned before.
    NoActivationForm layer = new NoActivationForm();
}    
public class NoActivationForm : Form {
    public NoActivationForm() {
        //The following initialization is very important
        TransparencyKey = BackColor;
        FormBorderStyle = FormBorderStyle.None;
        ShowInTaskbar = false;
        StartPosition = FormStartPosition.Manual;            
        //----------------------------------------------                          
    }
    protected override bool ShowWithoutActivation {
        get { return true; }
    }
}

一些屏幕截图:

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

编辑:(此编辑是由Hodaya ShalomOP 建议的(奇怪:)

我找到了解决左角问题的方法:

在 BeginInvoke 之前我保存变量并在调用中放入局部变量:

int _top = layer.Top + SizingBorderWidth;
int _left = layer.Left + SizingBorderWidth;
int _width = layer.Width - 2 * SizingBorderWidth;
int _height = layer.Height - SizingBorderWidth * 2;
BeginInvoke((Action)(() => {
    suppressSizing = true;
    Left = _left;
    Top = _top;
    Width =_width;
    Height =_height;
    suppressSizing = false;
}));
于 2013-10-06T10:55:38.123 回答