Managing `CheckBox_Checked` Event without an infinite loop - vb.net

I know this seems like an easy fix, but I am having trouble. I have a CheckBox, when checked, I remove the data source of a DataGridView on my Windows Form and remove the ReadOnly properties of a few Textbox.
I know the CheckedChanged event will send my code into an infinite loop, but I cannot figure out which event would handle this change without changing the CheckedState each time. I have tried using Click, MouseClick, and CheckStateChanged events with no luck.
This is my current code:
Private Sub chkManual_MouseClick(sender As Object, e As EventArgs) Handles chkManual.MouseClick
If Not Me.chkManual.Checked Then
Me.chkManual.Checked = False
Me.cbRegion.SelectedIndex = -1
Me.txtIssueDate.ReadOnly = True
Me.txtCasenum.ReadOnly = True
Me.txtCommnum.ReadOnly = True
Exit Sub
Else
Me.dgDataEntry.DataSource = Nothing
Me.cbRegion.SelectedIndex = -1
Me.txtIssueDate.ReadOnly = False
Me.txtCasenum.ReadOnly = False
Me.txtCommnum.ReadOnly = False
ClearForm()
frmPDF.Hide()
Exit Sub
End If
End Sub
Properties of CheckBox: AutoCheck = True, Checked = False, and CheckState = Unchecked
I have looked into these already:
CheckBox_Checked event
Is there a simpler way to process check boxes?
CheckBox reverts to checked after being unchecked
How to check if a checkboxes state has changed
How can I prevent an assignment statement to CheckBox.Checked from raising the CheckChanged event?
http://www.vbforums.com/showthread.php?758455-CheckBox-code-got-stuck-in-an-infinite-loop-can-not-unchecked-it
EDIT
It helps if your ClearForm() sub doesn't change the CheckedState of your CheckBox back to False every time. Thank you #Visual Vincent for pointing out the obvious. Nothing is wrong with the code, changed the EventHandler to CheckedChanged
Final code (so simple):
Private Sub chkManual_CheckedChanged(sender As Object, e As EventArgs) Handles chkManual.CheckedChanged
If Me.chkManual.Checked Then
Me.dgDataEntry.DataSource = Nothing
Me.cbRegion.SelectedIndex = -1
Me.txtIssueDate.ReadOnly = False
Me.txtCasenum.ReadOnly = False
Me.txtCommnum.ReadOnly = False
ClearForm()
frmPDF.Hide()
Else
Me.cbRegion.SelectedIndex = -1
Me.txtIssueDate.ReadOnly = True
Me.txtCasenum.ReadOnly = True
Me.txtCommnum.ReadOnly = True
End If
End Sub

I'm not sure if you want the CheckBox, when Checked, to Uncheck again automatically or not!?...seems like a weird interface.
At any rate, if you want something to occur when the Check state changes:
Private Sub chkManual_CheckedChanged(sender As Object, e As EventArgs) Handles chkManual.CheckedChanged
If chkManual.Checked Then
Debug.Print("Checked")
Me.dgDataEntry.DataSource = Nothing
Me.cbRegion.SelectedIndex = -1
Me.txtIssueDate.ReadOnly = False
Me.txtCasenum.ReadOnly = False
Me.txtCommnum.ReadOnly = False
ClearForm()
frmPDF.Hide()
Else
Debug.Print("UnChecked")
Me.cbRegion.SelectedIndex = -1
Me.txtIssueDate.ReadOnly = True
Me.txtCasenum.ReadOnly = True
Me.txtCommnum.ReadOnly = True
End If
End Sub
You can uncheck the checkbox without an infinite loop like this:
Private Sub chkManual_CheckedChanged(sender As Object, e As EventArgs) Handles chkManual.CheckedChanged
Static counter As Integer
If chkManual.Checked Then
counter = counter + 1 ' just to show we're not in an infinite loop...
Debug.Print("Checked " & counter) ' just to show we're not in an infinite loop...
chkManual.Checked = False
Else
Debug.Print("UnChecked")
End If
End Sub
Not sure why you'd want to do that...seems like that would basically be a "reset" button as it couldn't stay in a checked state...

Can you remove the code that changes the checkbox state? Ex:
Me.chkManual.Checked = False
The box will check or uncheck without your code having to do it, and the event will only throw once.

I think the easiest way is to remove event listener before handling checkbox checked state. Use try-finally block to ensure that checkbox event listener is always set back.
Try
RemoveHandler chkManual AddressOf chkManual_MouseClick
Me.chkManual.Checked = False
...
Finally
AddHandler chkManual AddressOf chkManual_MouseClick
End Try

