Anchoring a Form in vb.net 2010 - winforms

my question is how to anchor a child mdi to its parent mdi so that each time the user expands or minimizes the parent form the child form automatically follows. I already tried to use the resize function in form but it doesn't help
thanks all help is appriciated

See below - a quick version I wrote, which seems to handle most anchoring scenarios. You may need to polish this code a bit. But this should get you started:
Imports System.ComponentModel
Public Class MDIChildForm
Dim p_eMyAnchor As AnchorStyles
Dim p_mdiParent As Form
Dim p_iOldHeight, p_iOldWidth As Integer
<DefaultValue(AnchorStyles.Left Or AnchorStyles.Top)>
Public Property MyAnchor As AnchorStyles
Get
Return p_eMyAnchor
End Get
Set(value As AnchorStyles)
p_eMyAnchor = value
chkAnchorTop.Checked = (p_eMyAnchor And AnchorStyles.Top)
chkAnchorLeft.Checked = (p_eMyAnchor And AnchorStyles.Left)
chkAnchorRight.Checked = (p_eMyAnchor And AnchorStyles.Right)
chkAnchorBottom.Checked = (p_eMyAnchor And AnchorStyles.Bottom)
End Set
End Property
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
p_eMyAnchor = AnchorStyles.Left Or AnchorStyles.Top
End Sub
Public Sub ShowAsMDIChild(mdiParent As Form)
p_mdiParent = mdiParent
Me.MdiParent = mdiParent
AddHandler mdiParent.ResizeBegin, AddressOf MDIParentForm_ResizeBegin
AddHandler mdiParent.ResizeEnd, AddressOf MDIParentForm_ResizeEnd
Me.Show()
End Sub
Private Sub MDIParentForm_ResizeBegin(sender As Object, e As EventArgs)
Dim frm As Form = DirectCast(sender, Form)
p_iOldWidth = frm.Width
p_iOldHeight = frm.Height
End Sub
Private Sub MDIParentForm_ResizeEnd(sender As Object, e As EventArgs)
Dim parentForm As Form = DirectCast(sender, Form)
'handling for horizontal anchoring
Dim deltaWidth As Integer = parentForm.Width - p_iOldWidth
Dim fAnchorLeft As Boolean = p_eMyAnchor And AnchorStyles.Left
Dim fAnchorRight As Boolean = p_eMyAnchor And AnchorStyles.Right
Select Case fAnchorLeft
Case True : If fAnchorRight Then Me.Width += deltaWidth
Case False
Dim coef As Single = If(fAnchorRight, 1, 0.5)
Me.Left += deltaWidth * coef
End Select
'handling for vertical anchoring
Dim deltaHeight As Integer = parentForm.Height - p_iOldHeight
Dim fAnchorTop As Boolean = p_eMyAnchor And AnchorStyles.Top
Dim fAnchorBottom As Boolean = p_eMyAnchor And AnchorStyles.Bottom
Select Case fAnchorTop
Case True : If fAnchorBottom Then Me.Height += deltaHeight
Case False
Dim coef As Single = If(fAnchorBottom, 1, 0.5)
Me.Top += deltaHeight * coef
End Select
End Sub
End Class
For horizonal anchoring, the following rules are used:
left - nothing happens (default behavior)
left and right - expand width to parent form width delta
right - move left by parent form width delta
no anchor - move left by half parent form width delta.
Same principle applies to vertical anchoring, for top and bottom respectively.
You can get the full project to play with here (Mediafire).

try this:
Me.Anchor = AnchorStyles.Bottom
Me.Anchor = AnchorStyles.Left
Me.Anchor = AnchorStyles.Right
Me.Anchor = AnchorStyles.Top

Related

VB.NET add or subtract an integer value to a SQL Server value into a label when selecting a combobox item

