2011-05-17 61 views
2

我有一個自定義UserControl,它有一個StatusStrip。所以,當用戶拖動這個狀態條的角落時,我調整了這個控件的大小。但是,調整大小不是很好:在調整大小期間可以在父控件上觀察到臨時白色區域,有時如果調整大小太快,則用戶「失去」控件(停止調整大小)。優化控件大小調整

enter image description here

Option Infer On 

Public Class FloattingGrid 
    Inherits System.Windows.Forms.UserControl 

    Dim mouseDownLocation As Nullable(Of Point) 

    Private Sub StatusStrip1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles StatusStrip1.MouseMove 

    If mouseDownLocation.HasValue Then 
     Dim newPosition = Cursor.Position 
     Dim dx = newPosition.X - mouseDownLocation.Value.X 
     Dim dy = newPosition.Y - mouseDownLocation.Value.Y 
     'Dim oldRect = New Rectangle(Me.Location, Me.Size)' 
     Me.Size = New Size(Me.Width + dx, Me.Height + dy) 
     mouseDownLocation = newPosition 

     If Me.Parent IsNot Nothing Then 
     'Me.Parent.Invalidate(oldRect) ' 
     Me.Parent.Refresh() 
     End If 
    Else 

     If e.X > Me.Width - 20 Then 
     If Cursor <> Cursors.SizeNWSE Then Cursor = Cursors.SizeNWSE 
     Else 
     If Cursor = Cursors.SizeNWSE Then Cursor = Cursors.Default 
     End If 
    End If 
    End Sub 

    Private Sub StatusStrip1_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StatusStrip1.MouseLeave 
    Cursor = Cursors.Default 
    mouseDownLocation = Nothing 
    'Me.ResumeLayout() ' 
    End Sub 

    Private Sub StatusStrip1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles StatusStrip1.MouseDown 
    If Cursor = Cursors.SizeNWSE Then 
     'Me.SuspendLayout() ' 
     mouseDownLocation = Cursor.Position 
    End If 
    End Sub 

    Private Sub StatusStrip1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles StatusStrip1.MouseUp 
    mouseDownLocation = Nothing 
    'Me.ResumeLayout()' 
    End Sub 

    ' Private Sub FloattingGrid_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove '  
    ' End Sub ' 

    Private Sub FloattingGrid_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
    Me.ResizeRedraw = True 
    End Sub 
End Class 

我認爲這種行爲可以通過父母的的Invalidate引起的。有沒有辦法只是BeginInvalidate,而不是等到父節點全部失效?

回答

1

BeginInvoke與繪畫無關,與執行延遲無關。這完全是關於跨線程訪問,你在這裏沒有做的。這不是正確的解決方案。

而且撥打Invalidate沒什麼問題。它只是將該區域標記爲需要繪畫。它實際上並不會導致該區域多次重新繪製。如果您無效的區域已經失效,這是無效的,所以它不負責任何放慢速度的任務。如果您想要立即重新粉刷,則需要改爲調用類似Refresh的東西。

您可以做的一件事是防止父控件嘗試調整其自身大小並更改其子控件的佈局以適應StatusStrip的新位置。爲此,請在開始調整大小時調用SuspendLayout method,完成時調用ResumeLayout method

當然,這並不能保證解決您的問題。你仍然很可能會看到一個滯後區域,白色或黑色區域出現在尚未被繪製的區域。這發生在其他應用程序中,甚至是在調整窗口大小時。唯一的解決方法是雙緩衝,將所有內容繪製到臨時背景緩衝區中,然後將整個完整的圖像繪製到屏幕上。

+0

有效地,在調用parent.Refresh()而不是parent.Invalidate(oldRect)之後,白色區域消失。但是,當移動速度更快時,我總是失去控制。我不調整StatusStrip的大小,我直接調整UserControl的大小(statusStrip停靠在底部) – serhio 2011-05-17 10:24:04

+0

@serhio:是的,調用'Refresh'會立即*重繪*。這就是白色區域消失的原因。它們只是白色的,因爲Windows還沒有繪製任何東西。這樣做的副作用是計算機開始滯後,因爲它無法一下子跟上所有這一切。這就是爲什麼它通常不會畫這些區域,爲什麼當你強迫它,當你開始快速移動時,它似乎失去了控制。這是一個折中,你必須選擇哪一個更容易被你接受,或者使用雙緩衝等替代策略(這只是一個竅門,而不是真正的修復)。 – 2011-05-17 10:26:20

+0

一個原因可能是我僅在StatusStrip_MouseMove上跟隨移動,並且如果調整大小比鼠標移動慢,那麼鼠標離開StatusStip區域並且不再調用任何移動......另一件事是Refresh()似乎重畫所有的父母,而不僅僅是控制古代地區 - 它也需要時間... – serhio 2011-05-17 10:31:52