Access properties of controls on a programatically created user control VB .NET - vb.net

After taking a few years off from programming, I decided to start learning vb.net. I have created a user control that contains a picture box. I added some custom properties to the picture box that will hold general string data from a database.
My problem is that the user control is programatically created during run time, and during this time a DoubleClick event handler is added for the picture box that is within the user control.
I need to be able to set the custom properties for the picture box during the creation of the user control, so that when the control (picture box) is double clicked I can read these values but am unsure on how to access them.
The picture box is the entire size of the user control, or I would just add the custom properties right to the user control and add the DoubleClick event handler to that. However, double clicking needs to be done on the picture box since it takes up the entire user control, unless anyone has an idea to trigger the DoubleClick event of the user control when the picture box is double clicked.
Here is a bit of code I am using to add the user control to the form programatically -
hb_item = New PictureLoader
With hb_item
.Name = "item_" & i
.Left = itemLeft
.Top = itemTop
.SetImageSizeMode = ImageLayout.Stretch
.SetLoadingImageSizeMode = ImageLayout.Stretch
.Size = New Size(100, 126)
.SetImage = BlobToImage(sql_reader("ThumbImage"))
.Visible = True
.SetHighlight(True)
.SetHighlightColor = Color.GreenYellow
.TextColor = Color.White
.CircleColor = Color.GreenYellow
'--- THIS UPDATES ONE OF THE CUSTOM PROPERTIES FOR THE PICTURE BOX
'--- CONTAINED WITHIN THE USER CONTROL
.SetID = "test"
AddHandler .picMainClick, AddressOf frmHome.HBItem_Click
AddHandler .picMainDoubleClick, AddressOf frmHome.HBItem_DoubleClick
End With
Here is the event handler code I am trying to access the picture box's custom properties from
Public Sub HBItem_DoubleClick(ByVal sender As System.Object, ByVal e As EventArgs) Handles MyBase.DoubleClick
With sender
'--- THIS IS WHERE I WANT TO READ THE DATA IN THE CUSTOM PROPERTIES
'--- OF THE PICTURE BOX... SOMETHING SIMILAR TO THE FOLLOWING -
' Database_ID is one of the custom properties of the sender (picMain
' control on the user control)
MessageBox.Show(.Database_ID)
End With
End Sub
EDIT: Got it all worked out, thanks for everything. All that was needed was casting the sender to the actual picture box like stated, I was just looking way to deeply into things. A simple one line of code is all that was needed in the event handler -
Dim pb As xPictureBox = CType(sender, xPictureBox)
Then all the custom properties could be accessed using pb.property_here.

sender is of type System.Object - you need to cast (convert) sender to the type it actually is (in your case, your custom user control), i.e.:
Dim myControl As MyCustomControl = CType(sender, MyCustomControl)
With myControl
MessageBox.Show(.Database_ID)
End With

Related

Use a virtual Keyboard on focused Textboxes and DataGridView Cells