Related

How to prevent Checkbox Checkchanged event from firing in VB.Net

I have this code in my one function
If DataServices.IsGroupByMe(test) = True Then
chkGroup.Visible = True
chkGroup.Checked = True
Else
chkGroup.Checked = False
chkGroup.Visible = False
End If
Upon going through this line
chkGroup.Checked = True
It automatically calls my checkchanged event for that checkbox
Private Sub chkGroupByMe_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkGroupOper.CheckedChanged
LoadFilteredData()
End Sub
Which then distrupts the usual sequence of action to perform. Are there ways to prevent triggering the checkchanged event?
Please note that the first function in the base form. and the checkchanged event in a different child form inheriting the base.
You can simply use a variable to block the update:
private bool PreventUpdate;
// your function
If DataServices.IsGroupByMe(test) = True Then
PreventUpdate = true;
// ... all tasks
PreventUpdate = false;
// handler
Private Sub chkGroupByMe_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkGroupOper.CheckedChanged
if not PreventUpdate Then
LoadFilteredData()
End Sub
A simple method would be to remove the Event Handler before settings its value and then re-assigning it.
Before setting the checked value (or at the start of the function):
RemoveHandler chkGroup.CheckedChanged, AddressOf chkGroupByMe_CheckedChanged
And after setting the checked value (or at the end of the function):
AddHandler chkGroup.CheckedChanged, AddressOf chkGroupByMe_CheckedChanged
Note: Anytime you add an EventHandler using the method above, always make sure there is a corresponding RemoveHandler called before it. Calling RemoveHandler too many times won't be a problem, but having your events handled too many times will cause you a few headaches wondering what is going on.
This is tough to answer since we don't really know the structure of your forms, in which form each piece of code reside nor how you interact with them.
However, one option is that you create a Shared property in the base form that indicates when LoadFilterData() should be bypassed.
Put this in your base form:
Protected Shared Property BypassDataLoad As Boolean = False
Then in your function do:
If DataServices.IsGroupByMe(test) = True Then
BaseForm.BypassDataLoad = True
chkGroup.Visible = True
chkGroup.Checked = True
BaseForm.BypassDataLoad = False
Else
BaseForm.BypassDataLoad = True
chkGroup.Checked = False
chkGroup.Visible = False
BaseForm.BypassDataLoad = False
End If
...and in your event handler:
Private Sub chkGroupByMe_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkGroupOper.CheckedChanged
If Not BaseForm.BypassDataLoad Then
LoadFilteredData()
End If
End Sub
Replace BaseForm with the actual name of your base form class.
you can remove the event handler using RemoveHandler before setting the Checked property to true. Then in the else case where you set the Checked property to false you can add the eventhandler back using the AddHandler. so that whenever it is checked the actual event will fire.
You can use the "Tag" property of the checkbox in order to control the "CheckChanged" event instead of removing and re-adding the handler again.
Please try the following code:
If DataServices.IsGroupByMe(test) Then
chkGroup.Tag = "0"
chkGroup.Visible = True
chkGroup.Checked = True
Else
chkGroup.Tag = "0"
chkGroup.Checked = False
chkGroup.Visible = False
End If
Private Sub chkGroupByMe_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkGroupOper.CheckedChanged
If chkGroup.Tag <> "0" Then
LoadFilteredData()
End If
chkGroup.Tag = ""
End Sub

IndexOutOfRangeException error when DataGridView header is clicked

Iam trying to get DataGridView rowIndex and set it to textbox and all is well with this code
Private Sub dgv_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellContentClick
isitxt(e.RowIndex)
btnInsert.Enabled = False
btnUpdate.Enabled = True
btnDelete.Enabled = True
End Sub
and
Sub isitxt(ByVal x As Integer)
txtIDBarang.Text = dgv.Rows(x).Cells(0).Value
txtNamaBarang.Text = dgv.Rows(x).Cells(1).Value
cbJenisBarang.Text = dgv.Rows(x).Cells(2).Value
numHargaBeli.Value = dgv.Rows(x).Cells(3).Value
numHargaJual.Value = dgv.Rows(x).Cells(4).Value
End Sub
But i got IndexOutOfRangeException when i clicked on Column Header. how can i handle it ?
Note, that if you use CellContentClick, the code will be executed only if the user actually aims at text content of a cell. Usually a CellClick is makes more sense.
As for your code, you can debug and see, what's in "x", when you get an error - I guess "-1"... You can handle it then. However, the reason for this should not be in your code above.
You can also set SelectionMode = FullRowSelect and do it following way:
Private Sub dgv_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellClick
isitxt(Me.dgv.selectedRows(0).index)
btnInsert.Enabled = False
btnUpdate.Enabled = True
btnDelete.Enabled = True
End Sub
Unless you want to handle the cells separately, users usually prefer the FullRowSelect mode.

