VB There is no row at position 0 - vb.net

I have a database that currently has nothing in it and I'm trying to create and save the first record, but end up getting an error that says "There is no row at position 0."
What I've done is instead of having a textbox that allows a user to select a shipper or receiver name, I've pulled those out and put in comboboxes that I've bound to the appropriate field in two other databases (shippers.mdb and receivers.mdb).
So, on clicking the "save" button, I want to save the selecteditems (saved to strings) from those comboboxes to each column cell in the database that I want. However, the system isn't letting me save the record at all. I've been trying to figure out how to save the information for the "current" record being edited or entered so for some reason I've decided to use (0), thinking that might work but it seems that isn't right. Here is the code:
Private Sub Button16_Click_1(sender As System.Object, e As System.EventArgs) Handles Button16.Click
Me.OrdersDataSet.orders(0).orderstatus = ComboBox13.SelectedItem.ToString()
shipper1 = ComboBox8.SelectedItem.ToString()
Me.OrdersDataSet.orders(0).SHIPPER1 = shipper1
RECEIVER1 = ComboBox9.SelectedItem.ToString()
Me.OrdersDataSet.orders(0).RECEIVER1 = RECEIVER1
billtoacct = ComboBox7.SelectedItem.ToString()
Me.OrdersDataSet.orders(0).BILLTOACCT = billtoacct
driverassigned = ComboBox10.SelectedItem.ToString()
Me.OrdersDataSet.orders(0).DRIVERASSIGNED = driverassigned
truckassigned = ComboBox11.SelectedItem.ToString()
Me.OrdersDataSet.orders(0).TRUCKASSIGNED = truckassigned
trailerassigned = ComboBox12.SelectedItem.ToString()
Me.OrdersDataSet.orders(0).TRAILERASSIGNED = trailerassigned
Me.Validate()
Me.OrdersBindingSource.EndEdit()
Me.TableAdapterManager12.UpdateAll(Me.OrdersDataSet)
End Sub
What should I be using instead because I can't seem to find something to let me save (or substitute) the combo box items for the current record? I did check in the table adapter that the CRUD is there and I went through to make sure it's set up to fill, update, etc.
Thanks for having a look.

Give this a shot.... PUT ALL OF THIS IN YOUR BUTTON CLICK EVENT AND CHANGE AS NEEDED...
Dim customerOrders As DataSet = New DataSet("CustomerOrders")
Dim ordersTable As DataTable = customerOrders.Tables.Add("Orders")
'ADD YOUR COLUMNS YOU NEED TO...'
ordersTable.Columns.Add("OrderQuantity", Type.GetType("System.Int32"))
ordersTable.Columns.Add("CompanyName", Type.GetType("System.String"))
'AND WHATEVER ELSE YOU NEED TO ADD, CHANGE AS NEEDED'
' Add YOUR ROWS to those columns for the datatable.
ordersTable .Rows.Add(25, "Indocin")
ordersTable .Rows.Add(50, "Enebrel")
ordersTable .Rows.Add(10, "Hydralazine")
ordersTable .Rows.Add(21, "Combivent")
ordersTable .Rows.Add(100, "Dilantin")
Then you have your dataset with the table and your data to set to your table adapter manager
Thanks!

Related

ComboBox shows the first item when loaded into new form VB.Net