Following my previous question answered by #Andrew Morton, I have one more :)
Here is my whole code (not very long for now) :
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.Sql
Public Class Form1
Sub PopulateCB()
Dim connection As String = "Data Source=.\SQLEXPRESS;Initial Catalog=OST;Integrated Security=True"
Dim sql = "SELECT * FROM liste_unités"
Dim dt As New DataTable
Using conn As New SqlConnection(connection),
da As New SqlDataAdapter(sql, conn)
da.Fill(dt)
End Using
ComboBoxC1L1.DataSource = dt
ComboBoxC1L1.DisplayMember = "nom_unité"
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PopulateCB()
End Sub
Private Sub ComboBoxC1L1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBoxC1L1.SelectedIndexChanged
Dim cb = DirectCast(sender, ComboBox)
If cb.SelectedIndex >= 0 Then
Dim val = DirectCast(cb.SelectedItem, DataRowView).Row.Field(Of Integer)("cout_unité")
If ComboBoxQC1L1.Text = "ordinaire" Then
LabelPointsC1L1.Text = val
ElseIf ComboBoxQC1L1.Text = "médiocre" Then
LabelPointsC1L1.Text = val - 2
ElseIf ComboBoxQC1L1.Text = "élite" Then
LabelPointsC1L1.Text = val + 2
End If
If cb.SelectedIndex >= 0 Then
Dim val2 = DirectCast(cb.SelectedItem, DataRowView).Row.Field(Of String)("type_unité")
LabelUnitType.Text = val2
End If
End If
Try
Dim totalC1L1 As Integer
totalC1L1 = CInt(TextBoxC1L1.Text) * CInt(LabelPointsC1L1.Text)
LabelTotalC1L1.Text = totalC1L1
Catch ex As Exception
End Try
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ComboBoxQC1L1.Text = "ordinaire"
End Sub
Private Sub TextBoxC1L1_TextChanged(sender As Object, e As EventArgs) Handles TextBoxC1L1.TextChanged
Try
Dim totalC1L1 As Integer
totalC1L1 = CInt(TextBoxC1L1.Text) * CInt(LabelPointsC1L1.Text)
LabelTotalC1L1.Text = totalC1L1
Catch ex As exception
End Try
End Sub
End Class
Here is the program interface
Here is the SQL table look
Here is the program interface when the Button has been clicked
Red Arrow ComboBox text is a DropDownStyle box with 3 possible text choices:
ordinaire,
élite,
médiocre
What I want to do: when changing the red arrow combobox text, the cout_unité label should change too with a "cout_unité -2" in case of "médiocre" ComboBox text, or "cout_unité +2" in case of "élite" ComboBox text or remain = to "cout_unité" if the selected text is "ordinaire".
And it should calculate this only once from the original "cout_unité" value in the table (in case of clicking 10 times on "ordinaire", it shouldn't subtract 10 * 2 to the "cout_unité" value, only 1 * 2)
I can do it in the ComboBoxC1L1 (see code) but I can't reproduce it with this red arrow combobox (probably because of the type of data into this combobox which are "strings", I don't know).
Many thanks :)
Since there is only a single Handles clause, the following line is unnecessary. The sender can only be the ComboBox in the Handles.
Dim cb = DirectCast(sender, ComboBox)
If you set the ValueMember of the combo in the PopulateCB method, you can save a long line of code making the code more readable.
Dim val = DirectCast(cb.SelectedItem, DataRowView).Row.Field(Of Integer)("cout_unité")
To:
Dim val = CInt(ComboBoxC1L1.SelectedValue)
We need the CInt since SelectedValue is an Object.
Don't assign the DataSource until after the DisplayMember and ValueMember are set.
You are checking twice for ComboBoxC1L1.SelectedIndex >= 0.
Just include the unit type in the first If.
The user may not have to trigger the SelectedIndexChanged event if the correct value is already selected. Maybe a button click would be better.
Sub PopulateCB()
Dim connection As String = "Data Source=.\SQLEXPRESS;Initial Catalog=OST;Integrated Security=True"
Dim sql = "SELECT * FROM liste_unités"
Dim dt As New DataTable
Using conn As New SqlConnection(connection),
da As New SqlDataAdapter(sql, conn)
da.Fill(dt)
End Using
ComboBoxC1L1.DisplayMember = "nom_unité"
ComboBoxC1L1.ValueMember = "cout_unité"
ComboBoxC1L1.DataSource = dt
End Sub
Private Sub btnCalculateValue_Click(sender As Object, e As EventArgs) Handles btnCalculateValue.Click
If ComboBoxC1L1.SelectedIndex >= 0 Then
Dim val = CInt(ComboBoxC1L1.SelectedValue)
If ComboBoxQC1L1.Text = "ordinaire" Then
LabelPointsC1L1.Text = val.ToString
ElseIf ComboBoxQC1L1.Text = "médiocre" Then
LabelPointsC1L1.Text = (val - 2).ToString
ElseIf ComboBoxQC1L1.Text = "élite" Then
LabelPointsC1L1.Text = (val + 2).ToString
End If
Dim val2 = DirectCast(ComboBoxC1L1.SelectedItem, DataRowView).Row.Field(Of String)("type_unité")
LabelUnitType.Text = val2
End If
Dim totalC1L1 As Integer
totalC1L1 = CInt(TextBoxC1L1.Text) * CInt(LabelPointsC1L1.Text)
LabelTotalC1L1.Text = totalC1L1.ToString
End Sub

