Tablelayout panel rowstyle - vb.net

I have a table layout panel that I am dynamically adding rows to using the following code:
attemptstlp.RowCount += 2
attemptstlp.Height = attemptstlp.Height + 62
attemptstlp.RowStyles.Add(New RowStyle(SizeType.Absolute, 30))
(just so you know attemptstlp is the name of the panel)
I am using a loop to process through these rows adding them. I am finding that all is working except half way through the row style stops applying (so if i want to add 24 lots of 2 rows the height will stop applying after the 12th lot of rows has been added).
Could anyone offer suggestions on why the rows are reverting (i assume) to auto size after half of them have been added. The only other lines of code that refer to this panel is the lines adding the text boxes and the lines to suspend and resume layout to help reduce the flickering and time taken to load.
The table layout panel has an inital height of 40 with 1 row of height 39 when first created.
Thanks in advance,
mrtechguy

This works perfectly for adding rows and controls in a TableLayoutPanel. Try and see.
'Define a blank Tablelayoutpanel with 3 columns in the design page
Dim TableLayoutPanel3 As New TableLayoutPanel()
TableLayoutPanel3.Name = "TableLayoutPanel3"
TableLayoutPanel3.Location = New System.Drawing.Point(32, 287)
TableLayoutPanel3.AutoSize = True
TableLayoutPanel3.Size = New System.Drawing.Size(620, 20)
TableLayoutPanel3.ColumnCount = 3
TableLayoutPanel3.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
TableLayoutPanel3.BackColor = System.Drawing.Color.Transparent
TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 26.34146!))
TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 73.65854!))
TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Absolute, 85.0!))
Controls.Add(TableLayoutPanel3)
'Create a button btnAddRow to add rows on each click
Private Sub btnAddRow_Click(sender As System.Object, e As System.EventArgs) Handles btnAddRow.Click
TableLayoutPanel3.GrowStyle = TableLayoutPanelGrowStyle.AddRows
TableLayoutPanel3.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))
TableLayoutPanel3.SuspendLayout()
TableLayoutPanel3.RowCount += 1
Dim tb1 As New TextBox()
Dim tb2 As New TextBox()
Dim tb3 As New TextBox()
TableLayoutPanel3.Controls.Add(tb1 , 0, TableLayoutPanel3.RowCount - 1)
TableLayoutPanel3.Controls.Add(tb2, 1, TableLayoutPanel3.RowCount - 1)
TableLayoutPanel3.Controls.Add(tb3, 2, TableLayoutPanel3.RowCount - 1)
TableLayoutPanel3.ResumeLayout()
tb1.Focus()
End Sub

Related

ArgumentOutOfRangeException on Datagridview with 1 row