I have two forms which are connected, the first one has a datagridview(DGV) that will show list of staff.
When I double click the row the data from the FGV will transfer into second form for user to edit the data. Each column from the DGV will insert at textbox combobox etc.
But the combobox on second form are using database when I double click the DGV; the others is fine but for combobox it will show the first data in database.
This is the code for the double click on the first form:
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
Dim frmEdit As New Edit
frmEdit.lblEENo.Text = DataGridView1.CurrentRow.Cells(1).Value.ToString
frmEdit.txtName.Text = DataGridView1.CurrentRow.Cells(2).Value.ToString
frmEdit.txtAge.Text = DataGridView1.CurrentRow.Cells(3).Value.ToString
frmEdit.lblAgeCategory.Text = DataGridView1.CurrentRow.Cells(4).Value.ToString
frmEdit.txtGender.Text = DataGridView1.CurrentRow.Cells(5).Value.ToString
frmEdit.cbEthnicity.Text = DataGridView1.CurrentRow.Cells(6).Value.ToString
frmEdit.cbGrade.Text = DataGridView1.CurrentRow.Cells(7).Value.ToString
frmEdit.cbCategory.Text = DataGridView1.CurrentRow.Cells(8).Value.ToString
frmEdit.cbDepartment.Text = DataGridView1.CurrentRow.Cells(9).Value.ToString
frmEdit.cbPosition.Text = DataGridView1.CurrentRow.Cells(10).Value.ToString
frmEdit.txtReporting.Text = DataGridView1.CurrentRow.Cells(11).Value.ToString
frmEdit.DateTimePicker1.Value = DataGridView1.CurrentRow.Cells(12).Value.ToString
frmEdit.DateTimePicker2.Value = DataGridView1.CurrentRow.Cells(13).Value.ToString
If DataGridView1.CurrentRow.Cells(14).Value.ToString = "Y" Then
frmEdit.rbYes.Checked = True
ElseIf DataGridView1.CurrentRow.Cells(14).Value.ToString = "N" Then
frmEdit.rbNo.Checked = True
End If
frmEdit.cbStatus.Text = DataGridView1.CurrentRow.Cells(15).Value.ToString
frmEdit.txtNote.Text = DataGridView1.CurrentRow.Cells(16).Value.ToString
frmEdit.lblMody.Text = tslblLoginAs.Text
frmEdit.ShowDialog()
load_data()
End Sub
This is second form's code for connecting to the database table for the combobox:
Private Sub Edit_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim frmMasterList As New MasterStaff
Dim poscmd As New SqlCommand("SELECT * from MasterPositionList", conn)
Dim posadapt As New SqlDataAdapter(poscmd)
Dim postable As New DataTable
posadapt.Fill(postable)
cbPosition.DataSource = postable
cbPosition.DisplayMember = "PositionName"
Dim depcmd As New SqlCommand("SELECT * from MasterDepartmentList", conn)
Dim depadapt As New SqlDataAdapter(depcmd)
Dim deptable As New DataTable
depadapt.Fill(deptable)
cbDepartment.DataSource = deptable
cbDepartment.DisplayMember = "DeparmentName"
End Sub
The form load event fires too late to populate the combobox. The event is raised almost immediately when you create the form instance in the DataGridView1_CellDoubleClick() method, but the event handler can't actually run until control is returned to the messaging loop, and there's no chance for that to happen until the frmEdit.ShowDialog() line, which is after you have set the combobox values. Therefore the Load event runs after you have populated your desired value and will overwrite that work.
To fix this, move that Load code to the constructor, just after the InitializeComponent() method.
Additionally, since you want to select from the items provided by the database you should look at using the SelectedItem or SelectedValue property, instead of the Text property.
Finally, it's really poor practice to reuse the same connection object throughout an application or form. Yes, database connections are expensive objects to create and manage, but the ADO.Net library already handles this for you. The SqlConnection object you work with in code is a light-weight wrapper over a pool of the more-expensive actual raw connections. When you try to reuse one SqlConnection, you gain efficiency in the cheap thing while losing efficiency in the more expensive thing.
Instead, create (and promptly Dispose()!) a new SqlConnection object every time you need to use the database, and think about reducing connections by reducing round-trips to the database. In this case, you can combine the two SELECT statements into a single string and fill two DataTables in the same database trip:
Private Sub New ' Replaces the current Edit_Load() method
InitializeComponent()
Dim results As New DataSet
'Using block will make sure the connection is closed, **even if an exception is thrown**
' Do NOT(!) try to reuse the connection. Only reuse the connection string.
Using conn As New SqlConnection(connString), _
' Two SELECT queries in one string
cmd As New SqlCommand("SELECT * from MasterPositionList;SELECT * from MasterDepartmentList", conn), _
da As New DataAdapter(cmd)
da.Fill(results)
End Using 'Dispose the database objects as quickly as possible
cbPosition.DisplayMember = "PositionName"
cbDepartment.DisplayMember = "DeparmentName"
cbPosition.DataSource = results.Tables(0) 'Filled two tables in one database call
cbDepartment.DataSource = results.Tables(1)
End Sub
I am wondering why you need a separate form when you could edit the data directly in the DGV. When you think of it, all the data you're trying to edit is already found in the DGV (or should exist in its datasource). You can even have combo boxes inside the DGV, with their own bound datatables. Here is an example that shows how it could be done.
In Edit_Load there is unnecessary repetition. You load the same dataset twice. You could reuse it or even load it at startup and keep it in cache if it's not changing during application runtime.
Plus, rather than fetch values from the DGV, it would better to fetch the selected datarow instead. For this you just need the record ID...
There is no need to access UI attributes, use the underlying datatable instead.
You shouldn't be using index numbers. Imagine the mess and potential for bugs if you want to insert columns or move columns. Also, the user probably can reorder columns in the DGV by drag & drop... thus your logic is ruined and the program will not behave like it should.
Anyway, to answer your issue: you've loaded a datatable, now all you have to do is bind it to the combo (which you did). You have used the DataSource and DisplayMember attributes. You could use SelectedValue to preselect a value in the list like this:
With cbPosition
.DisplayMember = "PositionName"
.ValueMember = "PositionName"
.SelectedValue = "The text value that comes from the DGV"
.DataSource = postable
End With
As long as the value from the DGV is present in the datatable this should work.
Again, I think you should simplify your UI. All the data could be edited in-place in the DGV.

