VB.NET ContextMenuStrip dynamic subitems. How to add event on each subitems? - vb.net

how can I add an event or get the text of the subitem of the contextmenustrip control after I clicked the subitem?
Here's my code:
Try
enrollment_conn.Open()
command = New SqlCommand("SELECT DISTINCT Section FROM dbo.Enrollees WHERE Grade = '" & Main.Enrollees_Cbx_grade.Text & "' AND Strand = '" & Main.Enrollees_Cbx_strand.Text & "' AND School_Year = '" & Main.Enrollees_Cbx_sy.Text & "' AND Enrolled = 'Yes'", enrollment_conn)
reader = command.ExecuteReader
Main.Enrollees_CMS_enrolleesList.Items.Clear()
Dim tm = New ToolStripMenuItem("Filter")
Main.Enrollees_CMS_enrolleesList.Items.Add(tm)
While reader.Read
tm.DropDownItems.Add(reader.Item("Section").ToString)
End While
enrollment_conn.Close()
Catch ex As Exception
MsgBox(ex.Message, vbExclamation)
End Try
The code above adds a Toolstripitem called Filter and when I right click my datagridview. The item Filter shows and has subitems which I added by using a query. The question is how can I get the text or add an event to the subitems? Thanks.

The Add method that you're using here is overloaded:
tm.DropDownItems.Add(reader.Item("Section").ToString)
You should use the overload that lets you specify a Click event handler:
tm.DropDownItems.Add(reader.Item("Section").ToString, Nothing, AddressOf MenuItem_Click)
The third argument is a delegate to the event handler method. If you're not comfortable writing that from scratch yourself, the simplest option is to let the IDE create one for you. Simply double-click a menu item in the designer and an event handler will be generated in the usual way. You can then delete the Handles clause from the end of the declaration and change the name to something more generic. You can then access the menu item that was clicked via the sender parameter, which is always a reference to the object that raised the event:
Private Sub MenuItem_Click(sender As Object, e As EventArgs)
Dim menuItem = DirectCast(sender, ToolStripMenuItem)
'Use menuItem here.
End Sub
If you need data for each menu item then you can assign it to the Tag property when you create it, e.g.
tm.DropDownItems.Add(reader.Item("Section").ToString,
Nothing,
AddressOf MenuItem_Click).Tag = reader.Item("Data")
and then get it back again in the event handler:
Private Sub MenuItem_Click(sender As Object, e As EventArgs)
Dim menuItem = DirectCast(sender, ToolStripMenuItem)
Dim data = menuItem.Tag
'Use data here.
End Sub

Related

Dynamically generated buttons from XML always have the same attributes of the last node in XML file