I have a strange problem. I have a form with on it 2 unbounded datagridviews and 2 buttons. With the buttons I switch the rows from 1 datagrid to the other.
In the beginning the left datagrid is filled with a number of rows and the right datagrid is empty. So when I click on the button "Add" the selected row from the left datagrid is removed and added to the right datagrid. With the button "Delete" the selected row of the right datagrid is added back to the left datagrid.
When there is only one row in the right datagrid, and I select it to "delete" it, the row is removed from the right datagrid and added to the left without an exception. Now I have a situation where there is only one row in the left datagrid and when I click "Add" to move it to the right datagrid I get an ArgumentOutOfRangeException (index is out of bounds...)
Below is the code which throws the exception
For i As Integer = DgvLeft.SelectedRows.Count - 1 To 0 Step -1
ind = DgvLeft.SelectedRows(i).Index
If ind > 0 Then
DgvLeft.Rows.RemoveAt(ind)
Else
DgvLeft.Rows.Remove(DgvLeft.SelectedRows(i))
End If
Next
So I store the row index in a variable. The first time I used the RemoveAt function and the exception is thrown. To resolve this I added the If-structure and tried the Remove function. But again the exception is thrown.
I don't understand why the exception is thrown. I use the same code for the "delete" button and there it doesn't happen. Also when I store the RowIndex in a variable the index is known, but not when I try to Remove the row.
Can someone help me with this strange problem?
Since the posted for loop is “broken”, I feel it is unnecessary to question what you are trying to accomplish here. However, given what you described where there are two grids and two buttons (Add/Delete) on a form. When the “Add” button is clicked, it moves the “selected rows” from the “left” grid to the “right” grid, and then deletes the “selected rows” rows from the “left” grid. If the “Delete” button is clicked, then the opposite process happens moving the “selected rows” from the right grid to the left grid, then delete the selected rows from the right grid.
If this is correct, then it appears you are making this more complicated than it has to be. This would be much easier if you used a data source of some form. However, to break the above problem down, it appears that two methods may come in handy for what you want to do. The first one could simply add the selected rows from one given grid to another given grid. The next method would simply delete the selected rows from a given grid. With these two methods implemented, the “add” button would be…
AddSelectedRows(dgvLeft, dgvRight)
RemoveSelectedRows(dgvLeft)
The delete button would be…
AddSelectedRows(dgvRight, dgvLeft)
RemoveSelectedRows(dgvRight)
Before I explain the code below, it should be noted that your current posted code is making a huge programming “no-no” and without question is a problem for you. As Mary and others have pointed out, “changing the value of the counter variable in a loop or (as the code does) changing the collection it is looping through is rarely if ever done.”
Try the code below it may make things easier,
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddColumns(dgvLeft)
AddColumns(dgvRight)
FillGrid(dgvLeft)
End Sub
Private Sub FillGrid(dgv As DataGridView)
For i = 0 To 15
dgv.Rows.Add("C0R" + i.ToString(), "C1R" + i.ToString(), "C2R" + i.ToString())
Next
End Sub
Private Sub AddColumns(dgv As DataGridView)
Dim txtCol = New DataGridViewTextBoxColumn()
txtCol.Name = "Col0"
txtCol.HeaderText = "Col 0"
dgv.Columns.Add(txtCol)
txtCol = New DataGridViewTextBoxColumn()
txtCol.Name = "Col1"
txtCol.HeaderText = "Col 1"
dgv.Columns.Add(txtCol)
txtCol = New DataGridViewTextBoxColumn()
txtCol.Name = "Col2"
txtCol.HeaderText = "Col 2"
dgv.Columns.Add(txtCol)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
AddSelectedRows(dgvLeft, dgvRight)
RemoveSelectedRows(dgvLeft)
End Sub
Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
AddSelectedRows(dgvRight, dgvLeft)
RemoveSelectedRows(dgvRight)
End Sub
Private Sub RemoveSelectedRows(dgv As DataGridView)
Dim totalRowsToDelete = dgv.SelectedRows.Count
Dim selectedRow As DataGridViewRow
For i = totalRowsToDelete - 1 To 0 Step -1
selectedRow = dgv.SelectedRows(i)
If (Not selectedRow.IsNewRow) Then
dgv.Rows.RemoveAt(dgv.SelectedRows(i).Index)
End If
Next
End Sub
Private Sub AddSelectedRows(sourceDGV As DataGridView, destinationDGV As DataGridView)
Dim selectedRowCount = sourceDGV.Rows.GetRowCount(DataGridViewElementStates.Selected)
If (selectedRowCount > 0) Then
Dim selectedRow As DataGridViewRow
For i = 0 To selectedRowCount - 1
selectedRow = sourceDGV.SelectedRows(i)
If (Not selectedRow.IsNewRow) Then
destinationDGV.Rows.Add(selectedRow.Cells(0).Value.ToString(),
selectedRow.Cells(1).Value.ToString(),
selectedRow.Cells(2).Value.ToString())
End If
Next
End If
End Sub
You are changing the value of DgvLeft.SelectedRows.Count in your For loop.
Try...
Dim RowCount As Integer = DgvLeft.SelectedRows.Count
For i As Integer = RowCount - 1 To 0 Step -1
I want to thank Mary for her answer, because that made me think about my code. I looked at the code of the "delete" button, where I use the same for loop, and that code doesn't throw an exception. So there must be a difference between the code of my two buttons.
This is an expanded piece of my code in the "add" button:
For i As Integer = DgvLeft.SelectedRows.Count - 1 To 0 Step -1
'fill the array with the row values
For j As Integer = 0 To DgvLeft.Columns.Count - 1
fields(j) = DgvLeft.SelectedRows(i).Cells(DgvLeft.Columns(j).Name).Value
Next
'delete the row in datagrid Left
ind = DgvLeft.SelectedRows(i).Index
If ind > 0 Then
DgvLeft.Rows.RemoveAt(ind)
Else
DgvLeft.Rows.Remove(DgvLeft.SelectedRows(i))
End If
'add the row in datagrid Right
DgvRight.Rows.Add(fields)
Next
In the code snippet above I attempt to remove a row BEFORE I add the array of values from this row to the other datagrid. When I looked at the code of the "delete" button I attempt to remove the row AFTER I add the array of values to the other datagrid.
So I moved this piece of code below the code of adding the array of values and it worked. Probably the index exception is thrown by the array rather than the datagridview.