What is the correct event to use to catch a new row when the user has finished editing?

I need to add several bits of data to my record such as created date and createdby when a user adds a new row in a datatable.
I am looking for the correct event on the bindingsource to catch this so i can add the information then save the record before the user moves onto the next row.
C# seems to have a RowEditEnding event on the datagrid but a)i'm not using C# and b) I can see from searching that its better to work on the datasource, which in this case is a bound datagrid so i presume i should be looking at the bindingsource object but there is not an obvious event to choose.
I think need something like currentchanged with condition if isdirty then...
Please can someone point me in the right direction here.
thanks
john
this seems to work
Private Sub TblOppQuoteDetailBindingSource_CurrentChanged(sender As Object, e As EventArgs) Handles TblOppQuoteDetailBindingSource.CurrentChanged
If sender.current IsNot Nothing Then
If sender.current.IsNew Then
Dim nr As DataRowView = sender.current
nr.Item("OppQuoteID") = 2
nr.Item("Created") = Now
nr.Item("CreatedBy") = G_UserName
ElseIf sender.current.isedit Then
Dim nr As DataRowView = sender.current
nr.Item("OppQuoteID") = 2
nr.Item("Updated") = Now
nr.Item("UpdatedBy") = G_UserName
End If
End If
End Sub
is this the correct way?

Moving Data From Databound Listbox To Unbound Listbox And Back VB.NET

