Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WinForms deep nested controls resize kernel bug - Splitter Panels not scaling controls properly

(initial guess at nested proved to be incorrect. Problem seems to be that SplitContainer panels do not scale their hosted controls properly.)


I have some forms that have tab controls that fail to resize properly at load time. https://support.microsoft.com/en-us/kb/953934 describes such a kernel bug in 2008. Hard to believe it hasn't been fixed. I think it went away for a while but I'm beginning to see problems again.

The controls are nested pretty deep. Midi Parent, child form, tab control, splitter control with two panels and controls. For the top down the first control with the problem is the tab control. It resizes when the form is resized after loading but the anchors are incorrect and part of the control is clipped.

The problem seems to be specific to 100% desktop font size - desktops with 100+ size work OK. I develop at 125% using VS 2013 v5 - the issue was present on v4 as well.

Anyone know of a work around short of the custom control as outlined in the KB article?

Something else going on I've missed?


Looking at it more closely the SplitContainer is the control not resizing/honoring the anchors.


I tried running this code after the tab was shown and it didn't work - looks about the same as using anchors. It seems that the TabControl is reporting an incorrect ClientSize

    SplitContainer1.Width = TabControl1.ClientSize.Width - 10
    SplitContainer1.Height = TabControl1.ClientSize.Height - TabControl1.ItemSize.Height - 10

Here is a complete form that shows the problem. On a 125% desktop it shows as in the IDE on a 100% desktop the controls on the tab are not positioned properly.

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class frmChild
Inherits System.Windows.Forms.Form

