0

Some time ago I wrote a UsserControl. This control contains TP_PACKER as TableLayoutPanel with Dock = Fill and contains two rows. 1 row is absolute with variable value. It contains RichTextBox control. I can change size of RichTextBox and I resize 1 row also. 2 row is percentage = 100%. It contain a ListView.

.Add(New RowStyle(SizeType.Absolute, TextBoxHeight + MyBase.BorderStyleSize + BorderStyleSize))
.Add(New RowStyle(SizeType.Percent, 100))

On loading all is OK but on form resize my control was gone to top. Visually its look like ListView is placed in 1-st row of TP_PACKER, not 2-nd.

At start I decided to try resize control programmatically. I wrote a code:

        Private Sub ComboBoxExtended_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            UpdateSize()
        End Sub
        Protected Overrides Sub UpdateSize()
            If _ControlInit AndAlso Not _SuspendControlResize Then
                'If Not _TpSizeSet AndAlso Not _SuspendControlResize AndAlso _ControlInit AndAlso Not TP_PACKER Is Nothing Then
                '    _SuspendControlResize = True
                '    TP_PACKER.RowStyles(0).Height = TextBoxHeight + MyBase.BorderStyleSize
                '    _TpSizeSet = True
                'End If
                _SuspendControlResize = True

                Dim h%
                Invalidate()
                SuspendLayout()

                If Not TP_PACKER Is Nothing Then
                    With TP_PACKER
                        .Invalidate()
                        If Not .RowStyles(0).Height = TextBoxHeight + MyBase.BorderStyleSize Then
                            .RowStyles(0).Height = TextBoxHeight + MyBase.BorderStyleSize
                            .Refresh()
                        End If
                    End With
                End If

                If ListDropDownStyle = ListMode.Simple AndAlso Not ResultsList Is Nothing Then
                    h = ResultListsHeight(ResultsList, True)
                    ResultsList.Invalidate()
                    TP_PACKER.Invalidate()
                    ResultsList.Size = New Size(ResultsList.Width, h)
                    TP_PACKER.Refresh()
                    ResultsList.Refresh()
                    h += (TextBoxHeight + MyBase.BorderStyleSize + BorderStyleSize * 3)
                    h += 1
                Else
                    h = TextBoxHeight + MyBase.BorderStyleSize + BorderStyleSize
                End If

                'If Not Me Is Nothing AndAlso Not Parent Is Nothing Then
                '    Dim p = Parent.Height - Parent.Margin.Top - Parent.Margin.Bottom
                '    If h > p Then h = p
                'End If

                Try
                    Height = h
                    If _ControlInit Then Width = MinWidth
                Catch ex As Exception
                Finally
                    UpdateBounds()
                    ResumeLayout(True)
                    _SuspendControlResize = False
                End Try
            End If
        End Sub
        Private Function ResultListsHeight(ByRef l As ListView, ByVal IsMainList As Boolean) As Integer
            Dim h% = 1
            If Not l Is Nothing Then h = Math.Max(l.Items.Count, 1)
            h = Math.Min(ListMaxDropDownItems, h)
            If IsMainList AndAlso ListDropDownStyle = ListMode.Simple Then
                If Dock = DockStyle.Fill Then
                    If Not TP_PACKER Is Nothing Then
                        With TP_PACKER                            
                            Dim AdditHeight% = TextBoxHeight + MyBase.BorderStyleSize +
                                .Margin.Top + .Margin.Bottom +
                                .Padding.Top + .Padding.Bottom + BorderStyleSize * 2 '(BorderStyleSize * 3)
                            h = .Height - AdditHeight + ListColumnsHeigh() '- BorderStyleSize - 3
                            If Not Parent Is Nothing Then h -= Parent.Padding.Bottom
                        End With
                    End If
                Else
                    h = (ListMaxDropDownItems * ListRowHeigh + ListColumnsHeigh())
                End If
            Else
                h *= ListRowHeigh
                h = h + ListColumnsHeigh() + BorderStyleSize
            End If
            Return h
        End Function

ListView Created with parameters:

            ResultsList= New ListView With {
                .View = View.Details,
                .BorderStyle = BorderStyle.FixedSingle,
                .MultiSelect = False,
                .FullRowSelect = True,
                .HideSelection = False,
                .HeaderStyle = IIf(ListColumnsHeadersVisible, ColumnHeaderStyle.Nonclickable, ColumnHeaderStyle.None),
                .GridLines = ListGridVisible,
                .Dock = DockStyle.Fill,
                .Margin = New Padding(0)
            }

This function resize control to fit in parent. And it helps partially. In where I placed control into GroupBox my control is working and resizing correctly. But on other form where I place control into TableLayoutPanel it is not resize correctly. For example:

Correctly:

Before Resize

After Resize

NOT Correctly:

Before Resize

After Resize

I do not understand why is it happens. I tried to change Anchor to Left+Top and Left+Top+Right+Bottom. Nothing changed.

UPDATE:

After debug each element in my control and review these properties, control's bounds was dropped after resize, I noticed. So:

1-st: ListView should be docked as DockStyle.Top (not DockStyle.Fill);

2-nd: I set ListView bounds again on updating by ResultsList.SetBounds(1, TextBoxHeight + MyBase.BorderStyleSize + BorderStyleSize, ResultsList.Size.Width, ResultsList.Size.Height)

Now all is OK.