Checkbox does does not work in VB.Net form

I have two checkboxes for two groupboxes to enable visibility or invisibility of each one at a time but somehow one is working(chboNew) the other one(chboIssue) doesn't!
here is the code I have written for it, any help would be appreciated:
Private Sub chboIssue_CheckStateChanged(sender As Object, e As EventArgs) Handles chboIssue.CheckStateChanged
If chboIssue.Checked = True Then
gbIssueSearch.Visible = True
gbNewSearch.Visible = False
chboNew.Checked = False
ElseIf chboIssue.Checked = False Then
gbIssueSearch.Visible = False
End If
End Sub
Private Sub chboNew_CheckStateChanged(sender As Object, e As EventArgs) Handles chboNew.CheckStateChanged
If chboNew.Checked = True Then
gbNewSearch.Visible = True
gbIssueSearch.Visible = False
chboIssue.Checked = False
ElseIf chboIssue.Checked = False Then
gbNewSearch.Visible = False
End If
End Sub
If user has to choose between new issue and issue search,one at a time.
Then you should use radio buttons, instead of checkbox.
Checkbox gives idea that user can choose both checkboxes at same time.
Which in your case is not true.
Changing the name of the checkboxes is not going to solve your issue. I noticed that for your chboNew.CheckStateChanged event handler in your elseif clause you are checking if chboIssue is checked, whereas in your other handler for chboIssue both your if/else clauses look at chboIssue. I'm thinking that may be part of your issue. Also, if only one of these boxes is supposed to be checked at a time, you may want to add logic to automatically uncheck the other whenever one is checked. For instance, in your chboNew handler, "If chboNew.Checked = True Then chboIssue = False", and the inverse in your chboIssue handler. Hope this helps.

calling button class in a form in vb.net

