2012-07-17 35 views
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採取閃爍。

任何建議將不勝感激。

+0

您可以使用'System.Windows.Forms.Screen'來獲得顯示分辨率,例如'int xResolution = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;' – teamalpha5441 2012-07-17 21:39:13

+0

請注意,這將包含所有多監視器系統上的各種問題。 – MNGwinn 2012-07-19 19:11:21

回答

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

顯然,與實際所需的界限更換常數。

+0

這是太棒了,這正是我正在尋找的..!謝謝! – bit 2012-07-17 23:05:42