VB.Net : Writing SQL Table field into Link Label Parent Control - vb.net

I have a bunch of link label controls stored in SQL. I have figured out how to pull them and create the link label but when I try to write the lnk.Parent Control I get "Unable to cast object of type 'system.string' to type 'system.windows.forms.control'. Is there a way to convert this?
Private Sub CreateLinkLabel(Lnk_DT As DataTable)
Try
For Each row As DataRow In Lnk_DT.Rows
lnk = New LinkLabel
lnk.Name = row("FLD_LnkName").ToString
lnk.Text = row("FLD_LnkName").ToString
lnk.Font = New Font("Sans Serif", 10, FontStyle.Bold)
lnk.Location = New Point(20, i)
lnk.Parent = row("FLD_LnkPanel")
lnk.Tag = row("Fld_LnkTag").ToString
lnk.AutoSize = True
AddHandler lnk.LinkClicked, AddressOf lnk_LinkClicked
i = i + 25
Next
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try

try this:
For Each c As Control In Me.Controls
If TypeOf c Is Panel Then
If c.Name = row("FLD_LnkPanel") Then
lnk.Parent = c
End If
End If

The Parent property should be assigned to a Form object (or other container control) so I suppose that you should write lnk.Parent = Me but in any case the correct way to add controls to a container is through the Add method of the Controls control collection.
For example, to add the newly created label to the current form, you write this inside your loop
Me.Controls.Add(lnk)
Looking at your code it seems that the field row("FLD_LnkPanel") is the name of a Panel control on your form. If you want to add the created label to this panel then you should write
Private Sub CreateLinkLabel(Lnk_DT As DataTable)
Try
For Each row As DataRow In Lnk_DT.Rows
' Get the panel name '
Dim panelName = row("FLD_LnkPanel")
' Search the panel between the Form controls'
Dim panel = Me.Controls.OfType(Of Panel)
.FirstOrDefault(Function(x) x.Name = panelName)
' If you got it, then proceed with the label creation
if panel IsNot Nothing Then
lnk = New LinkLabel
lnk.Name = row("FLD_LnkName").ToString
lnk.Text = row("FLD_LnkName").ToString
lnk.Font = New Font("Sans Serif", 10, FontStyle.Bold)
lnk.Location = New Point(20, i)
' lnk.Parent = row("FLD_LnkPanel")'
lnk.Tag = row("Fld_LnkTag").ToString
lnk.AutoSize = True
AddHandler lnk.LinkClicked, AddressOf lnk_LinkClicked
i = i + 25
' Add the label to the panel child controls
panel.Controls.Add(lnk)
End If
Next
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub

Consider something like this:
Private Sub CreateUIControls(Lnk_DT As DataTable)
For Each row As DataRow In Lnk_DT.Rows
Dim isPanelNew As Boolean
Dim pnl As Panel = GetPanel(row, isPanelNew)
CreateLink(row, pnl)
If isPanelNew Then
pnl.Location = New Point(10, 20) ' whatever logic
End If
Next
End Sub
Private Function GetPanel(item As DataRow, ByRef isNew As Boolean) As Panel
isNew = False
Dim pnlItem As Panel = Nothing
Dim pnlName As String = item.Field(Of String)("FLD_LnkPanel")
' check if panel already exists on form.
Dim pnl As Panel = (From p In Controls.OfType(Of Panel)()
Where p.Name = pnlName
Select p).SingleOrDefault()
If pnl Is Nothing Then
pnlItem = New Panel
pnlItem.Width = 200 ' whatever logic
isNew = True
Else
pnlItem = pnl
End If
Return pnlItem
End Function
Private Sub CreateLink(item As DataRow, parentControl As Panel)
' get how many links are in the panel.
Dim linksCount = parentControl.Controls.OfType(Of LinkLabel).Count()
Dim lnk As New LinkLabel
With lnk
.Name = item.Field(Of String)("FLD_LnkName")
.Text = item.Field(Of String)("FLD_LnkName")
.Font = New Font("Sans Serif", 10, FontStyle.Bold)
.Tag = item.Field(Of String)("Fld_LnkTag")
.AutoSize = True
' increase panel height to fit the new link.
parentControl.Height = ((linksCount + 1) * 25) + 10
.Parent = parentControl
.Location = New Point(20, (linksCount * 25) + 3)
AddHandler .LinkClicked, AddressOf lnk_LinkClicked
End With
End Sub