In my Form I have various Textboxes that I write into with an in Form keyboard I created using Buttons. I have this code in Form.Load, which uses an event handler to determine which Textbox has the Focus:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
End If
Next
Then I use this on each button to write a specific character:
Private Sub btnQ_Click(sender As Object, e As EventArgs) Handles btnQ.Click
If btnQ.Text = "Q" Then
FocussedTextbox.Text += "Q"
ElseIf btnQ.Text = "q" Then
FocussedTextbox.Text += "q"
End If
End Sub
Up to that point I'm good and everything works as intended. The problem is I also have a DataGridView I want to write into but can't focus on it selected cells as I do on Textboxes.
I tried this:
For Each control As Control In Me.Controls
If control.GetType.Equals(GetType(TextBox)) Then
Dim textBox As TextBox = control
AddHandler textBox.Enter, Sub() FocussedTextbox = textBox
ElseIf control.GetType.Equals(GetType(DataGridViewCell)) Then
Dim DGVC As DataGridView = control
AddHandler DGVC.CellBeginEdit, Sub() FocussedTextbox = DGVC
End If
Next
But it just selects my last Textbox.
I declared the variable FocussedTextbox as Control so it's not specific to Textbox but any control.
Any help will be greatly appreciated.
To add text to the current ActiveControl using Buttons, these Button must not steal the focus from the ActiveControl (otherwise they become the ActiveControl).
This way, you can also avoid all those FocusedTextbox = textBox etc. and remove that code.
You just need Buttons that don't have the Selectable attribute set. You can use a Custom Control derived from Button and remove ControlStyles.Selectable in its constructor using the SetStyle method:
Public Class ButtonNoSel
Inherits Button
Public Sub New()
SetStyle(ControlStyles.Selectable, False)
End Sub
End Class
Replace your Buttons with this one (or, well, just set the Style if you're already using Custom Controls).
To replace the existing Buttons with this Custom Control:
Add a new class object to your Project, name it ButtonNoSel, copy all the code above inside the new class to replace the two lines of code you find there.
Build the Project. You can find the ButtonNoSel Control in your ToolBox now. Replace your Buttons with this one.
Or, open up the Form's Designer file and replace (CTRL+H) all System.Windows.Forms.Button() related to the Virtual KeyBoard with ButtonNoSel.
Remove the existing event handlers, these are not needed anymore.
Add the same Click event handler in the Constructor of the class that hosts those Buttons (a Form or whatever else you're using).
You can then remove all those event handlers, one for each control, that you have now; only one event handler is needed for all:
Public Sub New()
InitializeComponent()
For Each ctrl As Control In Me.Controls.OfType(Of ButtonNoSel)
AddHandler ctrl.Click, AddressOf KeyBoardButtons_Click
Next
End Sub
Of course, you also don't need to add event handlers to any other control, this is all that's required.
Now, you can filter the Control types you want your keyboard to work on, e.g., TextBoxBase Controls (TextBox and RichTextBox), DataGridView, NumericUpDown etc.
Or filter only special cases that need special treatment (e.g., MonthCalendar).
To add the char corresponding to the Button pressed, you can use SendKeys.Send(): it will insert the new char in the current insertion point, so you don't need any other code to store and reset the caret/cursor position as it happens if you set the Text property of a Control.
In this example, I'm checking whether the ActiveControl is a TextBoxBase Control, then just send the char that the clicked Button holds.
If it's a DataGridView, first send F2 to enter Edit Mode, then send the char.
You could also just send a char (so, no filter would be required), but in this case, you'll replace, not add to, the existing value of that Cell.
Private Sub KeyBoardButtons_Click(sender As Object, e As EventArgs)
Dim selectedButton = DirectCast(sender, Control)
Dim keysToSend = String.Empty
If TypeOf ActiveControl Is TextBoxBase Then
keysToSend = selectedButton.Text
ElseIf TypeOf ActiveControl Is DataGridView Then
Dim ctrl = DirectCast(ActiveControl, DataGridView)
If TypeOf ctrl.CurrentCell IsNot DataGridViewTextBoxCell Then Return
SendKeys.Send("{F2}")
keysToSend = selectedButton.Text
Else
' Whatever else
End If
If Not String.IsNullOrEmpty(keysToSend) Then
SendKeys.Send(keysToSend)
End If
End Sub
► Note that {F2} is sent just once: when the Cell enters Edit Mode, the ActiveControl is a DataGridViewTextBoxEditingControl, hence a TextBox Control, handled by the TextBoxBase filter.
This is how it works (using just the code posted here):

How to create any one dynamic controls with a for loop without using location property and the form should grow automatically

How to create multiple button controls with a for loop without getting the controls overlapped and without using location property in Vb.Net.
I have created 'n' number of vb controls dynamically but the created controls are getting overlapped to each other. When I use location property to each controls all the controls are getting displayed as per the location value.
The real problem is, I'm using a panel of width 300 and height 300, under that I need to display the dynamically created controls. I have figured it out which is tedious work and does take a lot of time. My idea is to find the panel width and height then need to check whether the new control which is getting created has ample of space to fit inside the panel.
I need to know few things,
1) How to display the controls dynamically using for loop without getting overlapped over each other and without using location property.
2) I need the container or the panel to grow as per the number of controls which gets created dynamically.
3) Accessing each controls which got displayed using an ID or educate or explain me any better idea.
I created a new WinForms project and added a Button to the top of the form. I added a FlowLayoutPanel under that and made it narrow enough to fit a single Button widthwise. I set the AutoSize property of the FLP to True and the FlowDirection to TopDown. I then added this code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Create the new Button.
Dim btn As New Button
'Add it to the FLP
FlowLayoutPanel1.Controls.Add(btn)
'Get the position of the bottom, left of the Button relative to the form.
Dim pt = PointToClient(btn.PointToScreen(New Point(0, btn.Height)))
'Resize the form to provide clearance below the new Button.
ClientSize = New Size(ClientSize.Width, pt.Y + 10)
End Sub
I then ran the project and started clicking the Button I added. As expected, each click added a new Button to the FLP in a vertical column and the form resized to fit. In order to access such controls in code, you can simply index the Controls collection of the FLP.
try this helps you.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
'Do Something
Else
'Do Something else
End If
Panel1.Controls.Clear()
For i As Integer = 0 To 10 Step 1
Dim b15 As New Button
b15.Text = "Test3"
b15.ID = "a" & i
AddHandler b15.Click, AddressOf updateFunc
Panel1.Controls.Add(b15)
Next
End Sub

