ComboBox shows the first item when loaded into new form VB.Net - 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.

Related

TableAdapter data has changed but property "has Changes" stays at "false" so udate does nothing

It's mostly in the title...
I'm using VB (obviously, see below), but I'm a total beginner with visual studio.
Here is the test code I'm using (it is a simple test button I designed to test the problem I have in the code elsewhere):
Private Sub Test_Click(sender As Object, e As EventArgs) Handles Test.Click
Dim FDBdataset As New FDBDataSet()
Dim FDBTableAdapter As New FDBDataSetTableAdapters.T_PicturesTableAdapter
For Each row As DataRow In FDBTableAdapter.GetData()
row.BeginEdit()
If row("id").ToString = 58672.ToString Then
row.BeginEdit()
Console.Write("Previous Value = " & row("ImgFileName").ToString)
row("ImgFileName") = "Tagada"
row.EndEdit()
Console.WriteLine(", Current Row Value = " & row("ImgFileName").ToString & " - HasChanges : " & FDBdataset.HasChanges())
End If
Next
FDBTableAdapter.Update(FDBdataset)
The output in the console is:
Previous Value = Aphidecta_obliterata_58672, Current Row Value = Tagada - HasChanges : False
I don't understand what is wrong and how to correct it...
I would be very grateful for some help here !
TableAdapter seems set up correctly, and I can read from it, parse rows; display field values, etc...
Update method reports as being correctly set up by the datasource designer.
Code runs without errors but does not affect the DB content.
Why would you think that FDBdataset has any changes in it? Where are you making any changes to it? You have this:
For Each row As DataRow In FDBTableAdapter.GetData()
and GetData returns a new DataTable, so you're making change to that DataTable completely independent of FDBdataset. Use one or the other but not both.
Based on the code you have there, you don't need the DataSet. You can just use the DataTable returnd by GetData:
Dim adapter As New FDBDataSetTableAdapters.T_PicturesTableAdapter
Dim table = FDBTableAdapter.GetData()
For Each row In table
If row.id = 58672 Then
row.ImgFileName = "Tagada"
End If
Next
adapter.Update(table)
Notice that I tidied up your code a lot too. If you're going to use a typed DataSet then use it.
If you actually do need a DataSet for some reason then make the changes to it, not an unrelated DataTable:
Dim data As New FDBDataSet
Dim adapter As New FDBDataSetTableAdapters.T_PicturesTableAdapter
adapter.Fill(data)
For Each row In data.T_Pictures
If row.id = 58672 Then
row.ImgFileName = "Tagada"
End If
Next
adapter.Update(data)
That second code snippet may need some adjustments but I think it should work.
So, the moral of the story is that the Fill method populates an existing DataTable, which can be part of a DataSet but doesn't have to be, while the GetData method creates a new DataTable, populates it and returns it. That new DataTable is not part of any DataSet.

datagridview last programmatically changed cell does not get included in changedrows

