controls not being displayed - vb.net

I have two similar methods to add a user control to a panel as needed. However, upon attempting to add, the method is called and completed, but does not add the user control to the form. While attempting various different ways of adding the user control, one time I could move the initial user control around and it would move to leave space for another user control, but the user control was not visible.
Edit: the initial add method (addInitialItemGroupTest) does work
Public Sub addItemGroupTest(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine(Me.GetType.ToString() + "||" + System.Reflection.MethodInfo.GetCurrentMethod.ToString())
Dim item_block_new As New ucItemsetItemBlock
' item_block_new.Visible = True
' item_block_new.Dock = DockStyle.Top
item_block_new.flpMain.Name = (10 + item_set.blocks.Count()).ToString
item_block_new.BringToFront()
frm.flpItemBlocks.Controls.Add(item_block_new)
' item_block_new.Show()
AddHandler item_block_new.flpMain.Click, AddressOf addItemToItemBlock
End Sub
Public Sub addInitialItemGroupTest()
Console.WriteLine(Me.GetType.ToString() + "||" + System.Reflection.MethodInfo.GetCurrentMethod.ToString())
Dim item_block As New ucItemsetItemBlock
' item_block.Dock = DockStyle.Top
item_block.flpMain.Name = (10 + item_set.blocks.Count()).ToString
item_block.BringToFront()
frm.flpItemBlocks.Controls.Add(item_block)
AddHandler item_block.flpMain.Click, AddressOf addItemToItemBlock
' item_block.Sh
End Sub
Public Sub showEditor()
frm = New frmItemsetEditor
frm.TopLevel = False
frm.WindowState = FormWindowState.Maximized
frm.FormBorderStyle = FormBorderStyle.None
If frm.Location.X < 0 Then
frm.Location = New Point(0, frm.Location.Y)
End If
If frm.Location.Y < 0 Then
frm.Location = New Point(frm.Location.X, 0)
End If
frm.Show()
addItems()
If id > 0 Then
Console.WriteLine("loading item set")
For Each item_block In item_set.blocks
frm.flpItemBlocks.Controls.Add(item_block)
Next
Else
Console.WriteLine("creating item set")
item_set = New LeagueItemSet
addInitialItemGroupTest()
' addInitialItemGroup()
End If
AddHandler frm.btnAddItemGroup.Click, AddressOf addItemGroupTest
loadUserControl()
frm.pnlItemSetUserControl.Controls.Add(uc)
frm.flpItemBlocks.BringToFront()
AddHandler uc.btnAddUpdate.Click, AddressOf updateSetting
End Sub
Private Sub btnCreateItemset_Click(sender As Object, e As EventArgs) Handles btnCreateItemset.Click
Parent.AccessibleDescription = "status:Loading: Itemset Creation Wizard"
rgoism.addSetting()
rgoism._Settings.Last.frm.Parent = Me.Parent
rgoism._Settings.Last.frm.Location = New Point(Convert.ToInt32((Parent.Size.Width / 2) - (rgoism._Settings.Last.frm.Size.Width / 2)), Convert.ToInt32((Parent.Size.Height / 2) - (rgoism._Settings.Last.frm.Size.Height / 2)))
rgoism._Settings.Last.frm.BringToFront()
Me.Hide()
Parent.AccessibleDescription = "status:Ready"
End Sub

I kept debugging for nearly 12 hours straight. While nearly falling asleep I entered a bunch of console.writeline() into a method to test it since I have been lost. Next thing I know, it is adding visible user controls to the form. I just need to test them and make sure they're unique but I am too tired. I have no idea how it works now since I did not intentionally change any lines of code. Maybe I just lucked out and changed the right line of code by accident. I did comment out and back in a few lines as well. I am completely and utterly lost but it works now.

Related

Is it possible to have things defined and controlled inside a class, without being assigned in the "form" (outside the class) in VB?

My problem:
I have a checkbox I use to control if certain textboxes are enabled or not, and I need to do this around 30+ times. I've named my textboxes numerically/sequentially (TB_name_1, TB_name_2, etc) so if I know the Checkbox name I know which textboxes are affected.
My question:
Can I make a class for my checkboxes that says "if this box is checked/unchecked, then enable/disable these 3 textboxes" without the class also having to be told which textboxes (finds them itself)?
Here's the copy/paste code I'm currently using (not a class, obviously). I change the first 2 values and the rest of the code solves itself. (PS - I see you laughing)
Private Sub T1_cb_c_1_CheckedChanged(sender As Object, e As EventArgs) Handles T1_cb_c_1.CheckedChanged
'change here for current checkbox
Dim b As CheckBox = T1_cb_c_1
'change here for start value of first textbox (of 3), the next 2 will be in sequence
Dim a As Integer = 1
'How much of the below code can be moved to, and controlled from, a class?
Dim a1 As Integer = a + 1
Dim a2 As Integer = a + 2
Dim TB_PtNum As TextBox = Me.Controls.Find("T1_tb_c_" & a, True).FirstOrDefault
Dim TB_Qty As TextBox = Me.Controls.Find("T1_tb_c_" & a1, True).FirstOrDefault
Dim TB_Seq As TextBox = Me.Controls.Find("T1_tb_c_" & a2, True).FirstOrDefault
If b.Checked = True Then
TB_PtNum.Enabled = True
TB_Qty.Enabled = True
TB_Seq.Enabled = True
Else
TB_PtNum.Enabled = False
TB_Qty.Enabled = False
TB_Seq.Enabled = False
End If
End Sub
Here's a design time only class that will do this. You only have to the AssociatedCheckbox property in the designer:
Public Class TextBoxWithCheckboxProperty
Inherits TextBox
Private m_CheckBox As CheckBox
Public Property AssociatedCheckBox As CheckBox
Get
Return m_CheckBox
End Get
Set(value As CheckBox)
If Not m_CheckBox Is Nothing Then
RemoveHandler m_CheckBox.CheckedChanged, AddressOf OnCheckBoxChanged
End If
m_CheckBox = value
If Not value Is Nothing Then
AddHandler m_CheckBox.CheckedChanged, AddressOf OnCheckBoxChanged
End If
OnCheckBoxChanged(m_CheckBox, Nothing)
End Set
End Property
Private Sub OnCheckBoxChanged(ByVal sender As Object, ByVal e As System.EventArgs)
If Not sender Is Nothing Then
Me.Enabled = CType(sender, CheckBox).Checked
Else
Me.Enabled = False
End If
End Sub
End Class
Here's a sample Form1 that uses it:
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Class Form1
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.CheckBox1 = New System.Windows.Forms.CheckBox()
Me.TextBoxWithCheckboxProperty1 = New WindowsApp4.TextBoxWithCheckboxProperty()
Me.SuspendLayout()
'
'CheckBox1
'
Me.CheckBox1.AutoSize = True
Me.CheckBox1.Location = New System.Drawing.Point(293, 131)
Me.CheckBox1.Name = "CheckBox1"
Me.CheckBox1.Size = New System.Drawing.Size(81, 17)
Me.CheckBox1.TabIndex = 0
Me.CheckBox1.Text = "CheckBox1"
Me.CheckBox1.UseVisualStyleBackColor = True
'
'TextBoxWithCheckboxProperty1
'
Me.TextBoxWithCheckboxProperty1.AssociatedCheckBox = Me.CheckBox1
Me.TextBoxWithCheckboxProperty1.Location = New System.Drawing.Point(428, 131)
Me.TextBoxWithCheckboxProperty1.Name = "TextBoxWithCheckboxProperty1"
Me.TextBoxWithCheckboxProperty1.Size = New System.Drawing.Size(100, 20)
Me.TextBoxWithCheckboxProperty1.TabIndex = 1
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
Me.Controls.Add(Me.TextBoxWithCheckboxProperty1)
Me.Controls.Add(Me.CheckBox1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Friend WithEvents CheckBox1 As CheckBox
Friend WithEvents TextBoxWithCheckboxProperty1 As TextBoxWithCheckboxProperty
End Class
I would use the property Tag for the related controls.
Suppose to set this property to the value "line1" for the first set of textboxes and on the checkbox that controls them.
Next row of controls (checkbox+textboxes) will have the property set to "line2" and so on until the last row. (You can do this through the Winforms Designer or through code)
At this point you could have a single event handler for all your checkboxes
Private Sub onCheckedChanged(sender As Object, e As EventArgs) _
Handles T1_cb_c_1.CheckedChanged, T2_cb_c_2.CheckedChanged, _
..... add other checkbox events here .......
' Get whatever checkbox has been clicked and extract its tag
Dim b As CheckBox = DirectCast(sender, CheckBox)
Dim tag = b.Tag.ToString()
' Find the textbox controls in this form with the same Tag
Dim ctrls = Me.Controls.OfType(Of TextBox).Where(Function(x) x.Tag.ToString() = tag)
' Enabled status matches the status of the Checked property
For Each c as TextBox in ctrls
c.Enabled = b.Checked
Next
End Sub

Dynamically assign reference of a control

I have a desktop application where I have many textboxes inside a tab control and four tabs, as each of the tabs is exact copy.
Currently I'm assigning line by line controls to corresponding control array so I can easily access control of active tab. Each tab represents a shopping basket. And I have four tabs for now. lvBasket1 is on the fist tab, lvBasket2 is on the second etc...
Part of my code:
Private Sub InitControlsArrayAndEventHandlers()
lvBasket(0) = lvBasket1
lvBasket(1) = lvBasket2
lvBasket(2) = lvBasket3
lvBasket(3) = lvBasket4
btnSave(0) = btnSave1
btnSave(1) = btnSave2
btnSave(2) = btnSave3
btnSave(3) = btnSave4
For i As Integer = 0 To 3
AddHandler lvBasket(i).MouseDoubleClick, AddressOf lvBasket_MouseDoubleClick
AddHandler btnSave(i).Click, AddressOf btnSave_Click
Next
End Sub
Question is; Is it possible somehow to assign control reference to its array, inside the for loop. Like eval in javascript:
lvBasket(i) = Eval("lvBasket" & i)
btnSave(i) = Eval("btnSave" & i)
It looks like you already have 3 references to the controls:
The one in the controls collection
the one in the array
Possibly the lvBasketN variables shown
Since it is pretty easy to get a control from the controls collection, you really do not need a separate collection of them. To hook up a set of newly added controls to event handlers (given the name, I am assuming Listviews):
For Each lv As ListView In TabPage8.Controls.OfType(Of ListView)()
AddHandler lv.MouseDoubleClick, AddressOf lv_MouseDoubleClick
Next
And I have four tabs for now. lvBasket1 is on the fist tab, lvBasket2 is on the second etc... [an edit not in the original post]
To keep track of controls scattered across different controls collections, use a List(of T) and just add them when they are created. If you hook up event handlers as part of creating the control, you dont need a loop at all.
Private baskets As New List(of Listview)
...
Dim lv As New ListView ' e.g lvbasjket1
lv.Name = "ziggy"
... many props
AddHandler lv.MouseDoubleClick, AddressOf lvBasket_MouseDoubleClick
baskets.Add(lv) ' add to secondary collection
BasketTab1.Controls.Add(lv) ' add to controls collection
lv = New ListView ' ie lvBasket2
...
baskets.Add(lv)
BasketTab2.Controls.Add(lv)
The handlers were added as the control was created, so there is no need for any loop, though you could create them in a loop and add them to the list.
Lists are easier to work with than arrays, but baskets(0) will refer to the first one created, baskets(1) to the second etc. You can do the same thing for buttons, textboxes etc, but these are all still grouped together in each TabPage's control collection making it easy to get them without creating additional references:
' do something to basket one on tabpage 1
Dim n = 1
Dim lv = TabControl2.TabPages(n - 1).Controls().OfType(Of ListView)().FirstOrDefault()
If lv IsNot Nothing Then
' do something wonderful
End If
Yes, use Me.Controls.Find as follows:
Option Strict On
Public Class Form1
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Call InitControlsArrayAndEventHandlers()
End Sub
Private lvBasket(-1) As ListView
Private btnSave(-1) As Button
Private Sub InitControlsArrayAndEventHandlers()
Dim i As Integer = 1
Do
Dim ctl() As Control = Me.Controls.Find("lvBasket" & i.ToString, True)
If ctl.GetUpperBound(0) = -1 Then Exit Do 'finished
ReDim Preserve lvBasket(i - 1)
lvBasket(i - 1) = DirectCast(ctl(0), ListView)
ctl = Me.Controls.Find("btnSave" & i.ToString, True)
ReDim Preserve btnSave(i - 1)
btnSave(i - 1) = DirectCast(ctl(0), Button)
i += 1
Loop
For i = 0 To lvBasket.GetUpperBound(0)
AddHandler lvBasket(i).MouseDoubleClick, AddressOf lvBasket_MouseDoubleClick
AddHandler btnSave(i).Click, AddressOf btnSave_Click
Next
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs)
MsgBox(DirectCast(sender, Button).Name)
End Sub
Private Sub lvBasket_MouseDoubleClick(sender As Object, e As MouseEventArgs)
MsgBox(DirectCast(sender, ListView).Name)
End Sub
End Class
Here is how I've implemented a solution. My actual controls are named without underscore, like lvBasket1.
Imports System.Linq.Expressions
Private _txtNameSurname(BasketCount), _txtPhone(BasketCount) As TextBox
Private _btnSelectCustomer(BasketCount), _btnAddProduct(BasketCount) As Button
Private _lblInfo(BasketCount) As Label
Private _lvBasket(BasketCount) As ListView
Private Sub AssignControl(Of ControlType)(index As Integer, controlArrayFunc As_
Expression(Of Func(Of ControlType())))
Dim controlArray = controlArrayFunc.Compile()()
Dim keyword = CType(controlArrayFunc.Body, MemberExpression).Member.Name.TrimStart("_"c)
controlArray(index) =_
Me.Controls.Find(keyword & (index + 1), True).OfType(Of ControlType).Single()
End Sub
Private Sub InitControlsArrayAndEventHandlers()
For i As Integer = 0 To BasketCount
AssignControl(i, Function() _lvBasket)
AssignControl(i, Function() _txtNameSurname)
AssignControl(i, Function() _txtPhone)
AssignControl(i, Function() _btnSelectCustomer)
AssignControl(i, Function() _btnAddProduct)
AssignControl(i, Function() _lblInfo)
AddHandler _lvBasket(i).MouseDoubleClick, AddressOf vlBasket_Click
AddHandler _btnSelectCustomer(i).Click, AddressOf btnSelectCustomer_Click
Next
End Sub

Modification of the UltraDateTimeEditor background

I need to set the background color of Infragistics.Win.UltraWinEditors.UltraDateTimeEditor to yellow when the time is not today, for example. Also, I need to show a warning message when I move the cursor over the editor. I know XAML has such property I can use. How about in winform?
A quick example on how you could accomplish your goal. I am pretty sure that there are other ways to get this done, but this works
' Globals controls and Forms
Dim f As Form
Dim dt As Infragistics.Win.UltraWinEditors.UltraDateTimeEditor
Dim tt As Infragistics.Win.ToolTip
' This Main has been built using LinqPAD, you could have problems
' running it, as is in a WinForms project, but the concepts are the same
Sub Main()
dt = New UltraDateTimeEditor()
dt.Dock = DockStyle.Top
' Add the event handlers of interest to the UltraDateTimeEditor
AddHandler dt.Validating, AddressOf onValidating
AddHandler dt.Enter, AddressOf onEnter
tt = New Infragistics.Win.ToolTip(dt)
' Just another control to trigger the OnEnter and Validating events
Dim b = New Button()
b.Dock = DockStyle.Bottom
f = New Form()
f.Size = New Size(500, 500)
f.Controls.Add(dt)
f.Controls.Add(b)
f.Show()
End Sub
Sub onValidating(sender As Object , e As EventArgs)
' Some condtions to check and then set the backcolor as you wish
dt.BackColor = Color.Yellow
End Sub
Sub onEnter(sender As Object, e As EventArgs)
' Set the background back
dt.BackColor = Color.White
' Some condition to check to display the tooltip
If dt.DateTime <> DateTime.Today Then
tt.ToolTipText = "Invalid date"
' Time to leave the message visible
tt.AutoPopDelay = 2000
tt.DisplayStyle = ToolTipDisplayStyle.BalloonTip
' Calculation to set the tooltip in the middle of the editor
Dim p = New Point(dt.Left + 50, dt.Top + (dt.Height \ 2))
p = dt.PointToScreen(p)
' Show the message....
tt.Show(p)
End If
End Sub

How do I add then select the dynamic control I just added

I've got an application in VB.net which adds a picturebox to the selected mouse position within another picturebox control. I need to create a click event to select that new picturebox so I can drag it and drop it to a new location in the event that the first one was wrong or use a keypress event, those events I will code later, but I can not figure out how to select ANY of the dynamic controls.
In vb6 there was a way to select an index of the control, but there is no such animal in VB.net.
I've tried control groups, but for some reason I'm not getting results from them.
Here is the code I have so far
Private Sub PictureBox1_Click(sender As System.Object,
e As System.EventArgs) Handles PictureBox1.Click
Dim pb As New PictureBox
pb.BackColor = Color.Blue
Me.PictureBox1.Controls.Add(pb)
pb.Size = New Size(64, 110)
pb.Location = New Point(Cursor.Position.X - 64, Cursor.Position.Y - 110)
pb.Visible = True
End Sub
What in the name of all good things am I doing wrong here?
You need to write a generic event handler before time, using the sender parameter to refer to the object that raised the event.
Private Sub PictureBoxes_Click(sender As Object, e As EventArgs)
Dim pb = DirectCast(sender, PictureBox)
'Use pb here.
End Sub
When you create your control at run time, use an AddHandler statement to attach the method to the event.
Dim pb As New PictureBox
AddHandler pb.Click, AddressOf PictureBoxes_Click
That said, if you want to implement drag-n-drop then it's not the Click event you should be handling.
This little bit of code took some time, but I was able to do what I set out to so far...
This is before the Sub Main event
Public Class dynamicPB 'create a picturebox element which
'can be called anytime
Inherits PictureBox 'sets the type of control to a
'picturebox
Public Sub New() 'sets the function of the new box to
'default values
MyBase.BackColor = Color.AliceBlue
MyBase.BorderStyle = Windows.Forms.BorderStyle.Fixed3D
MyBase.Height = 50
MyBase.Width = 26
End Sub
End Class
in the actual main class
Private Sub <control_event> (blah...) Blah...
Dim intPosAdj_X As Integer = 13 'get an offset for the cursor
Dim intPosAdj_Y As Integer = 25
Dim newPictureBox As New dynamicPB 'sets the click of the mouse into a
'mode of drawing a new PB
With newPictureBox 'clean use of the code
AddHandler newPictureBox.Click, _
AddressOf PictureBox_Click 'establishes events for the mouse
'activity on the objects
AddHandler newPictureBox.MouseEnter, _
AddressOf PictureBox_MouseEnter
AddHandler newPictureBox.MouseLeave, _
AddressOf PictureBox_MouseLeave
pbName += 1 'gives a unique name to the
'picturebox in an "array" style
.Location = New System.Drawing.Point _
(xPos - intPosAdj_X, yPos - intPosAdj_Y) 'establish where the box goes
'and center the object on the
'mouse pointer
.Visible = True 'ensures that the box is visible
.Name = pbName 'names the new control
End With
Controls.Add(newPictureBox) 'add control to form
End Sub
Private Sub PictureBox_Click(sender As System.Object, e As System.EventArgs)
Dim dblMouseClick As Double = CType(DirectCast _
(e, System.Windows.Forms.MouseEventArgs).Button, MouseButtons) _
'make it simple to manipulate
'the event by putting the long
'code into a variable
If dblMouseClick = MouseButtons.Left Then
MsgBox("Left CLick")
ElseIf dblMouseClick = MouseButtons.Right Then
MsgBox("right click")
Else
MsgBox("Center")
End If
This actually resolves the issue of adding and being able to select the object
Thanks for all of the suggestions and help

New Multi-threading not working

I'm trying to create a thread so when I click a button it creates a new PictureBox from a class, this is how far I've got but nothing comes up on the screen at all.
Form1 code:
Public Class Form1
Private pgClass As New SecondUIClass
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
pgClass = New SecondUIClass
pgClass.x += 100
pgClass.thread()
End Sub
End Class
Class Code:
Imports System.Threading
Public Class SecondUIClass
Public Const count As Integer = 1000
Public emeny(count - 1) As PictureBox
Public counter As Integer = 0
Public x As Integer = 0
Private trd As Thread
Public Sub thread()
trd = New Thread(AddressOf NewUIThread)
trd.SetApartmentState(ApartmentState.STA)
trd.IsBackground = False
trd.Start()
End Sub
Private Sub NewUIThread()
emeny(counter) = New PictureBox
emeny(counter).BackColor = Color.Red
emeny(counter).Visible = True
emeny(counter).Location = New System.Drawing.Point(x, 100)
emeny(counter).Size = New System.Drawing.Size(10, 50)
Form1.Controls.Add(emeny(counter))
For z = 0 To 13
emeny(counter).Location = New Point(emeny(counter).Location.X + 10, emeny(counter).Location.Y)
Application.DoEvents()
Threading.Thread.Sleep(100)
Next
counter += 1
End Sub
End Class
I have posted something similar before on here but it was different, the pictureBoxes were showing on the screen but I was trying to get them to move at the same time but they wouldn't move, they only moved one at a time. The question that I asked before was this Multi threading classes not working correctly
I made a few assumptions for this answer so it may not work for you out of the box but I think it will put you on the right track without using any Thread.Sleep calls because I personally don't like building intentional slows to my apps but that's a personal preference really.
So For my example I just used a bunch of textboxes because I didn't have any pictures handy to fiddle with. But basically to get it so that the user can still interact with the program while the moving is happening I used a background worker thread that is started by the user and once its started it moves the textboxes down the form until the user tells it to stop or it hits an arbitrary boundary that I made up. So in theory the start would be the space bar in your app and my stop would be adding another control to the collection. For your stuff you will want to lock the collection before you add anything and while you are updating the positions but that is up to your discretion.
So the meat and potatoes:
in the designer of the form I had three buttons, btnGo, btnStop and btnReset. The code below handles the click event on those buttons so you will need to create those before this will work.
Public Class Move_Test
'Flag to tell the program whether to continue or to stop the textboxes where they are at that moment.
Private blnStop As Boolean = False
'Worker to do all the calculations in the background
Private WithEvents bgWorker As System.ComponentModel.BackgroundWorker
'Controls to be moved.
Private lstTextBoxes As List(Of TextBox)
'Dictionary to hold the y positions of the textboxes.
Private dtnPositions As Dictionary(Of Integer, Integer)
Public Sub New()
' Default code. Must be present for VB.NET forms when overwriting the default constructor.
InitializeComponent()
' Here I instantiate all the pieces. The background worker to do the adjustments to the position collection, the list of textboxes to be placed and moved around the form
' and the dictionary of positions to be used by the background worker thread and UI thread to move the textboxes(because in VB.NET you can not adjust controls created on the UI thread from a background thread.
bgWorker = New System.ComponentModel.BackgroundWorker()
Me.lstTextBoxes = New List(Of TextBox)
Me.dtnPositions = New Dictionary(Of Integer, Integer)
For i As Integer = 0 To 10
Dim t As New TextBox()
t.Name = "txt" & i
t.Text = "Textbox " & i
'I used the tag to hold the ID of the textbox that coorelated to the correct position in the dictionary,
' technically you could use the same position for all of them for this example but if you want to make the things move at different speeds
' you will need to keep track of each individually and this would allow you to do it.
t.Tag = i
dtnPositions.Add(i, 10)
'Dynamically position the controls on the form, I used 9 textboxes so i spaced them evenly across the form(divide by 10 to account for the width of the 9th text box).
t.Location = New System.Drawing.Point(((Me.Size.Width / 10) * i) + 10, dtnPositions(i))
Me.lstTextBoxes.Add(t)
Next
'This just adds the controls to the form dynamically
For Each r In Me.lstTextBoxes
Me.Controls.Add(r)
Next
End Sub
Private Sub Move_Test_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
'Don't need to do anything here. Placeholder
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message)
End Try
End Sub
Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
Try
If Not bgWorker.IsBusy Then
'User starts the movement.
bgWorker.RunWorkerAsync()
End If
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message)
End Try
End Sub
Private Sub btnReset_Click(sender As Object, e As EventArgs) Handles btnReset.Click
Try
'Reset the positions and everything else on the form for the next time through
' I don't set the blnStop value to true in here because it looked cooler to keep reseting the textboxes
' and have them jump to the top of the form and keep scrolling on their own...
For Each r In Me.lstTextBoxes
r.Location = New System.Drawing.Point(r.Location.X, 10)
Next
For i As Integer = 0 To dtnPositions.Count - 1
dtnPositions(i) = 10
Next
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message)
End Try
End Sub
Private Sub bgWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork
Try
'This is where we do all the work.
' For this test app all its doing is scrolling through each value in the dictionary and incrementing the value
' You could make the dictionary hold a custom class and have them throttle themselves using variables on the class(or maybe travel at an angle?)
For i As Integer = 0 To dtnPositions.Count - 1
dtnPositions(i) += 1
Next
Catch ex As Exception
blnStop = True
End Try
End Sub
Private Sub bgWorker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
Try
'Once the background worker is done updating the positions this function scrolls through the textboxes and assigns them their new positions.
' We have to do it in this event because we don't have access to the textboxes on the backgroun thread.
For Each r In Me.lstTextBoxes
r.Location = New System.Drawing.Point(r.Location.X, dtnPositions(CInt(r.Tag)))
Next
'use linq to find any textboxes whose position is beyond the threshhold that signifies they are down far enough.
' I chose the number 100 arbitrarily but it could really be anything.
Dim temp = From r In Me.lstTextBoxes Where r.Location.Y > (Me.Size.Height - 100)
'If we found any textboxes beyond our threshold then we set the top boolean
If temp IsNot Nothing AndAlso temp.Count > 0 Then
Me.blnStop = True
End If
'If we don't want to stop yet we fire off the background worker again and let the code go otherwise we set the stop boolean to false without firing the background worker
' so we will be all set to reset and go again if the user clicks those buttons.
If Not Me.blnStop Then
bgWorker.RunWorkerAsync()
Else
Me.blnStop = False
End If
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message)
End Try
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
Try
'The user clicked the stop button so we set the boolean and let the bgWorker_RunWorkerCompleted handle the rest.
Me.blnStop = True
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message)
End Try
End Sub
End Class
Theres a lot of code there but a lot of it is comments and I tried to be as clear as possible so they are probably a little long winded. But you should be able to plop that code on a new form and it would work without any changes. I had the form size quite large (1166 x 633). So I think that's when it works best but any size should work(smaller forms will just be more cluttered).
Let me know if this doesn't work for your application.
This is a problem that is well suited to async/await. Await allows you to pause your code to handle other events for a specific period of time..
Private Async Function Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) As Task Handles Button1.Click
pgClass = New SecondUIClass
pgClass.x += 100
await pgClass.NewUIThread()
End Sub
End Class
Class Code:
Imports System.Threading
Public Class SecondUIClass
Public Const count As Integer = 1000
Public emeny(count - 1) As PictureBox
Public counter As Integer = 0
Public x As Integer = 0
Private Async Function NewUIThread() As Task
emeny(counter) = New PictureBox
emeny(counter).BackColor = Color.Red
emeny(counter).Visible = True
emeny(counter).Location = New System.Drawing.Point(x, 100)
emeny(counter).Size = New System.Drawing.Size(10, 50)
Form1.Controls.Add(emeny(counter))
For z = 0 To 13
emeny(counter).Location = New Point(emeny(counter).Location.X + 10, emeny(counter).Location.Y)
await Task.Delay(100) 'The await state machine pauses your code here in a similar way to application.doevents() until the sleep has completed.
Next
counter += 1
End Sub
End Class