Related

How to retrieve text from dynamic label and display it to message box using dynamic button?

I have these codes retrieving data from mysql database and display it into the dynamic panels, labels, and buttons. The problem is I don't know how to retrieve those texts from labels(lblProductName) to display it into message box when clicking the dynamic buttons(btnAddto). TIA!
Imports MySql.Data.MySqlClient
Module mdlMenu
Dim Cpanel As Panel
Dim lblProductName As Label
Dim btnAddto As Button
Dim count As Integer
Public Sub LoadMenu()
Try
SQLConnection()
With sqlcom
.CommandText = "SELECT * FROM tblproduct"
.Connection = sqlconn
End With
Dim datareader As MySqlDataReader = sqlcom.ExecuteReader
Do While datareader.Read()
Cpanel = New Panel()
With frmMenu
count = .TableLayoutPanel1.Controls.OfType(Of Panel)().ToList().Count
Cpanel.Location = New Point(10, (25 * count) * 7)
Cpanel.Size = New Size(450, 160)
Cpanel.Name = "Cpanel" & count
Cpanel.AutoScroll = True
Cpanel.BackColor = Color.White
.TableLayoutPanel1.Controls.Add(Cpanel)
lblProductName = New Label()
lblProductName.Location = New Point(165, 10)
lblProductName.AutoSize = True
lblProductName.Name = "lblProd" & count
lblProductName.Text = datareader.Item("ProductName").ToString & count
lblProductName.Font = New Font(lblProductName.Font.FontFamily, 14, FontStyle.Bold)
Cpanel.Controls.Add(lblProductName)
btnAddto = New Button()
btnAddto.Location = New Point(180, 115)
btnAddto.Size = New Size(80, 40)
btnAddto.Name = count
btnAddto.Text = count
btnAddto.Tag = count.ToString
btnAddto.Font = New Font(btnAddto.Font.FontFamily, 10, FontStyle.Bold)
AddHandler btnAddto.Click, AddressOf btnAddto_Click
Cpanel.Controls.Add(btnAddto)
count += 1
End With
Loop
Catch ex As Exception
MsgBox(ex.Message)
Finally
sqlconn.Close()
sqlconn.Dispose()
End Try
End Sub
There are a couple of concepts here:
How to reference a dynamic control
How to bind an event to a dynamic control
Regarding number 1 on how to reference a dynamic control, it looks like you are declaring a form level variable and setting the value. So you should be able to reference lblProductName after it is set in the LoadMenu method. However, if you did not want to create a form level variable, you could simply use the Controls.Find method (documentation).
Regarding number 2 on how to bind an event to a dynamic control, you would use the AddHandler statement (documentation), which it looks like you are already doing here:
AddHandler btnAddto.Click, AddressOf btnAddto_Click
So what would the btnAddto_Click method look like putting it all together?
Private Sub btnAddto_Click(sender As Object, e As EventArgs)
Dim button = DirectCast(sender, Button)
Dim count = If(button.Tag IsNot Nothing, button.Tag.ToString(), String.Empty)
Dim labels = Controls.Find("lblProd" & count, True)
If (labels.Length > 0) Then
Dim label = labels(0)
MessageBox.Show(label.Text)
End If
End Sub

How to add an dynamically a checkbox element on a Tabcontrol after Tabcontrol.Pages is from GUI Designer?