VB.net app changes values in a datagridview programmatically. The values are all as they should be, but the save routine (dtShipments is the datatable that is the source for the datagridview)
Dim dtChanges As DataTable = dtShipments.getchanges()
If more than one has changed, dtChanges is always missing the last row.
In the routine that changes the cell values, I have tried DatagridView1.EndEdit and DatagridView1.CommitEdit, but the behavior is the same. I even tried adding a SendKeys.Send(vbTab) line, since hitting the tab key when making the changes manually is enough to get all the changes to show up in .GetChanges.
What am I missing?
code per request:
Private Sub btnAssign_Click(sender As Object, e As EventArgs) Handles btnAssign.Click
strModErr = "Form1_btnAssign_Click"
Dim sTruck As String = ""
Try
sTruck = Me.DataGridView2.SelectedCells(0).Value.ToString
For Each row As DataGridViewRow In DataGridView1.SelectedRows
row.Cells("Truck").Value = sTruck
Next
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
Catch ex As Exception
WriteErrorToLog(Err.Number, strModErr + " - " + Err.Description)
End Try
End Sub
Private Function SaveChanges() As Boolean
strModErr = "Form1_SaveChanges"
Dim Conn As New SqlConnection(My.Settings.SQLConnectionString)
Dim sSQL As String = "UPDATE fs_Shipments SET Truck = #Truck, Stop = #Stop WHERE SalesOrder = #SO"
Dim cmd As New SqlCommand(sSQL, Conn)
Dim sSO, sTruck As String
Dim iStop As Integer = 0
Try
DataGridView1.EndEdit()
DataGridView1.ClearSelection()
Dim dtChanges As DataTable = dtShipments.getchanges() 'DataRowState.Modified
If Not dtChanges Is Nothing Then
Conn.Open()
For Each row As DataRow In dtChanges.Rows
sSO = row("SalesOrder").ToString
sTruck = row("Truck").ToString
iStop = CInt(row("Stop").ToString)
With cmd.Parameters
.Clear()
.AddWithValue("#SO", sSO)
.AddWithValue("#Truck", sTruck)
.AddWithValue("#Stop", iStop)
End With
cmd.ExecuteNonQuery()
Next
End If
Return True
Catch ex As Exception
WriteErrorToLog(Err.Number, strModErr + " - " + Err.Description)
Return False
End Try
End Function
I am not exactly 100% sure why this happens. The problem appears to be specific to when the user “selects” the cells in the first grid, and then calls the SaveChanges code “BEFORE” the user has made another selection in the first grid. In other words, if the user “selects” the rows to “assign” the truck to in grid 1, then, “AFTER” the “selected” cells have been filled with the selected truck, THEN, the user selects some other cell in grid 1, THEN calls the save changes code. In that case the code works as expected.
All my attempts at committing the changes, either failed or introduced other issues. I am confident a lot of this has to do with the grids SelectedRows collection. IMHO, this looks like a risky way to set the cell values, I would think a more user-friendly approach may be to add a check box on each row and assign the truck values to the rows that are checked. But this is an opinion.
Anyway, after multiple attempts, the solution I came up with only further demonstrates why using a BindingSource is useful in many ways. In this case, it appears the DataTable is not getting updated with the last cell change. Again, I am not sure “why” this is, however since it appears to work using a BindingSource, I can only assume it has something to do with the DataTable itself. In other words, before the “Save” code is executed, we could call the tables AcceptChanges method, but then we would lose those changes. So that is not an option.
To help, below is a full (no-fluff) example. In the future, I highly recommend you pull out the parts of the code that do NOT pertain to the question. Example, all the code that saves the changes to the DB is superfluous in relation to the question… so remove it. The more unnecessary code you add to your question only increases the number of SO users that will “ignore” the question. If you post minimal, complete and working code that reproduces the problem so that users can simply copy and paste without having to add addition code or remove unnecessary code will increase you chances of getting a good answer. Just a heads up for the future.
The solution below simply adds a BindingSource. The BindingSource’s DataSource is the DataTable dtShipments then the BindingSource is used a DataSource to DataGridView1. Then in the SaveChanges method, “before” the code calls the dtShipment.GetChanges() method, we will call the BindingSources.ResetBinding() method which should complete the edits to the underlying data source, in this case the DataTable dtShipments.
If you create a new VS-VB winforms solution, drop two (2) grids and two (2) buttons onto the form as shown below, then change the button names to “btnAssign” and “btnApplyChanges.” The assign button will add the selected truck in grid two to the selected rows in grid one. The apply changes button simply resets the binding source and displays a message box with the number of rows that were changed in the dtShipments DataTable. It should be noted, that the code calls the dtShipments.AcceptChanges() method to clear the changes. Otherwise, the code will update changes that have already been made.
Dim dtShipments As DataTable
Dim dtTrucks As DataTable
Dim shipBS As BindingSource
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtShipments = GetShipmentsDT()
shipBS = New BindingSource()
shipBS.DataSource = dtShipments
dtTrucks = GetTrucksDT()
dtShipments.AcceptChanges()
DataGridView1.DataSource = shipBS
DataGridView2.DataSource = dtTrucks
End Sub
Private Function GetShipmentsDT() As DataTable
Dim dt = New DataTable()
dt.Columns.Add("ID", GetType(String))
dt.Columns.Add("Truck", GetType(String))
dt.Rows.Add(1)
dt.Rows.Add(2)
dt.Rows.Add(3)
dt.Rows.Add(4)
Return dt
End Function
Private Function GetTrucksDT() As DataTable
Dim dt = New DataTable()
dt.Columns.Add("Truck", GetType(String))
For index = 1 To 10
dt.Rows.Add("Truck" + index.ToString())
Next
Return dt
End Function
Private Sub btnAssign_Click(sender As Object, e As EventArgs) Handles btnAssign.Click
Dim sTruck = DataGridView2.SelectedCells(0).Value.ToString
'Dim drv As DataRowView
For Each row As DataGridViewRow In DataGridView1.SelectedRows
'drv = row.DataBoundItem
'drv("Truck") = sTruck
row.Cells("Truck").Value = sTruck
Next
'DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
'shipBS.ResetBindings(True)
'DataGridView1.CurrentCell = DataGridView1.Rows(0).Cells(0)
End Sub
Private Function SaveChanges() As Boolean
Try
shipBS.ResetBindings(True)
Dim dtChanges As DataTable = dtShipments.GetChanges()
If (dtChanges IsNot Nothing) Then
MessageBox.Show("There are " & dtChanges.Rows.Count & " rows changed in the data table")
' update sql DB
dtShipments.AcceptChanges()
End If
Return True
Catch ex As Exception
Return False
End Try
End Function
Private Sub btnApplyChanges_Click(sender As Object, e As EventArgs) Handles btnApplyChanges.Click
Dim ChangesMade As Boolean
ChangesMade = SaveChanges()
End Sub
Lastly, since you are using VB… I highly recommend that you set the “Strict” option to “ON.” When this option is ON, it will flag possible errors that you may be missing. To do this for all future VB solutions, open VS, close any solutions that may be open, then go to Tools->Options->Projects and Solutions->VB Defaults, then set “Option Strict” to “On.” The default setting is off.
I hope this makes sense and helps.

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.

