动态 TableLayoutPanel 控件保持边框宽度 [英] Dynamic TableLayoutPanel Controls Keep Border Width

查看:40
本文介绍了动态 TableLayoutPanel 控件保持边框宽度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

默认情况下,我有一个包含 1 列和 3 行的 TableLayoutPanel.顶行和底行有包含按钮的子 TableLayoutPanels,而中间行有一个 TextBox.顶部和底部行中的按钮根据 My.Settings 中的值在加载时动态显示,默认情况下有五个按钮(因此有五个列).

我动态设置按钮文本以及是否要删除它们的方式是这样的(再重复四次):

Dim visibleButtonCount As Integer = {My.Settings.ValueVisible1, My.Settings.ValueVisible2, My.Settings.ValueVisible3, My.Settings.ValueVisible4, My.Settings.ValueVisible5}.Where(Function(setting) setting).数数()Dim buttonWidth As Double = 100/visibleButtonCountButtonValueDown1.Text = $"- {My.Settings.Value1.ToString("N3")}"ButtonValueUp1.Text = $"+ {My.Settings.Value1.ToString("N3")}"如果(不是 My.Settings.ValueVisible1)那么ButtonValueDown1.Parent.Controls.Remove(ButtonValueDown1)ButtonValueUp1.Parent.Controls.Remove(ButtonValueUp1)使用 TableLayoutPanelDown.ColumnStyles.Item(0).SizeType = SizeType.Absolute.宽度 = 0结束于使用 TableLayoutPanelUp.ColumnStyles.Item(0).SizeType = SizeType.Absolute.宽度 = 0结束于别的TableLayoutPanelDown.ColumnStyles.Item(0).Width = buttonWidthTableLayoutPanelUp.ColumnStyles.Item(0).Width = buttonWidth万一

我遇到的问题是,当所有 5 个按钮都可见时,顶行和底行中最右侧的 Button 与中间行中的 TextBox 齐平但是只要有一个或更多按钮被移除,最右边的按钮不再齐平(见图).

可能是什么原因造成的?值得一提的是,所有控件的边距/填充为 0.

解决方案

当未定义大小的控件添加到 TableLayoutPanel.Controls 集合,一种有效的方法是在设计时设置列的

上面浅灰色的TableLayoutPanel在示例代码中代表tableLayoutPanelUp控件.

由于在运行时添加和/或删除了子控件(此处为按钮),因此内部 TableLayoutPanel 需要均匀调整它们的大小以填充外部 TableLayoutPanel 容器大小,以保留布局.

► TableLayoutPanel 可以按预期执行此布局,前提是我们指定将包含一个控件的列和行(单元格),当控件添加到其 Controls 集合时.
如果我们不这样做,当 TableLayoutPanel 需要调整它们的大小以填充可用空间时,它就无法正确确定其子控件的新大小.

<小时>

在示例代码中,将子 Button 添加到 List(Of Button) 集合中(为方便起见),然后将 Button 添加到 TableLayoutPanel(名为 tableLayoutPanelUp)> 如问题中所述).

■ 子控件添加到

在示例代码中,添加和删除按钮被命名为btnAddControlbtnRemoveControl,ComboBox 被命名为 cboControlsIndexes

