SQL table only updating on a specific click event, not the other - vb.net

In code shown below, clicking on the btSave will cause the table to be updated, assuming that some data in vendmast has been changed. However, clicking on the label lblMyExit will run the code but it will not recognize that vendmast should be updated. Am very perplexed. This is the first question I have ever asked. Hope I am doing it right. Dennis
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click, _
lblMyExit.Click
CmdBldr.DataAdapter = DA
CMD.CommandText = SQVEND
DA.SelectCommand = CMD
CmdBldr.DataAdapter = DA
CmdBldr.RefreshSchema()
DS.Tables("vendmast").Rows(0).EndEdit()
Try
DA.Update(DS.Tables("vendmast"))
DS.Tables("vendmast").AcceptChanges()
Catch
Debug.Print("ERROR")
End Try
End Sub

A cleaner way to do this is to put the update code in a separate method and call it from both event handlers. Six months from now it will be much easier to figure out what is going on when the label is clicked. As to why your code isn't working, is the lblMyExit.Click declared With Events in the designer code?
I don't have enough information to comment on the actual update code but be aware that database objects usually need to be disposed. It is often a bad idea to declare them outside the method where they are used. The language provides Using...End Using blocks to help you manage these objects.
Private Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSave.Click
UpdateDatabase()
End Sub
Private Sub lblMyExit_Click(sender As Object, e As EventArgs) Handles lblMyExit.Click
UpdateDatabase()
End Sub
Private Sub UpdateDatabase()
CMD.CommandText = SQVEND
DA.SelectCommand = CMD
CmdBldr.DataAdapter = DA
CmdBldr.RefreshSchema()
DS.Tables("vendmast").Rows(0).EndEdit()
Try
DA.Update(DS.Tables("vendmast"))
DS.Tables("vendmast").AcceptChanges()
Catch
Debug.Print("ERROR")
End Try
End Sub

Related

auto filter in datagridview + searchtextbox

i have an access database with an address table with different types of clients. a column with "type" and columns with data from that clients (adress, name , etc).
I have 3 buttons that open separate panels in the mainscreen that should show the 2 most relevant addresses, and 1 that shows all. In that screen i would like to filter trough the use of a textbox that will appear when they press the search button.
I'm trying to work with dragging the datagridview to my screen and now i need to know what code i should add to the textbox to make it filter the addresses in that datagridview.
My current code for that page is below here
Public Class Patienten
Private Sub btnAddPatient_Click(sender As Object, e As EventArgs) Handles btnAddPatient.Click
'maak hier een nieuwe klantenfiche in een nieuwe form (mainpatientform)
'Dim Pat_frm As New MainPatientform
'Pat_frm.display(MainPatientform.soortenum.nieuw)
NewRelationForm.Show()
End Sub
Private Sub Tbl_RelatiesBindingNavigatorSaveItem_Click(sender As Object, e As EventArgs)
Me.Validate()
Me.Tbl_RelatiesBindingSource.EndEdit()
Me.TableAdapterManager.UpdateAll(Me.PatientenDatabaseDataSetX)
End Sub
Private Sub Patienten_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'PatientenDatabaseDataSetX.tbl_Relaties' table. You can move, or remove it, as needed.
Me.Tbl_RelatiesTableAdapter.Fill(Me.PatientenDatabaseDataSetX.tbl_Relaties)
End Sub
Private Sub Tbl_RelatiesDataGridView_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles Tbl_RelatiesDataGridView.CellContentClick
MainPatientform.Show()
MainPatientform.TabControl1.SelectedIndex = 0
End Sub
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
gbxSearhbox.Visible = True
End Sub
Private Sub txtSearchPatient_TextChanged(sender As Object, e As EventArgs) Handles txtSearchPatient.TextChanged
'no idea what to put in here
End Sub
End Class
My other two screens don't have code yet (need this one first) but here i need an "autofilter" for a type of clients.
So when i open that list , i only get clients of type "x"
but since i can't even filter in the main screen, how to do that one too...
I'm a beginner
you have 2 options,
you filter your data in ms-access then throw it to your datatable,
you can filter your data programmatically by doing this :
'this is a c# example and there is an equivalent code in vb.
var data = from x in myDataTable.asEnumerable()
where x.Field<string>("type") == "typeofClient"
select x;
after you filter programmatically, you can attach it to your datatable/dataadapter then display it to your datagridview.
Please refer to this document.
DataTable.DefaultView Property
Sample code:
Dim connection As New SqlConnection(" server info")
Dim sda As New SqlDataAdapter("select * from table", connection)
Dim dt As New DataTable
sda.Fill(dt)
dt.DefaultView.RowFilter = "type = 'x'"
DataGridView1.DataSource = dt
thanks for the ideas.
The easiest answer was to simply add a line after i filled the grid:
Private Sub Patienten_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'PatientenDatabaseDataSetX.tbl_Relaties' table. You can move, or remove it, as needed.
Me.Tbl_RelatiesTableAdapter.Fill(Me.PatientenDatabaseDataSetX.tbl_Relaties)
Me.Tbl_RelatiesBindingSource.Filter = "Rel_Type='Patient'" 'This line :-)
The filter bindingsource was the key!
Many thanks to #jmcilhinney for the comment!