can i add tabcontrol elements after programm started?
i use a Tabcontrol from GUI-Designer and wanna manipulate a TabPage.
i want there new dynamical checkboxes on Formular _load.
i can't see these checkboxes on my TabPages
For i = 0 To frmMain.cmbZielSpache.Items.Count - 1
Dim cBox = New CheckBox()
cBox.Name = "GEN_" & i
cBox.Location = New Point(offsetX, offsetY)
cBox.Text = frmMain.cmbZielSpache.Items(i)
If frmMain.cmbZielSpache.Items(i) = frmMain.cmbZielSpache.Text Or My.Settings.chkTranslate_normal_alleSprachen = True Then
cBox.Checked = True
End If
offsetX = offsetX + 120
Me.Controls.Add(cBox)
AddHandler cBox.CheckedChanged, AddressOf checkChangedHandler
Next i
Instead of using Me.Controls i wanna add the checkboxes after programm started dynamically.
The solution is TabControl1.TabPages(0).Controls.add()
Sub checkChangedHandler(sender As Object, e As EventArgs)
lblSprachenListeZielSprachen.Text = "Ziel Übersetzungsprache: "
For Each chkBox In TabControl1.TabPages(0).Controls.OfType(Of CheckBox)()
'Check here whether your check boxes are checked true/false
If chkBox.Checked = True Then
If Not chkBox.Name.IndexOf("GEN_") = -1 Then
lblSprachenListeZielSprachen.Text &= chkBox.Text & ","
End If
End If
Next
gblAktiveÜbersetzungssprachen = lblSprachenListeZielSprachen.Text.Replace("Ziel Übersetzungsprache: ", "")
End Sub
For i = 0 To frmMain.cmbZielSpache.Items.Count - 1
Dim cBox = New CheckBox()
cBox.Name = "GEN_" & i
cBox.Location = New Point(offsetX, offsetY)
cBox.Text = frmMain.cmbZielSpache.Items(i)
If frmMain.cmbZielSpache.Items(i) = frmMain.cmbZielSpache.Text Or My.Settings.chkTranslate_normal_alleSprachen = True Then
cBox.Checked = True
End If
offsetX = offsetX + 120
AddHandler cBox.CheckedChanged, AddressOf checkChangedHandler
Me.TabControl1.TabPages(0).Controls.Add(cBox)
Next i

Swap positions between three Panels

I have three panel type objects (A, B, and C), which have been dynamically generated within another panel type control.
My question is, how can I exchange panel B to the position of panel A and panel A to the position of panel B? This will be triggered by a click on a ToolStripMenuItem.
What I had thought, was to go through the arrangement of panels to know who exists and from there to work them, is that correct?
For Each obj As Control In Panel1.Controls
MsgBox(obj.Name)
Next
This is the code that I use to move to right:
Private Sub ToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItem1.Click
Dim clickedPanel = DirectCast(DirectCast(DirectCast(sender, ToolStripMenuItem).Owner, ContextMenuStrip).SourceControl, Panel)
clickedPanel.Location = New Point((clickedPanel.Location.X + 120), clickedPanel.Location.Y)
End Sub
This is the code I use to generate objects dynamically:
Private Sub TileNavItem5_ElementClick(sender As Object, e As NavElementEventArgs) Handles TileNavItem5.ElementClick
Dim pos As Int32 = cInt(TextBox38.Text)
Dim poslabel As Int16 = cInt(TextBox42.Text)
Dim posY As Int16 = 330
Dim posX As Int16 = 3
Panel1.AutoScrollPosition = New Point(0, 0)
Dim pb As New Panel With
{
.Width = 120,
.Height = 460,
.Top = 10,
.Left = 10,
.BorderStyle = BorderStyle.FixedSingle,
.BackgroundImage = Image.FromFile("C:\example.bmp"),
.BackgroundImageLayout = ImageLayout.Stretch,
.ContextMenuStrip = CntxtMnuStrpSection,
.Name = "Panel" & Val(TextBox37.Text)
}
AddHandler pb.Click, AddressOf myClickHandler_b
Dim labela As New Label With {
.AutoSize = True,
.Location = New Point((poslabel), 12),
.Text = "Section " & CInt(TextBox37.Text),
.ForeColor = Color.White,
.BackColor = Color.Transparent,
.Font = New Font(Me.Font, FontStyle.Bold),
.Name = "Label" & CInt(TextBox37.Text)
}
pb.Location = New Point(0, 0)
pb.Location = New Point(pos, 20)
Panel1.Controls.Add(pb)
pb.Controls.Add(labela)
For j = 1 To 4
Dim pbdoors As New Panel With
{
.Width = 114,
.Height = 98,
.Top = 10,
.Left = 10,
.BorderStyle = BorderStyle.FixedSingle,
.BackgroundImageLayout = ImageLayout.Stretch,
.ContextMenuStrip = CntxtMnuStrpUnit,
.Name = "Unit" & Val(TextBox37.Text) & j
}
AddHandler pbdoors.Click, AddressOf myClickHandler_doors
pbdoors.Location = New Point(posX, posY)
pb.Controls.Add(pbdoors)
posY = (posY - 100)
Next
Panel1.AutoScrollPosition = New Point(Panel1.HorizontalScroll.Maximum, Panel1.VerticalScroll.Maximum)
TextBox37.Text = CInt(TextBox37.Text) + 1
TextBox38.Text = Val(TextBox38.Text) + 120
End Sub
You just need to find the controls. Swapping is the easy part.
Finding controls is also easy if you use Control.Controls.Find(String, Boolean). But you must at least know the control's name.
The difficulty comes in here
' TextBox37.Text = CInt(TextBox37.Text) + 1 ' implicit conversion from int to string
TextBox37.Text = (CInt(TextBox37.Text) + 1).ToString()
where you must find the control by name and you have built some integer into the name. Can you keep track of how many times 1 is added to TextBox37.Text?
If you can, you can pass it into this function, and the swapping will be performed
Private Sub swap(index1 As Integer, index2 As Integer)
' build the panel names
Dim p1Name = $"Panel{index1}"
Dim p2Name = $"Panel{index2}"
' find the panels
Dim p1 = DirectCast(Panel1.Controls.Find(p1Name, True).FirstOrDefault(), Panel)
If p1 Is Nothing Then Throw New ArgumentException("index1")
Dim p2 = DirectCast(Panel1.Controls.Find(p2Name, True).FirstOrDefault(), Panel)
If p2 Is Nothing Then Throw New ArgumentException("index2")
' swap the panels
Dim temp = p2.Location
p2.Location = p1.Location
p1.Location = temp
End Sub
swap(1, 2) will swap panel 1 with 2. swap(4, 6) will swap the panel 4 with 6. This logic is not included in your question (i.e. how many times is TileNavItem5_ElementClick called?), so you know better how to incorporate it. I hope it works for you.