How to access several dymanically created Combobox at form load?

I'm creating comboboxes on form load, but the thing is once I have added a new cb I can't access (set value, edit properties, etc) of the prior ones.
See Below Example:
Sub Start_stackoverflow()
Dim strings() As String = {"Green", "Purple", "Red"}
Dim x as integer
For x = LBound(strings) To UBound(strings)
NewDropDown(x,50,100,strings(x),strings(x))
Next x
End Sub
Private Sub NewDropDown(ByVal Number As Integer, ByVal PosX As Integer, ByVal PosY As Integer, ByVal Name As String, ByVal Text As String)
cbComboBox = New ComboBox
cbComboBox.Location = New Point(150, PosY - 4%)
cbComboBox.Name = Number
cbComboBox.ForeColor = Color.White
cbComboBox.BackColor = Color.DarkBlue
cbComboBox.Text = Name
cbComboBox.AutoSize = True
Me.Controls.Add(cbComboBox)
End Sub
So this is what happens, I can create the comboboxes just fine, add the values but if I wanted to edit the combobox Green for example (since it was first) I cant.
Even If I try this:
Sub Test()
UpdateComboBoxCurrentlySelected(Green, MyValueIwantSelected)
End Sub
Sub UpdateComboBoxCurrentlySelected(ByVal SetGrpName As ComboBox, ByVal CurrentItem As String)
SetGrpName.Text = (CurrentItem)
SetGrpName.SelectedText = (CurrentItem)
SetGrpName.SelectedItem = (CurrentItem)
SetGrpName.SelectedIndex = (CurrentItem)
SetGrpName.SelectedValue = (CurrentItem)
End Sub
Can anyone shed some light on this, that way I will know how to do it properly.
Thanks
You either need to hold a reference to the object you want to edit:
' At form level
Private dropdowns As Dictionary(Of String, Combobox) = New Dictionary(Of String, ComboBox)
' Populate from Sub Start_stackoverflow()
Dim dropdown As ComboBox = Nothing
' ...
dropdown = NewDropDown(x,50,100,strings(x),strings(x))
dropdowns.Add(dropdown.Name, dropdown)
' change UpdateComboBoxCurrentlySelected signature to
Sub UpdateComboBoxCurrentlySelected(ByVal SetGrpName As String, ByVal CurrentItem As String)
' get the dropdown by name
Dim dropdown as ComboBox = dropdowns(SetGrpName)
' ...
Or you can iterate over all the controls in the form looking for the one with the name you asked for.
Dim foundControl As ComboBox = Nothing
For Each control As Control In Me.Controls
If control.GetType Is GetType(ComboBox) AndAlso (control.Name = SetGrpName) Then
foundControl = control
End If
Next
If Not Nothing Is foundControl Then
' Do something with your control.
End If

