Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
451 views
in Technique[技术] by (71.8m points)

c# - Form move inside client desktop area

My goal is to prevent partial or total hidden of my form when user move it through mouse. For instance, if my desktop resolution is 1024x768 the following will be "x/y" minimum/maximum value of coordinates for form location properties: 0, 1024 - form.width, 0, 768 - form.height.

I use some native APi to accomplish all this and all works fine, but often I notice a bad refresh (flickering) of my form (I'm managing all on form_move event).
It seems like SuspendLayout method doesn't works fine, or else the form move event doesn't fire every pixel changed, but maybe more than one (see the below code to realize what I mean).

My code looks like this:

private void Form1_Move(object sender, EventArgs e)
{
    this.SuspendLayout();

    // Desktop Resolution (API utility)
    int x = Desktop.GetXResolution();
    int y = Desktop.GetYResolution();

    // Taskbar Info (API utility)
    Taskbar tb = new Taskbar();
    int minX = 0;
    int maxX = x - this.Width;
    int minY = 0;
    int maxY = y - this.Height;
    if (!tb.AutoHide)
    {
        if (tb.Position != TaskbarPosition.Unknown && !tb.Size.IsEmpty)
        {
            if (tb.Position == TaskbarPosition.Top) minY += tb.Size.Height;
            switch (tb.Position)
            {
                case TaskbarPosition.Top: minY = tb.Size.Height; break;
                case TaskbarPosition.Bottom: maxY -= tb.Size.Height; break;
                case TaskbarPosition.Left: minX = tb.Size.Width; break;
                case TaskbarPosition.Right: maxX -= tb.Size.Width; break;
            }
        }
    }

    // Restore X Position
    if (this.Location.X < minX) this.Location = new Point(minX, this.Location.Y);
    if (this.Location.X > maxX) this.Location = new Point(maxX, this.Location.Y);


    // Restore Y Poistion
    if (this.Location.Y < minY) this.Location = new Point(this.Location.X, minY);
    if (this.Location.Y > maxY) this.Location = new Point(this.Location.X, maxY);

    this.ResumeLayout(false);
}

As I already said, often when I restore Location property my winForm take a flickering.

Any suggestion will be appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Move occurs after a move has completed. The form has moved and then you move it back. It's going to flicker anyway.

Instead, prevent it from moving in the first place:

private const int WM_MOVING = 0x216;

private void WriteTheRect(IntPtr dest, Rectangle rect) {
    System.Runtime.InteropServices.Marshal.WriteInt32(dest, 0, rect.Left);
    System.Runtime.InteropServices.Marshal.WriteInt32(dest, 4, rect.Top);
    System.Runtime.InteropServices.Marshal.WriteInt32(dest, 8, rect.Right);
    System.Runtime.InteropServices.Marshal.WriteInt32(dest, 12, rect.Bottom);
}

protected override void WndProc(ref Message m) {
    if (m.Msg == WM_MOVING)
    {
        // RECT structure pointed to by lParam: left, top, right, bottom

        Rectangle r = Rectangle.FromLTRB(System.Runtime.InteropServices.Marshal.ReadInt32(m.LParam, 0),
                                         System.Runtime.InteropServices.Marshal.ReadInt32(m.LParam, 4),
                                         System.Runtime.InteropServices.Marshal.ReadInt32(m.LParam, 8),
                                         System.Runtime.InteropServices.Marshal.ReadInt32(m.LParam, 12)
                                         );

        Rectangle allowed = Rectangle.FromLTRB(0, 0, 1600, 900);

        if (r.Left <= allowed.Left || r.Top <= allowed.Top || r.Right >= allowed.Right || r.Bottom >= allowed.Bottom)
        {
            int offset_x = r.Left < allowed.Left ? (allowed.Left - r.Left) : (r.Right > allowed.Right ? (allowed.Right - r.Right) : (0));
            int offset_y = r.Top < allowed.Top ? (allowed.Top - r.Top) : (r.Bottom > allowed.Bottom ? (allowed.Bottom - r.Bottom) : (0));

            r.Offset(offset_x, offset_y);

            WriteTheRect(m.LParam, r);
        }
    }
    base.WndProc(ref m);
}

Obviously, replace the constants with your actual desired bounds.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...