Unusual Glitch when Opening Forms

When I maximise a form in my project and open another form from it (using a button), I'm getting an unusual glitch which I can only explain with the use of the screenshots below.
In this image, I have got an order screen and a freight screen. The order screen is maximised into an MDI screen when I hit the 'Add Freight' button, then upon opening the freight management screen, it is setting both forms to WindowState.Normal, which I'm doing programmatically and I understand why it sets both forms to normal window state, however, as you can, it is leaving a trace of the order screen behind in maximised view.
To explain more clearly, the forms have been changed from WindowState.Maximized to WindowState.Normal, and in the image the form in the top left corner is fine, but the order form is still showing in both normalised and maximised, but the maximised window doesn't exist, it disappears when you move the other screens around.
The strangest thing about this is that I'm using the same code to open other windows in the exact same way elsewhere in the program yet this glitch isn't happening.
There are only 2 "parent" forms which do this when opening other forms from within them.
Has anyone else ever had this issue? What is a way around it? This also happens even if I open the other form in maximised mode, so it's not as simple as just opening it in maximised view.
The code to open the form in the example is the following:
ugProducts.UpdateData()
Try
Dim dt As New DataTable
dt = ugProducts.DataSource
Dim ordnum As Integer
Dim osql As New OleDbCommand
osql.CommandType = CommandType.Text
osql.Connection = con
osql.CommandText = "SELECT [Order_Number] FROM [Order_Freight] WHERE [Order_Reference] = ?"
osql.Parameters.AddWithValue("#onum", lblReference.Text.ToString)
ordnum = Convert.ToInt32(osql.ExecuteScalar)
Dim ORef As String
ORef = lblReference.Text
Dim FNumber As Integer
Dim fsql As New OleDbCommand
fsql.CommandType = CommandType.Text
fsql.Connection = con
fsql.CommandText = "SELECT [Freight_Number] FROM [Order_Freight] WHERE [Order_Reference] = ?"
fsql.Parameters.AddWithValue("#fnum", lblReference.Text.ToString)
FNumber = Convert.ToInt32(fsql.ExecuteScalar)
Dim PC As String
Try
PC = ugProducts.ActiveRow.Cells("Product_Code").Text.ToString
Catch
PC = ugProducts.Rows(0).Cells("Product_Code").Text.ToString
End Try
Dim SC As String
Try
SC = ugProducts.ActiveRow.Cells("Supplier_Code").Text.ToString
Catch
SC = ugProducts.Rows(0).Cells("Supplier_Code").Text.ToString
End Try
Dim f As New frmEditFreight(con, dt, Me, cmbCustCode.Text, ordnum, ORef, FNumber, PC, SC)
f.MdiParent = Me.MdiParent
f.Show()
Catch ex As Exception
errorLog(ex)
End Try
Then, on the form that is loaded, I have this
Me.Location = New Point(0, 0)
Me.WindowState = FormWindowState.Normal
txtTotal.ReadOnly = True
lftable = New DataTable
If isNewOrder = False Then
Try
For Each dc As DataColumn In lineTable.Columns
If dc.ColumnName = "Order_Number" OrElse dc.ColumnName = "Product_Code" OrElse dc.ColumnName = "Supplier_Code" Then
lftable.Columns.Add(New DataColumn(dc.ColumnName, dc.DataType))
End If
Next
Dim product As String = ""
Dim supplier As String = fOrder.cmbSupplier.Text
Dim ds As New DataSet
Dim da As New OleDbDataAdapter("SELECT * FROM [Order_Freight] WHERE [Order_Number] = ?", con)
da.SelectCommand.Parameters.Add("#num", OleDbType.Integer).Value = orderNum
da.Fill(ds)
Dim nDt As New DataTable
nDt = ds.Tables(0).Copy()
For Each row As DataRow In nDt.Rows
product = row.Item("Product_Code")
For Each dr As DataRow In lineTable.Rows
If dr.RowState <> DataRowState.Deleted Then
If dr.Item("Product_Code") = product Then
dr.Delete()
Else
End If
Else
If dr.Item("Product_Code", DataRowVersion.Original) = product Then
dr.Delete()
Else
End If
End If
Next
Next
For Each dr As DataRow In lineTable.Rows
If dr.RowState <> DataRowState.Deleted Then
dr.Item("Order_Number") = orderNum
End If
Next
Me.ugProducts.DataSource = lineTable
For Each dc As UltraGridColumn In ugProducts.DisplayLayout.Bands(0).Columns
Dim cName As String = dc.ToString
Select Case cName
Case "Product_Code"
dc.Hidden = False
Case "Order_Number"
dc.Hidden = False
Case "Supplier_Code"
dc.Hidden = False
Case Else
dc.Hidden = True
End Select
Next
loadAddresses(custCode, con)
dtEstDelivery.Value = Date.Today
ugProducts.DisplayLayout.Bands(0).Override.CellClickAction = CellClickAction.RowSelect
selectedTable.Columns.Add("Product_Code")
selectedTable.Columns.Add("Supplier_Code")
selectedTable.Columns.Add("RowIndex")
freightTable = New DataTable
With freightTable.Columns
.Add("Freight_Number")
.Add("Address_Code")
.Add("Est_Delivery")
.Add("Product_Code")
.Add("Freight_Desc")
.Add("Freight_Val", GetType(Decimal))
.Add("Supplier_Code")
.Add("freeDelivery", GetType(Boolean))
End With
ugFreight.DataSource = freightTable
ugSelected.DataSource = selectedTable
ugSelected.DisplayLayout.Bands(0).Override.CellClickAction = CellClickAction.RowSelect
Catch ex As Exception
errorLog(ex)
End Try
Else
Try
Me.ugProducts.DataSource = lineTable
For Each dc As UltraGridColumn In ugProducts.DisplayLayout.Bands(0).Columns
Dim cName As String = dc.ToString
Select Case cName
Case "Product_Code"
dc.Hidden = False
Case "Product_Description"
dc.Hidden = False
dc.Header.Caption = "Description"
Case "Supplier_Code"
dc.Hidden = False
dc.Header.Caption = "Supplier"
Case Else
dc.Hidden = True
End Select
Next
loadAddresses(custCode, con)
dtEstDelivery.Value = Date.Today
ugProducts.DisplayLayout.Bands(0).Override.CellClickAction = CellClickAction.RowSelect
selectedTable.Columns.Add("Product_Code")
selectedTable.Columns.Add("Supplier_Code")
selectedTable.Columns.Add("RowIndex")
freightTable = New DataTable
With freightTable.Columns
.Add("Freight_Number")
.Add("Address_Code")
.Add("Est_Delivery")
.Add("Product_Code")
.Add("Freight_Desc")
.Add("Freight_Val", GetType(Decimal))
.Add("Supplier_Code")
.Add("freeDelivery", GetType(Boolean))
End With
ugFreight.DataSource = freightTable
ugSelected.DataSource = selectedTable
ugSelected.DisplayLayout.Bands(0).Override.CellClickAction = CellClickAction.RowSelect
Catch ex As Exception
errorLog(ex)
End Try
End If
bLoading = False
Followed by some ordinary stuff, setting DataTables, loading in data, etc.
The other form which is having the issue has this code:
Try
Dim grid As UltraGrid = DirectCast(sender, UltraGrid)
Dim lastElement As UIElement = ugRates.DisplayLayout.UIElement.LastElementEntered
Dim rowElement As RowUIElement
If TypeOf lastElement Is RowUIElement Then
rowElement = DirectCast(lastElement, RowUIElement)
Else
rowElement = DirectCast(lastElement.GetAncestor(GetType(RowUIElement)), RowUIElement)
End If
If rowElement Is Nothing Then Return
Dim row As UltraGridRow = DirectCast(rowElement.GetContext(GetType(UltraGridRow)), UltraGridRow)
If (row Is Nothing) Then Return
Dim MousePosition As Point = grid.PointToClient(Control.MousePosition)
If Not lastElement.AdjustableElementFromPoint(MousePosition) Is Nothing Then Return
Select Case row.Cells("cType").Value
Case "Acquisition Rate"
Dim supplier As String
If rbtnAllSuppliers.Checked = True Then
supplier = row.Cells("Supp_Code").Value
Else
supplier = cmbSupplier.Text
End If
Dim f As New frmCommission(con, row.Cells("Comm_Code").Value, supplier, True)
f.MdiParent = Me.MdiParent
f.Show()
With the rest of the select case below. The form being opened in this case then has the code
Me.Location = New Point(0, 0)
Me.WindowState = FormWindowState.Normal
Me.Cursor = Cursors.Default
isUpdate = False
Me.ugComm.ContextMenuStrip = cmCommRate
With updateDT.Columns
.Add("Apply", GetType(Boolean)).DefaultValue = False
.Add("Product_Code")
.Add("Commission_Rate")
.Add("Multiplier")
End With
btnCustomerSearch.Enabled = False
Try
Dim da As New OleDb.OleDbDataAdapter
Dim ds As New DataSet
sql = "SELECT * FROM [System Settings]"
da = New OleDb.OleDbDataAdapter(sql, con)
Dim dt As New DataTable
da.Fill(dt)
If dt.Rows(0).Item("enableAqDate") = False Then
rbtnAcq.Enabled = False
End If
If cCode <> "" And sCode <> "" Then
cmbSupp.Text = sCode
cmbSupp_ValueChanged(sender, New EventArgs)
End If
disableControls()
cmbSupp.Refresh()
txtCommCode.Refresh()
ugComm.Refresh()
cmbSupp.Enabled = False
isLoad = False
If isEnquiry = True Then
txtCommCode.Text = cCode
loadEnquiry()
ugComm.Enabled = True
cmdAddRange.Enabled = False
cmdUpdateRange.Enabled = True
cmbSupp.Value = sCode
txtCommCode.Text = cCode
End If
Catch ex As Exception
errorLog(ex)
End Try
When trying to insert the code suggested for making dpiaware = True, I've not been able to see anywhere in the code that this would go?
The culprit seems to be setting the WindowState property to Normal inside the Load event of a mdi child form when active mdi child form is maximized.
At this time the target form is in some intermediate state - the event is called as part of the window handle creation, the handle is already created, Visible property is True (but the form is not really shown on screen), WindowState returns Maximized and trying to set it to Normal leads internally to ShowWindow API call.
It's hard to tell where exactly is the bug (there are a lot of internal flags and windows messages handling inside the Form class), but the end effect is that the MDIClient and the currently active mdi child form are not correctly invalidated, hence the visual effect you are experiencing.
With that being said, there are several workarounds:
(1) At the form being shown side:
Move the Me.WindowState = FormWindowState.Normal to the Shown event.
(2) At the caller side:
(A) Add Me.WindowState = FormWindowState.Normal before f.Show()
or
(B) Add Me.MdiParent.Invalidate(True) after f.Show()
or
(C) Add Me.MdiParent.Refresh() after f.Show()
My personal preference would be the option (1) since it encapsulates a logic which is specific to the called form inside that form.