I am herewith develop an application but I have created a class which calls button events(i.e. enable or visible)
Public Class ClassfrmLoad
Dim btnAdd As New Button
Dim btnEdit As New Button
Private Sub FormLoad()
Me.btnAdd.Visible = True
Me.btnAdd.Enabled = True
Me.btnEdit.Visible = True
Me.btnEdit.Enabled = False
End Sub
End Class
I am actually created the button events class(classfrmLoad) for the way which buttons should be enabled and visible when each & every form loading.
There are 6 buttons in the forms (frm1, frm2 etc.,) like btnAdd, btnEdit, btnCancel etc., i don't want to display the buttons(visible/enable) while loading the form.
Here is the question:
How can i call this class(classfrmLoad) events to alter (enable/visible) the buttons positioned in the forms(frm1, frm2, etc.,) and how to get the buttons events in those forms?
Dear Sergio,
Thanks for your immediate response. I am missing something and it is not as expected, here is my complete code for the form including yours.
This is the code you suggested for the classfrmLoad:
Public Class ClassfrmLoad
Public Shared Sub FormLoad(ByRef Target As Form)
For Each ctl As Control In Target.Controls
If Not TypeOf ctl Is Button Then Continue For
Dim btn As Button = DirectCast(ctl, Button)
Select Case btn.Name.ToLower()
Case "btnadd"
btn.Visible = True
btn.Enabled = True
Case "btnsave"
btn.Visible = False
btn.Enabled = False
Case "btnedit"
btn.Visible = True
btn.Enabled = True
Case "btncancel"
btn.Visible = True
btn.Enabled = False
Case "btnclose"
btn.Visible = True
btn.Enabled = True
Case "btnupdate"
btn.Visible = False
btn.Enabled = False
Case "btnfind"
btn.Visible = False
btn.Enabled = False
'and so on
End Select
Next
End Sub
End Class
This is the code for the formload event:
Private Sub frmCreate_Unit_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ClassfrmLoad.FormLoad(Me)
'Display software and title of the page
Me.Text = msgCap & " | " & " CREATE UNIT"
Me.lblComp.Text = CompName
Me.stBar_User.Text = frmMain.stBar_User.Text
Me.stBar_UserID.Text = frmMain.stBar_UserID.Text
Me.stBar_G_ID.Text = frmMain.stBar_G_ID.Text
Me.stBar_G_No.Text = frmMain.stBar_G_No.Text
Me.cboUnit.Visible = False
Me.txtUnit_Long.Visible = True
Me.btnfind.Visible = False
Me.txtUnit_ID.Enabled = False
Me.btnadd.Focus()
End Sub
Please help me to sort out this one. Thanks...
Every form in WinForms is a class instance, inherited from Form class.
Because of this, you cannot make static references to it's members from another class, given any Form instance.
Generic class won't cut it either because you're after specific class members.
I would take advantage of the Controls collection and would check it's name and type. Once caught, we can cast the control to button and set it's visibility and access.
For this, you should make small adjustments to your code:
Public Class ClassfrmLoad
Public Shared Sub FormLoad(ByRef Target As Form)
For Each ctl As Control In Target.Controls
If Not TypeOf ctl Is Button Then Continue For
Dim btn As Button = DirectCast(ctl, Button)
Select Case btn.Name.ToLower()
Case "btnadd", "btnedit"
btn.Visible = True
btn.Enabled = True
'and so on
End Select
Next
End Sub
End Class
Changed the FormLoad visibility and access. It should be shared so we don't need to create unnecessary instances of this class
Added a parameter, passe by reference that referrs the target form. This will assure that you can use it on any class that inherits Form class
Iterated the Controls collection and find a candidate based on it's type and name
When found, we cast it to Button and access it's properties normally.
It's just an example, based on your code.
You should now call it on every Form's formload handler, like so:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ClassfrmLoad.FormLoad(Me)
End Sub
Finally I got the solution. It is very simple and any way thanks to sergio.
Here is the complete code.
Public Class ClassfrmLoad
Public Shared Sub formLoad(ByVal btnAdd As Button, ByVal btnEdit As Button, ByVal btnSave As Button, ByVal btnCancel As Button, ByVal btnClose As Button, ByVal btnUpdate As Button, ByVal btnFind As Button)
btnAdd.Visible = True
btnAdd.Enabled = True
btnSave.Visible = False
btnSave.Enabled = False
btnCancel.Visible = True
btnCancel.Enabled = False
btnClose.Visible = True
btnClose.Enabled = True
btnEdit.Visible = True
btnEdit.Enabled = True
btnUpdate.Visible = False
btnUpdate.Enabled = False
btnFind.Visible = False
btnFind.Enabled = False
End Sub
End Class
And calling proceedure in a form like this:
Dim x As New ClassfrmLoad
ClassfrmLoad.formLoad(Me.btnAdd, Me.btnEdit, Me.btnSave, Me.btnCancel, Me.btnClose, Me.btnUpdate, Me.btnFind)

How to make each form it's own thread and able to update?

I am have three(4 counting the main one) threads in my application(chat app) and I want to put each form into it's own thread(one thread does not need a form so it is irrelevant). The 2 forms I am working with are clocks with a local digital font included. The problem is that threadb will start and run, but threadc will remain as the text LABEL1 and not change at all to: MM/dd/yyyy hh:mm:ss tt. I am wondering how to get these threads to work together.
Here is the thread code(creating at beginning of porgram, this is from sub official_start):
threadb = New Threading.Thread(AddressOf form3threadsub)
threadc = New Threading.Thread(AddressOf form4threadsub)
threadb.IsBackground = False
threadc.IsBackground = False
threadb.Start()
threadc.Start()
Here is the code for the thread subs:
Private Sub form3threadsub()
Dim first As Boolean = False
Do
System.Threading.Thread.Sleep(100)
If first = False Then
form3.ShowDialog()
first = True
End If
form3.Label1.Text = DateTime.UtcNow.ToString("MM/dd/yyyy hh:mm:ss tt")
form3.Update()
Loop
End Sub
Private Sub form4threadsub()
Dim first As Boolean = False
Do
System.Threading.Thread.Sleep(100)
If first = False Then
Form4.ShowDialog()
first = True
End If
Form4.Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss tt")
Form4.Update()
Loop
End Sub
Here is the button2 click:
Dim clicked As Boolean = True
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If clicked Then
threadb.Suspend()'obsolete
threadc.Suspend()'obsolete
Button2.Text = "Resume Clocks"
clicked = False
Else
threadb.Resume()'obsolete
threadc.Resume()'obsolete
Button2.Text = "Pause Clocks"
clicked = True
End If
End Sub
I think I found my working solution. I took the extra forms out and replaced them with labels on the main form. Each label is it's own thread and updates accordingly.