Make checkbox.Checked = True whose corresponding PictureBox is clicked - vb.net

I have 28 CheckBoxes in a windows form. Each box has PictureBox above it. When the user clicks on a PictureBox, I want to change the BackColor of the PictureBox to green, and make its corresponding CheckBox.Checked = True
The code I am using:
Private Sub PictureBox1_Click
PictureBox1.BackColor = Color. Green
CheckBox1.Checked = true
For 28 it will be a lengthy process. Is there any easy solution?

Programmatically add MouseClick even handlers to all your PictureBoxes in Form_Load. The event handler will parse the sender (PictureBox) and find the CheckBox based on the fact that the corresponding controls' names end in the same index. Remove the handlers when the form closes.
Private pictureBoxPrefix As String = "PictureBox"
Private checkBoxPrefix As String = "CheckBox"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each pb In Me.Controls.OfType(Of PictureBox).Where(Function(p) p.Name.Contains(pictureBoxPrefix))
AddHandler pb.MouseClick, AddressOf PictureBox_MouseClick
Next
End Sub
Private Sub PictureBox_MouseClick(sender As Object, e As MouseEventArgs)
Dim index = Integer.Parse(pb.Name.Replace(pictureBoxPrefix, ""))
Dim pb = CType(sender, PictureBox)
Dim cb = CType(Me.Controls.Find($"{checkBoxPrefix}{index}", True).First(), CheckBox)
pb.BackColor = Color.Green
cb.Checked = True
End Sub
Private Sub Form1_Closed(sender As Object, e As EventArgs) Handles Me.Closed
For Each pb In Me.Controls.OfType(Of PictureBox).Where(Function(p) p.Name.Contains(pictureBoxPrefix))
RemoveHandler pb.MouseClick, AddressOf PictureBox_MouseClick
Next
End Sub