Buttons Added to FlowLayoutPanel pile up on top of each other

I'm using VS 2012 (vb.net) and I have a form with a flowLayoutPanel which is meant to contain an unknown number of buttons. To make it simple, basically, when the form Loads I fetch items from a table based one some criteria and then a use a For...Next block to add a button for each item to the flowLayoutPanel. So if I find 5 items I add 5 buttons all named differently but the problem is that they seem to pile up on each other instead of lining up nicely. When I use a button to add the items one after the other it works fine but when I use the For...Next block it does not work. I have tried refreshing the flowLayoutPanel after adding each button, I have tried to set the location of each new button relative to the location of the previous button but it still does to work.
I have researched this for over a week now and there is a ton of stuff out there but nothing specifically deals with this.
Thanks for your help.
This is the relevant part of my code:
`Try
If conn.State <> ConnectionState.Open Then
conn.Open()
End If
sql = "SELECT ItemCode, Description, NormalPrice FROM items WHERE items.Class = 'ICE CREAM'"
cmd = New MySqlCommand(sql, conn)
da.SelectCommand = cmd
'fill dataset
da.Fill(ds, "items")
rowscount = ds.Tables("items").Rows.Count
If rowscount > 0 Then 'there are records so go ahead
Dim ID As Integer
Dim desc As String
Dim newbutton As New Button
Dim newCode As New TextBox
For i As Integer = 0 To rowscount - 1
ID = ds.Tables("items").Rows(i).Item("ItemCode")
desc = ds.Tables("items").Rows(i).Item("Description")
newCode.Name = "mnuCode" & i
newCode.Text = ID
newCode.Visible = False
Me.Controls.Add(newCode)
newbutton.Name = "mnuButton" & i
newbutton.Text = desc
newbutton.Size = New Size(150, 100)
newbutton.BackColor = Color.Orange
newbutton.ForeColor = Color.White
newbutton.Font = New Font("Arial", 16, FontStyle.Bold)
newbutton.TextAlign = ContentAlignment.MiddleCenter
newbutton.Text = Regex.Unescape(desc)
newbutton.Top = (150 + (i * 100))
fPanel.Refresh()
AddHandler newbutton.Click, AddressOf ButtonClicked
fPanel.Controls.Add(newbutton)
Next
End If
ds.Reset()
conn.Close()
Catch ex As MySqlException
Finally
conn.Dispose()
End Try`
You are not creating multiple buttons. You just keep changing the properties on the same button over and over again. Since Button is a reference type, you need to call New each time you need a new object instance
For instance, instead of this:
Dim newbutton As New Button
For i As Integer = 0 To rowscount - 1
' ...
fPanel.Controls.Add(newbutton)
Next
Do this:
For i As Integer = 0 To rowscount - 1
Dim newbutton As New Button
' ...
fPanel.Controls.Add(newbutton)
Next
Or:
Dim newbutton As Button = Nothing
For i As Integer = 0 To rowscount - 1
newbutton = New Button
' ...
fPanel.Controls.Add(newbutton)
Next