New form "is never disposed" message

I've recently moved over to Visual Studio 2019 V16.2 and it's now showing me a new "message" whenever I move between forms in my Windows Forms App.
IDE0067 Disposable object created by 'New FindFile' is never disposed
I've always moved to the "next" form in my project with code snippets like:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim frmFindFile As New FindFile
frmFindFile.Show()
Me.Close()
End Sub
What am I doing wrong? Should I be disposing of the form variable once the new one is showing? The below gets rid of the warning, but my second form never shows up!
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim frmFindFile As New FindFile
frmFindFile.Show()
Me.Close()
frmFindFile.Dispose()
End Sub
VB.NET has default instances of forms, so if you just use FindFile.Show() it will not give a warning.
For more information, please see the answers at Why is there a default instance of every form in VB.Net but not in C#?
I haven't seen the proper answer to this question yet, but there is one.
Original code as listed above is:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim frmFindFile As New FindFile
frmFindFile.Show()
Me.Close()
End Sub
Yet, the proper way to do this is:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Using frmFindFile As FindFile = New FindFile()
frmFindFile.Show()
End Using
Me.Close()
End Sub
This will automatically dispose of anything within the Using structure that requires disposal.
Pretty much anything that can be instantiated using the Dim/As class structure can be placed within a Using structure.
Another example would be using streamreader/writer. Instantiate it with the Using, then instead of using instance.Close(), just use End Using to close it out and dispose of it.

How to close a form that open by a BackgroundWorker.?

How to close a form that open by a BackgroundWorker.? I need to close Form3 end of the Button1_Click. This is my code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
con.Open()
Dim cmd As New SqlCommand(("SELECT * FROM sales"), con)
Dim da As New SqlDataAdapter
Dim ds As New Data.DataSet
da.SelectCommand = cmd
cmd.ExecuteNonQuery()
ds.Clear()
da.Fill(ds, "sales")
con.Close()
DataGridView1.DataSource = ds
DataGridView1.DataMember = "sales"
Form3.Close()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Form3.ShowDialog()
End Sub
The problem with your code is that, by using the class name, you are using the default instance and default instances are thread-specific. That means that the Form3 instance that you're referring to in the DoWork event handler, which is executed on a secondary thread, is a different instance than the one you're referring to in the Click event handler, which is executed on the UI thread. In order to refer to the same instance, you would need to create an instance yourself and use that in both cases.
Private f3 As Form3
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
'...
f3.Close()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
f3 = New Form3
f3.ShowDialog()
End Sub
That code is problematic though, because you're then calling the Close method on a thread other than the one the form was created on. To avoid that, you need to marshal a method call to the thread that the form was created on.
f3.Invoke(Sub() f3.Close())
That addresses your question but the real issue here is that you are trying to display a modal dialogue to prevent access to the calling form while it's doing some work but you're failing in that aim. Because you're calling ShowDialog on a secondary thread, it won't actually behave the way a modal dialogue should. That's because modality is thread-specific too.
You're actually doing things the wrong way around. You should not be displaying the form on a secondary thread and doing the work on the UI thread. Rather, you should be displaying the form on the UI thread and doing the work on a secondary thread.
Click here for a demo that does as I describe in that last paragraph.

use the same method for two different events?

