Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
480 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 Answer

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...