So I have been browsing about and there are a lot of explanations on how to move data from listbox to listbox.
I have a listbox bound to a source from my SQL server and another unbound. My aim is to move the data from the first (LBsearch) to the second (LBselect) and back. I have seen people say use
LBselect.Items.Add(LBsearch.SelectedItem) however it doesn't return data and instead shows System.Data.DataRowView. I've tried many different suffixes and all show this apart from LBsearch.text. Then to remove the data from the first one I've been removing the databindingsource (PersonBindingSource) with
PersonBindingSource.Remove(LBsearch.SelectedItem) but my issue is adding the data back again.
PersonBindingSource.Add(LBselect.SelectedItem) gives an error:
System.InvalidOperationException: Objects added to a BindingSource's list must all be of the same type.
at System.Windows.Forms.BindingSource.Add(Object value)
at Project_Program.Participants.btnremoveselect_Click(Object sender, EventArgs e) in E:\Documents\Visual Studio\Project Program\Project Program\Participants.vb:line 39
PersonBindingSource.Add(PersonBindingSource.Item(LBsearch.SelectedIndex))
gives an error:
System.ArgumentException: Cannot add external objects to this list.
at System.Data.DataView.System.Collections.IList.Add(Object value)
at System.Windows.Forms.BindingSource.Add(Object value)
at Project_Program.Participants.btnremoveselect_Click(Object sender, EventArgs e) in E:\Documents\Visual Studio\Project Program\Project Program\Participants.vb:line 38
Any help would be appreciated. Thanks
Private Sub btnaddselect_Click(sender As Object, e As EventArgs) Handles btnaddselect.Click
If LBsearch.Items.Count > 0 Then
MsgBox(LBsearch.Text)
' PersonBindingSource.Remove(PersonBindingSource.Item(LBsearch.SelectedIndex))
LBselect.Items.Add(LBsearch.Text)
PersonBindingSource.Remove(LBsearch.SelectedItem)
' filter()
End If
End Sub
Private Sub btnremoveselect_Click(sender As Object, e As EventArgs) Handles btnremoveselect.Click
If LBselect.Items.Count > 0 Then
Try
'PersonBindingSource.Add(PersonBindingSource.Item(LBsearch.SelectedIndex))
PersonBindingSource.Add(LBselect.SelectedItem)
MsgBox(LBselect.SelectedItem.ToString())
LBselect.Items.Remove(LBselect.SelectedItem)
Catch ex As Exception
TextBox1.Text = (ex.ToString)
End Try
'filter()
End If
End Sub
A major problem with moving rows is that since they are DataRows, they will not display well in the unbound control. If you pull out something useful like a name, you will have to recreate the DataRow to return it to the original/bound/source control.
This is a problem because, now it is a new row, so a DataAdpter might add it to the database again! One way to avoid that is to clone the table. Also, if/when you move them back, they will appear at the bottom of the list and not in their original position.
There is a better way than duplicating the table data and moving anything anywhere.
Since the act of being selected can be represented with a simple Boolean, it can be coded so that the Selected ones show in one control, the unSelected ones in the other. For this, a new Selected column is needed. If possible, add one using your SQL:
' MS Access syntax
Dim SQL = "SELECT a, b, c,..., False As Selected FROM tblFoo"
This will create the new column in your datatable with all the values initialized to False. You can also add the column manually.
' form level vars
Private dvSource As DataView
Private dvDest As DataView
...
' set up:
' *** Add a column manually if you cant use SQL
dtSample.Columns.Add("Selected", GetType(Boolean))
' we need to loop and set the initial value for an added column
For Each r As DataRow In dtSample.Rows
r("Selected") = False
Next
' *** end of code for adding col manually
' when the column is added from SQL, you will need:
dtSample.Columns("Selected").ReadOnly = False
' create Source DV as Selected = False
dvSource = New DataView(dtSample,"Selected=False", "",
DataViewRowState.CurrentRows)
' create Dest DV as Selected = True
dvDest = New DataView(dtSample, "Selected=True", "",
DataViewRowState.CurrentRows)
' assign DS
lbSource.DataSource = dvSource
lbSource.DisplayMember = "Name"
lbSource.ValueMember = "Id"
lbDest.DataSource = dvDest
lbDest.DisplayMember = "Name"
lbDest.ValueMember = "Id"
Then in the click events:
' select
CType(lbSource.SelectedItem, DataRowView).Row("Selected") = True
' deselect:
CType(lbSource.SelectedItem, DataRowView).Row("Selected") = False
The two DataView objects will filter on Selected inversely. When you change the state of a row, it is instantly removed from one and appears in the other without actually being added/removed from any table (or collection or control). If you move it back to the Source it will appear in the same position as before.
In this case, the RowState of any item moved will be Modified, which of course it is (unlike the move-to-table approach where they would be new rows (Added) which they are not).
It is hard to illustrate without 5 or 6 images, but the idea:
It is actually a pretty simple method and more economical than one invovling actually moving rows. Using DataViews the rows/items look like they move to another table or control, but they do not, nor do they need to.

vb.net - click on listview subitem and open window

I'm not sure if this is possible after doing a bunch of googling, but hopefully it is. I have an application that pulls a list of information from a MySQL database and populates a listview (Unfortunately, I can't change to a datagrid at this time.) What I'm tasked to do is make it so that when clicking on a certain column, a window will open and, based on the ID of the row that was clicked on, retrieve another set of results from the same database.
The list view is created as such:
Do While result.Read()
Dim siteid = (result.Item("idsite").ToString())
Dim sitename = (result.Item("name").ToString())
Dim last_import_date = (result.Item("import_finished").ToString())
Dim last_import_file = (result.Item("file_name").ToString())
Dim last_line = (result.Item("last_line").ToString())
Dim status = (result.Item("status").ToString())
Dim lv As ListViewItem = ListView1.Items.Add(siteid)
lv.SubItems.Add(sitename)
lv.SubItems.Add(last_import_date)
lv.SubItems.Add(last_import_file)
lv.SubItems.Add(last_line)
lv.SubItems.Add(status)
Loop
So preferably I'd like to click on "Last_import_file" and have that open the window. I've tried a bunch of ItemClicked type commands, but haven't had much luck.
Is what I'm attempting possible? I don't need any special text formatting, just want to register the click and pop open the dialog.
Thanks!
Yes it is possible. To do this in a Listview it is a bit more complicated than a DataGridView. You'll need to make use of the ListViewHitTestInfo class. Using the MouseDown Event of your listview, use this code:
Private Sub ListView1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseDown
Dim info As ListViewHitTestInfo = ListView1.HitTest(e.X, e.Y)
MsgBox(info.Location.ToString())
If Not IsNothing(info.SubItem) Then
'info will contain the information of the clicked listview column. You can then go through it's subitems for more information, if any.
End If
End Sub