Using the below function, a series of buttons are generated into a flow layout panel based on an existing XML document.
The function is called at program load, and successfully generates buttons with different attributes, until they are clicked.
When the buttons are clicked, they should output it's attributes to a data grid view panel, but it only enters the attributes of the last node in the XML document.
Function loadMenuItems() As Double
m_xmld = New XmlDocument
m_xmld.Load("Menu.xml")
m_nodelist = m_xmld.GetElementsByTagName("menuItems")
For Each m_node In m_nodelist
Dim newButton As New Button
strID = m_node.Item("ID").InnerText
strName = m_node.Item("Name").InnerText
strPrice = m_node.Item("Price").InnerText
strOptions = m_node.Item("Options").InnerText
newButton.Name = "BTN_" & strID
newButton.Width = 150
newButton.Height = 150
newButton.BackgroundImageLayout = ImageLayout.Zoom
newButton.TextImageRelation = TextImageRelation.TextAboveImage
newButton.ForeColor = Color.White
newButton.Text = strName
AddHandler newButton.Click, Sub()
DGV_Receipt.Rows.Add(strName, strOptions, strPrice)
End Sub
newButton.BackgroundImage = Image.FromFile(".\Resources\Icons\" & strName & ".png")
FLP_Icons.Controls.Add(newButton)
Next
End Function 'end the function definition.
The function being loaded:
Private Sub FORM_Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
loadMenuItems()
End Sub
I am a beginner at VB, so if I'm missing something obvious, please let me know!
As suggested in the comments, the issue is your event handler. There is some nuance in how Lambda expressions work and you are running afoul of that.
One option would be to store the correct data in the Tag property, which is a general-purpose data field, of each Button, e.g.
newButton.Tag = {strName, strOptions, strPrice}
and then get the data back from the Button in the event handler:
AddHandler newButton.Click, Sub(sender, e)
Dim btn = DirectCast(sender, Button)
Dim data = DirectCast(btn.Tag, String())
DGV_Receipt.Rows.Add(data(0), data(1), data(2))
End Sub
Alternatively, define your own custom class that inherits Button, add dedicated properties for those values and then use them in your code. That custom class will work just like a regular Button but you can set those properties when you create it and then get the data back from them in the event handler.

Update From DataGridView to Database

Dim sb As New MySqlConnectionStringBuilder
sb.Server = Form1.hostname.Text
sb.UserID = Form1.rootuser.Text
sb.Password = Form1.rootpassword.Text
sb.Database = Form1.hostdb.Text
sb.Port = Form1.hostport.Text
Using connection As New MySqlConnection(sb.ConnectionString)
Try
connection.Open()
Dim adapter1 As New MySqlDataAdapter(TextBox1.Text, connection)
Dim cmdb1 = New MySqlCommandBuilder(adapter1)
Dim ds As New DataSet
Dim words As String() = TextBox1.Text.Split(New Char() {" "c})
Dim tablenamewords = (words(3))
adapter1.Update(ds, tablenamewords)
Catch ex As MySqlException
MessageBox.Show(ex.Message)
Finally
connection.Dispose()
End Try
End Using
It's giving me this error:
Update unable to find TableMapping['creature_template'] or DataTable 'creature_template'.
I want to select items then use a DataGrid to update them.
Note: tablenamewords = "creature_template"
You can solve this in alot of different methods.
I prefer to update the DB with a single query every time the the user ends editing a cell.
BUT FIRST you have to bind a source to your DataGridView!
How to bind a source:
Go to your application design an click on your DataGridView
Click on the pause/start like little button as shown:
Click on the "ComboBox" like textbox labeled as "chose data source" as shown and click on it:
It will open a "form", click on the Add data source as shown:
Follow the wizard, you can do it without any furhter explanation!
Well done, you almost completed it. Just go in your code, and look for this sub:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.your_table_nameTableAdapter.Fill(Me.your_db_nameDataSet.your_table_name)
End Sub
The line inside your Form1_Load Sub will upload the data inside your DataGridView, leave it there if you want it to load with the form or cut/paste it wherever you like.
Now you can add this the code to programmatically update the DB:
Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
Try
Dim location As Point = DataGridView1.CurrentCellAddress
Dim sqlCmd As String = "UPDATE table_name SET " & _
DataGridView1.Columns(location.X).Name.Replace("DataGridViewTextBoxColumn", "") & " = #Data " & _
"WHERE " & _
DataGridView1.Columns(0).Name.Replace("DataGridViewTextBoxColumn", "") & " = #ID"
Using myConn As New SqlConnection(My.Settings.VISURE_DA_PDFConnectionString)
myConn.Open()
Using myCmd As New SqlCommand(sqlCmd, myConn)
myCmd.Parameters.Add("#Data", SqlDbType.VarChar)
myCmd.Parameters.Add("#ID", SqlDbType.Int)
myCmd.Parameters("#Data").Value = DataGridView1.Rows(location.Y).Cells(location.X).Value
myCmd.Parameters("#ID").Value = DataGridView1.Rows(0).Cells(location.X).Value
myCmd.ExecuteNonQuery()
End Using
myConn.Close()
End Using
Catch ex As Exception
Err.Clear()
End Try
End Sub
Remarks:
location.X is the col index, location.Y is the row index
DataGridView1.Columns(0).Name This is my ID (primary key) and it is always in the first column. Change it with yours.
Don't forget to add .Replace("DataGridViewTextBoxColumn", "") whan you are getting your column name
As previously said, this code will update your DB every time the user edits one cell on your DataGridView updating only the edited cell. This is not a big issue because if you want to edit two ore more cell, every time you leave an edited cell the method DataGridView1_CellEndEdit is fired!

DataGridView : Update SQL Database when cell value changed

I have created a form which contains DataGridView and have created first column as checkbox column and fullrowselect is True.
I want like when I click the checkbox of the row or change the checkbox value of the selected row, that particular record should be updated in the database...
I wrote the query properly but facing some problems mentioned below.
Now I first tried in cell click event...
Private Sub DGVHelp_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DGVHelp.CellClick
Try
If PubHelpCode = "ACTMAST" And e.ColumnIndex = 0 Then 'if only checkbox column is clicked
cmd = New SqlCommand("Update FAMPAR SET Tag = '" & DGVHelp(0, e.RowIndex).Value & "' where Account_Code = '" & DGVHelp(1, e.RowIndex).Value & "' ", con1)
ExecuteQuery(con1, "EDITCHECKBOX") ' Its my UDF
DGV_Reset()' This clears the datagrid and fetch the data again
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
When I click the checkbox cell (First column), the event first runs and then the value of the cell is changed... i.e during cellclick event, the DGVHelp(0, e.RowIndex).Value doesn't change its value if its ticked or unticked.
I even tried cellvaluechanged event but it hanged the program by some continuous process that I don't know...
Which event should I use to complete my task??
If any other opinion/idea relating to this task is there then please share...
The Code OneDrive link shared below..
Solution Code link
You have to use DataGridView.CellValueChanged event. This is the best event to work with in your case. It is not a good idea to use MouseClick event.
https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.cellvaluechanged(v=vs.110).aspx
Inside the event sub use the DataGridViewCellEventArgs property e.columnIndex to check that the colunn edited is the one containing the checkbox. Otherwise you have to check your code.
it is better to use a Using clause when working with sqlcommand class
Using cmd as New SqlCommand("Update FAMPAR SET Tag = '" & DGVHelp(0, e.RowIndex).Value & "' where Account_Code = '" & DGVHelp(1, e.RowIndex).Value & "' ", con1)
ExecuteQuery(con1, "EDITCHECKBOX") ' Its my UDF
End Using
EDIT 1:
After checking you solution. it is not so clear but you can do some workaround.
1- Define a boolean variable m_BoolValueChanged
Private m_BoolValueChanged as Boolean = True
2- Use this variable in DGVHelp_CellValueChanged Sub to prevent infinite loop. like to following:
Private Sub DGVHelp_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DGVHelp.CellValueChanged
Try
If PubHelpCode = "ACTMAST" And e.ColumnIndex = 0 Then
If m_BoolValueChanged Then
m_BoolValueChanged = False
cmd = New SqlCommand("Update FAMPAR SET Tag = '" & DGVHelp(0, e.RowIndex).Value & "' where Account_Code = '" & DGVHelp(1, e.RowIndex).Value & "' ", con1)
ExecuteQuery(con1, "EDITCHECKBOX")
Dim ri As Integer = DGVHelp.CurrentRow.Index
DGV_Reset()
DGVHelp.Rows(ri).Selected = True
m_BoolValueChanged = False
End If
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
You may find better solution but this will helps
In this problem better solution will be use DataGridView.CellMouseClick event. This event will fire when you only click on any cell.
Private Sub DataGridView1_CellMouseClick(sender as Object, e as DataGridViewCellMouseEventArgs) _
Handles DataGridView1.CellMouseClick
'todo
End Sub

How do I pass a value from one TextBox to another TextBox in a different form?

Currently I have a TextBox on the first form called txtuserid and I want to pass the value of this to another TextBox called USERIDTextBox on a second form.
But when I try to run my code below, nothing gets passed to the TextBox on the second form. So I'm just wondering how I can pass this value from one form to another form?
Here is my code:
Private Sub cmdlogin_Click(sender As Object, e As EventArgs) Handles cmdlogin.Click
Try
If cn.State = ConnectionState.Open Then
cn.Close()
End If
cn.Open()
cmd.CommandText = "select userid,state from registration where userid= " & _
"'" & txtuserid.Text & "' and state='" & txtpw.Text & "'"
Dim dr As OleDb.OleDbDataReader
dr = cmd.ExecuteReader
If (dr.HasRows) Then
While dr.Read
' My Problem:
' This code shows the 2nd form but the USERIDTextBox value doesn't change?
Dim obj As New Sale
obj.USERIDTextBox.Text = txtuserid.Text
obj.Show()
End While
Else
MsgBox("Invalid username or PW")
End If
cn.Close()
Catch ex As Exception
End Try
End Sub
As a general rule, it's not a good idea to try accessing another object/forms controls directly. Instead, a better way to do it would be to pass the text in the 1st form's TextBox to a custom constructor on the 2nd form (the Sale one). Then the constructor on the 2nd form will be responsible for setting the value of the TextBox .
Here is an example of one way you could do this:
Sale.vb
Public Class Sale
Dim secondFormInputText As String
Public Sub New(inputTextFromFirstForm As String)
InitializeComponent()
' Set the class variable to whatever text string was passed to this form
secondFormInputText = inputTextFromFirstForm
End Sub
Private Sub Sale_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Set the textbox text using this class variable
USERIDTextBox.Text = secondFormInputText
End Sub
End Class
Login.vb
Private Sub cmdLoginExample_Click(sender As Object, e As EventArgs) Handles cmdLogin.Click
Dim obj As New Sale(txtuserid.Text)
obj.Show()
End Sub
So now instead of setting the Sale form's TextBox directly, you can pass the text on the 1st form to the constructor of the 2nd form. The constructor can then save the text it received to a class variable that the rest of the 2nd form can use.
One of the main benefits of this, is that if in the future you change your TextBox to a RichTextBox or possibly another control that might not even have a Text property, you won't have to go updating every single piece of code that tries to set the textbox value directly.
Instead you can change the TextBox to some other control, update the Sales form once with whatever changes you need to work with the new control, and none of the code on the other forms should need to be changed.
Edit:
Even though this question was specifically about how to pass a textbox value from one form to another form, you may also like to read the comments under your question. In particular, Plutonix had some very helpful advice on how you can improve your database code which might be of use to you.

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