自定义虚线边框拖拽异常修复及Form边框绘制失效问题
Let's break down your problems and fix them step by step:
1. Fixing the Missing Form Border
The issue here is that your Form isn't part of its own Controls collection—so your loop over Me.Controls never checks for the Form itself. The line you marked was trying to draw a border using e.ClipRectangle, but that's tied to the current child control (ComboBox/Button) in the loop, which is why it didn't work for the Form.
Here's the corrected addBorders method that draws the Form's border separately:
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) addBorders(e) End Sub Public Sub addBorders(ByVal e As PaintEventArgs) ' Draw borders for child controls (TextBox, ComboBox, Button) For Each ctl As Control In Me.Controls Select Case True Case TypeOf ctl Is TextBox ctl.AutoSize = False ctl.Height = 19 Dim borderRectangle As Rectangle = New Rectangle(ctl.Location, ctl.Size) borderRectangle.Inflate(1, 1) ControlPaint.DrawBorder(e.Graphics, borderRectangle, ctl.ForeColor, ButtonBorderStyle.Dashed) Case TypeOf ctl Is ComboBox, TypeOf ctl Is Button Dim borderRectangle As Rectangle = New Rectangle(ctl.Location, ctl.Size) borderRectangle.Inflate(1, 1) ControlPaint.DrawBorder(e.Graphics, borderRectangle, ctl.ForeColor, ButtonBorderStyle.Dashed) End Select Next ' Draw the Form's border directly (outside the child control loop) ' Adjust the rectangle to fit within the Form's client area Dim formBorderRect As Rectangle = New Rectangle(0, 0, Me.Width - 1, Me.Height - 1) ControlPaint.DrawBorder(e.Graphics, formBorderRect, Me.ForeColor, ButtonBorderStyle.Dashed) End Sub
2. Fixing Border Distortion & Flickering on Screen Re-entry
Using Me.Reload() is overkill, and a timer causes constant flickering because it refreshes too often. Instead, we'll use your IsOnScreen function to trigger a refresh only when the Form fully re-enters the screen, plus enable double-buffering to eliminate flicker.
Step 1: Enable Double-Buffering
Add this code to your Form's Load event (or constructor) to smooth out drawing:
Private Sub YourForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load Me.DoubleBuffered = True ' Set additional styles to reduce flicker Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or _ ControlStyles.AllPaintingInWmPaint Or _ ControlStyles.UserPaint, True) Me.UpdateStyles() End Sub
Step 2: Track Screen State & Refresh Only When Needed
Add a private variable to track if the Form was previously off-screen, then use the Move event to check for re-entry:
Private _wasOffScreen As Boolean = False Private Sub YourForm_Move(sender As Object, e As EventArgs) Handles MyBase.Move Dim isCurrentlyOnScreen As Boolean = IsOnScreen(Me) ' Only refresh if we just transitioned from off-screen to fully on-screen If _wasOffScreen AndAlso isCurrentlyOnScreen Then ' Invalidate marks the Form for redraw (much smoother than Reload) Me.Invalidate() End If ' Update the state for the next check _wasOffScreen = Not isCurrentlyOnScreen End Sub ' Keep your existing IsOnScreen function Public Function IsOnScreen(ByVal form As Form) As Boolean Dim screens() As Screen = Screen.AllScreens For Each scrn As Screen In screens Dim formRectangle As Rectangle = New Rectangle(form.Left, form.Top, form.Width, form.Height) If scrn.WorkingArea.Contains(formRectangle) Then Return True End If Next Return False End Function
Why This Works:
- Double-buffering renders all drawing to an off-screen buffer first, then displays it at once—no more flicker.
- The
Moveevent checks the Form's position only when it's moved, so we don't waste resources with constant refreshes. Invalidate()tells the system to redraw the Form, which is far more efficient than reloading the entire form.
内容的提问来源于stack exchange,提问作者JoeBobJr