So basically I've got three listboxes containing items. I want the items to be deletable, so for this I've got a ContextMenuStrip with only one item : Delete. Though, I'd like the items to be deletable, too, via a press on the Delete key. So i've got my code, that you can see here :
Dim TempList As New List(Of String)
For Each Trigger In ListBoxTriggers.SelectedItems
TempList.Add(Trigger)
Next
For Each Trigger In TempList
ListBoxTriggers.Items.Remove(Trigger)
Next
It's a little longer because there is data related stuff but now this is the part concerning the removing from the ListBox. Now, for this I've been using
Private Sub ToolStripMenuItemTriggers_Click(sender As Object, e As EventArgs) Handles SupprimerToolStripMenuItemTriggers.Click
(supprimer means delete in French). But the thing is I'd like to process the
Private Sub ListBoxDescription_KeyDown(sender As Object, e As KeyEventArgs) Handles ListBoxDescription.KeyDown
in the same method. But I can't since e is not the same type... I of course can copy the same code in both handlers but that's not really... clean. I can, too, just create another method that I'll call in both ases like
Private Sub ListBoxDescription_KeyDown(sender As Object, e As KeyEventArgs) Handles ListBoxDescription.KeyDown
Delete()
End Sub
Private Sub ToolStripMenuItemTriggers_Click(sender As Object, e As EventArgs) Handles SupprimerToolStripMenuItemTriggers.Click
Delete()
End Sub
But I don't really like it neither... doesn't look like the most efficient solution...
Is there anything I can do for this ?
Thank you in advance
KeyEventArgs derives from EventArgs, so you can declare
Private Sub ListBoxDescription_KeyDown(sender As Object, e As EventArgs) Handles ListBoxDescription.KeyDown
and if you actually need e as KeyEventArgs then you can use
Dim kea = DirectCast(e, KeyEventArgs)
Also, if your delete method has a signature like
Sub DeleteThings(sender As Object, e As EventArgs)
then you can do
AddHandler ListBoxDescription.KeyDown, AddressOf DeleteThings
AddHandler ToolStripButton1.Click, AddressOf DeleteThings
Note that you do not need a Handles clause when using AddHandler.
You'll have to write the common event handler similar to this:
Private Sub CommonEventHandler(sender As Object, e As EventArgs) _
Handles ToolStripMenuItemTriggers.Click, ListBoxDescription.KeyDown
If sender Is ListBoxDescription Then
Dim kea = DirectCast(e, KeyEventArgs)
If kea.KeyData <> Keys.F2 Then Exit Sub
End If
'' Common code
''...
End Sub
Works fine, pretty hard to win elegance points with it however. You might as well move the Common code into a separate private method. The usual advice is to treat whomever is going to maintain your code some day as a homicidal maniac that knows where you live.

Using Background Worker VB.NET

I have to show many transaction on any table. It takes so much long time to process.
I want to use a background process in visual basic 2010, but it always give an error message like this "Cross thread operation detected". I have try so many ways that i found in the internet, but still can't find what the problem is.
Please help me about how to fix this problem.
This is my code :
Private Sub CHK_A_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CHK_A.CheckedChanged
Disabled()
P_Panel.Visible = True
B_Worker.RunWorkerAsync()
End Sub
Private Sub BTN_Search_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BTN_Search.Click
USP_Select_Registration()
End Sub
Private Sub B_Worker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles B_Worker.DoWork
Threading.Thread.Sleep(25)
USP_Select_Registration()
End Sub
Private Sub B_Worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles B_Worker.RunWorkerCompleted
P_Panel.Visible = False
End Sub
This one is my store procedure
Public Sub USP_Select_Registration()
Dim Con As New SqlConnection(SQLCon)
Try
Con.Open()
Dim Cmd As New SqlCommand("USP_Select_Registration", Con)
Cmd.CommandType = CommandType.StoredProcedure
Cmd.Parameters.Add("#Check", SqlDbType.Bit).Value = CHK_A.EditValue
Cmd.Parameters.Add("#Month", SqlDbType.Int).Value = CBO_Month.SelectedIndex + 1
Cmd.Parameters.Add("#Year", SqlDbType.Int).Value = SPE_Year.EditValue
Cmd.Parameters.Add("#Search", SqlDbType.VarChar, 150).Value = TXT_Search.Text
DS_Registration.Tables("MST_Registration").Clear()
Dim Adt As New SqlDataAdapter(Cmd)
Adt.Fill(DS_Registration.Tables("MST_Registration"))
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
Finally
Con.Close()
End Try
End Sub
I think you get error because inside of USP_Select_Registration you trying to read values from form control's. Which was created by another thread.
RunWorkComleted executes in the same thread where Backgroundworker was created, thats why code P_Panel.Visible = False will executes normally.
But DoWork executes on the another thread.
And when you tried to access some forms controls to read values
TXT_Search.Text - it raise error
You can pass you searching parameters to BackgroundWorker, but you need to add parameters to USP_Select_Registration function.
For example:
Private Sub USP_Select_Registration(searchText as String)
'Your code here
End Sub
Then where you start BackgroundWorker:
B_Worker.RunWorkerAsync(TXT_Search.Text)
And
Private Sub B_Worker_DoWork(ByVal sender As Object,
ByVal e As DoWorkEventArgs) Handles B_Worker.DoWork
Threading.Thread.Sleep(25)
USP_Select_Registration(e.Argument)
End Sub
In your case you need to pass more then one parameter.
So you can create some structure/class or whatever object where you can keep all needed values. And pass that object to RunWorkerAsync