私有 tlpButtons 作为 List(Of Button) = NothingProtected Overrides Sub OnLoad(e As EventArgs)MyBase.OnLoad(e)tlpButtons = New List(Of Button)() From {New Button() with {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button1"},New Button() with {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button2"},New Button() with {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button3"},New Button() with {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button4"},New Button() with {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button5"}}cboControlsIndexes.DisplayMember = "文本"cboControlsIndexes.DataSource = tlpButtonstableLayoutPanelUp.SuspendLayout()对于 i As Integer = 0 To tlpButtons.Count - 1tableLayoutPanelUp.Controls.Add(tlpButtons(i))tableLayoutPanelUp.SetRow(tlpButtons(i), 0)tableLayoutPanelUp.SetColumn(tlpButtons(i), i)下一个tableLayoutPanelUp.ResumeLayout(True)tableLayoutPanelUp.PerformLayout()结束子Private Sub btnRemoveControl_Click(sender As Object, e As EventArgs) 处理 btnRemoveControl.ClickDim removeAtIndex As Integer = cboControlsIndexes.SelectedIndextableLayoutPanelUp.Controls.Remove(tlpButtons(removeAtIndex))tableLayoutPanelUp.ColumnStyles(removeAtIndex).Width = 0结束子Private Sub btnAddControl_Click(sender As Object, e As EventArgs) 处理 btnAddControl.ClickDim addAtIndex As Integer = cboControlsIndexes.SelectedIndextableLayoutPanelUp.Controls.Add(tlpButtons(addAtIndex))tableLayoutPanelUp.SetRow(tlpButtons(addAtIndex), 0)tableLayoutPanelUp.SetColumn(tlpButtons(addAtIndex), addAtIndex)tableLayoutPanelUp.ColumnStyles(addAtIndex).Width = 100/tableLayoutPanelUp.ColumnCount结束子

By default I have a TableLayoutPanel with 1 column and three rows. The top and bottom rows have child TableLayoutPanels that contains buttons whereas the middle row has a TextBox. The buttons in the top and bottom rows are dynamically shown upon load based on values in My.Settings and by default there are five buttons (and therefore five columns).

The way that I'm dynamically setting the button's Text as well as if they're to be removed is as such (repeated four more times):

Dim visibleButtonCount As Integer = {My.Settings.ValueVisible1, My.Settings.ValueVisible2, My.Settings.ValueVisible3, My.Settings.ValueVisible4, My.Settings.ValueVisible5}.Where(Function(setting) setting).Count()
Dim buttonWidth As Double = 100 / visibleButtonCount

ButtonValueDown1.Text = $"- {My.Settings.Value1.ToString("N3")}"
ButtonValueUp1.Text = $"+ {My.Settings.Value1.ToString("N3")}"
If (Not My.Settings.ValueVisible1) Then
    ButtonValueDown1.Parent.Controls.Remove(ButtonValueDown1)
    ButtonValueUp1.Parent.Controls.Remove(ButtonValueUp1)

    With TableLayoutPanelDown.ColumnStyles.Item(0)
        .SizeType = SizeType.Absolute
        .Width = 0
    End With
    With TableLayoutPanelUp.ColumnStyles.Item(0)
        .SizeType = SizeType.Absolute
        .Width = 0
    End With
Else
    TableLayoutPanelDown.ColumnStyles.Item(0).Width = buttonWidth
    TableLayoutPanelUp.ColumnStyles.Item(0).Width = buttonWidth
End If

The issue that I'm running into is that whenever all 5 buttons are visible, the right-most Buttons in the top and bottom rows is flush with the TextBox in the middle row but whenever one or more of the Buttons are removed the right-most Buttons are no longer flush (see image).

What could be causing this? It is worth mentioning that all controls have a margin/padding of 0.

解决方案

To allow a TableLayoutPanel to resize its Columns dynamically at run-time, when Controls of an undefined size are added to the TableLayoutPanel.Controls collection, one effective method is to set, at design-time, the Columns' TableLayoutStyle.SizeType to SizeType.Percent.
When adding Columns using the designer, we can set the Percent value of each new Column to 100%. The TableLayoutPanel will automatically determine the correct percentage value, based on its current Size and the number of Columns added.

In the current scenario, we have an outer TableLayoutPanel with one Column that hosts other TableLayoutPanels in some of its Cells.
→ The inner TableLayoutPanels are set to Dock = Fill, filling the Cell they occupy.
→ The inner TLPs will host a variable number of Controls, so they need to dynamically adjust the size of the child Controls to fill the width of the outer TLP container.

Sample layout at design-time:

The upper, light gray, TableLayoutPanel in represent the tableLayoutPanelUp control in the sample code.

Since the child Controls (Buttons, here) are added and/or removed at run-time, the inner TableLayoutPanel needs to resize them evenly to fill the outer TableLayoutPanel container size, to preserve the layout.

► The TableLayoutPanel can perform this layout as expected, provided that we specify the Column and Row (the Cell) that will contain a Control when one is added to its Controls collection.
If we don't, the TableLayoutPanel cannot correctly determine the new size of its child Controls when it needs to resize them to fill the available space.


In the sample code, the child Buttons are added to a List(Of Button) collection (for convenience), then the Buttons are added to a TableLayoutPanel (named tableLayoutPanelUp as in the question).

■ The child Controls are added in a SuspendLayout() / PerformLayout() section, to suspend the layout until all Controls are added and then perform the layout when all pieces are in place.

■ for each new Control, its Cell position is set explicitly, using the TableLayoutPanel's SetRow() and SetColumn() methods.

■ To remove a Control, the Control instance is specified using the Controls.Remove(Control) method (the Control is not disposed of, so it's still inside its container List) and the corresponding Column's ColumnStyles.Width (representing a Percent value) is set to 0.

■ When a child Control is added, again the SetRow() and SetColumn() are called to define the Cell that will contain the new Control. In this case, the Size (percentage) of the corresponding Column is set to 100 / tableLayoutPanelUp.ColumnCount. Since the TableLayoutPanel is docked, this will force it to evaluate the new values and generate a new layout, recalculating all values to fit the docking requirements.

A visual sample of the result:

In the sample code, the Add and Remove Buttons are named btnAddControl and btnRemoveControl, the ComboBox is named cboControlsIndexes

Private tlpButtons As List(Of Button) = Nothing

Protected Overrides Sub OnLoad(e As EventArgs)
    MyBase.OnLoad(e)

    tlpButtons = New List(Of Button)() From {
        New Button() With {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button1"},
        New Button() With {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button2"},
        New Button() With {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button3"},
        New Button() With {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button4"},
        New Button() With {.Dock = DockStyle.Fill, .FlatStyle = FlatStyle.Flat, .Text = "Button5"}
    }

    cboControlsIndexes.DisplayMember = "Text"
    cboControlsIndexes.DataSource = tlpButtons

    tableLayoutPanelUp.SuspendLayout()

    For i As Integer = 0 To tlpButtons.Count - 1
        tableLayoutPanelUp.Controls.Add(tlpButtons(i))
        tableLayoutPanelUp.SetRow(tlpButtons(i), 0)
        tableLayoutPanelUp.SetColumn(tlpButtons(i), i)
    Next
    tableLayoutPanelUp.ResumeLayout(True)
    tableLayoutPanelUp.PerformLayout()
End Sub

Private Sub btnRemoveControl_Click(sender As Object, e As EventArgs) Handles btnRemoveControl.Click
    Dim removeAtIndex As Integer = cboControlsIndexes.SelectedIndex

    tableLayoutPanelUp.Controls.Remove(tlpButtons(removeAtIndex))
    tableLayoutPanelUp.ColumnStyles(removeAtIndex).Width = 0
End Sub

Private Sub btnAddControl_Click(sender As Object, e As EventArgs) Handles btnAddControl.Click
    Dim addAtIndex As Integer = cboControlsIndexes.SelectedIndex

    tableLayoutPanelUp.Controls.Add(tlpButtons(addAtIndex))
    tableLayoutPanelUp.SetRow(tlpButtons(addAtIndex), 0)
    tableLayoutPanelUp.SetColumn(tlpButtons(addAtIndex), addAtIndex)
    tableLayoutPanelUp.ColumnStyles(addAtIndex).Width = 100 / tableLayoutPanelUp.ColumnCount
End Sub

这篇关于动态 TableLayoutPanel 控件保持边框宽度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