RichEditControl event handler, prompting to save upon form close with nothing has changed - vb.net

Having an issue when closing the form and nothing has changed, it still prompts to save the form. We have a form that has multiple controls. There are a few lookup combo boxes with data. They select their data and then click a button called "view". View then brings up a few textboxes and combo boxes etc and populates with data. There is also a RichEditControl that also gets loaded. After all the data is loaded in the load event. The last line is to call the following method to set event handlers for all controls. If something has changed after that then prompt to save upon form closing.
customFunc.AddDirtyEvent(Me)
The issue is and we have test if there is no richtextbox, it works. If the only control on a form is a RichEditControl, it always prompts to save no matter what, even if nothing has changed upon load. I noticed if you have a form that has a RichEditControl, and it gets populated upon form load. Even if you call the eventhandler after that, it still prompts you to save BUT if you add the eventhandler call in the form shown event, it seems to work as it doesn't set the dirty bit again. Its almost like the events are queue at the end of the form load event. But then it goes to the shown event, the call is made there and the dirty bit doesn't get reset back to true.
Issue is in our case, we can't use a shown event, because we have a button "view" that loads all the data and populates a RichEditControl. So even if we add the event handlers after the data gets loaded in the same method, it always goes back to set the dirty bit to true. We need to somehow keep the dirty bit to false after this, so if there is no changes and they just want to view data don't prompt to save upon form closing. Below is my code.
If customFunc.IsDirty = True Then
Dim dr As DialogResult = MessageBox.Show("Do you want save changes before leaving?", "Closing Mud Report", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)
If dr = Windows.Forms.DialogResult.Yes Then
SimpleButtonSave.PerformClick()
ElseIf dr = Windows.Forms.DialogResult.Cancel Then
e.Cancel = True
End If
End If
Private Sub SetIsDirty(ByVal sender As System.Object, ByVal e As System.EventArgs)
is_Dirty = True
End Sub
Public Sub AddDirtyEvent(ByVal ctrl As Control)
For Each c As Control In ctrl.Controls
If TypeOf c Is RichEditControl Then
Dim rtb As RichEditControl = CType(c, RichEditControl)
AddHandler rtb.RtfTextChanged, AddressOf SetIsDirty
End If
If c.Controls.Count > 0 Then
AddDirtyEvent(c)
End If
Next
End Sub

In your SetIsDirty method check for RichEditControl.Modified property.
Here is example:
Private Sub SetIsDirty(ByVal sender As System.Object, ByVal e As System.EventArgs)
If TypeOf sender Is RichEditControl Then
Dim rtb As RichEditControl = CType(sender, RichEditControl)
is_Dirty = is_Dirty OrElse rtb.Modified
Else
is_Dirty = True
End If
End Sub

Related

Radio buttons fire in VB net at form load

I have a simple VB net form with two radio buttons in a group box and button outside the group box that calls another form that sets up other parameters. The radio buttons both send data over the serial port.
Form1_load event has a boolean value form_loading = True. This is checked in the rbtn handler and if true should exit the subroutine. On debug, the check changed even fires one button's event that is checked at design time and at this point the form_loading value is set to false and I have no idea why. There is no form_loading = false statement. If I remove the rbtn handler, the form_loading = True persists when the other form is called and returned. The groupbox with buttons is activated as it sees a rbtn1-CheckChanged when the form loads and form_loading value get set to false. I suspect that the rbtn event is firing as the form begins to load, before the form_loading = True statement is reached, but how do I stop it firing the button event?
As its stands, when debug start, there is an IO exception error:
Serialport is closed, and the code associated with the button is in
the buffer to send to a (closed) com port
Private Sub rbtnDon_CheckedChanged(sender As Object, e As EventArgs) Handles rbtnDon.CheckedChanged
If form_loading Then
Exit Sub
ElseIf rbtnDoff.Checked = True Then 'event fires when other button checkchanged = true, this stops it
Exit Sub
Else
data_out = (SOT + "N" + EOT)
SendtoBoard(data_out)
End If
End Sub`enter code here`
Thanks for your help Everyone. Elsewhere I found this tip: Remove the "handles rbtnDon checkchanged" from the sub:
Private Sub rbtnDon_CheckedChanged(sender As Object, e As EventArgs)handles rbtnDon checkchanged
and add this to the form1_load sub:
AddHandler rbtnDon.CheckedChanged, New EventHandler(AddressOf rbtnDon_CheckedChanged)
That seems to have solved the problem completely.
I could not add the startup code on my original post as for some reason the box will not accept two lots of separate code - or I am not doing it right:
It is here:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 0 To My.Computer.Ports.SerialPortNames.Count - 1
ccbComPort.Items.Add(My.Computer.Ports.SerialPortNames(i))
Next
If ccbComPort.Items Is Nothing Then
lblMessage.ForeColor = Color.Red
lblMessage.Text = "No Serial Ports found"
Else
ccbComPort.Text = My.Settings.oldPort
End If
ccbBaudrate.Text = My.Settings.oldBaud
pnlComPorts.Visible = True
'form_loading = True
rbtnDon.Enabled = True
AddHandler rbtnDon.CheckedChanged, New EventHandler(AddressOf rbtnDon_CheckedChanged)
End Sub
Originally I had one form with a panel for the Com port setup and everything was fine, the issue only started when I moved the port set up to form2, after which the rbtnDon event fired before form1 started.
I did try the Sub New() approach but then I just get a small blank form on debug. Adding Form1_load to it results in "NotImplemented Exception".
The method described above seems OK and fairly simple to add but maybe it is not good practice?