combobox recalling previous datasource

Looking for some insight here...
On my form, I have three ComboBox controls. When the left most receives a selection, it calls a routine to enable and populate the 2nd, then the same happens for the 3rd when a selection is made in the 2nd.
Private Sub cboEquipment_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles cboEquipment.SelectedIndexChanged
Me.transData.isMobile = If(Me.cboEquipment.Text = MOBIEQIP, 1, 0)
If cboMembership.Enabled = False Then
Me.cboMembership.Enabled = True
End If
Call loadGroups()
End Sub
The method 'loadGroups'
Private Sub loadGroups()
Dim cn As New SqlConnection(My.Settings.MyConnectionString)
Dim cm As New SqlCommand("SELECT ... ORDER BY codeHumanName ASC", cn)
Dim ta As New SqlDataAdapter(cm)
Dim dt As New DataTable
Me.cboMembership.DataSource = Nothing
Me.cboMembership.Items.Clear()
Me.transData.membership = Nothing
cn.Open()
ta.Fill(dt)
With Me.cboMembership
.DataSource = dt
.DisplayMember = "codeHumanName"
.ValueMember = "codeID"
End With
cn.Close()
End Sub
This works fine an dandy, everything loads at should, and provides the appropriate .ValueMember results.
I should mention that when the Form first loads, boxes 2 and 3 are empty and disabled. After their initial load, I have to select an item from the list to get values (as expected).
The odd part is that once the 2nd or 3rd Combobox have been 'initialized', they seem to recall last settings. For example, if I call the Reset method, which sets the .DataSource property to Nothing, clear the list, and set the Text to Nothing; the next time I change the SelectedIndex on cboEquipment, the other boxes come back to life with SelectedItems and SelectedValues.
These values aren't wrong according to the new DataTable, but it is odd that they remember at all (they shouldn't have any reference, and behave as a fresh load).
Other points of interest; the populate methods are called during the SelectedIndexChanged event.
Any thoughts would be great!
UPDATE -
This behavior is tied in with the SelectedIndexChange Event bouncing around (raise! raise! raise!)
Removing and adding event handlers at strategic points has my code working as I want/expect it to.
Here is the article that put me on the right path...
On your second and third combo boxes try clearing the .Text/.SelectedText properties before you set the .DataTable
The combo box is probably just being too helpful and assuming that when you set the .DataTable a second time, you'd want the selected item to match your .Text property.
I ended up using AddHandler and RemoveHandler to prevent chain-firing events as the comboboxes were being populated.

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