iTextsharp - draw a line at the end and start of a page with tables

Selecting records from a table I create iTextsharp's Tables one for every first letter of the records
On the picture a table for the "G" letter:
"G" is a row of 6 cells
Then a row of 6 cells with the "headers"
and then rows with records
The cells of the rows only need left and right border.
But I need to draw or "close" the line for the last row of the page and also draw or "open" the line of the first row of the next page.
I read a lot of post but I can't figure it out the solution
I know how to draw a graphic line and how to find the coords or how to set bottom or top border, but I don´t know how to detect the page break or if I can manage this situation with forced footers or headers only on cases like the one of the picture.
The code of the class adapated to VB
Thanks to COeDev for the support
Now I only need to resolve the Rectangle (or draw a line) because is not the same on VB.NET (Lines marked as comment)
Imports iTextSharp.text.pdf
Public Class LineaBottom
Implements IPdfPTableEvent
Public Sub TableLayout(table As PdfPTable, widths As Single()(), heights() As Single, headerRows As Integer, rowStart As Integer, canvases() As PdfContentByte) Implements IPdfPTableEvent.TableLayout
'Throw New NotImplementedException()
Dim columns As Integer
Dim rect As Rectangle
Dim footer As Integer = widths.Length - table.FooterRows
Dim header As Integer = table.HeaderRows - table.FooterRows + 1
Dim ultima As Integer = footer - 1
If ultima <> -1 Then
columns = widths(ultima).Length - 1
rect = New Rectangle(widths(ultima)(0), heights(ultima), widths(footer - 1)(columns), heights(ultima + 1))
'rect.BorderColor = BaseColor.BLACK
'rect.BorderWidth = 1
'rect.Border = Rectangle.TOP_BORDER
'canvases(PdfPTable.BASECANVAS).Rectangle(rect)
End If
End Sub
I hope this code will serve other people because there is not much information on the Internet
This should be helpful for you: itextsharp: how to show the bottom line of a table with property HeaderRows=1 if border bottom of the row is not set?
You will need to add some code to draw an additional header line, too
e.g.:
columns = widths[0].Length - 1;
rect = new Rectangle(widths[0][0], heights[0], widths[0][columns], heights[0]);
rect.BorderColor = Color.BLACK;
rect.BorderWidth = 1;
rect.Border = Rectangle.TOP_BORDER;
canvases[PdfPTable.BASECANVAS].Rectangle(rect);
4.1.6.0
I found the solution, no new class required
Dim heightActualLetter, verticalSpaceAvailable As Integer
heightActualLetter = table.TotalHeight
verticalSpaceAvailable = pdfWrite.GetVerticalPosition(False) - pdfDoc.BottomMargin
If heightActualLetter > verticalSpaceAvailable Then
Dim finalLine As PdfContentByte
finalLine = pdfWrite.DirectContent
Dim curY As Int32
curY = pdfWrite.GetVerticalPosition(False)
finalLine.SetLineWidth(0.5)
finalLine.MoveTo(xStart, curY)
finalLine.LineTo(xEnd + 1, curY)
finalLine.Stroke()
End If
I don´t know why I need the +1 on xEnd + 1 but maybe is because of the other lines being 0.5 I need to rounded up

VB.NET - Button Resizing

I'm writing a full screen 'kiosk-esque' application and I want the buttons to fit accordingly.
Currently when the form opens, I have the buttons anchored and they stretch vertically, but I want them to resize horizontally as well?
Is there an easy way to do this?
For WinForms, use a TableLayoutPanel with 3 columns, with widths set to 33.33% for your example. Put a button in each panel, set their Dock properties to Fill, and use Anchors to stretch the entire TableLayoutPanel.
For WPF you would use a Grid control.
Used code to do it.Just add this code to your form.
Private Sub Form1_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
Button1.Width = (Me.Width - 100) / 3 - 10 'That "10" in the last comes from 15*2/3 .So if the space2 is 15 this number must be 10.
Button2.Width = (Me.Width - 100) / 3 - 10 'That "Me.Width - 100" comes from 2*50 .If you want space1 50,this number must be 100.
Button3.Width = (Me.Width - 100) / 3 - 10 'Resize the last.
Me.Button1.Location = New Point(50, Button1.Location.Y) 'Start from 50 in X Coordinate.
Me.Button2.Location = New Point(Button1.Width + 65, Button2.Location.Y) 'That 65 means "50 + 15".(50 is space1,15 is space2.)
Me.Button3.Location = New Point(Button1.Width + Button2.Width + 80, Button3.Location.Y) 'As you expected "50 + 15 + 15 = 80"
'This works for only 3 buttons(horizontally).Get the logic and improve your code for your button count.
End Sub
You can see the space1 and space2 that I used in my code here.That 3 buttons resize horizontaly if your form SizeChanged.