VB DataGridView CellMouseClick event Prevents CellMouseDoubleClick

I'm using Visual Basic to write a WinForm Application. In my DataGridView I have the Selection Mode property set to CellSelect. I am trying to set my DataGrid up so that on a single click, a few textboxes are populated with some data, and on a double click, it will open up a new form and display all kinds of other info.
I have tried both the CellClick + CellDoubleClick events as well as the CellMouseClick + CellMouseDoubleClick however, everytime I double click, the single click event fires first and prevents the doubleclick event from ever firing.
Maybe this is just a lack of understanding on my part and I need to do something different, I thought about just adding a button column and firing the buttonclick event but that will require a lot of re-coding since I hard-coded existing data columns properties such as Column(1...15).visible = false and a lot more. Anyone have any thoughts on how to get both events to fire?
Double Click event
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
CallLookup.ShowDialog()
Dim PatientID As String = SelectGrid.Rows(SelectGrid.CurrentRow.Index).Cells("PatientID").Value.ToString
PatientID = CallLookup.patientID2
End Sub
Single Click
Private Sub DataGridView1_CellMouseClick1(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseClick
Dim reader As SqlClient.SqlDataReader = mycommand.ExecuteReader
While reader.Read
Dispatchtxt2.Text = (reader("PickupDispatchedTime").ToString)
Enroute2Txt.Text = (reader("PickupEnRouteTime").ToString)
OnScene2Txt.Text = (reader("PickupOnSceneTime").ToString)
Transport2Txt.Text = (reader("PickupTransportTime").ToString)
Arrival2Txt.Text = (reader("PickupArrivalTime").ToString)
clear2txt.Text = (reader("PickupClearTime").ToString)
End While
DataGridView1.Refresh()
DataGridView1.InvalidateRow(DataGridView1.CurrentRow.Index)
Else
End If
End Sub
I left a few lines out that were just a data connection

How do I use the Tag property with forms and code in VB 2012?

I am writing a program using a database for customers and technicians. The main form (CustomerIncidents) has a toolstripbutton that opens a different form to (SearchByState) where the user inputs a state code and looks for any incidents.
If the user clicks into one of the datagrid cells I want that customers information to be stored in the TAG so that when the form is closed using the OK button that it will show back up in the main form (CustomerIncidents).
Edited 03/11/14 12:21pm
The problem is in the Main Form. When I click the OK button in the Second Form it tries to convert the DialogResult Button to a String. I can't figure out how to fix it.
Customer Form (Main Form) Opens to Secondary Form
Private Sub btnOpenState_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles btnOpenState.Click
Dim frmSearchState As New FindCustomer
----->>Dim selectedButton As DialogResult = frmSearchState.ShowDialog()
If selectedButton = Windows.Forms.DialogResult.OK Then
CustomerIDToolStripTextBox.Text = frmSearchState.Tag.ToString
End If'
Search By State Form (Secondary Form) Or "Child Form"
Private Sub btnOk_Click(message As String, ByVal e As DataGridViewCellEventArgs) Handles btnOk.Click
message = CustomersDataGridView.Rows(e.RowIndex).Cells(e.ColumnIndex).Value.ToString
Me.Tag = message
Me.DialogResult = DialogResult.OK
End Sub
The click event for a button does not have a DataGridViewCellEventArgs parameter, and will throw an exception when you try to use it.
You don't need to use the Tag property since you can just create your own property.
In your child form, create a property called GridValue:
Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
If dgv.CurrentCell Is Nothing OrElse dgv.CurrentCell.Value Is Nothing Then
MessageBox.Show("A cell needs to be selected.")
Else
Me.DialogResult = DialogResult.OK
End If
End Sub
Public ReadOnly Property GridValue As String
Get
Return dgv.CurrentCell.Value.ToString
End Get
End Property
In your parent form, you can now access your information:
Using frmSearchState As New FindCustomer
If frmSearchState.ShowDialog(Me) = DialogResult.Ok Then
CustomerIDToolStripTextBox.Text = frmSearchState.GridValue
End If
End Using
My personal approach for doing this kind of stuff is to create a public property in the child form, having the same type as the DATA you want to take back to your main form. So instead of storing DataGridView's reference in Tag property, you should really be storing the actual value that was there in the cell that the user clicked on.
For example, if your DGV cell has a string value in it, you could do something like:
Public Readonly Property StateName As String
Get
If YourDGV.SelectedCell IsNot Nothing Then
Return YourDGV.SelectedCell.Value
Else
Return ""
End If
End Get
End Property
(I have written that code by hand, so there may be some syntax problems, but you should be able to get the idea.)
You can now use ShowDialog() in the main form to bring up this child form and upon OK or Cancel, you could check the value of StateName property of your child form to get this value. The thing to remember here is that closing a form doesn't dispose off all its constituent controls and properties and therefore you can access them even after the form has finished ShowDialog() call.

Checkbox events when Form is opened and closed fire when form is reloaded

First... I am open to skinning this cat a different way if I am going at it wrong to begin with. Using VB 2010 .net 4.0 and I am very much a beginner.
I am making a product billing application that has a main form and a subform with additional options. Whenever that subform is reopened after being opened once, the checkbox events that were selected are blank by default. If I recheck them (so someone can uncheck) then any that are rechecked all refire and increase the variable again.
I ultimately need to be able to open that second form after closing it, display any checkboxes that were selected before as selected again and not increase the variable in the process.
Main form Checkbox code to set booleans and increase or decrease subtotal variable of most used products.
Private Sub chkbox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkbox1.CheckedChanged
If chkbox1.Checked = True Then
bChkbox1 = True
Subtotal += 15
Else
bChkbox1 = False
Subtotal -= 15
End If
End Sub
Main form button to launch subform with all products listed.
Private Sub btnAllProducts_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAllProducts.Click
Form3.Show()
End Sub
Subform checkbox code works perfectly the first time it is opened but not when relaunched.
Private Sub chkbox2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkbox2.CheckedChanged
If chkbox2.Checked = True Then 'also tried without the nested if with same results
If Me.IsHandleCreated = True Then 'me.visible behaves the same way
MsgBox("form visible true")'launches after clicking button but before form is actually on screen
Form1.bcheckbox2 = True
Form1.Subtotal += 105
End If
Else
Form1.bcheckbox2 = False
Form1.Subtotal -= 105
End If
End Sub
Booleans are used to check boxes that were checked on the main page or when it was open before.
If Form1.bcheckbox2 = True Then
chkbox2.Checked = True
End If
As I said, I can completely rework the code if it makes sense to do so or just fix something if I have made some sort of mistake.
For example, I was thinking of changing to wipe the subtotal on each form load and rebuild it based off the toggled booleans but it seems like there should be a much more elegant way with less overhead and I am just doing something incorrectly.
It is not common to have to tell checks and radios to ignore events while loading the form. You just need an Ignore or Loaded flag:
Public Class Form1
Private ignore As Boolean = True
...
Private Sub Form1_Load(...
' do normal stuff
ignore = False ' should be the ONLY place it is set
End Sub
Private Sub CheckBox2_CheckedChanged(...
If ignore Then Exit Sub
End Sub
The Form Designer code will fire events as it creates the form and controls, which CAN be handy for initializing stuff but often it causes trouble. Some controls will even get the same event twice. There isnt really a "reload" action for forms. If you hide them, Show() won't fire the Load event again.
You can avoid the flag and manually add the handlers for the troublesome controls when the form loads, but that can be tedious if there are lots of them. Flags can be abused and misused, but if it is set in that one spot only, its fine.
If someone is looking for alternative or have similar problem here's my workaround to detect event change so checkbox wouldn't get triggered on re-load:
If ((Me.CheckBox2.Value <> Sheets(1).Range("t6").Value) And (Me.CheckBox2 = True)) = True Then
' do your stuff
Me.CheckBox2.Value = False
Else
Me.CheckBox2.Value = True
End If
Where Sheets(1).Range("t6").Value is where checkbox2 value is being stored.
I have this assigned to a msgbox input so when vbno event is being triggered else is executed.
Cheers.

Remove the windows form controls on exit

I'm adding the form controls on loading the form manually:
Me.FieldI = New TextBox()
Me.FieldI.Location = New System.Drawing.Point(50, 10)
Me.FieldI.Name = "FieldI"
Me.FieldI.Size = New System.Drawing.Size(40, 20)
Me.FieldI.TabIndex = 5
Me.Conversion.Controls.Add(Me.FieldI)
[..]
When I close the form window and reopen it, the control is still there (with the old .Text content , because its an textbox in this case).
I would like to remove the controls that have been created while form loading on the form close event, to prevent doubling the elements on my form.
How can I achieve this?
edit
Form closing code looks following (just showing up the main form back):
Private Sub Form1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.FormClosing
Main.Show()
End Sub
The problem here is that the form is not being disposed, so when you open it again the controls are still there from the last time it was opened.
Try the following:
Using frm = New subForm()
frm.ShowDialog()
End Using
The variable frm will be disposed after the using.
Also...
You can also provide feedback from a dialog, to check whether the form was successful or not. For example:
Dim frm As New subForm()
If frm.ShowDialog = DialogResult.OK Then
'YAY!
Else
'Something failed
End If