More info on click event in VB

I would like to create a bot that repeats the same action many times. Is there any way I can get more info about a click event. Lets say I click somewhere on the opened file explorer window. Can the program tell that I clicked on a specific area or button in that window? Can I make the program click or type on a specific(opened) window?
Thanks
Yes the program can tell when you click on a specific button. Whatever button it is that you clicked on will have its click event fired, if it exists. In order to manually tell the program to perform this action, you can implement the phrase..
btn.PerformClick()
where "btn" is the name of whatever button you are needing to click. Whenever this phrase is called, the btn_Click event handler will be fired just the same as if you yourself actually clicked the button.
To do the same thing with an actual window or form in your program is trickier because there are no built in methods you can call to trigger a windows form click event. But it is possible. The code that will define a window's event handler and trigger it will be..
Private Sub myWindow_Click() Handles MyBase.Click
'code you want to run on click event here
End Sub
myWindow_Click() 'where you want the click to be triggered
The above would be much simpler to simulate in a method call however.
And lastly to simulate the typing of text into a window, you could simply access the text property of the control you are wanting to alter, and then change that text property to the desired text. But judging from your question, you are wanting this to be done in a similar fashion to how a human would.
This can also be accomplished with some work, using a timer interval that appends to the text of the control.
Lets say for example, you wanted "hello world" to be typed into a text box on screen as a person would. Add a timer control to your form and set its interval to 250 or however fast you want the word to be type and in a method..
Dim str as String = ""
Dim pos as Integer = 0
Public Sub humanType(word as String)
str = word
Timer1.enabled = true
End Sub
public Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
myTextBox.Text = myTextBox.Text + str[pos]
pos = pos + 1
If pos = str.length Then
Timer1.enabled = false
End If
End Sub
If you have never worked with timer intervals before, this tutorial has some good info on them for VB.Net. http://www.techrepublic.com/article/perform-actions-at-set-intervals-with-vbnets-timer-control/
Hope it helps!

Determine an object's runtime X-location

