2

私の目標は、ユーザーがマウスでフォームを移動したときにフォームが部分的または完全に非表示になるのを防ぐことです。たとえば、デスクトップの解像度が 1024x768 の場合、フォームの場所のプロパティの座標の "x/y" 最小/最大値は次のようになります: 0, 1024 - form.width、0, 768 - form.height。

私はいくつかのネイティブ APi を使用してこれらすべてを達成し、すべて正常に動作しますが、フォームのリフレッシュ (ちらつき) が悪いことに気付くことがよくあります (form_move イベントですべてを管理しています)。メソッドが正常に動作しないか、フォーム移動イベントが変更されたすべてのピクセルで発生するわけではなく、おそらく複数のピクセルが発生するようです (以下のコードを参照して、私の意味を理解してください)
SuspendLayout

私のコードは次のようになります。

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);
}

既に述べたように、多くの場合、Location プロパティを復元すると、winForm がちらつきます。

任意の提案をいただければ幸いです。

4

1 に答える 1

2

Move移動が完了した後に発生します。フォームが移動した後、元に戻します。とにかくちらつきます。

代わりに、そもそも動かないようにしてください。

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);
}

明らかに、定数を実際の目的の境界に置き換えます。

于 2012-07-17T21:51:39.117 に答える