In the Load() event of your form, use Controls.Find() to get a reference to both the PictureBoxes and CheckBoxes. Store the CheckBox reference in the Tag() property of each PictureBox. Wire up the Click() event of you PB. In that event, change the color of the PB, then retrieve the CheckBox from the Tag() property and check the box as well:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 1 To 28
Dim PB As PictureBox = Me.Controls.Find("PictureBox" & i, True).FirstOrDefault
Dim CB As CheckBox = Me.Controls.Find("CheckBox" & i, True).FirstOrDefault
If Not IsNothing(PB) AndAlso Not IsNothing(CB) Then
PB.Tag = CB
CB.Tag = PB
AddHandler PB.Click, AddressOf PB_Click
AddHandler CB.CheckedChanged, AddressOf CB_CheckedChanged
End If
Next
End Sub
Private Sub PB_Click(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Dim cb As CheckBox = DirectCast(pb.Tag, CheckBox)
If pb.BackColor.Equals(Color.Green) Then
pb.BackColor = Color.Empty
cb.Checked = False
Else
pb.BackColor = Color.Green
cb.Checked = True
End If
End Sub
Private Sub CB_CheckedChanged(sender As Object, e As EventArgs)
Dim cb As CheckBox = DirectCast(sender, CheckBox)
Dim pb As PictureBox = DirectCast(cb.Tag, PictureBox)
pb.BackColor = If(cb.Checked, Color.Green, Color.Empty)
End Sub

Related

Is there a way to simplify this code? Visual Basic Here

I'm a newbie to Visual Basic and I have this code over here that's been bugging me. I can't think of another way to simplify this. Can you please help? Thanks!:
Private Sub PictureBox_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click,
PictureBox2.Click, PictureBox3.Click, PictureBox4.Click, PictureBox5.Click, PictureBox6.Click,
PictureBox7.Click, PictureBox8.Click, PictureBox9.Click, PictureBox10.Click, PictureBox11.Click,
PictureBox12.Click, PictureBox13.Click, PictureBox14.Click, PictureBox15.Click, PictureBox16.Click,
PictureBox17.Click, PictureBox18.Click, PictureBox19.Click, PictureBox20.Click, PictureBox21.Click,
PictureBox22.Click, PictureBox23.Click, PictureBox24.Click, PictureBox25.Click, PictureBox26.Click,
PictureBox27.Click, PictureBox28.Click, PictureBox29.Click, PictureBox30.Click, PictureBox31.Click,
PictureBox32.Click, PictureBox33.Click, PictureBox34.Click, PictureBox35.Click, PictureBox36.Click,
PictureBox37.Click, PictureBox38.Click, PictureBox39.Click, PictureBox40.Click, PictureBox41.Click,
PictureBox42.Click, PictureBox43.Click, PictureBox44.Click, PictureBox45.Click, PictureBox46.Click,
PictureBox47.Click, PictureBox48.Click, PictureBox49.Click, PictureBox50.Click, PictureBox51.Click,
PictureBox52.Click, PictureBox53.Click, PictureBox54.Click, PictureBox55.Click, PictureBox56.Click,
PictureBox57.Click, PictureBox58.Click, PictureBox59.Click, PictureBox60.Click, PictureBox61.Click,
PictureBox62.Click, PictureBox63.Click, PictureBox64.Click
...............
............... (stuff is down here.)
...............
...............
End Sub
You will need to store the lists in a collection of some sort. This can either be an array or a List(Of PictureBox) or if all of the controls have the same parent you can simply leverage the Controls property.
Once you have the collection in place, you will need to iterate over collection and use AddHandler to reference. Inside the referenced method, you would get the sender, and convert it to a PictureBox.
Here is an example assuming all the PictureBox controls are on the Form:
Private Sub Form1_Load(sender As Object, e As EventArgs)
For Each pb In Controls.OfType(Of PictureBox)()
AddHandler pb.Click, AddressOf pb_Click
Next
End Sub
Private Sub pb_Click(sender As Object, e As EventArgs)
Dim pb = DirectCast(sender, PictureBox)
' pb is the control that was clicked
End Sub
Here's how to build a list of the pictureboxes, with them "in order", assuming they are already on the form:
Public Class Form1
Private PBs As New List(Of PictureBox)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 1 To 64
Dim ctlName As String = "PictureBox" & i
Dim ctl As Control = Me.Controls.Find(ctlName, True).FirstOrDefault
If Not IsNothing(ctl) AndAlso TypeOf ctl Is PictureBox Then
Dim pb As PictureBox = DirectCast(ctl, PictureBox)
AddHandler pb.Click, AddressOf PB_Click
PBs.Add(pb)
Else
MessageBox.Show("Unable to find " & ctlName)
End If
Next
End Sub
Private Sub PB_Click(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
' ... do something with pb ...
End Sub
End Class
From the comments:
Wait a minute, how do I do For Each pb In Controls.OfType(Of
PictureBox)() AddHandler pb.Click, AddressOf pb_Click Next But for a
List(Of Picturebox) named "Formula"?
For Each pb As PictureBox in Formula
AddHandler pb.Click, AddressOf pb_Click
Next
Here's what you code produces after turning on the BorderStyle:

How to handle an event for TextBox and MaskTextBox without InvalidCastException?

Any buddy please correct my script, TextBox variable working done but MaskTextBox Returning error in this EnterEvent.
I want to use one Function of event-handling for TextBox and MaskTextBox
Private Sub TextBox_Enter(sender As Object, e As EventArgs) Handles OrgNameTextBox.Enter, AddressTextBox.Enter, ContactNumMaskedTextBox.Enter
Dim Tb As TextBox = CType(sender, TextBox)
Dim Mtb As MaskedTextBox = CType(sender, MaskedTextBox)
If Type = MASKTEXTBOX Then
MTb.BackColor = Color.Yellow
MTb.ForeColor = Color.Black
ElseIf Type = TextBox Then
Tb.BackColor = Color.Yellow
Tb.ForeColor = Color.Black
End If
End Sub
The event handler cannot work because there is always type conversion error
The correct version is
Private Sub TextBox_Enter(sender As Object, e As EventArgs) Handles OrgNameTextBox.Enter, AddressTextBox.Enter, ContactNumMaskedTextBox.Enter
If TypeOf sender Is MaskedTextBox Then
Dim Mtb As MaskedTextBox = CType(sender, MaskedTextBox)
Mtb.BackColor = Color.Yellow
Mtb.ForeColor = Color.Black
ElseIf TypeOf sender Is TextBox Then
Dim Tb As TextBox = CType(sender, TextBox)
Tb.BackColor = Color.Yellow
Tb.ForeColor = Color.Black
End If
End Sub
Better is using common ancestor of both controls TextBoxBase
Private Sub TextBox_Enter(sender As Object, e As EventArgs) Handles OrgNameTextBox.Enter, AddressTextBox.Enter, ContactNumMaskedTextBox.Enter
Dim bt As TextBoxBase = TryCast(sender, TextBoxBase)
If bt IsNot Nothing Then
bt.BackColor = Color.Yellow
bt.ForeColor = Color.Black
End If
End Sub
i am used Example of #Jimi and its Working...
Private Sub MaskedTextBox_Enter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OrgNameTextBox.Enter, OrgNameTextBox.Leave
CType(sender, Control).BackColor = Color.Yellow
CType(sender, Control).ForeColor = Color.Black
End Sub

Suggestion for a time grid?

In VB.NET I'm looking to build a "Time" grid very similar to the Time Restriction grid of the Parental Section of Windows: http://www.thinkbroadband.com/images/guides/time-restrictions.png
It needs to toggle between 2 colors on cell-click
I've played around with One-Cell = One-Label and it kinda works but, like the Windows Time Restriction grid, I'd like to have the labels change colors if I move over the label whilst having the left button pressed (and not only on label click).
Here is what I currently have:
Private Sub ColorToggle(sender As Object, e As MouseEventArgs) Handles Label1.Click, Label2.Click, Label3.Click 'etc..
If e.Button = Windows.Forms.MouseButtons.Left Then
sender.backcolor = If(sender.backcolor = SystemColors.Control, Color.LightGreen, SystemColors.Control)
End If
End Sub
Since the sender stays the same when I hover the labels (sender = label I've originally clicked on), this code doesn't work for my purpose.
I'm looking for suggestions!
Thanks :)
When you click on a control and you hold the mouse button down, this control captures the following mouse events, so that you won't get events from the other lables when moving the mouse over them.
The trick is to set label.Capture = False.
Lets define colors:
Private ReadOnly selectedColor As Color = Color.Blue
Private ReadOnly unselectedColor As Color = Color.White
And Booleans storing the current state of our operations
Private isSelecting As Boolean = False
Private isUnselecting As Boolean = False
(All four as fields of the form class)
Now lets write these three event handlers:
Private Sub Label_MouseDown(sender As Object, e As EventArgs)
'This event starts selecting/unselecting
Dim label = DirectCast(sender, Label)
label.Capture = False '<=== THIS IS IMPORTANT!
If label.BackColor = selectedColor Then
isUnselecting = True
Else
isSelecting = True
End If
SelectLabel(label)
End Sub
Private Sub Label_MouseUp(sender As Object, e As EventArgs)
'This event stops selecting/unselecting
isSelecting = False
isUnselecting = False
End Sub
Private Sub Label_MouseEnter(sender As Object, e As EventArgs)
SelectLabel(DirectCast(sender, Label))
End Sub
And we need this procedure that selects or unselects the labels:
Private Sub SelectLabel(label As Label)
If isSelecting Then
label.BackColor = selectedColor
ElseIf isUnselecting Then
label.BackColor = unselectedColor
End If
End Sub
That's it!
Footnote: I have created the lables like this:
Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Const w As Integer = 50, h As Integer = 50
For x = 1 To 10
For y = 1 To 10
Dim lbl As New Label() With {
.Location = New Point(x * w, y * h),
.Size = New Size(w, h),
.BorderStyle = BorderStyle.FixedSingle,
.BackColor = unselectedColor
}
AddHandler lbl.MouseDown, AddressOf Label_MouseDown
AddHandler lbl.MouseUp, AddressOf Label_MouseUp
AddHandler lbl.MouseEnter, AddressOf Label_MouseEnter
Controls.Add(lbl)
Next
Next
End Sub
I hope this isn't homework...
Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
Dim i As Integer
With dgv
.ColumnCount = 0
.DataSource = Nothing
.Columns.Add("Day", "Day")
For i = 0 To 23
.Columns.Add(i, i)
.Columns(.Columns.Count - 1).Width = 30
Next
For i = 1 To 7
.Rows.Add({i})
Next
End With
End Sub
Private Sub dgv_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellClick
dgv.CurrentCell.Style.BackColor = Color.Blue
End Sub
Here is a drag version:
Private Sub dgv_MouseUp(sender As Object, e As MouseEventArgs) Handles dgv.MouseUp
For Each cell As DataGridViewCell In dgv.SelectedCells
If cell.Style.BackColor = Color.Blue Then
cell.Style.BackColor = Color.White
Else
cell.Style.BackColor = Color.Blue
End If
Next
dgv.ClearSelection()
End Sub

ContextMenuStrip selected item lost in UserControl

I have a VB.NET User Control which is embedded into another User Control and that into a form. The inner User Control has a contextmenustrip triggered by a DataGridView row click. This successfully activates the event handler (I see the "OK" message), but the sender does not send the selected item (I don't see the other MsgBox messages). Here is the code:
Public CMSV As ContextMenuStrip
Private grdSourceViewerCurrentRow As Long
Public Sub grdSourceViewer_RowHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles grdSourceViewer.RowHeaderMouseClick
'code to review/edit source details
Select Case e.Button
Case Windows.Forms.MouseButtons.Right
grdSourceViewerCurrentRow = e.RowIndex 'retain for downstream code
CMSV = New ContextMenuStrip
AddHandler CMSV.MouseClick, AddressOf SourceViewDocumentationEdit
CMSV.Items.Add("Edit")
CMSV.Items.Add("Transfer to Evidence")
Dim Pt As Point = New Point()
Pt.X = grdSourceViewer.PointToClient(Cursor.Position).X
Pt.Y = grdSourceViewer.PointToClient(Cursor.Position).Y + 20
CMSV.Show(sender, Pt)
Case Windows.Forms.MouseButtons.Left
Exit Sub
Case Else
Exit Sub
End Select
End Sub
Public Sub SourceViewDocumentationEdit()
MsgBox("OK") 'I can see it reaches here
Dim cc As ToolStripItemCollection = CMSV.Items
Dim SelectedItem As Integer = -1
Dim SelectedValue As String = ""
For i As Integer = 0 To cc.Count - 1
If cc.Item(i).Selected Then
SelectedItem = i
SelectedValue = cc.Item(SelectedItem).Text
Exit For
End If
Next
Select Case SelectedValue
Case "Edit"
MsgBox("Edit code here")
Case "Transfer to Evidence"
MsgBox("Transfer code here")
End Select
End Sub
What is wrong here? Why am I losing the info about the item that was clicked?
Why are you recreating the menu each time?
At any rate, store the ToolStripMenuItem returned by CMSV.Items.Add() and wire that up instead.
Simplified example:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
CMSV = New ContextMenuStrip
Dim TSMI As ToolStripMenuItem
TSMI = CMSV.Items.Add("Edit")
AddHandler TSMI.Click, AddressOf TSMI_Click
TSMI = CMSV.Items.Add("Transfer to Evidence")
AddHandler TSMI.Click, AddressOf TSMI_Click
' ...
End Sub
Private Sub TSMI_Click(sender As Object, e As EventArgs)
Dim TSMI As ToolStripMenuItem = DirectCast(sender, toolstripmenuitem)
Select Case TSMI.Text
Case "Edit"
Debug.Print("...Edit Code...")
' use "grdSourceViewerCurrentRow " in here?
Case "Transfer to Evidence"
Debug.Print("...Transfer to Evidence Code...")
' use "grdSourceViewerCurrentRow " in here?
End Select
End Sub
You need to use a ToolStripMenuItem and not just a string. Then you can add the handler for it's click event.
Dim tsmi As New ToolStripMenuItem
tsmi.Text = "Edit"
AddHandler tsmi.Click, AddressOf ItemClicked
CMSV.Items.Add(tsmi)
Then the event sub:
Private Sub ItemClicked(sender As Object, e As EventArgs)
'item clicked
'sender object would be the ToolStripMenuItem
End Sub

Combobox in vb.net datagridview not showing value first time

Following is my code:
Public Class Form1
Private DT_LocalTransactionList As DataTable
Private Sub DataGridView1_CellEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEnter
DT_LocalTransactionList = New DataTable
DT_LocalTransactionList.Columns.Add("TransactionName")
DT_LocalTransactionList.Columns.Add("TransactionType")
For iVisible As Integer = 0 To 5
DT_LocalTransactionList.Rows.Add()
DT_LocalTransactionList.Rows(iVisible).Item("TransactionName") = "Name " & iVisible
DT_LocalTransactionList.Rows(iVisible).Item("TransactionType") = "Add " & iVisible
Next
If e.ColumnIndex = colName.Index Then
Dim dgvCbo As New DataGridViewComboBoxCell
dgvCbo = TryCast(DataGridView1(colName.Index, e.RowIndex), DataGridViewComboBoxCell)
dgvCbo.DataSource = DT_LocalTransactionList
dgvCbo.DisplayMember = "TransactionName"
dgvCbo.ValueMember = "TransactionType"
End If
End Sub
Private Sub DataGridView1_EditingControlShowing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
Select Case Me.DataGridView1.CurrentCell.ColumnIndex
Case colName.Index
If TypeOf e.Control Is ComboBox Then
Dim cb As ComboBox = TryCast(e.Control, ComboBox)
cb.DropDownStyle = ComboBoxStyle.DropDown
cb.AutoCompleteSource = AutoCompleteSource.ListItems
cb.AutoCompleteMode = AutoCompleteMode.Suggest
RemoveHandler cb.DrawItem, AddressOf GridCombo_DrawItem
RemoveHandler cb.DropDownClosed, AddressOf cbDropDownClosed
RemoveHandler cb.Validating, AddressOf GridCombo_Validating
RemoveHandler cb.KeyDown, AddressOf GridCombo_KeyDown
AddHandler cb.DrawItem, AddressOf GridCombo_DrawItem
cb.DrawMode = DrawMode.OwnerDrawFixed
AddHandler cb.DropDownClosed, AddressOf cbDropDownClosed
AddHandler cb.Validating, AddressOf GridCombo_Validating
AddHandler cb.KeyDown, AddressOf GridCombo_KeyDown
End If
End Select
End Sub
Private Sub GridCombo_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs)
Dim text As String = sender.GetItemText(sender.Items(e.Index))
e.DrawBackground()
Using br As New SolidBrush(e.ForeColor)
e.Graphics.DrawString(text, e.Font, Brushes.Black, e.Bounds)
End Using
e.DrawFocusRectangle()
End Sub
Private Sub cbDropDownClosed(ByVal sender As Object, ByVal e As System.EventArgs)
End Sub
Private Sub GridCombo_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs)
Dim cb As ComboBox = TryCast(sender, ComboBox)
If Not IsItemExistInList(cb) Then
e.Cancel = True
End If
End Sub
Private Sub GridCombo_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
Dim cb As ComboBox = TryCast(sender, ComboBox)
cb.Refresh()
If e.KeyCode = Keys.Enter Then
If IsItemExistInList(cb) Then
System.Windows.Forms.SendKeys.Send("{TAB}")
End If
End If
End Sub
Public Function IsItemExistInList(ByRef cboCombo As ComboBox) As Boolean
Dim blnContinue As Boolean
Dim intCount As Integer
blnContinue = False
If cboCombo.Text.Trim = "" Then
blnContinue = True
End If
If blnContinue = False Then
For intCount = 0 To cboCombo.Items.Count - 1 And blnContinue = False
If cboCombo.Text.Trim = cboCombo.GetItemText(cboCombo.Items(intCount)).Trim Then
blnContinue = True
End If
Next
End If
IsItemExistInList = blnContinue
End Function
End Class
When I type 'n' in the combobox control of datagridview then it shows all the values from Autocomplete feature, then selecting one and pressing tab it does not show the selected value in that field. When second time doing the same thing it shows correct selection there. How to implement that thing in first time?
You should look at CommitEdit method of DataGridView once the editing control is validating as per the criteria specified.
Private Sub GridCombo_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs)
Dim cb As ComboBox = TryCast(sender, ComboBox)
If Not IsItemExistInList(cb) Then
e.Cancel = True
Else
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
End If
End Sub
In this case you can ignore the value returned by CommitEdit method since the provided sample only allows values from the collection. So if value does not exist cell will not be populated.
Recommended read
I have also experienced while working with DataGridViewComboBoxColumn that it require 2-3 click in order to edit value of the cell. I would suggest to use:
DataGridView1.EditMode = DataGridViewEditMode.EditOnEnter
at some starting point. Above code itself elaborates what it does.