Drage and move on click a control on Canvas wpf

I want to Drag Move a userControl which is in a canvas(named as grd) and that canvas is in a larger canvas on which there are a lot of other controls. I am using this code, but it does not work. I am making mouseDown and MouseUpevents of userControl and a MouseMve event of the larger canvas which has a lot of controls.
Where is the problem?
Dim _pressed As Boolean = False
Dim grd As Canvas
Dim mp As Point
Private Sub DeviceIcon_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
_pressed = True
grd = sender
mp = mousePosition
End Sub
Private Sub DeviceIcon_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
_pressed = False
End Sub
Private Sub gridimgFloor_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles gridimgFloor.MouseMove
If _pressed = False Then Exit Sub
Dim nmp As Point = mousePosition
Dim _x As Integer = nmp.X - mp.X
Dim _y As Integer = nmp.Y - mp.Y
Dim thk As Thickness = grd.Margin
thk.Left = thk.Left + _x
thk.Top = thk.Top + _y
grd.Margin = thk
mp = nmp
End Sub
You should use e.GetPosition(parentControl) to get the position from the event args.

Winforms (Horizontal) Scrollbar Unexplained Behavior

When I resize my form with the resize handle on the bottom right corner of the form, it fires the sizechanged event of my user control. Inside the user control I have code to set the maximum and value of the horizontal scroll bar.
If I resize to the right, the code works as expected. When I resize to the left, the scrolling thumb gets really big and scrolling does not work as expected. It's as if the Maximum got set to a low number, but my Debug.WriteLine shows that this is not the case. Actually, as I slowly resize the form to be narrower, it quickly toggles between doing it right and doing it wrong.
I deal with scroll bars rarely and when I do they are always a pain. Is there a ScrollBar guru who knows why this is happening? I googled it and searched SO too, but I really don't know what to search on.
Here is my code. The relevant part is what is called from the sizechanged event handler, which is almost to the bottom of the code.
Imports System.Reflection
Public Class Grid
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.DoubleBuffer, True) 'Or ControlStyles.ResizeRedraw
End Sub
Private _FirstVisibleRow As Row
Private Property FirstVisibleRow As Row
Get
If _FirstVisibleRow Is Nothing And Rows.Any Then
_FirstVisibleRow = Rows.First
End If
Return _FirstVisibleRow
End Get
Set(value As Row)
_FirstVisibleRow = value
LastVisibleRow = GetLastVisibleRow()
End Set
End Property
Private _HeaderRow As Row
Public Property HeaderRow As Row
Get
If _HeaderRow Is Nothing Then
_HeaderRow = New Row(Me, RowHeight)
For Each Column As Column In Columns
_HeaderRow.Cells.Add(New Cell(Column, _HeaderRow))
Next
End If
Return _HeaderRow
End Get
Private Set(value As Row)
_HeaderRow = value
End Set
End Property
Private _LastVisibleRow As Row
Private Property LastVisibleRow As Row
Get
If _LastVisibleRow Is Nothing Then
_LastVisibleRow = GetLastVisibleRow()
End If
Return _LastVisibleRow
End Get
Set(value As Row)
_LastVisibleRow = value
End Set
End Property
Private _TotalColumnWidth As Integer
Friend Property TotalColumnWidth As Integer
Get
If _TotalColumnWidth = Nothing Then
_TotalColumnWidth = GetTotalColumnWidth()
End If
Return _TotalColumnWidth
End Get
Set(value As Integer)
_TotalColumnWidth = value
SetScrollBarVisibility()
End Set
End Property
Private _TotalRowHeight As Integer
Friend Property TotalRowHeight As Integer
Get
If _TotalRowHeight = Nothing Then
_TotalRowHeight = GetTotalRowHeight()
End If
Return _TotalRowHeight
End Get
Set(value As Integer)
_TotalRowHeight = value
SetScrollBarVisibility()
End Set
End Property
Private _VisibleGridSize As Size
Private Property VisibleGridSize As Size
Get
If _VisibleGridSize = Nothing Then
_VisibleGridSize = GetVisibleGridSize()
End If
Return _VisibleGridSize
End Get
Set(value As Size)
_VisibleGridSize = value
VisibleRowCount = GetVisibleRowCount()
SetScrollBarVisibility()
End Set
End Property
Private Sub SetScrollBarVisibility()
VScrollBar1.Bounds = New Rectangle(Width - VScrollBar1.Width, 0, VScrollBar1.Width, Height - IIf(HScrollBar1.Visible, HScrollBar1.Height, 0))
HScrollBar1.Bounds = New Rectangle(0, Height - HScrollBar1.Height, Width - IIf(VScrollBar1.Visible, VScrollBar1.Width, 0), HScrollBar1.Height)
VScrollBar1.Maximum = Math.Max(0, TotalRowHeight - Height - IIf(HScrollBar1.Visible, HScrollBar1.Height, 0))
HScrollBar1.Maximum = Math.Max(0, TotalColumnWidth - Width + IIf(VScrollBar1.Visible, VScrollBar1.Width, 0))
HScrollBar1.Value = 0
VScrollBar1.Visible = TotalRowHeight > VisibleGridSize.Height
HScrollBar1.Visible = TotalColumnWidth > VisibleGridSize.Width
Debug.WriteLine(String.Format("HScrollBar1.Minimum {0}, HScrollBar1.Maximum {1}, HScrollBar1.Value {2}", HScrollBar1.Minimum, HScrollBar1.Maximum, HScrollBar1.Value))
End Sub
Private _VisibleRowCount As Integer
Private Property VisibleRowCount As Integer
Get
If _VisibleRowCount = 0 Then
_VisibleRowCount = GetVisibleRowCount()
End If
Return _VisibleRowCount
End Get
Set(value As Integer)
_VisibleRowCount = value
LastVisibleRow = GetLastVisibleRow()
PageHeight = GetPageHeight()
End Set
End Property
Private Function GetLastVisibleRow() As Row
If Not Rows.Any Then Return Nothing
Return Rows(Math.Min(FirstVisibleRow.Index + VisibleRowCount - 1, Rows.Count - 1))
End Function
Private Function GetPageHeight() As Integer
Return RowHeight * GetVisibleRowCount()
End Function
Private Function GetRowHeight() As Integer
Return TextRenderer.MeasureText("X", Font).Height + 6
End Function
Private Function GetVisibleGridSize() As Size
Return New Size(Width - IIf(VScrollBar1.Visible, VScrollBar1.Width, 0),
Height - HeaderRow.Height - IIf(HScrollBar1.Visible, HScrollBar1.Height, 0)) 'don't count header row or horiz scroll bar
End Function
Private Function GetVisibleRowCount() As Integer
Return Math.Ceiling(VisibleGridSize.Height / RowHeight)
End Function
Public Shadows Sub Refresh()
ClearSelection()
_HeaderRow = Nothing
_Rows = Nothing
AutoSizeColumns()
TotalRowHeight = GetTotalRowHeight()
Invalidate()
End Sub
Friend Function GetTotalColumnWidth() As Integer
Return Columns.Select(Function(x) x.Width).Aggregate(0, Function(x, y) x + y)
End Function
Friend Function GetTotalRowHeight() As Integer
Return Rows.Select(Function(x) x.Height).Aggregate(0, Function(x, y) x + y)
End Function
Private Function VisibleRows() As List(Of Row)
Return Rows.Where(Function(x) x.Index >= FirstVisibleRow.Index AndAlso x.Index <= LastVisibleRow.Index).ToList
End Function
Private Sub Grid_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
e.Graphics.Clear(BackColor)
'e.ClipRectangle
Dim Left As Integer = -HScrollBar1.Value
For Each Column As Column In Columns
Left = Column.Draw(e.Graphics, Left)
Next
Dim Top As Integer = HeaderRow.Draw(e.Graphics)
For Each Row As Row In VisibleRows()
Top = Row.Draw(e.Graphics, Top)
Next
End Sub
Private Sub Grid_Scroll(sender As Object, e As System.Windows.Forms.ScrollEventArgs) Handles Me.Scroll
If e.ScrollOrientation = ScrollOrientation.VerticalScroll Then
Select Case e.Type
Case ScrollEventType.First
FirstVisibleRow = Rows.First
Case ScrollEventType.Last
FirstVisibleRow = Rows(Rows.Last.Index - VisibleRowCount + 1)
Case ScrollEventType.SmallDecrement
FirstVisibleRow = Rows(Math.Max(FirstVisibleRow.Index - 1, 0))
Case ScrollEventType.SmallIncrement
FirstVisibleRow = Rows(Math.Min(FirstVisibleRow.Index + 1, Rows.Last.Index - VisibleRowCount + 1))
Case ScrollEventType.LargeDecrement
FirstVisibleRow = Rows(Math.Max(FirstVisibleRow.Index - VisibleRowCount, 0))
Case ScrollEventType.LargeIncrement
FirstVisibleRow = Rows(Math.Min(LastVisibleRow.Index, Rows.Last.Index - VisibleRowCount + 1))
End Select
End If
Invalidate()
End Sub
Private Sub Grid_SizeChanged(sender As Object, e As System.EventArgs) Handles Me.SizeChanged
VisibleGridSize = GetVisibleGridSize()
End Sub
Private Sub HScrollBar1_Scroll(sender As Object, e As System.Windows.Forms.ScrollEventArgs) Handles HScrollBar1.Scroll
Invalidate()
End Sub
End Class
The AutoScroll property of my UserControl was getting set to True by a parent control. Once I set it back to False in the designer, my code works as expected 100% of the time.