Andy
  • 21
  • 8
  • There's too much code here that tries to do *something*, but it's not clear to what end. Your TablaLayoutPanel needs a first Row set to a fixed value in the designer. The second Row set to 100%. When you add controls to these Cells, set `Dock = Fill`. Anchor the TLP to its Container. At run-time, you can change the first Row's Height, e.g., in case the Font changes, to something like: `TP_PACKER.RowStyles(0).Height = richTextBox1.Font.Height * 3`. The other Row will auto-scale. When the TLP's Container is resized, all is resized automatically. Set a max/min size if needed. – Jimi Mar 13 '21 at 18:20
  • BTW, if you add RowStyles/ColumnStyles at run-time, clear the existing before adding new ones, otherwise you make a mess. – Jimi Mar 13 '21 at 18:21
  • Thank you, Jimi. But I did all of you write already. Each control has `Dock = Fill` and I added TLP RowStyles & ColumnStyles once at Control Initializing (not in designer, because it control Inherits other control). `TP_PACKER.RowStyles(0).Height` will be changed only if I change `RichTextBox` Height and not in runtime – Andy Mar 13 '21 at 18:37
  • This code calculating control dimensions for set control size because without this code my control looks like https://i.stack.imgur.com/JVMn2.png – Andy Mar 13 '21 at 18:45
  • It's the other way around. If you want to change the size of a RichTextBox (multi-line or not), just change the Height of the TLP's Row where the RTB is **Docked**. Remove any code that tries to override the standard behavior of a TLP. Test in a clean form. – Jimi Mar 13 '21 at 18:45
  • The ListView also needs to be Docked inside the TLP Cell. I don't see to what collection you're adding these child Controls. Test in the Designer what I just described. Remember to Anchor the TLP. Possibly, try with a standard TLP. If yours doesn't work, then it's doing something that it shouldn't. – Jimi Mar 13 '21 at 18:50
  • I understand and I tried it. The problem (as I understand) not in [0] TLP Row but in [1] TLP Row. RowHeight of [0] row is should calculating because Base Control has another stiles witch cutting text space. About RTB. RTB is a Base's class control and it placed (with Dock = Fill) in Base Control TLP. On initializing this control I removing BaseTLP from Me.Controls and place it in 1-st row TP_PACKER. And then I add TP_PACKER in Control.Controls `Me.Controls.Add(TP_PACKER)` EACH control I added has Dock = Fill – Andy Mar 13 '21 at 18:55
  • If you need to resize the RichTextBox to show more than one line of text (with one line, the size is calculated automatically, you don't need to do anything, since the TLP Rows will auto-size), you calculated it using the info provided by the FontFamily object of the RTB Font. See here: [Properly draw text using Graphics Path](https://stackoverflow.com/a/53074638/7444103). – Jimi Mar 13 '21 at 20:38
  • With 3 line of text, the Control's Height is `dim fontHeight = Font.GetHeight([Graphics]) dim linesHeight = (3 * fontHeight) + (fontHeight * Font.FontFamily.GetCellAscent(Font.Style) / Font.FontFamily.GetLineSpacing(Font.Style))` (The `[Graphics]` object can be created with `Control.CrreateGraphics()`). If you set this measure to `RowStyles(0).Height`, you'll have 3 visible lines of text. The TLP will auto-size to the new size. Do you want to increase the overall height of the TLP when you do this? Then add the same value to the second Row. That's all there is to it. – Jimi Mar 13 '21 at 20:38
  • Why are we still talking about RTB in `TLP.RowStyles(0)`? I have no problem with it! I have a problems with `ListView` in `TLP.RowStyles(1)`! – Andy Mar 13 '21 at 20:46
  • I'm referring to the RichTextBox because that's only thing that *may* need some care, if it's multi-line and you want to change the number of visible lines at run-time. The *problem* with the ListView will disappear as soon as you have set its layout as described. No calculations needed. If your ListView *moves*, then you have not docked it inside the Cell it belongs to, or you're doing something equally weird somewhere else. As mentioned, build a clean Form with just a TLP, a RTB and a ListView setup as described. Add them all in the designer. Then adapt your design to what you see there. – Jimi Mar 13 '21 at 20:59
  • Ok. I will try to explain again. RTB is not created in this class! It derived by Base class (other one control created by me). My this control is not inherits `System.Windows.Forms.UserControl`. It inherits my control! And RTB placed exactly in that base control. In that class RTB also placed in TLP named `TP_MAIN`. So on created THIS control I inherits that other control and in `Public Sub New()` I create `TP_PACKER` with two rowstyles. Then I remove `TP_MAIN` from `Me.Controls`, then `TP_PACKER.Controls.Add(TP_MAIN,0,0)` and after that I do `Me.Controls.Add(TP_PACKER)`. – Andy Mar 13 '21 at 22:15
  • If I trieng to do the same in designer I cant remove `TP_MAIN` from `Me.Controls`! Is that enough clear explain? – Andy Mar 13 '21 at 22:17
  • And If I will create this control with inherits `System.Windows.Forms.UserControl`, then add other (currently base) control as control itself - I will loose base control property manipulation possibility! – Andy Mar 13 '21 at 22:23
  • `ListView.Bounds` are dropped, debugger said me. Before resize Bounds x-y coordinates is {X=1,Y=62}; after - {X=0,Y=0} – Andy Mar 14 '21 at 00:03
  • I found solution. Look at **UPDATE** in topic – Andy Mar 14 '21 at 00:40

0 Answers0