DataGridView losing initial state specified at design time

When I try to change the datasource of my DataGridView, I am loosing the order of the columns and their type(checkboxes,comboboxes) that i specified at design time.
It's like changing the datasource is generating again the datagridview, why ? and How can I change the datasource without losing these information ?
Please if you know give me help
Thanks in advance
On form load i do something like
Private Sub frmGrid_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim Path as string
Path="C:\......Myfile.xml"
Dim oData as dataset
oData = New DataSet
oData.ReadXml(Path)
oData.AcceptChanges()
DataGridView1.DataSource = oData
DataGridView1.DataMember = oData.Tables(0).TableName
end sub
Till now everything is fine the design mode is preserved.
Then I have in my interface I have a button to save the content of my Grid to an excel file (it's an xml, formatted for excel)
Then i want to import this, on a button action, so i do the following
Private Sub Button13_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button13.Click
Dim MyDs As DataSet
MyDs = New DataSet
Dim InputFileStream As New System.IO.FileStream(Path, System.IO.FileMode.Open)
MyDs = ImportExcelXML(InputFileStream, True, True)
MyDs.ReadXml(Path)
MyDs.AcceptChanges()
DataGridView1.DataSource = MyDs
DataGridView1.DataMember = MyDs.Tables(0).TableName
end sub
Probabily you have set up GenerateColums property to "True"
That means the GridView will generate the columns(name and number of them) againts the data sorce.
If the data source (in you case data table) are different it will come up a different grid.
If the datasource are different you can design the layout of your gridView but after that you have to manually bind the data to the columns as you wish.You can do that into
RowDataBound event.
The datatable you are trying to assign to the DataGridView1.DataSource is structured different from the way you defined the DataGridView at design time. Put a break point in your code right before you reassign the new DataTable to the DataSource and see what is different in the structure. It is most likely that you either have more or less DataColumns in place, or the columns could be in a different order. They might even be named different. If at design time you set your DataGridViewColumn's DataProperty to a specific name, than then name needs to be exact.
You'll just have to check it at that breakpoint and see what the differences are.
I found a solution, your hints helped me to look on the right direction to find a solution !
What i was doing was on form load
MaGrille.DataSource = oData
MaGrille.DataMember = oData.Tables(0).TableName
Then in the button click I do :
MaGrille.DataSource = MyDs
MaGrille.DataMember = MyDs.Tables(0).TableName
The problem is that the grid is rebuild and i loose the formatting, column order etc..
After many tests, I understood that It wasn't working because the names of datatables are differents ! I don't understand why, but it was the error as it seems.
I had the following values
oData.Tables(0) = "DECLARATION"
MyDs.Tables(0) = "Sheet1"
So I noticed that if I rename MyDs.Tables(0) by "DECLARATION" instead of "Sheet1", and i click on the button, this time I don't loose formatting, neither orders ...
This inspired me to find the SOLUTION :
After many tries, I realized that if instead of doing on form load
MaGrille.DataSource = oData
MaGrille.DataMember = oData.Tables(0).TableName
and on button click :
MaGrille.DataSource = MyDs
MaGrille.DataMember = MyDs.Tables(0).TableName
I do :
on form load
MaGrille.DataSource = oData.Tables(0)
and on button click
MaGrille.DataSource = MyDs.Tables(0)
All works fine even if the oData.Tables(0).TableName is different from MyDs.Tables(0).TableName !!
I found the solution Now, but still can't understand the WHY If anyone get an explication, please let me know.
Thanks to all again