Saving nameless textboxes into Database in VB.NET

I'm a student currently doing my programming coursework. I have created a piece of code which creates text boxes for the user to input the names of tracks from a vinyl. As you can choose the amount of text boxes you create, these text boxes end up not having a name (e.g. textbox1, textbox2...), this makes me unsure of how to send the values of the textboxes to the database table. The table is currently empty and only has one column. Could someone please let me know how I will send these values to the database and also the code to create a new column for the tracks. Here is my current code below:
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Label11.Show()
GroupBox1.Show()
GroupBox1.AutoSize = True
Dim number As Integer
number = TextBox8.Text
Dim boxes(number) As TextBox
Dim newbox As TextBox
For i As Integer = 1 To number
newbox = New TextBox
newbox.Size = New Drawing.Size(100, 20)
newbox.Location = New Point(10, 10 + 25 * (i - 1))
AddHandler newbox.TextChanged, AddressOf TextBox_TextChanged
boxes(i) = newbox
GroupBox1.Controls.Add(newbox)
newbox.Name = ("Trackbox" & i)
Next
End Sub
Your boxes array needs to be declared at form level.
Private boxes() As TextBox
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Label11.Show()
GroupBox1.Show()
GroupBox1.AutoSize = True
Dim number As Integer
'need to insert validation code here to make sure a number is entered in TextBox8
number = Integer.Parse(TextBox8.Text)
ReDim boxes(number)
Dim newbox As TextBox
For i As Integer = 1 To number
newbox = New TextBox
newbox.Size = New Drawing.Size(100, 20)
newbox.Location = New Point(10, 10 + 25 * (i - 1))
AddHandler newbox.TextChanged, AddressOf TextBox_TextChanged
GroupBox1.Controls.Add(newbox)
newbox.Name = ("Trackbox" & i.ToString)
boxes(i) = newbox
Next
End Sub
Then you can reference your text boxes as follows:
MessageBox.Show(boxes(5).Text)

Resources