'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    Try
        If disposing AndAlso components IsNot Nothing Then
            components.Dispose()
        End If
    Finally
        MyBase.Dispose(disposing)
    End Try
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.  
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
    Me.TabControl1 = New System.Windows.Forms.TabControl()
    Me.TabPage1 = New System.Windows.Forms.TabPage()
    Me.SplitContainer1 = New System.Windows.Forms.SplitContainer()
    Me.Button1 = New System.Windows.Forms.Button()
    Me.TabPage2 = New System.Windows.Forms.TabPage()
    Me.TextBox1 = New System.Windows.Forms.TextBox()
    Me.Button2 = New System.Windows.Forms.Button()
    Me.TabControl1.SuspendLayout()
    Me.TabPage1.SuspendLayout()
    CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).BeginInit()
    Me.SplitContainer1.Panel1.SuspendLayout()
    Me.SplitContainer1.Panel2.SuspendLayout()
    Me.SplitContainer1.SuspendLayout()
    Me.SuspendLayout()
    '
    'TabControl1
    '
    Me.TabControl1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
        Or System.Windows.Forms.AnchorStyles.Left) _
        Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
    Me.TabControl1.Controls.Add(Me.TabPage1)
    Me.TabControl1.Controls.Add(Me.TabPage2)
    Me.TabControl1.Location = New System.Drawing.Point(82, 2)
    Me.TabControl1.Name = "TabControl1"
    Me.TabControl1.SelectedIndex = 0
    Me.TabControl1.Size = New System.Drawing.Size(466, 436)
    Me.TabControl1.TabIndex = 2
    '
    'TabPage1
    '
    Me.TabPage1.Controls.Add(Me.SplitContainer1)
    Me.TabPage1.Location = New System.Drawing.Point(4, 25)
    Me.TabPage1.Name = "TabPage1"
    Me.TabPage1.Padding = New System.Windows.Forms.Padding(3)
    Me.TabPage1.Size = New System.Drawing.Size(458, 407)
    Me.TabPage1.TabIndex = 0
    Me.TabPage1.Text = "TabPage1"
    Me.TabPage1.UseVisualStyleBackColor = True
    '
    'SplitContainer1
    '
    Me.SplitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
    Me.SplitContainer1.Dock = System.Windows.Forms.DockStyle.Fill
    Me.SplitContainer1.Location = New System.Drawing.Point(3, 3)
    Me.SplitContainer1.Name = "SplitContainer1"
    Me.SplitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal
    '
    'SplitContainer1.Panel1
    '
    Me.SplitContainer1.Panel1.Controls.Add(Me.Button2)
    Me.SplitContainer1.Panel1.Controls.Add(Me.TextBox1)
    '
    'SplitContainer1.Panel2
    '
    Me.SplitContainer1.Panel2.Controls.Add(Me.Button1)
    Me.SplitContainer1.Size = New System.Drawing.Size(452, 401)
    Me.SplitContainer1.SplitterDistance = 223
    Me.SplitContainer1.TabIndex = 0
    '
    'Button1
    '
    Me.Button1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
    Me.Button1.Location = New System.Drawing.Point(371, 146)
    Me.Button1.Name = "Button1"
    Me.Button1.Size = New System.Drawing.Size(75, 23)
    Me.Button1.TabIndex = 0
    Me.Button1.Text = "Button1"
    Me.Button1.UseVisualStyleBackColor = True
    '
    'TabPage2
    '
    Me.TabPage2.Location = New System.Drawing.Point(4, 25)
    Me.TabPage2.Name = "TabPage2"
    Me.TabPage2.Padding = New System.Windows.Forms.Padding(3)
    Me.TabPage2.Size = New System.Drawing.Size(854, 450)
    Me.TabPage2.TabIndex = 1
    Me.TabPage2.Text = "TabPage2"
    Me.TabPage2.UseVisualStyleBackColor = True
    '
    'TextBox1
    '
    Me.TextBox1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
        Or System.Windows.Forms.AnchorStyles.Left) _
        Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
    Me.TextBox1.BackColor = System.Drawing.SystemColors.Info
    Me.TextBox1.Location = New System.Drawing.Point(17, 13)
    Me.TextBox1.Multiline = True
    Me.TextBox1.Name = "TextBox1"
    Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical
    Me.TextBox1.Size = New System.Drawing.Size(344, 177)
    Me.TextBox1.TabIndex = 0
    '
    'Button2
    '
    Me.Button2.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
    Me.Button2.Location = New System.Drawing.Point(371, 195)
    Me.Button2.Name = "Button2"
    Me.Button2.Size = New System.Drawing.Size(75, 23)
    Me.Button2.TabIndex = 1
    Me.Button2.Text = "Button2"
    Me.Button2.UseVisualStyleBackColor = True
    '
    'frmChild
    '
    Me.AutoScaleDimensions = New System.Drawing.SizeF(120.0!, 120.0!)
    Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
    Me.ClientSize = New System.Drawing.Size(548, 439)
    Me.Controls.Add(Me.TabControl1)
    Me.Name = "frmChild"
    Me.Text = "frmChild"
    Me.TabControl1.ResumeLayout(False)
    Me.TabPage1.ResumeLayout(False)
    Me.SplitContainer1.Panel1.ResumeLayout(False)
    Me.SplitContainer1.Panel1.PerformLayout()
    Me.SplitContainer1.Panel2.ResumeLayout(False)
    CType(Me.SplitContainer1, System.ComponentModel.ISupportInitialize).EndInit()
    Me.SplitContainer1.ResumeLayout(False)
    Me.ResumeLayout(False)

End Sub
Friend WithEvents TabControl1 As System.Windows.Forms.TabControl
Friend WithEvents TabPage1 As System.Windows.Forms.TabPage
Friend WithEvents SplitContainer1 As System.Windows.Forms.SplitContainer
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents TabPage2 As System.Windows.Forms.TabPage
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
End Class
like image 288
rheitzman Avatar asked Oct 19 '22 06:10

rheitzman


1 Answers

If the SplitPanel isn't anchoring its contents correctly, you could try putting the contents into another container that is less buggy.

Try putting a TableLayoutPanel inside the SplitPanel. Set the TableLayoutPanel.Dock property to Fill, and then .Anchor your controls inside that. (Don't use .Dock inside a TableLayoutPanel, it's a bit flaky).

The controls inside the TableLayoutPanel will have new properties called .RowSpan and .ColumnSpan which allow the controls to span multiple cells.

There is a little arrow in the top right of the TableLayoutPanel that will allow you to edit the rows and columns. I find the best is to make as many as possible fixed width/height and then use percentage for the rest. I don't use Autosize but you could try that.

like image 90
SSS Avatar answered Dec 28 '22 08:12

SSS