Have CustomListView resize last column to fit width

I have a custom list view control in WinForms that applies some custom styles. This works well, however I have a part of the control that is not covered when the user maximises the screen (columns are set to fixed width) and ColumnHeaderAutoResizeStyle.None is set. I'd like to have the last column auto fill the gap.
To achieve this inside of the custom control I have added the following code to ListView.SizeChanged event.
Private Sub CustomListView_Resized(sender As Object, e As EventArgs) Handles Me.SizeChanged
Try
If (Not _isResizing) Then
_isResizing = True
Dim myListView As customListView = DirectCast(sender, customListView)
' Work out current column widths
Dim totalColumWidthInPx As Integer = 0
For i = 1 To Columns.Count - 1
totalColumWidthInPx += Me.Columns(i).Width
Next
' Increment the final column by the difference in width to make up the gap
Me.Columns.Item(Columns.Count - 1).Width += (myListView.ClientRectangle.Width - totalColumWidthInPx)
End If
Finally
_isResizing = False
End Try
End Sub
This is always giving me inconsistent results, the column width is incremented to much and adds the scrollbars as below.
Little bit of debug info.
Control: lvAppointments, Width (px): 701, Client Rectangle Width (px):
697, All Column Widths: 648, Diff: 49, Last Column: 234, Last Column +
Diff: 283

How to Implement Rowspan in a GridView (for .NET 3.5)

I created a custom GridView (actually a RadGrid) which does roughly the following.
Initialize GridView formatting
Setup Columns (depending on type of data to be displayed)
Populate the rows
When Instantiating this GridView, and adding it to my page, I want the first column to contain a "rowspan" attribute on the first row of repeated, but similar data. The "rowspan" value should be equal to the number of similar rows following it. In this way I hope to make the final view cleaner.
The logic for this, I figure, should take place while populating the rows. Initially I add rows to a DataTable and then bind it to the GridView as the final step.
Here's the general logic I was attempting, but it didn't work for me. What am I doing wrong?
Dim dt As New DataTable() 'Has three default columns
For Each d In Documents 'MAIN ITEM (First Column Data)
Dim rowspan As Integer
rowspan = 0
For Each f In Files
If rowspan = 0 Then
Me.dt.Rows.Add(New Object() {d.Title, f.Language, f.FileSize})
'THIS DOESN'T WORK!
Me.dt.Columns(0).ExtendedProperties.Item("rowspan") = rowspan.ToString()
Else
Me.dt.Rows.Add(New Object() {Nothing, f.Language, f.FileSize})
End If
rowspan += 1
Next
Next
Also keep in mind that the this is dumped into a DataView which is sorted by the first column, so I would imagine it must actually be sorted first, then somehow count the rows for each "like" first column, then set the "rowspan" value for the first row of that column equal to the number of rows belonging to it.
Does this make sense? Here is an ideal example of what I would like to accomplish in the layout:
Try this.
Protected Sub DemoGrid_PreRender(sender As Object, e As System.EventArgs) Handles DemoGrid.PreRender
MergeRowsWithSameContent(sender)
End Sub
Public Sub MergeRowsWithSameContent(gvw As GridView)
For rowIndex As Integer = gvw.Rows.Count - 2 To 0 Step -1
Dim row As GridViewRow = gvw.Rows(rowIndex)
Dim previousRow As GridViewRow = gvw.Rows(rowIndex + 1)
For i As Integer = 0 To row.Cells.Count - 1
If row.Cells(i).Text = previousRow.Cells(i).Text Then
row.Cells(i).RowSpan = If(previousRow.Cells(i).RowSpan < 2, 2, previousRow.Cells(i).RowSpan + 1)
previousRow.Cells(i).Visible = False
End If
Next
Next
End Sub
P.S: Shameless port of this wonderful code I have been using for years.