2011-05-17 108 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