Databinding one control per row in the same datasource - vb.net

I've been trying to deal with a frustrating issue with regards to databinding in Winforms.
I have a data source, which is a DataTable in a DataSet. This DataTable has three rows. I have three CheckBox controls on my form, and a Button. I want to bind each CheckBox to one row in this data source, and have the data source reflect the value in the Checked property whenever the CheckBox is updated. I also want these changes to be correctly picked up by calls to HasChanges() and calls to GetChanges().
When the Button is clicked, EndCurrentEdit() is called and passed the data-source that was bound to, and the DataSet is checked for changes using the HasChanges() method.
However, in my attempts to do this, I encounter one of two scenarios after the call to EndCurrentEdit().
In the first scenario, only the first CheckBox has its changes detected. In the second scenario, all other CheckBoxes are updated to the value of the CheckBox that was last checked on the call to EndCurrentEdit().
In looking at the RowState values after the call to EndCurrentEdit(), in Scenario 1, only the first row ever has a state of Modified. In Scenario 2, only the third row ever has a state of Modified. For Scenario 2, it doesn't matter whether the user updated the third CheckBox or not.
To demonstrate my problem, I have created a simple example which demonstrates it.
It's a stock Windows form containing three CheckBox controls and a Button control, all with their default names.
Option Strict On
Option Explicit On
Public Class Form1
Public ds As DataSet
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
ds = New DataSet()
Dim dt As New DataTable()
dt.Columns.Add("ID", GetType(Integer))
dt.Columns.Add("Selected", GetType(Boolean))
dt.Rows.Add(1, False)
dt.Rows.Add(2, False)
dt.Rows.Add(3, False)
dt.TableName = "Table1"
ds.Tables.Add(dt)
ds.AcceptChanges()
For i As Integer = 1 To 3
Dim bs As New BindingSource()
'After the call to Me.BindingContext(ds.Tables("Table1")).EndCurrentEdit() there are two scenarios:
'Scenario 1 - only changes to the first CheckBox are detected.
'Scenario 2 - when any CheckBox is checked, they all become checked.
'Uncomment the first and comment out the second to see Scenario 1.
'Uncomment the second and comment out the first to see Scenario 2.
'bs.DataSource = New DataView(ds.Tables("Table1")) 'Scenario 1
bs.DataSource = ds.Tables("Table1") 'Scenario 2
bs.Filter = "ID=" & i
Dim db As New Binding("Checked", bs, "Selected")
db.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
If i = 1
CheckBox1.DataBindings.Add(db)
ElseIf i = 2
CheckBox2.DataBindings.Add(db)
ElseIf i = 3
CheckBox3.DataBindings.Add(db)
End If
Next
End Sub
Private Sub Button1_Click( sender As Object, e As EventArgs) Handles Button1.Click
Me.BindingContext(ds.Tables("Table1")).EndCurrentEdit()
If ds.HasChanges()
MessageBox.Show("Number of rows changed: " & ds.GetChanges().Tables("Table1").Rows.Count)
ds.AcceptChanges()
End If
End Sub
End Class
I've done a lot of searching but haven't been able to work out what's happening, and am thus at a complete loss. It feels like what I'm trying to do is pretty simple, but I suspect that I must have misunderstood something somewhere or missed something important with regards to the binding process.
EDIT
It's already in the second paragraph, but just to make it clear, here is the basic outline of what I'm trying to do:
I have a DataSet containing a DataTable with values. For this example, there's two columns. ID could be any Integer, 'Selected' could be any Boolean value. None of these will ever be Nothing or DBNull.
I want to bind each row to ONE Checkbox control. One CheckBox per ID value. The Checked property should be bound to the Selected column in the DataTable.
When changes are made, and the user clicks the Button, I want to be able to tell what changes the user made, using the HasChanges() and GetChanges() methods of the DataSet (ie 2 rows updated if the user has changed the Checked property of two of the Checkbox controls).
EDIT 2
Thanks to #RezaAghaei I have come up with a solution. I have refined the code from my example of the problem, and made all controls generate based on the data (and position themselves accordingly) to make this example simple to copy-and-paste. Also, this uses a RowFilter on the DataView, rather than the Position property of the BindingSource.
Option Strict On
Option Explicit On
Public Class Form1
Public ds As DataSet
Private Sub Form1_Load( sender As Object, e As EventArgs) Handles MyBase.Load
ds = New DataSet()
Dim dt As New DataTable()
dt.Columns.Add("ID", GetType(Integer))
dt.Columns.Add("Selected", GetType(Boolean))
dt.Rows.Add(1, False)
dt.Rows.Add(2, False)
dt.Rows.Add(3, False)
dt.TableName = "Table1"
ds.Tables.Add(dt)
ds.AcceptChanges()
AddHandler dt.ColumnChanged, Sub(sender2 As Object, e2 As DataColumnChangeEventArgs)
e2.Row.EndEdit()
End Sub
For i As Integer = 0 To dt.Rows.Count-1
Dim cb As New CheckBox() With {.Text = "CheckBox" & i+1, .Location = New Point(10, 25 * (i))}
Dim dv As New DataView(dt)
dv.RowFilter = "ID=" & DirectCast(dt.Rows(i)(0), Integer)
Dim bs As New BindingSource(dv, Nothing)
Dim db As New Binding("Checked", bs, "Selected")
db.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
cb.DataBindings.Add(db)
Me.Controls.Add(cb)
Next
Dim btn As New Button()
btn.Location = New Point(10, 30 * dt.Rows.Count)
btn.Text = "Submit"
AddHandler btn.Click, AddressOf Button1_Click
Me.Controls.Add(btn)
End Sub
Private Sub Button1_Click( sender As Object, e As EventArgs)
'Me.BindingContext(ds.Tables("Table1")).EndCurrentEdit() 'Doesn't cut the mustard!
If ds.HasChanges()
MessageBox.Show("Number of rows changed: " & ds.GetChanges().Tables("Table1").Rows.Count)
ds.AcceptChanges()
Else
MessageBox.Show("Number of rows changed: 0")
End If
End Sub
End Class
The key is the call to EndEdit() in the ColumnChanged event for DataTable (a general call to EndCurrentEdit() just doesn't appear to cut it), although one additional problem I encountered was that this code won't work if it's in the form's New() method, even if it's after the call to InitializeComponent(). I'm guessing this is because there's some initialisation that Winforms does after the call to New() which is necessary for data binding to work properly.
I hope this example saves others the time I spent looking into this.

Consider these corrections and the problem will be solved:
To bind a control to an specific index of a list, bind control to a binding source containing the list, and then set the Position of binding source to the specifixindex.
When adding data-binding to CheckBox controls, set update mode to OnPropertyChanged.
Handle CheckedChanged event of CheckBox controls and call Invalidate method of grid to show changes in grid.
In CheckedChanged also call EndEdit of the BindingSource which the CheckBox is bound to.
Note: Call EndEdit usnig BeginInvoke to let all processes of checking the checkbox (including updating data source) be completed.
C# Example
DataTable dt = new DataTable();
private void Form3_Load(object sender, EventArgs e)
{
dt.Columns.Add("Id");
dt.Columns.Add("Selected", typeof(bool));
dt.Rows.Add("1", true);
dt.Rows.Add("2", false);
dt.Rows.Add("3", true);
this.dataGridView1.DataSource = dt;
var chekBoxes = new CheckBox[] { checkBox1, checkBox2, checkBox3 };
for (int i = 0; i < dt.Rows.Count; i++)
{
var bs = new BindingSource(dt, null);
chekBoxes[i].DataBindings.Add("Checked", bs, "Selected",
true, DataSourceUpdateMode.OnPropertyChanged);
chekBoxes[i].CheckedChanged += (obj, arg) =>
{
this.dataGridView1.Invalidate();
var c = (CheckBox)obj;
var b = (BindingSource)(c.DataBindings[0].DataSource);
this.BeginInvoke(()=>{b.EndEdit();});
};
bs.Position = i;
}
}
VB Example
Dim dt As DataTable = New DataTable()
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
dt.Columns.Add("Id")
dt.Columns.Add("Selected", GetType(Boolean))
dt.Rows.Add("1", True)
dt.Rows.Add("2", False)
dt.Rows.Add("3", True)
dt.AcceptChanges()
Me.DataGridView1.DataSource = dt
Dim chekBoxes = New CheckBox() {CheckBox1, CheckBox2, CheckBox3}
For i = 0 To dt.Rows.Count - 1
Dim bs = New BindingSource(dt, Nothing)
chekBoxes(i).DataBindings.Add("Checked", bs, "Selected", _
True, DataSourceUpdateMode.OnPropertyChanged)
AddHandler chekBoxes(i).CheckedChanged, _
Sub(obj, arg)
Me.DataGridView1.Invalidate()
Dim c = DirectCast(obj, CheckBox)
Dim b = DirectCast(c.DataBindings(0).DataSource, BindingSource)
Me.BeginInvoke(Sub() b.EndEdit())
End Sub
bs.Position = i
Next i
End Sub

Related

Add data into new added row in `DataGridView` from `DataBindingSource`

In Form4 i have a DataGridView named DbTableDataGridView.
In Form3 there is a set of fields (text boxes) that are all bound to the DbTableBindingSource . When I run application the Form4 shows up. There is a button to open new form (Form3) and in there enter details about customers to be added as new row into database (DataGridView). My code for the "Add" button in Form4 looks like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.DbTableDataGridView.Refresh()
Me.DbTableBindingSource.AddNew()
Form3.ShowDialog()
Form3.ImiéTextBox.Text = ""
Form3.NazwiskoTextBox.Text = ""
Form3.Numer_TelefonuTextBox.Text = ""
Form3.Numer_RejestracyjnyTextBox.Text = ""
Form3.MarkaTextBox.Text = ""
Form3.ModelTextBox.Text = ""
Form3.Poj_SilnikaTextBox.Text = ""
Form3.RocznikTextBox.Text = ""
Form3.PaliwoTextBox.Text = ""
Form3.Data_PrzyjeciaDateTimePicker.Value = DateTime.Now
Form3.RichTextBox1.Text = ""
End Sub
It does add new row, selects it and clears entries in the text boxes (that are bound into 'DbTableBindingSource'.
In this form after I fill in all the fields I press button save:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
Me.Validate()
Form4.DbTableBindingSource.EndEdit()
Me.DbTableTableAdapter.Update(CartronicDBDataSet.dbTable)
TableAdapterManager.UpdateAll(CartronicDBDataSet)
DbTableTableAdapter.Fill(Form4.CartronicDBDataSet.dbTable)
MsgBox("Saved")
Catch ex As Exception
MessageBox.Show("Blad zapisu. Sprobuj ponownie. W razie potrzeby zamknij, a nastepnie uruchom ponownie program Cartronic")
End Try
End Sub
It goes to the message "Saved" but actually does not fill in added new recently.
Any thoughts?
There is no link that I can see between Form3 and your data.
I'd recommend passing the newly created data row to a new instance of Form3.
Get the reference to your newly added row
Create a new Form3 (avoid default instance forms, they're ugly and evil). This will mean you don't need to clear the textboxes as you have a brand new form every time.
Pass the datarow into your form where you will bind it directly to the textboxes
Dim newRow = CType(Me.DbTableBindingSource.AddNew(), DataRow)
Using frmEditor As New Form3
frmEditor.DataSource = newRow
frmEditor.ShowDialog()
End Using
In form3 add the property (or preferably a constructor)
Private mDataSource As DataRow
Public Property DataSource As DataRow
Get
Return mDataSource
End Get
Set(value As DataRow)
mDataSource = value
Me.ImiéTextBox.DataBindings.Add("Text", mDataSource, "ImiéFieldName")
' ....
End Set
End Property
If you use this approach then you can get rid of all of the textbox clearing code.
I have done what you have suggested but little bit simpler.
Assigned all text boxes to each cell in current row as follows:
Form4.DbTableDataGridView.CurrentRow.Cells(5).Value = Me.NazwiskoTextBox.Text.ToString
Form4.DbTableDataGridView.CurrentRow.Cells(4).Value = Me.ImiéTextBox.Text.ToString
It works fine.
Cheers

How do I add a new row to a binding source

I am trying to programmatically add a new row to a binding source . I know calling the bsSource.AddNew() adds a new row which I cast as a DataRowView and I set my values. My problem is this - the DataRowView.Row shows a RowState of detached. I do not want it to be detached ; I believe it should show added - I also do NOT want it to commit the change to the database (There is a very valid reason for this). I want to pick the time for that later.
My code is as follows:
private Sub AddToRelationSource(binID As Integer, gradeID As Integer, IsChecked As Boolean)
Dim drv As DataRowView = DirectCast(bsBinGrades.AddNew(), DataRowView)
drv.Row("IsSelected") = IsChecked
drv.Row("BinID") = binID
drv.Row("GradeID") = gradeID
' I tried drv.EmdEdit(0 drv.Row.EndEdit() - Row State still shows detached
End Sub
The BindingSource AddNew method does not actually add a new record to the underlying datasource , it simply adds it to the bindingsource as a detached item. When using the datatabel as a datasource I needed to get the datatable and use the AddRow() method - this properly set the value in my bindingsource to added so that when the changes would be committed to the database on bindingsource.Update() method.
The code I used:
Dim drv As DataRowView = DirectCast(bsData.AddNew(), DataRowView)
drv.BeginEdit()
drv.Row.BeginEdit()
drv.Row("IsSelected") = IsChecked
drv.Row.EndEdit()
drv.DataView.Table.Rows.Add(drv.Row)
The last line is what actually added the item to the datasource - I misunderstood BindingSource.AddNew() .
The following may be in the right direction. First I used a few language extension methods e.g.
Public Module BindingSourceExtensions
<Runtime.CompilerServices.Extension()>
Public Function DataTable(ByVal sender As BindingSource) As DataTable
Return CType(sender.DataSource, DataTable)
End Function
<Runtime.CompilerServices.Extension()>
Public Sub AddCustomer(ByVal sender As BindingSource, ByVal FirstName As String, ByVal LastName As String)
sender.DataTable.Rows.Add(New Object() {Nothing, FirstName, LastName})
End Sub
<Runtime.CompilerServices.Extension()>
Public Function DetachedTable(ByVal sender As BindingSource) As DataTable
Return CType(sender.DataSource, DataTable).GetChanges(DataRowState.Detached)
End Function
<Runtime.CompilerServices.Extension()>
Public Function AddedTable(ByVal sender As BindingSource) As DataTable
Return CType(sender.DataSource, DataTable).GetChanges(DataRowState.Added)
End Function
End Module
Now load ID, FirstName and LastName into a DataTable, Datatable becomes the DataSource of a BindingSource which is the BindingSource for a BindingNavigator and are wired up to a DataGridView.
Keeping things simple I mocked up data, has no assertions e.g. make sure we have valid first and last name, instead concentrate on the methods.
First use a extension method to add a row to the underlying DataTable of the BindingSource.
bsCustomers.AddCustomer("Karen", "Payne")
Now check to see if there are detached or added rows
Dim detachedTable As DataTable = bsCustomers.DetachedTable
If detachedTable IsNot Nothing Then
Console.WriteLine("Has detached")
Else
Console.WriteLine("No detached")
End If
Dim AddedTable As DataTable = bsCustomers.AddedTable
If AddedTable IsNot Nothing Then
Console.WriteLine("Has added")
Else
Console.WriteLine("None added")
End If
Since we are not talking to the database table, the primary key is not updated as expected and since you don't want to update the database table this is fine. Of course there is a method to get the primary key for newly added records if you desire later in your project.
Addition
Private Sub BindingSource1_AddingNew(ByVal sender As System.Object, ByVal e As System.ComponentModel.AddingNewEventArgs) Handles BindingSource1.AddingNew
Dim drv As DataRowView = DirectCast(BindingSource1.List, DataView).AddNew()
drv.Row.Item(0) = "some value"
e.NewObject = drv
' move to new record
'BindingSource1.MoveLast()
End Sub
'This routine takes the AddForm with the various fields that the user
'fills in and calls the TableAdapter's Insert method.
'After that is done, then the table has be be reflected back to the
'various components.
Private Sub AddRecord()
'The following line did not work because I could not get
'the bs definition down.
'Tried the BindingSource but in gave an error on
'DataRowView so I came up with an alternate way of
'adding the row.
'Dim drv As DataRowView = DirectCast(bsData.AddNew(), DataRowView)
'Dim drv As DataRowView = DirectCast(RecTableBindingSource.AddNew(), DataRowView)
'drv.BeginEdit()
'drv.Row.BeginEdit()
'drv.Row("Title") = "Order, The"
'drv.Row.EndEdit()
'drv.DataView.Table.Rows.Add(drv.Row)
RecTableTableAdapter.Insert(pAddForm.tTitle.Text,
pAddForm.tCast.Text,
pAddForm.tAKA.Text,
pAddForm.tRelated.Text,
pAddForm.tGenre.Text,
pAddForm.tRated.Text,
pAddForm.tRelease.Text,
pAddForm.tLength.Text)
Validate()
RecTableBindingSource.EndEdit()
RecTableTableAdapter.Update(VideoDBDataSet.RecTable)
RecTableAdapterManager.UpdateAll(VideoDBDataSet)
RecTableTableAdapter.Fill(VideoDBDataSet.RecTable)
VideoDBDataSet.AcceptChanges()
End Sub
'Here is my Delete Record routine
Private Sub DeleteRecordToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles DeleteRecordToolStripMenuItem.Click
Dim RowIndex As Int32
If (dgvRec.SelectedRows.Count > 0) Then
RowIndex = dgvRec.SelectedRows(0).Index
'Now we have to delete the record
dgvRec.Rows.RemoveAt(RowIndex)
dgvRec.CommitEdit(RowIndex)
dgvRec.EndEdit()
Validate()
RecTableBindingSource.EndEdit()
RecTableTableAdapter.Update(VideoDBDataSet.RecTable)
RecTableAdapterManager.UpdateAll(VideoDBDataSet)
RecTableTableAdapter.Fill(VideoDBDataSet.RecTable)
VideoDBDataSet.AcceptChanges()
Else
'No row selected to work with
End If
End Sub
'The pAddForm MUST be open for this routine to work
Private Sub UpdateGridFromForm()
Dim RowIndex As Int32
Dim Index As Int32
Dim RecIndex As Int32
Dim dt As DataTable
If ((pAddForm Is Nothing) = False) Then
RowIndex = pAddForm.GridIndex
If (RowIndex >= 0) Then
Index = pAddForm.Index
If (Index = dgvRec.Rows(RowIndex).Cells(constRecGridColIndex).Value) Then
'OK, we have a match so we are good to go
Call PopulateGridFields(RowIndex)
Else
MsgBox("Unable to save data back to the Grid because the record is no longer the same")
End If
Else
'This must be a NEW record
Call AddRecord()
End If
Else
'No form to work with
End If
End Sub
'Populate the dgvRec fields from pAddForm
Private Sub PopulateGridFields(RowIndex As Int32)
dgvRec.Rows(RowIndex).Cells(constRecGridTitle).Value = pAddForm.tTitle.Text
dgvRec.Rows(RowIndex).Cells(constRecGridCast).Value = pAddForm.tCast.Text
dgvRec.Rows(RowIndex).Cells(constRecGridAKA).Value = pAddForm.tAKA.Text
dgvRec.Rows(RowIndex).Cells(constRecGridRelated).Value = pAddForm.tRelated.Text
dgvRec.Rows(RowIndex).Cells(constRecGridGenre).Value = pAddForm.tGenre.Text
dgvRec.Rows(RowIndex).Cells(constRecGridRated).Value = pAddForm.tRated.Text
dgvRec.Rows(RowIndex).Cells(constRecGridRelease).Value = pAddForm.tRelease.Text
dgvRec.Rows(RowIndex).Cells(constRecGridLength).Value = pAddForm.tLength.Text
dgvRec.CommitEdit(RowIndex)
dgvRec.EndEdit()
Validate()
RecTableBindingSource.EndEdit()
RecTableTableAdapter.Update(VideoDBDataSet.RecTable)
RecTableAdapterManager.UpdateAll(VideoDBDataSet)
RecTableTableAdapter.Fill(VideoDBDataSet.RecTable)
VideoDBDataSet.AcceptChanges()
End Sub
'This all works great.
'The only problem I have now is that the DataGridView will
'always'Repopulate the grid (including any changes with 'Add/Delete/Modify) sending the active
'row back to the top of the grid
'I will work on a solution to this now that I have the rest working

Making a Datatable's content appear in a DataGridView

I am continuing my rewrite of an old VB6 into .Net as part of my .Net learning. I have managed to read a CSV file into a Datatable, and I can view it has populated properly using the 'datatable visualiser' when I look at 'dt', but it doesn't seem to populate the DataGridView control I am trying to tie it to. I have spent a couple of hours browsing other threads and trying things, but I cannot see what I am doing wrong. The DataGridView is on another form in the App, and I am reading the CSV file (a config file of sorts) from the main MDI form. When I show the child form containing the DataGridView it is always empty (it actually seems to have added the two datatable rows, but their content is all blank).
Public dt As New DataTable
Public ThisFilename As String = "c:\SitesDB.cfg"
Private Sub GetSitesDB()
Dim sr As New IO.StreamReader(ThisFilename)
Dim newline() As String = sr.ReadLine.Split(","c)
dt.Columns.AddRange({New DataColumn(newline(0)), New DataColumn(newline(1)), New DataColumn(newline(2)), New DataColumn(newline(3)),
New DataColumn(newline(4)), New DataColumn(newline(5)), New DataColumn(newline(6)), New DataColumn(newline(7)), New DataColumn(newline(8)),
New DataColumn(newline(9)), New DataColumn(newline(10)), New DataColumn(newline(11))})
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(","c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1), newline(2), newline(3), newline(4), newline(5), newline(6), newline(7), newline(8), newline(9), newline(10), newline(11)}
dt.Rows.Add(newrow)
End While
Form1.DataGridView1.DataSource = dt ' data can be seen here using datatable visualiser hovering over 'dt'
End Sub
Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click
Form1.Show()
End Sub
I have tried refreshing the DataGridView, to no avail. I am wondering if its something to do with Form1.Show() being actioned after the datatable is tied to the DataGridView?
But the following didn't help
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' chkBit.Checked = False
' Dim cfgtext As String : cfgtext = ""
DataGridView1.DataSource = NAMS.dt
End Sub

DataGridView is not showing first row after removing other rows

I am having a problem that I have been debugging for some days.
Some context, I have an application where I store the data (in the following code a list of class Expediente) in xml files using serialization. For displaying the data I deserialize it and then I create a datatable which I use as the datasource for the datagrid. I added a datagridcheckbox column to check the ones to delete.
In the datagrid I have a toolstrip button that when clicked it removes the checked -or checked in edit mode thus the line CType(dgvr.Cells(0).GetEditedFormattedValue(dgvr.Index, DataGridViewDataErrorContexts.Commit), Boolean) = True- elements from the datasource and persists the datasource to an xml.
The problem is that when deserializing the xml and loading it again to a datatable and binding the datagrid datasource to it, it removes the first row. If I close the application and open it, the first row appears.
I have debuged and in the datatable the correct numbers of rows appear. Moreover, I have narrowed the problem to the binding navigator, when it sets its binding source to the datable there the first row of the datagrid disappears.
I paste a simplified version of the code, I can provide more if needed.
Note that if in LoadGridExpedientes() I comment the lines
navExpedientes.BindingSource = Nothing
navExpedientes.BindingSource = bs
The first row doesn't disappear but obviously the counter of the binding navigator does not update.
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim chk As New DataGridViewCheckBoxColumn()
grdExpedientes.Columns.Add(chk)
chk.HeaderText = ""
chk.Name = "chk"
'fills a datatable from an xml, it works ok, it fills it with the correct amount of rows
Dim dt As DataTable = Sistema.getInstance.getDataExpedienteForGrid()
Dim bs As New BindingSource
bs.DataSource = dt
grdExpedientes.DataSource = bs
navExpedientes.BindingSource = bs
For i As Integer = 0 To grdExpedientes.Rows.Count - 2
grdExpedientes.Rows(i).Cells(0).Value = True
Next
End Sub
Private Sub LoadGridExpedientes()
grdExpedientes.DataSource = Nothing
navExpedientes.BindingSource = Nothing
grdExpedientes.Columns.Clear()
grdExpedientes.Rows.Clear()
'This is to know if there is already the checkbox column
If Not (grdExpedientes.Columns.Count > 0 AndAlso grdExpedientes.Columns(0).Name = "chk") Then
Dim chk As New DataGridViewCheckBoxColumn()
grdExpedientes.Columns.Add(chk)
chk.HeaderText = ""
chk.Name = "chk"
End If
Dim dt As DataTable = Sistema.getInstance.getDataExpedienteForGrid()
Dim bs As New BindingSource
bs.DataSource = dt
grdExpedientes.DataSource = bs
navExpedientes.BindingSource = bs
End Sub
Private Sub navExpedientesDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles navExpedientesDelete.Click
For i As Integer = 0 To grdExpedientes.Rows.Count - 2
Dim dgvr As DataGridViewRow = grdExpedientes.Rows(i)
If CType(dgvr.Cells(0).Value, Boolean) = True Or _
CType(dgvr.Cells(0).GetEditedFormattedValue(dgvr.Index, DataGridViewDataErrorContexts.Commit), Boolean) = True Then
Dim draux As DataGridViewRow = dgvr
Dim expABorrar As Expediente = CType((From elem As Expediente In Sistema.listExpedientes
Where elem.Expediente = CType(draux.Cells("Expediente (Ficha)").Value, String)
Select elem).FirstOrDefault, Expediente)
Sistema.listExpedientes.Remove(expABorrar)
End If
Next
If System.IO.File.Exists(Sistema.pathListExpedientes) Then
System.IO.File.Delete(Sistema.pathListExpedientes)
End If
Dim sw As System.IO.TextWriter = New System.IO.StreamWriter(Sistema.rutaListaExpedientes, 0)
Serializer(Of Expediente).Serialize(Sistema.listExpedientes, sw, New List(Of Type) From {GetType(Movimiento)})
sw.Close()
LoadGridExpedientes()
End Sub
The problem was that I was using the delete toolstrip button that comes with the binding navigator, it seems that when clicked it has 'embedded' that it deletes the row that was selected that by default is the first one.
I created a new toolstrip button in the binding navigator and the problem was solved. I do not know why not updating the binding navigator binding source also avoided the first row from being removed.

vb.net combobox population getting index of the 1st combobox

I populated my combobox1 with this code in load
sql = "select name1,id1 from table1"
da = New Odbc.OdbcDataAdapter(sql, con)
da.Fill(ds, "cbtbl1")
ComboBox1.DataSource = ds.Tables("cbtbl1")
ComboBox1.DisplayMember = ds.Tables("cbtbl1").Columns("name1").Caption
I have my 2nd combobox2 related to combobox1. I inserted this code in combobox1 selectedvaluechanged. This to change to value of combobox2 based on their related ids
sql = "select name2,id2 from table2 where id1=" & ???????
da = New Odbc.OdbcDataAdapter(sql, con)
da.Fill(ds, "cbtbl2")
ComboBox2.DataSource = ds.Tables("cbtbl2")
ComboBox2.DisplayMember = ds.Tables("cbtbl2").Columns("name2").Caption
In my code i have question marks. It supposed to be the id of table1 which i don't know how to get :( or what to put
You should set the ValueMember of Combobox1 to be the ID you retrieved from the database and the use the SelectedValue property to retrieve the ID of the selected item.
I don't think it's gonna work unless you specify the ValueMember property when you databind Combobox1, so don't forget to do that first.
OK, I knocked something together quickly with a database I am working on at the moment (it's OLEDB, but shouldn't matter for this)
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Dim ds As New DataSet()
Dim test As New OleDbDataAdapter("SELECT [ID], [名前] FROM [Tレイヤ管理]", DBConnections.PrimaryAccessDBConnection)
Call test.Fill(ds, "testTable")
Me.ComboBox1.DataSource = ds.Tables("testTable")
Me.ComboBox1.ValueMember = "ID"
Me.ComboBox1.DisplayMember = "名前"
AddHandler Me.ComboBox1.SelectedValueChanged, AddressOf Something
End Sub
Private Sub Something(sender As Object, e As EventArgs)
Call MessageBox.Show(String.Format("ID {0}", Me.ComboBox1.SelectedValue))
End Sub
I get the ID showing just fine with this.
UPDATE:
If this still doesn't work then you can get the selected item this way:
Private Sub Something(sender As Object, e As EventArgs)
Dim selectedItem As DataRowView = CType(Me.ComboBox1.SelectedItem, DataRowView)
Call MessageBox.Show(String.Format("ID {0} Name {1}", New Object() {selectedItem("ID"), selectedItem("名前")}))
End Sub