This might be a stupid question, but I'm attempting to move a button to the left by roughly 160 pixels each time the button is pressed. However, I need to know what the x-location is of the object at runtime so I can dynamically add those 160 pixels to it. A real world example of this would be right above (if you happen to be using chrome/firefox-which who isn't?) when the new tab button moves every time a new tab is opened (additionally subtracting those pixels too which is harder because I have to figure out how to handle the tab close event within a QTab control in the QIOS devsuite).
You could do this:
Button1.Location = New Point(Button1.Location.X - 160, Button1.Location.Y)
or this:
Dim pt As Point = Button1.Location
Button1.Location = New Point(pt.X - 160, pt.Y)
or maybe this:
Dim pt As Point = Button1.Location
pt.Offset(-160, 0)
Button1.Location = pt
When you use the WinForm designer, each control on your form is assigned a unique name. When you place a control on the form, the designer automatically assigns a unique name (e.g. Button1), but you can change it to whatever you want. The designer automatically creates a class-level variable (i.e. field) for each control. The name of the variable matches the name of the control. So, for instance, if you call your control Button1, then you can access the X-location of that button via the Button1 variable, like this:
Dim x As Integer = Button1.Left
If you are writing code that is intended to handle events from multiple controls, so you wouldn't know which variable to use, you can use the event handler's sender parameter. Every event handler has a sender As Object parameter which points to the control that is raising the event.
So, for instance, in a the click event, you could do something like this:
Private Sub ClickHandler(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click, Button3.Click
Dim clickedButton As Button = DirectCast(sender, Button)
Dim x As Integer = clickedButton.Left
End Sub

Change a checkbox text and function based on checkbox.checkstate in groupbox

I'm trying to teach myself VB .net and as my first project I'm trying to design a form that functions much like the checkboxes in Gmail. Tons of checkboxes in a group and one checkbox that sits outside the group to select/deselect those within.
I've gotten far enough to have that master checkbox do its thing, but I would really like to have the form notice whenever anything within the groupbox is checked by the user, then to change its text & function automatically. The code I came up with to change the text works, but I can't figure out where to put it:
For Each ctrl As CheckBox In GroupBox1.Controls
If ctrl.CheckState = 1 Then
CheckBox1.Text = "Deselect All"
End If
Next
I can link the code to a button push or a checkbox change, but I'd like it to be automatic since having the user click something to run the check defeats the purpose. I tried double clicking the groupbox and placing the code there but it does nothing. Also tried double clicking the form background but it does nothing there either. Please help.
As you have probably noticed, there may be a few different places where you need to do this. To reuse a piece of functionality, create a new method that does that job. Double-click the form, and place this just before the End Class:
''' <summary>Update each of the CheckBoxes that in the same GroupBox</summary>
''' <param name="sender">The CheckBox that was clicked.</param>
''' <param name="e"></param>
''' <remarks>It is assumed that only checkboxed that live in a GroupBox will use this method.</remarks>
Public Sub UpdateCheckBoxState(ByVal sender As System.Object, ByVal e As System.EventArgs)
'Get the group box that the clicked checkbox lives in
Dim parentGroupBox As System.Windows.Forms.GroupBox = DirectCast(DirectCast(sender, System.Windows.Forms.CheckBox).Parent, System.Windows.Forms.GroupBox)
For Each ctrl As System.Windows.Forms.Control In parentGroupBox.Controls
'Only process the checkboxes (in case there's other stuff in the GroupBox as well)
If TypeOf ctrl Is System.Windows.Forms.CheckBox Then
'This control is a checkbox. Let's remember that to make it easier.
Dim chkBox As System.Windows.Forms.CheckBox = DirectCast(ctrl, System.Windows.Forms.CheckBox)
If chkBox.CheckState = 1 Then
chkBox.Text = "Deselect All"
Else
chkBox.Text = "Select All"
End If
End If ' - is CheckBox
Next ctrl
End Sub
Now you have a method that will do what you want, you need to connect it to each CheckBox that you want to manage. Do this by adding the following code in The Form_Load event:
AddHandler CheckBox1.CheckedChanged, AddressOf UpdateCheckBoxState
AddHandler CheckBox2.CheckedChanged, AddressOf UpdateCheckBoxState
...
So now the same method will handle the ClickChanged method of all of your connected checkboxes.
You can also update the checkBoxes in addition to when the user clicks it by calling the Method UpdateCheckBoxState(CheckBoxThatYouWantToProgramaticallyUpdate, Nothing) perhaps in Form_Load, or elsewhere.